diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
index 7a79b28b09aa..4dfa55a79231 100644
--- a/.github/CODEOWNERS
+++ b/.github/CODEOWNERS
@@ -24,9 +24,8 @@
/tools/docker/ @Fira
/Dockerfile @Fira
-# MorrowWolf
+# Zonespace
-/maps/map_files/LV522_Chances_Claim/LV522_Chances_Claim.dmm @morrowwolf
-/code/modules/gear_presets/survivors.dm @morrowwolf
+/code/modules/gear_presets/survivors.dm @zonespace27
# MULTIPLE OWNERS
diff --git a/.github/ISSUE_TEMPLATE/bug_report.yml b/.github/ISSUE_TEMPLATE/bug_report.yml
index 49eda07616c2..5eb8f0219e73 100644
--- a/.github/ISSUE_TEMPLATE/bug_report.yml
+++ b/.github/ISSUE_TEMPLATE/bug_report.yml
@@ -10,6 +10,12 @@ body:
placeholder: "#1, #2, #3, etc"
validations:
required: true
+ - type: input
+ id: round-id
+ attributes:
+ label: Round ID
+ description: If known, what was the Round ID this bug was found on? Can be left blank if unknown or occured across multiple rounds.
+ placeholder: "12345"
- type: textarea
id: what-happened
attributes:
diff --git a/.github/workflows/ci_suite.yml b/.github/workflows/ci_suite.yml
index 683f3909b447..0488055312f7 100644
--- a/.github/workflows/ci_suite.yml
+++ b/.github/workflows/ci_suite.yml
@@ -60,6 +60,34 @@ jobs:
with:
outputFile: output-annotations.txt
+
+ odlint:
+ name: Lint with OpenDream
+ runs-on: ubuntu-20.04
+ steps:
+ - uses: actions/checkout@v3
+ - name: Get OpenDream Version
+ run: |
+ source dependencies.sh
+ echo "OPENDREAM_VERSION=$OPENDREAM_VERSION" >> $GITHUB_ENV
+ - name: Restore OpenDream cache
+ uses: actions/cache@v3
+ id: cache-od
+ with:
+ path: ~/OpenDream
+ key: ${{ runner.os }}-opendream-${{ env.OPENDREAM_VERSION }}
+ - name: Download OpenDream
+ if: steps.cache-od.outputs.cache-hit != 'true'
+ run: |
+ bash tools/ci/download_od.sh
+ - name: Setup OpenDream
+ if: steps.cache-od.outputs.cache-hit != 'true'
+ run: |
+ bash tools/ci/setup_od.sh
+ - name: Run OpenDream
+ run: |
+ bash tools/ci/run_od.sh
+
compile_all_maps:
if: "!contains(github.event.head_commit.message, '[ci skip]')"
name: Compile Maps
diff --git a/.gitignore b/.gitignore
index 210efc84d75b..4d2b7e810de8 100644
--- a/.gitignore
+++ b/.gitignore
@@ -31,3 +31,6 @@ test_environment.txt
# byond-tracy backend, not shipped with the codebase so it shouldn't be maintained
prof.dll
libprof.so
+
+# OpenDream compatibility stuff
+colonialmarines.json
diff --git a/.vscode/settings.json b/.vscode/settings.json
index 201562aaf7c7..c7b218b77591 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -9,7 +9,7 @@
"**/.pnp.*": true
},
"editor.codeActionsOnSave": {
- "source.fixAll.eslint": true
+ "source.fixAll.eslint": "explicit"
},
"files.eol": "\n",
"files.insertFinalNewline": true,
diff --git a/code/__DEFINES/__game.dm b/code/__DEFINES/__game.dm
index 113b78dbada1..ead4c9665c7c 100644
--- a/code/__DEFINES/__game.dm
+++ b/code/__DEFINES/__game.dm
@@ -103,7 +103,7 @@ block( \
#define SOUND_MIDI (1<<1)
#define SOUND_AMBIENCE (1<<2)
#define SOUND_LOBBY (1<<3)
-#define SOUND_INTERNET (1<<4)
+#define SOUND_INTERNET (1<<4) // Unused currently. Kept for default prefs compat only
#define SOUND_REBOOT (1<<5)
#define SOUND_ADMIN_MEME (1<<6)
#define SOUND_ADMIN_ATMOSPHERIC (1<<7)
@@ -124,6 +124,7 @@ block( \
#define CHAT_FFATTACKLOGS (1<<11)
#define CHAT_GHOSTHIVEMIND (1<<12)
#define CHAT_NICHELOGS (1<<13)
+#define CHAT_LISTENINGBUG (1<<14)
//toggles_ghost
#define GHOST_HEALTH_SCAN (1<<0)
@@ -151,6 +152,7 @@ block( \
//toggles_admin
/// Splits admin tabs in Statpanel
#define SPLIT_ADMIN_TABS (1<<0)
+#define ADMIN_STEALTHMODE (1<<1)
//=================================================
@@ -283,7 +285,6 @@ block( \
/// Only use the CEILING_PROTECTION_TIER_X defines for `protection_level`
#define CEILING_IS_PROTECTED(ceiling, protection_level) (ceiling >= protection_level)
-
// Default font settings
#define FONT_SIZE "5pt"
#define DEFAULT_FONT_COLOR "#09f"
@@ -392,6 +393,7 @@ block( \
#define FIRE_MISSION_WEAPON_REMOVED 8
#define FIRE_MISSION_WEAPON_UNUSABLE 16
#define FIRE_MISSION_WEAPON_OUT_OF_AMMO 32
+#define FIRE_MISSION_BAD_DIRECTION 64
#define FIRE_MISSION_NOT_EXECUTABLE -1
//Defines for firemission state
@@ -493,6 +495,18 @@ block( \
#define TURF_PROTECTION_CAS 2
#define TURF_PROTECTION_OB 3
+/// Convert a turf protection level to a ceiling protection level
+/proc/get_ceiling_protection_level(turf_protection_level)
+ switch(turf_protection_level)
+ if(TURF_PROTECTION_OB)
+ return CEILING_PROTECTION_TIER_4
+ if(TURF_PROTECTION_CAS)
+ return CEILING_PROTECTION_TIER_3
+ if(TURF_PROTECTION_MORTAR)
+ return CEILING_PROTECTION_TIER_2
+ else
+ return CEILING_NO_PROTECTION
+
// Anything above the deck boundary is the upper deck, anything below is the lower deck
// This is exclusive, so anything ON the boundary is an edge case that's neither on the upper nor the lower deck
#define ALMAYER_DECK_BOUNDARY 101
diff --git a/code/__DEFINES/_math.dm b/code/__DEFINES/_math.dm
index 7f19c95b2bcf..6fb634e66720 100644
--- a/code/__DEFINES/_math.dm
+++ b/code/__DEFINES/_math.dm
@@ -9,23 +9,6 @@
#define CARDINAL_DIRS list(1,2,4,8)
#define CARDINAL_ALL_DIRS list(1,2,4,5,6,8,9,10)
-//some colors
-#define COLOR_RED "#FF0000"
-#define COLOR_GREEN "#00FF00"
-#define COLOR_BLUE "#0000FF"
-#define COLOR_CYAN "#00FFFF"
-#define COLOR_PINK "#FF00FF"
-#define COLOR_YELLOW "#FFFF00"
-#define COLOR_ORANGE "#FF9900"
-#define COLOR_WHITE "#FFFFFF"
-#define COLOR_BLACK "#000000"
-#define COLOR_OIL "#030303"
-
-//Grass Colors
-#define COLOR_G_ICE "#C7EDDE" //faded cyan
-#define COLOR_G_DES "#FF7C1C" //bright orange
-#define COLOR_G_JUNG "#64AA6E" //faded green
-
#define LEFT 1
#define RIGHT 2
diff --git a/code/__DEFINES/access.dm b/code/__DEFINES/access.dm
index 97e4b0dbd1e8..be96a2e32b85 100644
--- a/code/__DEFINES/access.dm
+++ b/code/__DEFINES/access.dm
@@ -152,6 +152,8 @@ most of them are tied into map-placed objects. This should be reworked in the fu
/// Ancients only
#define ACCESS_YAUTJA_ANCIENT 392
+/// Anything in a tutorial sequence that shouldn't be accessed
+#define ACCESS_TUTORIAL_LOCKED 998
///Temporary, just so I can flag places I need to change
#define ACCESS_COME_BACK_TO_ME 999
diff --git a/code/__DEFINES/admin.dm b/code/__DEFINES/admin.dm
index 6844721cd7f0..31103fee93ee 100644
--- a/code/__DEFINES/admin.dm
+++ b/code/__DEFINES/admin.dm
@@ -22,7 +22,7 @@
#define NOTE_SYNTHETIC 4
#define NOTE_YAUTJA 5
///Note categories in text form, in order of their numerical #defines.
-var/global/list/note_categories = list("Admin", "Merit", "Commanding Officer", "Synthetic", "Yautja")
+GLOBAL_LIST_INIT(note_categories, list("Admin", "Merit", "Commanding Officer", "Synthetic", "Yautja"))
#define ADMIN_FLW(user) "(FLW)"
#define ADMIN_PP(user) "(PP)"
diff --git a/code/__DEFINES/alerts.dm b/code/__DEFINES/alerts.dm
new file mode 100644
index 000000000000..b4fc5e04c9c7
--- /dev/null
+++ b/code/__DEFINES/alerts.dm
@@ -0,0 +1,7 @@
+#define ALERT_BUCKLED "buckled"
+#define ALERT_HANDCUFFED "handcuffed"
+#define ALERT_LEGCUFFED "legcuffed"
+#define ALERT_FLOORED "floored"
+#define ALERT_INCAPACITATED "incapacitated"
+#define ALERT_KNOCKEDOUT "knockedout"
+#define ALERT_IMMOBILIZED "immobilized"
diff --git a/code/__DEFINES/assert.dm b/code/__DEFINES/assert.dm
new file mode 100644
index 000000000000..cff78107714c
--- /dev/null
+++ b/code/__DEFINES/assert.dm
@@ -0,0 +1,13 @@
+#undef ASSERT
+
+/// Override BYOND's native ASSERT to optionally specify a message
+#define ASSERT(condition, message...) \
+ if (!(condition)) { \
+ CRASH(assertion_message(__FILE__, __LINE__, #condition, ##message)) \
+ }
+
+/proc/assertion_message(file, line, condition, message)
+ if (!isnull(message))
+ message = " - [message]"
+
+ return "[file]:[line]:Assertion failed: [condition][message]"
diff --git a/code/__DEFINES/atmospherics.dm b/code/__DEFINES/atmospherics.dm
index 3abd79708f7a..999a840b7fdd 100644
--- a/code/__DEFINES/atmospherics.dm
+++ b/code/__DEFINES/atmospherics.dm
@@ -23,6 +23,8 @@
#define T0C 273.15 // 0degC
#define T20C 293.15 // 20degC
+#define T90C 363.15 // 90degC
+#define T120C 393.15 // 120degC
#define TCMB 2.7 // -270.3degC
#define ICE_COLONY_TEMPERATURE 223 //-50degC
#define SOROKYNE_TEMPERATURE 223 // Same as Ice for now
@@ -35,9 +37,6 @@
#define GAS_TYPE_PHORON "phoron"
#define GAS_TYPE_CO2 "carbon dioxyde"
-/// This was a define, but I changed it to a variable so it can be changed in-game.(kept the all-caps definition because... code...) -Errorage
-var/MAX_EXPLOSION_RANGE = 14
-
/// Used in /obj/structure/pipes/vents/proc/create_gas
#define VENT_GAS_SMOKE "Smoke"
#define VENT_GAS_CN20 "CN20 Nerve Gas"
diff --git a/code/__DEFINES/bullet_traits.dm b/code/__DEFINES/bullet_traits.dm
index 0ca3bce2e602..40e250cd0dd2 100644
--- a/code/__DEFINES/bullet_traits.dm
+++ b/code/__DEFINES/bullet_traits.dm
@@ -3,7 +3,7 @@
// list of args if there are any args
/// An entry to a list for giving projectiles bullet traits
/// Must be placed inside of a list
-#define BULLET_TRAIT_ENTRY(trait, args...) trait = #args ? list(##args) : null
+#define BULLET_TRAIT_ENTRY(trait, args...) trait = list(##args)
/// An entry to a list for giving projectiles bullet traits with a unique ID
/// Must be placed inside of a list
#define BULLET_TRAIT_ENTRY_ID(id, trait, args...) id = list(trait, ##args)
diff --git a/code/__DEFINES/chat.dm b/code/__DEFINES/chat.dm
index 85966e4032e2..f2db3980e887 100644
--- a/code/__DEFINES/chat.dm
+++ b/code/__DEFINES/chat.dm
@@ -6,6 +6,7 @@
#define MESSAGE_TYPE_SYSTEM "system"
#define MESSAGE_TYPE_LOCALCHAT "localchat"
#define MESSAGE_TYPE_RADIO "radio"
+#define MESSAGE_TYPE_HIVEMIND "hivemind"
#define MESSAGE_TYPE_INFO "info"
#define MESSAGE_TYPE_WARNING "warning"
#define MESSAGE_TYPE_DEADCHAT "deadchat"
diff --git a/code/__DEFINES/clans.dm b/code/__DEFINES/clans.dm
index 1b95d11c030c..576bbf6b76d5 100644
--- a/code/__DEFINES/clans.dm
+++ b/code/__DEFINES/clans.dm
@@ -49,26 +49,6 @@
/// Scales with clan size
#define CLAN_LIMIT_SIZE 2
-var/global/list/datum/yautja_rank/clan_ranks = list(
- CLAN_RANK_UNBLOODED = new /datum/yautja_rank/unblooded(),
- CLAN_RANK_YOUNG = new /datum/yautja_rank/young(),
- CLAN_RANK_BLOODED = new /datum/yautja_rank/blooded(),
- CLAN_RANK_ELITE = new /datum/yautja_rank/elite(),
- CLAN_RANK_ELDER = new /datum/yautja_rank/elder(),
- CLAN_RANK_LEADER = new /datum/yautja_rank/leader(),
- CLAN_RANK_ADMIN = new /datum/yautja_rank/ancient()
-)
-
-var/global/list/clan_ranks_ordered = list(
- CLAN_RANK_UNBLOODED = CLAN_RANK_UNBLOODED_INT,
- CLAN_RANK_YOUNG = CLAN_RANK_YOUNG_INT,
- CLAN_RANK_BLOODED = CLAN_RANK_BLOODED_INT,
- CLAN_RANK_ELITE = CLAN_RANK_ELITE_INT,
- CLAN_RANK_ELDER = CLAN_RANK_ELDER_INT,
- CLAN_RANK_LEADER = CLAN_RANK_LEADER_INT,
- CLAN_RANK_ADMIN = CLAN_RANK_ADMIN_INT
-)
-
#define CLAN_HREF "clan_href"
#define CLAN_TARGET_HREF "clan_target_href"
diff --git a/code/__DEFINES/colours.dm b/code/__DEFINES/colours.dm
index 5fa106715f39..e96546cdf7d2 100644
--- a/code/__DEFINES/colours.dm
+++ b/code/__DEFINES/colours.dm
@@ -1,214 +1,146 @@
// tg port thing
-//different types of atom colourations
-/// Only used by rare effects like greentext colouring mobs and when admins varedit color
-#define ADMIN_COLOUR_PRIORITY 1
+//different types of atom colorations
+/// Only used by rare effects like greentext coloring mobs and when admins varedit color
+#define ADMIN_COLOR_PRIORITY 1
/// e.g. purple effect of the revenant on a mob, black effect when mob electrocuted
-#define TEMPORARY_COLOUR_PRIORITY 2
-/// Colour splashed onto an atom (e.g. paint on turf)
-#define WASHABLE_COLOUR_PRIORITY 3
-/// Colour inherent to the atom (e.g. blob color)
-#define FIXED_COLOUR_PRIORITY 4
+#define TEMPORARY_COLOR_PRIORITY 2
+/// Color splashed onto an atom (e.g. paint on turf)
+#define WASHABLE_COLOR_PRIORITY 3
+/// Color inherent to the atom (e.g. blob color)
+#define FIXED_COLOR_PRIORITY 4
///how many color priority levels there are.
-#define COLOUR_PRIORITY_AMOUNT 4
-
-#define COLOUR_DARKMODE_BACKGROUND "#202020"
-#define COLOUR_DARKMODE_DARKBACKGROUND "#171717"
-#define COLOUR_DARKMODE_TEXT "#a4bad6"
-
-#define COLOUR_WHITE "#FFFFFF"
-#define COLOUR_VERY_LIGHT_GRAY "#EEEEEE"
-#define COLOUR_SILVER "#C0C0C0"
-#define COLOUR_GRAY "#808080"
-#define COLOUR_FLOORTILE_GRAY "#8D8B8B"
-#define COLOUR_DARK "#454545"
-#define COLOUR_ALMOST_BLACK "#333333"
-#define COLOUR_BLACK "#000000"
-#define COLOUR_HALF_TRANSPARENT_BLACK "#0000007A"
-
-#define COLOUR_RED "#FF0000"
-#define COLOUR_MOSTLY_PURE_RED "#FF3300"
-#define COLOUR_DARK_RED "#A50824"
-#define COLOUR_RED_LIGHT "#FF3333"
-#define COLOUR_MAROON "#800000"
-#define COLOUR_VIVID_RED "#FF3232"
-#define COLOUR_LIGHT_GRAYISH_RED "#E4C7C5"
-#define COLOUR_SOFT_RED "#FA8282"
-#define COLOUR_CULT_RED "#960000"
-#define COLOUR_BUBBLEGUM_RED "#950A0A"
-
-#define COLOUR_YELLOW "#FFFF00"
-#define COLOUR_VIVID_YELLOW "#FBFF23"
-#define COLOUR_VERY_SOFT_YELLOW "#FAE48E"
-
-#define COLOUR_OLIVE "#808000"
-#define COLOUR_VIBRANT_LIME "#00FF00"
-#define COLOUR_LIME "#32CD32"
-#define COLOUR_DARK_LIME "#00aa00"
-#define COLOUR_VERY_PALE_LIME_GREEN "#DDFFD3"
-#define COLOUR_VERY_DARK_LIME_GREEN "#003300"
-#define COLOUR_GREEN "#008000"
-#define COLOUR_DARK_MODERATE_LIME_GREEN "#44964A"
-
-#define COLOUR_CYAN "#00FFFF"
-#define COLOUR_DARK_CYAN "#00A2FF"
-#define COLOUR_TEAL "#008080"
-#define COLOUR_BLUE "#0000FF"
-#define COLOUR_STRONG_BLUE "#1919c8"
-#define COLOUR_BRIGHT_BLUE "#2CB2E8"
-#define COLOUR_MODERATE_BLUE "#555CC2"
-#define COLOUR_AMETHYST "#822BFF"
-#define COLOUR_BLUE_LIGHT "#33CCFF"
-#define COLOUR_NAVY "#000080"
-#define COLOUR_BLUE_GRAY "#75A2BB"
-
-#define COLOUR_PINK "#FFC0CB"
-#define COLOUR_LIGHT_PINK "#ff3cc8"
-#define COLOUR_MOSTLY_PURE_PINK "#E4005B"
-#define COLOUR_BLUSH_PINK "#DE5D83"
-#define COLOUR_MAGENTA "#FF00FF"
-#define COLOUR_STRONG_MAGENTA "#B800B8"
-#define COLOUR_PURPLE "#800080"
-#define COLOUR_VIOLET "#B900F7"
-#define COLOUR_STRONG_VIOLET "#6927c5"
-
-#define COLOUR_ORANGE "#FF9900"
-#define COLOUR_MOSTLY_PURE_ORANGE "#ff8000"
-#define COLOUR_TAN_ORANGE "#FF7B00"
-#define COLOUR_BRIGHT_ORANGE "#E2853D"
-#define COLOUR_LIGHT_ORANGE "#ffc44d"
-#define COLOUR_PALE_ORANGE "#FFBE9D"
-#define COLOUR_BEIGE "#CEB689"
-#define COLOUR_DARK_ORANGE "#C3630C"
-#define COLOUR_DARK_MODERATE_ORANGE "#8B633B"
-
-#define COLOUR_BROWN "#BA9F6D"
-#define COLOUR_DARK_BROWN "#997C4F"
-#define COLOUR_ORANGE_BROWN "#a9734f"
-
-//Colour defines used by the soapstone (based on readability against grey tiles)
-#define COLOUR_SOAPSTONE_PLASTIC "#a19d94"
-#define COLOUR_SOAPSTONE_IRON "#b2b2b2"
-#define COLOUR_SOAPSTONE_BRONZE "#FE8001"
-#define COLOUR_SOAPSTONE_SILVER "#FFFFFF"
-#define COLOUR_SOAPSTONE_GOLD "#FFD900"
-#define COLOUR_SOAPSTONE_DIAMOND "#00ffee"
-
-#define COLOUR_GREEN_GRAY "#99BB76"
-#define COLOUR_RED_GRAY "#B4696A"
-#define COLOUR_PALE_BLUE_GRAY "#98C5DF"
-#define COLOUR_PALE_GREEN_GRAY "#B7D993"
-#define COLOUR_PALE_RED_GRAY "#D59998"
-#define COLOUR_PALE_PURPLE_GRAY "#CBB1CA"
-#define COLOUR_PURPLE_GRAY "#AE8CA8"
-
-//Colour defines used by the assembly detailer.
-#define COLOUR_ASSEMBLY_BLACK "#545454"
-#define COLOUR_ASSEMBLY_BGRAY "#9497AB"
-#define COLOUR_ASSEMBLY_WHITE "#E2E2E2"
-#define COLOUR_ASSEMBLY_RED "#CC4242"
-#define COLOUR_ASSEMBLY_ORANGE "#E39751"
-#define COLOUR_ASSEMBLY_BEIGE "#AF9366"
-#define COLOUR_ASSEMBLY_BROWN "#97670E"
-#define COLOUR_ASSEMBLY_GOLD "#AA9100"
-#define COLOUR_ASSEMBLY_YELLOW "#CECA2B"
-#define COLOUR_ASSEMBLY_GURKHA "#999875"
-#define COLOUR_ASSEMBLY_LGREEN "#789876"
-#define COLOUR_ASSEMBLY_GREEN "#44843C"
-#define COLOUR_ASSEMBLY_LBLUE "#5D99BE"
-#define COLOUR_ASSEMBLY_BLUE "#38559E"
-#define COLOUR_ASSEMBLY_PURPLE "#6F6192"
-
-///Colours for xenobiology vatgrowing
-#define COLOUR_SAMPLE_YELLOW "#c0b823"
-#define COLOUR_SAMPLE_PURPLE "#342941"
-#define COLOUR_SAMPLE_GREEN "#98b944"
-#define COLOUR_SAMPLE_BROWN "#91542d"
-#define COLOUR_SAMPLE_GRAY "#5e5856"
-
-///Main colours for UI themes
-#define COLOUR_THEME_MIDNIGHT "#6086A0"
-#define COLOUR_THEME_PLASMAFIRE "#FFB200"
-#define COLOUR_THEME_RETRO "#24CA00"
-#define COLOUR_THEME_SLIMECORE "#4FB259"
-#define COLOUR_THEME_OPERATIVE "#B8221F"
-#define COLOUR_THEME_GLASS "#75A4C4"
-#define COLOUR_THEME_CLOCKWORK "#CFBA47"
-
-///Colours for eigenstates
-#define COLOUR_PERIWINKLEE "#9999FF"
+#define COLOR_PRIORITY_AMOUNT 4
+
+// BLACK AND WHITE COLOR DEFINE.
+
+/// Full white. rgb(255, 255, 255)
+#define COLOR_WHITE "#FFFFFF"
+/// Full black. rgb(0, 0, 0)
+#define COLOR_BLACK "#000000"
+
+// THE THREE PRIMARIES COLORS DEFINES.
+
+/// Full red. rgb(255, 0, 0)
+#define COLOR_RED "#FF0000"
+/// Full green. rgb(0, 255, 0)
+#define COLOR_GREEN "#00FF00"
+/// Full blue. rgb(0, 0, 255)
+#define COLOR_BLUE "#0000FF"
+
+//mix of two full primary colors
+
+/// full cyan rgb(0, 255, 255) B + G
+#define COLOR_CYAN "#00FFFF"
+/// full magenta(not pink) rgb(255, 0, 255) R+B
+#define COLOR_PINK "#FF00FF"
+/// full yellow rgb(255, 255, 0) R+G
+#define COLOR_YELLOW "#FFFF00"
+
+// colors define in use bellow
+#define COLOR_SILVER "#C0C0C0"
+
+#define COLOR_FLOORTILE_GRAY "#8D8B8B"
+
+#define COLOR_HALF_TRANSPARENT_BLACK "#0000007A"
+
+#define COLOR_DARK_RED "#A50824"
+
+#define COLOR_MAROON "#800000"
+#define COLOR_VIVID_RED "#FF3232"
+#define COLOR_LIGHT_GRAYISH_RED "#E4C7C5"
+#define COLOR_SOFT_RED "#FA8282"
+
+#define COLOR_VERY_SOFT_YELLOW "#FAE48E"
+
+#define COLOR_OLIVE "#808000"
+
+///light green rgb( 0, 128, 0)
+#define COLOR_LIGHT_GREEN "#008000"
+#define COLOR_DARK_MODERATE_LIME_GREEN "#44964A"
+
+#define COLOR_TEAL "#008080"
+
+#define COLOR_MODERATE_BLUE "#555CC2"
+
+#define COLOR_PURPLE "#800080"
+#define COLOR_STRONG_VIOLET "#6927c5"
+
+#define COLOR_BEIGE "#CEB689"
+#define COLOR_DARK_MODERATE_ORANGE "#8B633B"
+
+#define COLOR_BROWN "#BA9F6D"
+#define COLOR_DARK_BROWN "#997C4F"
+
/**
- * Some defines to generalise colours used in lighting.
+ * Some defines to generalise Colors used in lighting.
*
- * Important note: colours can end up significantly different from the basic html picture, especially when saturated
+ * Important note: Colors can end up significantly different from the basic html picture, especially when saturated
*/
-/// Full white. rgb(255, 255, 255)
-#define LIGHT_COLOR_WHITE "#FFFFFF"
/// Bright but quickly dissipating neon green. rgb(100, 200, 100)
-#define LIGHT_COLOUR_GREEN "#64C864"
-/// Electric green. rgb(0, 255, 0)
-#define LIGHT_COLOUR_ELECTRIC_GREEN "#00FF00"
+#define LIGHT_COLOR_GREEN "#64C864"
/// Cold, diluted blue. rgb(100, 150, 250)
-#define LIGHT_COLOUR_BLUE "#6496FA"
+#define LIGHT_COLOR_BLUE "#6496FA"
/// Light blueish green. rgb(125, 225, 175)
-#define LIGHT_COLOUR_BLUEGREEN "#7DE1AF"
+#define LIGHT_COLOR_BLUEGREEN "#7DE1AF"
/// Diluted cyan. rgb(125, 225, 225)
-#define LIGHT_COLOUR_CYAN "#7DE1E1"
-/// Electric cyan rgb(0, 255, 255)
-#define LIGHT_COLOUR_ELECTRIC_CYAN "#00FFFF"
+#define LIGHT_COLOR_CYAN "#7DE1E1"
/// More-saturated cyan. rgb(64, 206, 255)
-#define LIGHT_COLOUR_LIGHT_CYAN "#40CEFF"
+#define LIGHT_COLOR_LIGHT_CYAN "#40CEFF"
/// Saturated blue. rgb(51, 117, 248)
-#define LIGHT_COLOUR_DARK_BLUE "#6496FA"
+#define LIGHT_COLOR_DARK_BLUE "#3375F8"
/// Diluted, mid-warmth pink. rgb(225, 125, 225)
-#define LIGHT_COLOUR_PINK "#E17DE1"
+#define LIGHT_COLOR_PINK "#E17DE1"
/// Dimmed yellow, leaning kaki. rgb(225, 225, 125)
-#define LIGHT_COLOUR_YELLOW "#E1E17D"
+#define LIGHT_COLOR_YELLOW "#E1E17D"
/// Clear brown, mostly dim. rgb(150, 100, 50)
-#define LIGHT_COLOUR_BROWN "#966432"
+#define LIGHT_COLOR_BROWN "#966432"
/// Mostly pure orange. rgb(250, 150, 50)
-#define LIGHT_COLOUR_ORANGE "#FA9632"
+#define LIGHT_COLOR_ORANGE "#FA9632"
/// Light Purple. rgb(149, 44, 244)
-#define LIGHT_COLOUR_PURPLE "#952CF4"
+#define LIGHT_COLOR_PURPLE "#952CF4"
/// Less-saturated light purple. rgb(155, 81, 255)
-#define LIGHT_COLOUR_LAVENDER "#9B51FF"
+#define LIGHT_COLOR_LAVENDER "#9B51FF"
///slightly desaturated bright yellow.
-#define LIGHT_COLOUR_HOLY_MAGIC "#FFF743"
+#define LIGHT_COLOR_HOLY_MAGIC "#FFF743"
/// deep crimson
-#define LIGHT_COLOUR_BLOOD_MAGIC "#D00000"
+#define LIGHT_COLOR_BLOOD_MAGIC "#D00000"
/* These ones aren't a direct color like the ones above, because nothing would fit */
/// Warm orange color, leaning strongly towards yellow. rgb(250, 160, 25)
-#define LIGHT_COLOUR_FIRE "#FAA019"
+#define LIGHT_COLOR_FIRE "#FAA019"
/// Very warm yellow, leaning slightly towards orange. rgb(196, 138, 24)
-#define LIGHT_COLOUR_LAVA "#C48A18"
+#define LIGHT_COLOR_LAVA "#C48A18"
/// Bright, non-saturated red. Leaning slightly towards pink for visibility. rgb(250, 100, 75)
-#define LIGHT_COLOUR_FLARE "#FA644B"
+#define LIGHT_COLOR_FLARE "#FA644B"
/// Weird color, between yellow and green, very slimy. rgb(175, 200, 75)
-#define LIGHT_COLOUR_SLIME_LAMP "#AFC84B"
+#define LIGHT_COLOR_SLIME_LAMP "#AFC84B"
/// Extremely diluted yellow, close to skin color (for some reason). rgb(250, 225, 175)
-#define LIGHT_COLOUR_TUNGSTEN "#FAE1AF"
+#define LIGHT_COLOR_TUNGSTEN "#FAE1AF"
/// Barely visible cyan-ish hue, as the doctor prescribed. rgb(240, 250, 250)
-#define LIGHT_COLOUR_HALOGEN "#F0FAFA"
-
-//The GAGS greyscale_colours for each department's computer/machine circuits
-#define CIRCUIT_COLOUR_GENERIC "#1A7A13"
-#define CIRCUIT_COLOUR_COMMAND "#1B4594"
-#define CIRCUIT_COLOUR_SECURITY "#9A151E"
-#define CIRCUIT_COLOUR_SCIENCE "#BC4A9B"
-#define CIRCUIT_COLOUR_SERVICE "#92DCBA"
-#define CIRCUIT_COLOUR_MEDICAL "#00CCFF"
-#define CIRCUIT_COLOUR_ENGINEERING "#F8D700"
-#define CIRCUIT_COLOUR_SUPPLY "#C47749"
+#define LIGHT_COLOR_HALOGEN "#F0FAFA"
/// The default color for admin say, used as a fallback when the preference is not enabled
-#define DEFAULT_ASAY_COLOUR COLOUR_MOSTLY_PURE_RED
-#define DEFAULT_HEX_COLOUR_LEN 6
+#define COLOR_MOSTLY_PURE_RED "#FF3300"
+#define DEFAULT_ASAY_COLOR COLOR_MOSTLY_PURE_RED
+
+#define DEFAULT_HEX_COLOR_LEN 6
-// Colour filters
+// Color filters
/// Icon filter that creates ambient occlusion
#define AMBIENT_OCCLUSION filter(type="drop_shadow", x=0, y=-2, size=4, border=4, color="#04080FAA")
/// Icon filter that creates gaussian blur
#define GAUSSIAN_BLUR(filter_size) filter(type="blur", size=filter_size)
+
+//some colors coming from _math.dm
+
+#define COLOR_ORANGE "#FF9900"
+#define COLOR_OIL "#030303"
+
+//Grass Colors coming from _math.dm
+
+#define COLOR_G_ICE "#C7EDDE" //faded cyan
+#define COLOR_G_DES "#FF7C1C" //bright orange
+#define COLOR_G_JUNG "#64AA6E" //faded green
diff --git a/code/__DEFINES/conflict.dm b/code/__DEFINES/conflict.dm
index 0820c709cdae..d69f0891ffa0 100644
--- a/code/__DEFINES/conflict.dm
+++ b/code/__DEFINES/conflict.dm
@@ -109,6 +109,7 @@
#define SHOES_SLOWDOWN -1
#define SLOWDOWN_ARMOR_NONE 0
+#define SLOWDOWN_ARMOR_SUPER_LIGHT 0.10
#define SLOWDOWN_ARMOR_VERY_LIGHT 0.20
#define SLOWDOWN_ARMOR_LIGHT 0.35
#define SLOWDOWN_ARMOR_MEDIUM 0.55
diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm
index 0a9e00b59e04..2e247cdccc73 100644
--- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm
+++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm
@@ -36,6 +36,10 @@
#define COMSIG_HUMAN_UPDATE_SIGHT "human_update_sight"
#define COMPONENT_OVERRIDE_UPDATE_SIGHT (1<<0)
+///from /mob/living/carbon/human/movement_delay()
+#define COMSIG_HUMAN_MOVEMENT_CANCEL_INTERACTION "human_movement_cancel_interaction"
+ #define COMPONENT_HUMAN_MOVEMENT_KEEP_USING (1<<0)
+
///from /mob/living/carbon/human/update_sight()
#define COMSIG_HUMAN_POST_UPDATE_SIGHT "human_post_update_sight"
///from /mob/living/carbon/human/movement_delay(): (list/movedata)
@@ -63,3 +67,6 @@
#define COMSIG_HUMAN_SURGERY_APPLY_MODIFIERS "human_surgery_apply_modifiers"
/// From /mob/living/carbon/human/proc/get_flags_cold_protection()
#define COMSIG_HUMAN_COLD_PROTECTION_APPLY_MODIFIERS "human_cold_protection_apply_modifiers"
+
+/// From /obj/item/proc/dig_out_shrapnel() : ()
+#define COMSIG_HUMAN_SHRAPNEL_REMOVED "human_shrapnel_removed"
diff --git a/code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm b/code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm
index 89a65dad230e..cea905dd1011 100644
--- a/code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm
+++ b/code/__DEFINES/dcs/signals/atom/mob/living/signals_living.dm
@@ -23,13 +23,25 @@
#define COMSIG_LIVING_SPEAK "living_speak"
#define COMPONENT_OVERRIDE_SPEAK (1<<0)
-#define COMSIG_LIVING_APPLY_EFFECT "living_apply_effect"
-#define COMSIG_LIVING_ADJUST_EFFECT "living_adjust_effect"
-#define COMSIG_LIVING_SET_EFFECT "living_set_effect"
- #define COMPONENT_CANCEL_EFFECT (1<<0)
-
/// From /obj/structure/proc/do_climb(var/mob/living/user, mods)
#define COMSIG_LIVING_CLIMB_STRUCTURE "climb_over_structure"
/// From /mob/living/Collide(): (atom/A)
#define COMSIG_LIVING_PRE_COLLIDE "living_pre_collide"
#define COMPONENT_LIVING_COLLIDE_HANDLED (1<<0)
+
+/// From /mob/living/proc/do_ghost() : (mob/dead/observer/ghost)
+#define COMSIG_LIVING_GHOSTED "living_ghosted"
+
+/// From /mob/living/carbon/human/attack_hand() : (mob/living/carbon/human/attacked_mob)
+#define COMSIG_LIVING_ATTACKHAND_HUMAN "living_attackhand_human"
+
+/// From /obj/item/reagent_container/hypospray/attack() : (obj/item/reagent_container/hypospray/injector)
+#define COMSIG_LIVING_HYPOSPRAY_INJECTED "living_hypospray_injected"
+
+///from base of mob/living/set_buckled(): (new_buckled)
+#define COMSIG_LIVING_SET_BUCKLED "living_set_buckled"
+///from base of mob/living/set_body_position()
+#define COMSIG_LIVING_SET_BODY_POSITION "living_set_body_position"
+
+/// from base of /mob/living/apply_status_effect(): (datum/status_effect/new_effect)
+#define COMSIG_LIVING_APPLY_EFFECT "living_apply_effect"
diff --git a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
index bab6064cfdbf..58021ba564a2 100644
--- a/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
+++ b/code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
@@ -1,3 +1,5 @@
+///from base of mob/set_stat(): (new_stat, old_stat)
+#define COMSIG_MOB_STATCHANGE "mob_statchange"
/// From /obj/structure/machinery/door/airlock/proc/take_damage
#define COMSIG_MOB_DESTROY_AIRLOCK "mob_destroy_airlock"
@@ -35,10 +37,6 @@
#define COMSIG_MOB_FIRED_GUN_ATTACHMENT "mob_fired_gun_attachment"
/// From /mob/proc/death
#define COMSIG_MOB_DEATH "mob_death"
-/// From /mob/proc/update_canmove()
-#define COMSIG_MOB_GETTING_UP "mob_getting_up"
-/// From /mob/proc/update_canmove()
-#define COMSIG_MOB_KNOCKED_DOWN "mob_knocked_down"
/// For when a mob is dragged
#define COMSIG_MOB_DRAGGED "mob_dragged"
/// From /obj/item/proc/unequipped()
@@ -79,13 +77,14 @@
///from base of /mob/Logout(): ()
#define COMSIG_MOB_LOGOUT "mob_logout"
+/// From /mob/proc/change_real_name(): (old_name, new_name)
+#define COMSIG_MOB_REAL_NAME_CHANGED "mob_real_name_changed"
+
//from /mob/proc/on_deafness_gain()
#define COMSIG_MOB_DEAFENED "mob_deafened"
//from /mob/proc/on_deafness_loss()
#define COMSIG_MOB_REGAINED_HEARING "mob_regained_hearing"
-#define COMSIG_MOB_POST_UPDATE_CANMOVE "mob_can_move"
-
#define COMSIG_ATTEMPT_MOB_PULL "attempt_mob_pull"
#define COMPONENT_CANCEL_MOB_PULL (1<<0)
@@ -99,6 +98,9 @@
#define COMSIG_MOB_MOVE_OR_LOOK "mob_move_or_look"
#define COMPONENT_OVERRIDE_MOB_MOVE_OR_LOOK (1<<0)
+///from rejuv
+#define COMSIG_LIVING_POST_FULLY_HEAL "living_post_fully_heal"
+
///from /mob/living/emote(): ()
#define COMSIG_MOB_EMOTE "mob_emote"
@@ -128,3 +130,43 @@
/// From /obj/item/proc/pickup() : (obj/item/picked_up)
#define COMSIG_MOB_PICKUP_ITEM "mob_pickup_item"
+
+/// From /obj/item/proc/attack_self() : (obj/item/used)
+#define COMSIG_MOB_ITEM_ATTACK_SELF "mob_item_attack_self"
+
+/// From /obj/item/proc/dropped() : (obj/item/dropped)
+#define COMSIG_MOB_ITEM_DROPPED "mob_item_dropped"
+
+
+/// From /obj/item/reagent_container/food/snacks/proc/on_Consume() : (obj/item/reagent_container/food/snacks/eaten_food)
+#define COMSIG_MOB_EATEN_SNACK "mob_eaten_snack"
+
+/// From /atom/proc/attackby() : (atom/attacked, obj/item/attacked_with)
+#define COMSIG_MOB_PARENT_ATTACKBY "mob_parent_attackby"
+
+/// From /obj/item/weapon/gun/proc/reload_into_chamber() : (obj/item/weapon/gun/empty_gun)
+#define COMSIG_MOB_GUN_EMPTY "mob_gun_empty"
+
+/// From /obj/item/weapon/gun/proc/reload() : (obj/item/weapon/gun/reloaded)
+#define COMSIG_MOB_RELOADED_GUN "mob_reloaded_gun"
+
+/// From /mob/proc/get_status_tab_items() : (list/status_list)
+#define COMSIG_MOB_GET_STATUS_TAB_ITEMS "mob_get_status_tab_items"
+
+/// From /datum/tutorial/proc/update_objective() : (new_objective)
+#define COMSIG_MOB_TUTORIAL_UPDATE_OBJECTIVE "mob_tutorial_update_objective"
+
+/// From /mob/proc/swap_hand() : ()
+#define COMSIG_MOB_SWAPPED_HAND "mob_swapped_hand"
+
+/// From /mob/proc/a_intent_change() : (new_intent)
+#define COMSIG_MOB_INTENT_CHANGE "mob_intent_change"
+
+/// From /obj/item/grab/proc/progress_passive() : (mob/living/carbon/human/grabber)
+#define COMSIG_MOB_AGGRESSIVELY_GRABBED "mob_aggressively_grabbed"
+ #define COMSIG_MOB_AGGRESIVE_GRAB_CANCEL (1<<0)
+
+/// Cancels all running cloaking effects on target
+#define COMSIG_MOB_EFFECT_CLOAK_CANCEL "mob_effect_cloak_cancel"
+
+#define COMSIG_MOB_END_TUTORIAL "mob_end_tutorial"
diff --git a/code/__DEFINES/dcs/signals/atom/signals_atom.dm b/code/__DEFINES/dcs/signals/atom/signals_atom.dm
index 7431c5593b17..d9bd1202c159 100644
--- a/code/__DEFINES/dcs/signals/atom/signals_atom.dm
+++ b/code/__DEFINES/dcs/signals/atom/signals_atom.dm
@@ -45,3 +45,12 @@
///When the transform or an atom is varedited through vv topic.
#define COMSIG_ATOM_VV_MODIFY_TRANSFORM "atom_vv_modify_transform"
+
+/// Called when an atom has something mouse dropped on it, from /client/MouseDrop: (atom/dropped_on)
+#define COMSIG_ATOM_DROPPED_ON "atom_dropped_on"
+
+/// Called when an atom is mouse dropped on another atom, from /client/MouseDrop: (atom/dropped_onto)
+#define COMSIG_ATOM_DROP_ON "atom_drop_on"
+
+/// Called when an atom has emp_act called on it, from /atom/emp_act: (severity)
+#define COMSIG_ATOM_EMP_ACT "atom_emp_act"
diff --git a/code/__DEFINES/dcs/signals/atom/signals_cell.dm b/code/__DEFINES/dcs/signals/atom/signals_cell.dm
new file mode 100644
index 000000000000..75e13d8bfdfc
--- /dev/null
+++ b/code/__DEFINES/dcs/signals/atom/signals_cell.dm
@@ -0,0 +1,26 @@
+/// (charge_amount)
+#define COMSIG_CELL_USE_CHARGE "cell_use_charge"
+ #define COMPONENT_CELL_NO_USE_CHARGE (1<<0)
+
+/// (charge_amount)
+#define COMSIG_CELL_ADD_CHARGE "cell_add_charge"
+
+#define COMSIG_CELL_START_TICK_DRAIN "cell_start_tick_drain"
+
+#define COMSIG_CELL_STOP_TICK_DRAIN "cell_stop_tick_drain"
+
+/// (mob/living/user)
+#define COMSIG_CELL_TRY_RECHARGING "cell_try_recharging"
+ #define COMPONENT_CELL_NO_RECHARGE (1<<0)
+
+#define COMSIG_CELL_OUT_OF_CHARGE "cell_out_of_charge"
+
+/// (charge_amount)
+#define COMSIG_CELL_CHECK_CHARGE "cell_check_charge"
+ #define COMPONENT_CELL_CHARGE_INSUFFICIENT (1<<0)
+
+#define COMSIG_CELL_TRY_INSERT_CELL "cell_try_insert_cell"
+ #define COMPONENT_CANCEL_CELL_INSERT (1<<0)
+
+/// (mob/living/user)
+#define COMSIG_CELL_REMOVE_CELL "cell_remove_cell"
diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm
index 6c31b77f76a4..7b3b218e658a 100644
--- a/code/__DEFINES/dcs/signals/atom/signals_item.dm
+++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm
@@ -65,3 +65,15 @@
/// from /obj/item/weapon/gun/proc/load_into_chamber() : ()
#define COMSIG_GUN_INTERRUPT_FIRE "gun_interrupt_fire"
+
+//from /datum/authority/branch/role/proc/equip_role()
+#define COMSIG_POST_SPAWN_UPDATE "post_spawn_update"
+
+#define COMSIG_CAMERA_MAPNAME_ASSIGNED "camera_manager_mapname_assigned"
+#define COMSIG_CAMERA_REGISTER_UI "camera_manager_register_ui"
+#define COMSIG_CAMERA_UNREGISTER_UI "camera_manager_unregister_ui"
+#define COMSIG_CAMERA_SET_NVG "camera_manager_set_nvg"
+#define COMSIG_CAMERA_CLEAR_NVG "camera_manager_clear_nvg"
+#define COMSIG_CAMERA_SET_TARGET "camera_manager_set_target"
+#define COMSIG_CAMERA_SET_AREA "camera_manager_set_area"
+#define COMSIG_CAMERA_CLEAR "camera_manager_clear_target"
diff --git a/code/__DEFINES/dcs/signals/atom/signals_obj.dm b/code/__DEFINES/dcs/signals/atom/signals_obj.dm
index aebd0d09d0d2..c870a55ed746 100644
--- a/code/__DEFINES/dcs/signals/atom/signals_obj.dm
+++ b/code/__DEFINES/dcs/signals/atom/signals_obj.dm
@@ -29,3 +29,17 @@
/// from /obj/proc/afterbuckle()
#define COSMIG_OBJ_AFTER_BUCKLE "signal_obj_after_buckle"
+
+/// from /obj/structure/machinery/cryopod/go_out()
+#define COMSIG_CRYOPOD_GO_OUT "cryopod_go_out"
+
+/// from /proc/vendor_successful_vend() : (obj/structure/machinery/cm_vending/vendor, list/itemspec, mob/living/carbon/human/user)
+#define COMSIG_VENDOR_SUCCESSFUL_VEND "vendor_successful_vend"
+
+/// from /obj/limb/proc/remove_all_bleeding() : (external, internal)
+#define COMSIG_LIMB_STOP_BLEEDING "limb_stop_bleeding"
+
+#define COMSIG_DROPSHIP_ADD_EQUIPMENT "dropship_add_equipment"
+#define COMSIG_DROPSHIP_REMOVE_EQUIPMENT "dropship_remove_equipment"
+
+#define COMSIG_STRUCTURE_CRATE_SQUAD_LAUNCHED "structure_crate_squad_launched"
diff --git a/code/__DEFINES/dcs/signals/signals_client.dm b/code/__DEFINES/dcs/signals/signals_client.dm
index 6733e0703514..3968f654c486 100644
--- a/code/__DEFINES/dcs/signals/signals_client.dm
+++ b/code/__DEFINES/dcs/signals/signals_client.dm
@@ -27,6 +27,3 @@
/// Called when something is removed from a client's screen : /client/proc/remove_from_screen(screen_remove)
#define COMSIG_CLIENT_SCREEN_REMOVE "client_screen_remove"
-
-/// When a mind is transfered to another mob at /datum/mind/proc/transfer_to()
-#define COMSIG_CLIENT_MIND_TRANSFER "mind_transfer"
diff --git a/code/__DEFINES/dcs/signals/signals_global.dm b/code/__DEFINES/dcs/signals/signals_global.dm
index 032a1891a808..5569ded71586 100644
--- a/code/__DEFINES/dcs/signals/signals_global.dm
+++ b/code/__DEFINES/dcs/signals/signals_global.dm
@@ -60,8 +60,14 @@
#define COMSIG_GLOB_GROUNDSIDE_FORSAKEN_HANDLING "!groundside_forsaken_handling"
/// From
-#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "yautja_armory_opened"
+#define COMSIG_GLOB_YAUTJA_ARMORY_OPENED "!yautja_armory_opened"
/// From /proc/biohazard_lockdown()
-#define COMSIG_GLOB_RESEARCH_LOCKDOWN "research_lockdown_closed"
-#define COMSIG_GLOB_RESEARCH_LIFT "research_lockdown_opened"
+#define COMSIG_GLOB_RESEARCH_LOCKDOWN "!research_lockdown_closed"
+#define COMSIG_GLOB_RESEARCH_LIFT "!research_lockdown_opened"
+
+/// From /obj/structure/machinery/power/fusion_engine/proc/set_overloading() : (set_overloading)
+#define COMSIG_GLOB_GENERATOR_SET_OVERLOADING "!generator_set_overloading"
+
+#define COMSIG_GLOB_HIJACK_IMPACTED "!hijack_impacted"
+#define COMSIG_GLOB_HIJACK_LANDED "!hijack_landed"
diff --git a/code/__DEFINES/equipment.dm b/code/__DEFINES/equipment.dm
index 82e91c5680b8..375dd0db540d 100644
--- a/code/__DEFINES/equipment.dm
+++ b/code/__DEFINES/equipment.dm
@@ -80,10 +80,8 @@
#define CAN_DIG_SHRAPNEL (1<<11)
/// whether it has an animated icon state of "[icon_state]_on" to be used during surgeries.
#define ANIMATED_SURGICAL_TOOL (1<<12)
-/// The item goes on top of tables, instead of into them with the overlay system
-#define NOTABLEMERGE (1<<13)
/// Has heat source but isn't 'on fire' and thus can be stored
-#define IGNITING_ITEM (1<<14)
+#define IGNITING_ITEM (1<<13)
//==========================================================================================
@@ -196,11 +194,11 @@
//===========================================================================================
//Marine armor only, use for flags_marine_armor.
-#define ARMOR_SQUAD_OVERLAY 1
-#define ARMOR_LAMP_OVERLAY 2
-#define ARMOR_LAMP_ON 4
-#define ARMOR_IS_REINFORCED 8
-#define SYNTH_ALLOWED 16
+#define ARMOR_SQUAD_OVERLAY (1<<0)
+#define ARMOR_LAMP_OVERLAY (1<<1)
+#define ARMOR_LAMP_ON (1<<2)
+#define ARMOR_IS_REINFORCED (1<<3)
+#define SYNTH_ALLOWED (1<<4)
//===========================================================================================
//===========================================================================================
@@ -495,7 +493,7 @@ GLOBAL_LIST_INIT(slot_to_contained_sprite_shorthand, list(
#define UNIFORM_VEND_DRESS_EXTRA "dress extra"
-var/global/list/uniform_categories = list(
+GLOBAL_LIST_INIT(uniform_categories, list(
"UTILITY" = list(UNIFORM_VEND_UTILITY_UNIFORM, UNIFORM_VEND_UTILITY_JACKET, UNIFORM_VEND_UTILITY_HEAD, UNIFORM_VEND_UTILITY_GLOVES, UNIFORM_VEND_UTILITY_SHOES),
"UTILITY EXTRAS" = list(UNIFORM_VEND_UTILITY_EXTRA),
"SERVICE" = list(UNIFORM_VEND_SERVICE_UNIFORM, UNIFORM_VEND_SERVICE_JACKET, UNIFORM_VEND_SERVICE_GLOVES, UNIFORM_VEND_SERVICE_SHOES),
@@ -504,7 +502,7 @@ var/global/list/uniform_categories = list(
"DRESS" = list(UNIFORM_VEND_DRESS_UNIFORM, UNIFORM_VEND_DRESS_JACKET, UNIFORM_VEND_DRESS_GLOVES, UNIFORM_VEND_DRESS_SHOES),
"DRESS HEADWEAR" = list(UNIFORM_VEND_DRESS_HEAD),
"DRESS EXTRAS" = list(UNIFORM_VEND_DRESS_EXTRA)
-)
+))
//=================================================
@@ -551,3 +549,8 @@ var/global/list/uniform_categories = list(
#define PHONE_MARINE "Marine"
#define PHONE_UPP_SOLDIER "Soldier"
#define PHONE_IO "IO"
+
+#define PHONE_DND_FORCED 2
+#define PHONE_DND_ON 1
+#define PHONE_DND_OFF 0
+#define PHONE_DND_FORBIDDEN -1
diff --git a/code/__DEFINES/hijack.dm b/code/__DEFINES/hijack.dm
new file mode 100644
index 000000000000..85d4c227ae70
--- /dev/null
+++ b/code/__DEFINES/hijack.dm
@@ -0,0 +1,13 @@
+#define EVACUATION_TYPE_NONE 0
+#define EVACUATION_TYPE_ADDITIVE 1
+#define EVACUATION_TYPE_MULTIPLICATIVE 2
+
+#define HIJACK_ANNOUNCE "ARES Emergency Procedures"
+#define XENO_HIJACK_ANNOUNCE "You sense something unusual..."
+
+#define EVACUATION_STATUS_NOT_INITIATED 0
+#define EVACUATION_STATUS_INITIATED 1
+
+#define HIJACK_OBJECTIVES_NOT_STARTED 0
+#define HIJACK_OBJECTIVES_STARTED 1
+#define HIJACK_OBJECTIVES_COMPLETE 2
diff --git a/code/__DEFINES/hud.dm b/code/__DEFINES/hud.dm
index 38e5693dcbe5..deee80c7a91d 100644
--- a/code/__DEFINES/hud.dm
+++ b/code/__DEFINES/hud.dm
@@ -23,3 +23,5 @@
#define NOTIFY_ATTACK "attack"
#define NOTIFY_ORBIT "orbit"
#define NOTIFY_JOIN_XENO "join_xeno"
+#define NOTIFY_XENO_TACMAP "xeno_tacmap"
+#define NOTIFY_USCM_TACMAP "uscm_tacmap"
diff --git a/code/__DEFINES/job.dm b/code/__DEFINES/job.dm
index 52263a5e1367..ad3b9fe3af32 100644
--- a/code/__DEFINES/job.dm
+++ b/code/__DEFINES/job.dm
@@ -1,6 +1,6 @@
#define get_job_playtime(client, job) (client.player_data? LAZYACCESS(client.player_data.playtimes, job)? client.player_data.playtimes[job].total_minutes MINUTES_TO_DECISECOND : 0 : 0)
-#define GET_MAPPED_ROLE(title) (RoleAuthority?.role_mappings[title] ? RoleAuthority.role_mappings[title] : RoleAuthority.roles_by_name[title])
-#define GET_DEFAULT_ROLE(title) (RoleAuthority?.default_roles[title] ? RoleAuthority.default_roles[title] : title)
+#define GET_MAPPED_ROLE(title) (GLOB.RoleAuthority?.role_mappings[title] ? GLOB.RoleAuthority.role_mappings[title] : GLOB.RoleAuthority.roles_by_name[title])
+#define GET_DEFAULT_ROLE(title) (GLOB.RoleAuthority?.default_roles[title] ? GLOB.RoleAuthority.default_roles[title] : title)
// Squad name defines
#define SQUAD_MARINE_1 "Alpha"
@@ -11,6 +11,7 @@
#define SQUAD_MARINE_CRYO "Foxtrot"
#define SQUAD_MARINE_INTEL "Intel"
#define SQUAD_SOF "SOF"
+#define SQUAD_CBRN "CBRN"
// Job name defines
#define JOB_SQUAD_MARINE "Rifleman"
@@ -23,7 +24,7 @@
#define JOB_SQUAD_ROLES /datum/timelock/squad
#define JOB_SQUAD_ROLES_LIST list(JOB_SQUAD_MARINE, JOB_SQUAD_LEADER, JOB_SQUAD_ENGI, JOB_SQUAD_MEDIC, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_TEAM_LEADER)
-var/global/list/job_squad_roles = JOB_SQUAD_ROLES_LIST
+GLOBAL_LIST_INIT(job_squad_roles, JOB_SQUAD_ROLES_LIST)
#define JOB_COLONIST "Colonist"
#define JOB_PASSENGER "Passenger"
@@ -71,7 +72,7 @@ var/global/list/job_squad_roles = JOB_SQUAD_ROLES_LIST
#define JOB_SO "Staff Officer"
#define JOB_COMMAND_ROLES /datum/timelock/command
#define JOB_COMMAND_ROLES_LIST list(JOB_CO, JOB_XO, JOB_SO)
-var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST
+GLOBAL_LIST_INIT(job_command_roles, JOB_COMMAND_ROLES_LIST)
#define JOB_AUXILIARY_OFFICER "Auxiliary Support Officer"
#define JOB_PILOT "Pilot Officer"
@@ -267,6 +268,7 @@ var/global/list/job_command_roles = JOB_COMMAND_ROLES_LIST
#define JOB_UPP_GENERAL "UPP Army General"
#define JOB_UPP_COMBAT_SYNTH "UPP Combat Synthetic"
+#define JOB_UPP_SUPPORT_SYNTH "UPP Support Synthetic"
#define UPP_JOB_LIST list(JOB_UPP, JOB_UPP_ENGI, JOB_UPP_MEDIC, JOB_UPP_SPECIALIST, JOB_UPP_LEADER, JOB_UPP_POLICE, JOB_UPP_LT_OFFICER, JOB_UPP_LT_DOKTOR, JOB_UPP_SRLT_OFFICER, JOB_UPP_KPT_OFFICER, JOB_UPP_KOL_OFFICER, JOB_UPP_COMBAT_SYNTH)
#define UPP_JOB_GRUNT_LIST list(JOB_UPP, JOB_UPP_ENGI, JOB_UPP_MEDIC, JOB_UPP_SPECIALIST, JOB_UPP_LEADER, JOB_UPP_POLICE, JOB_UPP_CREWMAN)
diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm
index b044e3426bc1..f4503aeea5d5 100644
--- a/code/__DEFINES/keybinding.dm
+++ b/code/__DEFINES/keybinding.dm
@@ -14,6 +14,7 @@
#define COMSIG_KB_ADMIN_INVISIMINTOGGLE_DOWN "keybinding_admin_invisimintoggle_down"
#define COMSIG_KB_ADMIN_DEADMIN_DOWN "keybinding_admin_deadmin_down"
#define COMSIG_KB_ADMIN_READMIN_DOWN "keybinding_admin_readmin_down"
+#define COMSIG_KB_ADMIN_MENTORSAY_DOWN "keybinding_admin_mentorsay_down"
//Carbon
#define COMSIG_KB_CARBON_HOLDRUNMOVEINTENT_DOWN "keybinding_carbon_holdrunmoveintent_down"
@@ -43,12 +44,6 @@
#define COMSIG_KG_CLIENT_RADIO_DOWN "keybinding_client_radio_down"
//Human
-#define COMSIG_KB_HUMAN_QUICKEQUIP_DOWN "keybinding_human_quickequip_down"
-#define COMSIG_KB_HUMAN_SECONDARY_DOWN "keybinding_human_secondary_down"
-#define COMSIG_KB_HUMAN_TERTIARY_DOWN "keybinding_human_tertiary_down"
-#define COMSIG_KB_HUMAN_QUATERNARY_DOWN "keybinding_human_quaternary_down"
-#define COMSIG_KB_HUMAN_QUICK_EQUIP_DOWN "keybinding_human_quick_equip_down"
-
#define COMSIG_KB_HUMAN_ISSUE_ORDER "keybinding_human_issue_order"
#define COMSIG_KB_HUMAN_ISSUE_ORDER_MOVE "keybinding_human_issue_order_move"
#define COMSIG_KB_HUMAN_ISSUE_ORDER_HOLD "keybinding_human_issue_order_hold"
@@ -57,12 +52,31 @@
#define COMSIG_KB_HUMAN_SPECIALIST_ACTIVATION_ONE "keybinding_human_specialist_activation_one"
#define COMSIG_KB_HUMAN_SPECIALIST_ACTIVATION_TWO "keybinding_human_specialist_activation_two"
-#define COMSIG_KB_HUMAN_PICK_UP "keybinding_human_pick_up"
-
#define COMSIG_KB_HUMAN_ROTATE_CHAIR "keybinding_human_rotate_chair"
#define COMSIG_KB_HUMAN_SHOW_HELD_ITEM "keybinding_human_show_held_item"
+#define COMSIG_KB_HUMAN_CYCLE_HELMET_HUD "keybinding_human_cycle_helmet_hud"
+
+// Human Inventory Navigation
+#define COMSIG_KB_HUMAN_INTERACT_OTHER_HAND "keybinding_human_interact_other_hand"
+#define COMSIG_KB_HUMAN_INTERACT_SLOT_BACK "keybinding_human_interact_slot_back"
+#define COMSIG_KB_HUMAN_INTERACT_SLOT_BELT "keybinding_human_interact_slot_belt"
+#define COMSIG_KB_HUMAN_INTERACT_SLOT_UNIFORM "keybinding_human_interact_slot_uniform"
+#define COMSIG_KB_HUMAN_INTERACT_SLOT_SUIT "keybinding_human_interact_slot_suit"
+#define COMSIG_KB_HUMAN_INTERACT_SLOT_HELMET "keybinding_human_interact_slot_helmet"
+#define COMSIG_KB_HUMAN_INTERACT_SLOT_LEFT_POUCH "keybinding_human_interact_slot_left_pouch"
+#define COMSIG_KB_HUMAN_INTERACT_SLOT_RIGHT_POUCH "keybinding_human_interact_slot_right_pouch"
+#define COMSIG_KB_HUMAN_INTERACT_SUIT_S_STORE "keybinding_human_interact_slot_suit_storage"
+
+#define COMSIG_KB_HUMAN_INTERACT_QUICKEQUIP_DOWN "keybinding_human_interact_quickequip_down"
+#define COMSIG_KB_HUMAN_INTERACT_SECONDARY_DOWN "keybinding_human_interact_secondary_down"
+#define COMSIG_KB_HUMAN_INTERACT_TERTIARY_DOWN "keybinding_human_interact_tertiary_down"
+#define COMSIG_KB_HUMAN_INTERACT_QUATERNARY_DOWN "keybinding_human_interact_quaternary_down"
+#define COMSIG_KB_HUMAN_INTERACT_QUICK_EQUIP_DOWN "keybinding_human_interact_quick_equip_down"
+
+#define COMSIG_KB_HUMAN_INTERACT_PICK_UP "keybinding_human_interact_pick_up"
+
// Human Combat
#define COMSIG_KB_HUMAN_WEAPON_FIELDSTRIP "keybinding_human_weapon_fieldstrip"
#define COMSIG_KB_HUMAN_WEAPON_BURSTFIRE "keybinding_human_weapon_burstfire"
@@ -74,6 +88,7 @@
#define COMSIG_KB_HUMAN_WEAPON_UNLOAD "keybinding_human_weapon_unload"
#define COMSIG_KB_HUMAN_WEAPON_ATTACHMENT "keybinding_human_weapon_attachment"
#define COMSIG_KB_HUMAN_WEAPON_ATTACHMENT_RAIL "keybinding_human_weapon_attachment_rail"
+#define COMSIG_KB_HUMAN_WEAPON_SHOTGUN_TUBE "keybinding_human_weapon_shotgun_tube"
#define COMSIG_KB_HUMAN_WEAPON_TOGGLE_IFF "keybinding_human_weapon_toggle_iff"
@@ -155,8 +170,7 @@
#define COMSIG_KB_YAUTJA_BUTCHER "keybinding_yautja_butcher"
#define COMSIG_KB_YAUTJA_PRED_BUY "keybinding_yautja_pred_buy"
#define COMSIG_KB_YAUTJA_MARK_PANEL "keybinding_yautja_mark_panel"
-#define COMSIG_KB_YAUTJA_MARK_FOR_HUNT "keybinding_yautja_mark_for_hunt"
-#define COMSIG_KB_YAUTJA_REMOVE_FROM_HUNT "keybinding_yautja_remove_from_hunt"
+#define COMSIG_KB_YAUTJA_TOGGLE_MARK_FOR_HUNT "keybinding_yautja_toggle_mark_for_hunt"
// Yautja Bracer
#define COMSIG_KB_YAUTJA_TOGGLE_NOTIFICATION_SOUND "keybinding_yautja_toggle_notification_sound"
@@ -177,6 +191,7 @@
#define COMSIG_KB_YAUTJA_BRACERNAME "keybinding_yautja_bracername"
#define COMSIG_KB_YAUTJA_IDCHIP "keybinding_yautja_idchip"
#define COMSIG_KB_YAUTJA_LINK_BRACER "keybinding_yautja_link_bracer"
+#define COMSIG_KB_YAUTJA_CONTROL_FALCON "keybinding_yautja_control_falcon"
//mask
#define COMSIG_KB_YAUTJA_MASK_TOGGLE_ZOOM "keybinding_yautja_mask_toggle_zoom"
@@ -199,6 +214,7 @@
#define CATEGORY_CARBON "CARBON"
#define CATEGORY_HUMAN "HUMAN"
#define CATEGORY_HUMAN_COMBAT "HUMAN COMBAT"
+#define CATEGORY_HUMAN_INVENTORY "HUMAN INVENTORY"
#define CATEGORY_ROBOT "ROBOT"
#define CATEGORY_YAUTJA "YAUTJA"
#define CATEGORY_MISC "MISC"
diff --git a/code/__DEFINES/layers.dm b/code/__DEFINES/layers.dm
index c0ccd5164b0b..5628395d7ffb 100644
--- a/code/__DEFINES/layers.dm
+++ b/code/__DEFINES/layers.dm
@@ -230,6 +230,7 @@
///--------------- FULLSCREEN RUNECHAT BUBBLES ------------
#define LIGHTING_PLANE 100
#define EXTERIOR_LIGHTING_PLANE 101
+#define NVG_PLANE 110
///Popup Chat Messages
#define RUNECHAT_PLANE 501
diff --git a/code/__DEFINES/maps.dm b/code/__DEFINES/maps.dm
index 3f6a4a44ee07..155a91fa62ed 100644
--- a/code/__DEFINES/maps.dm
+++ b/code/__DEFINES/maps.dm
@@ -32,6 +32,7 @@ require only minor tweaks.
#define ZTRAIT_FOG "Fog"
#define ZTRAIT_LOCKDOWN "Lockdown"
#define ZTRAIT_BASIC_RT "BasicRT"
+#define ZTRAIT_IN_SPACE "InSpace" // Is our ground_level considered in space or on a space station
// boolean - weather types that occur on the level
#define ZTRAIT_SNOWSTORM "weather_snowstorm"
diff --git a/code/__DEFINES/minimap.dm b/code/__DEFINES/minimap.dm
index 71d0ed8e7445..003d723600c4 100644
--- a/code/__DEFINES/minimap.dm
+++ b/code/__DEFINES/minimap.dm
@@ -5,7 +5,17 @@
#define MINIMAP_FLAG_UPP (1<<3)
#define MINIMAP_FLAG_CLF (1<<4)
#define MINIMAP_FLAG_YAUTJA (1<<5)
-#define MINIMAP_FLAG_ALL (1<<6) - 1
+#define MINIMAP_FLAG_XENO_CORRUPTED (1<<6)
+#define MINIMAP_FLAG_XENO_ALPHA (1<<7)
+#define MINIMAP_FLAG_XENO_BRAVO (1<<8)
+#define MINIMAP_FLAG_XENO_CHARLIE (1<<9)
+#define MINIMAP_FLAG_XENO_DELTA (1<<10)
+#define MINIMAP_FLAG_XENO_FERAL (1<<11)
+#define MINIMAP_FLAG_XENO_TAMED (1<<12)
+#define MINIMAP_FLAG_XENO_MUTATED (1<<13)
+#define MINIMAP_FLAG_XENO_FORSAKEN (1<<14)
+#define MINIMAP_FLAG_XENO_RENEGADE (1<<15)
+#define MINIMAP_FLAG_ALL (1<<16) - 1
///Converts the overworld x and y to minimap x and y values
#define MINIMAP_SCALE 2
@@ -77,9 +87,3 @@ GLOBAL_LIST_INIT(all_minimap_flags, bitfield2list(MINIMAP_FLAG_ALL))
#define TACMAP_BASE_OCCLUDED "Occluded"
#define TACMAP_BASE_OPEN "Open"
-
-#define TACMAP_DEFAULT "Default"
-#define TACMAP_XENO "Xeno"
-#define TACMAP_YAUTJA "Yautja"
-#define TACMAP_FACTION "Faction"
-
diff --git a/code/__DEFINES/misc.dm b/code/__DEFINES/misc.dm
index b024f22ebfff..8a8e9678fbdf 100644
--- a/code/__DEFINES/misc.dm
+++ b/code/__DEFINES/misc.dm
@@ -124,7 +124,6 @@
#define MATERIAL_METAL "metal"
#define MATERIAL_PLASTEEL "plasteel"
#define MATERIAL_WOOD "wood plank"
-#define MATERIAL_CRYSTAL "plasmagas"
// SIZES FOR ITEMS, use it for w_class
diff --git a/code/__DEFINES/mob.dm b/code/__DEFINES/mob.dm
new file mode 100644
index 000000000000..7f9f33ea483c
--- /dev/null
+++ b/code/__DEFINES/mob.dm
@@ -0,0 +1 @@
+#define DEFAULT_MOB_STATUS_FLAGS CANKNOCKDOWN|CANPUSH|STATUS_FLAGS_DEBILITATE
diff --git a/code/__DEFINES/mobs.dm b/code/__DEFINES/mobs.dm
index 1bd030313a43..9cd69e61c8b2 100644
--- a/code/__DEFINES/mobs.dm
+++ b/code/__DEFINES/mobs.dm
@@ -1,3 +1,6 @@
+/// Multiplier for Stun/KD/KO/etc durations in new backend, due to old system being based on life ticks
+#define GLOBAL_STATUS_MULTIPLIER 20 // each in-code unit is worth 20ds of duration
+
#define HEALTH_THRESHOLD_DEAD -100
#define HEALTH_THRESHOLD_CRIT -50
@@ -44,9 +47,7 @@
//disabilities
#define NEARSIGHTED (1<<0)
-#define EPILEPSY (1<<1)
-#define COUGHING (1<<2)
-#define TOURETTES (1<<3)
+
#define NERVOUS (1<<4)
#define OPIATE_RECEPTOR_DEFICIENCY (1<<5)
//=================================================
@@ -194,22 +195,22 @@
//=================================================
//Species flags.
-#define NO_BLOOD (1<<0)
-#define NO_BREATHE (1<<1)
+#define NO_BLOOD (1<<0)
+#define NO_BREATHE (1<<1)
#define NO_CLONE_LOSS (1<<2)
-#define NO_SLIP (1<<3)
+#define NO_SLIP (1<<3)
#define NO_POISON (1<<4)
-#define NO_CHEM_METABOLIZATION (1<<5) //Prevents reagents from acting on_mob_life().
+#define NO_CHEM_METABOLIZATION (1<<5) //Prevents reagents from acting on_mob_life().
#define HAS_SKIN_TONE (1<<6)
-#define HAS_SKIN_COLOR (1<<7)
-#define HAS_LIPS (1<<8)
+#define HAS_SKIN_COLOR (1<<7)
+#define HAS_LIPS (1<<8)
#define HAS_UNDERWEAR (1<<9)
-#define IS_WHITELISTED (1<<10)
-#define IS_SYNTHETIC (1<<11)
-#define NO_NEURO (1<<12)
+#define IS_WHITELISTED (1<<10)
+#define IS_SYNTHETIC (1<<11)
+#define NO_NEURO (1<<12)
#define SPECIAL_BONEBREAK (1<<13) //species do not get their bonebreak chance modified by endurance
-#define NO_SHRAPNEL (1<<14)
-#define HAS_HARDCRIT (1<<15)
+#define NO_SHRAPNEL (1<<14)
+#define HAS_HARDCRIT (1<<15)
//=================================================
@@ -374,7 +375,7 @@
// Hellhound strain flags
#define HELLHOUND_NORMAL "Normal"
-var/list/default_onmob_icons = list(
+GLOBAL_LIST_INIT(default_onmob_icons, list(
WEAR_L_HAND = 'icons/mob/humans/onmob/items_lefthand_0.dmi',
WEAR_R_HAND = 'icons/mob/humans/onmob/items_righthand_0.dmi',
WEAR_WAIST = 'icons/mob/humans/onmob/belt.dmi',
@@ -393,9 +394,9 @@ var/list/default_onmob_icons = list(
WEAR_HANDS = 'icons/mob/humans/onmob/hands.dmi',
WEAR_J_STORE = 'icons/mob/humans/onmob/suit_slot.dmi',
WEAR_ACCESSORIES = 'icons/mob/humans/onmob/ties.dmi'
- )
+ ))
-var/list/default_xeno_onmob_icons = list(
+GLOBAL_LIST_INIT(default_xeno_onmob_icons, list(
/mob/living/carbon/xenomorph/runner = 'icons/mob/xenos/onmob/runner.dmi',
/mob/living/carbon/xenomorph/praetorian = 'icons/mob/xenos/onmob/praetorian.dmi',
/mob/living/carbon/xenomorph/drone = 'icons/mob/xenos/onmob/drone.dmi',
@@ -403,7 +404,7 @@ var/list/default_xeno_onmob_icons = list(
/mob/living/carbon/xenomorph/defender = 'icons/mob/xenos/onmob/defender.dmi',
/mob/living/carbon/xenomorph/sentinel = 'icons/mob/xenos/onmob/sentinel.dmi',
/mob/living/carbon/xenomorph/spitter = 'icons/mob/xenos/onmob/spitter.dmi'
- )
+ ))
// species names
#define SPECIES_HUMAN "Human"
@@ -417,3 +418,33 @@ var/list/default_xeno_onmob_icons = list(
#define HANDLING_LIMBS list("l_arm","l_hand", "r_arm", "r_hand")
#define EXTREMITY_LIMBS list("l_leg","l_foot","r_leg","r_foot","l_arm","l_hand","r_arm","r_hand")
#define CORE_LIMBS list("chest","head","groin")
+
+#define SYMPTOM_ACTIVATION_PROB 3
+
+// Body position defines.
+/// Mob is standing up, usually associated with lying_angle value of 0.
+#define STANDING_UP 0
+/// Mob is lying down, usually associated with lying_angle values of 90 or 270.
+#define LYING_DOWN 1
+
+/// Possible value of [/atom/movable/buckle_lying]. If set to a different (positive-or-zero) value than this, the buckling thing will force a lying angle on the buckled.
+#define NO_BUCKLE_LYING -1
+
+// ====================================
+// /mob/living /tg/ mobility_flags
+// These represent in what capacity the mob is capable of moving
+// Because porting this is underway, NOT ALL FLAGS ARE CURRENTLY IN.
+
+/// can move
+#define MOBILITY_MOVE (1<<0)
+/// can, and is, standing up
+#define MOBILITY_STAND (1<<1)
+/// can rest
+#define MOBILITY_REST (1<<7)
+/// can lie down
+#define MOBILITY_LIEDOWN (1<<8)
+
+#define MOBILITY_FLAGS_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND)
+#define MOBILITY_FLAGS_CARBON_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_REST | MOBILITY_LIEDOWN)
+#define MOBILITY_FLAGS_REST_CAPABLE_DEFAULT (MOBILITY_MOVE | MOBILITY_STAND | MOBILITY_REST | MOBILITY_LIEDOWN)
+
diff --git a/code/__DEFINES/mode.dm b/code/__DEFINES/mode.dm
index b73b2a0d89af..0f04006859e9 100644
--- a/code/__DEFINES/mode.dm
+++ b/code/__DEFINES/mode.dm
@@ -91,8 +91,8 @@
//=================================================
-//Number of marine players against which the Marine's gear scales
-#define MARINE_GEAR_SCALING_NORMAL 30
+/// Number of weighted marine players for 1 gear_scale. gear_scale is clamped to 1 minimum
+#define MARINE_GEAR_SCALING_NORMAL 50
#define RESOURCE_NODE_SCALE 95 //How many players minimum per extra set of resource nodes
#define RESOURCE_NODE_QUANTITY_PER_POP 11 //How many resources total per pop
@@ -109,34 +109,34 @@
//=================================================
//Role defines, specifically lists of roles for job bans, crew manifests and the like.
-var/global/list/ROLES_COMMAND = list(JOB_CO, JOB_XO, JOB_SO, JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_CREWMAN, JOB_POLICE, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_CHIEF_REQUISITION, JOB_CHIEF_ENGINEER, JOB_CMO, JOB_CHIEF_POLICE, JOB_SEA, JOB_SYNTH, JOB_WARDEN)
+GLOBAL_LIST_INIT(ROLES_COMMAND, list(JOB_CO, JOB_XO, JOB_SO, JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_CREWMAN, JOB_POLICE, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_CHIEF_REQUISITION, JOB_CHIEF_ENGINEER, JOB_CMO, JOB_CHIEF_POLICE, JOB_SEA, JOB_SYNTH, JOB_WARDEN))
//Marine roles
#define ROLES_OFFICERS list(JOB_CO, JOB_XO, JOB_SO, JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_SEA, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_SYNTH, JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE)
-var/global/list/ROLES_CIC = list(JOB_CO, JOB_XO, JOB_SO, JOB_WO_CO, JOB_WO_XO)
-var/global/list/ROLES_AUXIL_SUPPORT = list(JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_WO_PILOT)
-var/global/list/ROLES_MISC = list(JOB_SYNTH, JOB_WORKING_JOE, JOB_SEA, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_MESS_SERGEANT, JOB_WO_CORPORATE_LIAISON, JOB_WO_SYNTH)
-var/global/list/ROLES_POLICE = list(JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE)
-var/global/list/ROLES_ENGINEERING = list(JOB_CHIEF_ENGINEER, JOB_ORDNANCE_TECH, JOB_MAINT_TECH, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH)
-var/global/list/ROLES_REQUISITION = list(JOB_CHIEF_REQUISITION, JOB_CARGO_TECH, JOB_WO_CHIEF_REQUISITION, JOB_WO_REQUISITION)
-var/global/list/ROLES_MEDICAL = list(JOB_CMO, JOB_RESEARCHER, JOB_DOCTOR, JOB_NURSE, JOB_WO_CMO, JOB_WO_RESEARCHER, JOB_WO_DOCTOR)
-var/global/list/ROLES_MARINES = list(JOB_SQUAD_LEADER, JOB_SQUAD_TEAM_LEADER, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE)
-var/global/list/ROLES_SQUAD_ALL = list(SQUAD_MARINE_1, SQUAD_MARINE_2, SQUAD_MARINE_3, SQUAD_MARINE_4, SQUAD_MARINE_5, SQUAD_MARINE_CRYO, SQUAD_MARINE_INTEL)
+GLOBAL_LIST_INIT(ROLES_CIC, list(JOB_CO, JOB_XO, JOB_SO, JOB_WO_CO, JOB_WO_XO))
+GLOBAL_LIST_INIT(ROLES_AUXIL_SUPPORT, list(JOB_AUXILIARY_OFFICER, JOB_INTEL, JOB_PILOT, JOB_DROPSHIP_CREW_CHIEF, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_WO_PILOT))
+GLOBAL_LIST_INIT(ROLES_MISC, list(JOB_SYNTH, JOB_WORKING_JOE, JOB_SEA, JOB_CORPORATE_LIAISON, JOB_COMBAT_REPORTER, JOB_MESS_SERGEANT, JOB_WO_CORPORATE_LIAISON, JOB_WO_SYNTH))
+GLOBAL_LIST_INIT(ROLES_POLICE, list(JOB_CHIEF_POLICE, JOB_WARDEN, JOB_POLICE))
+GLOBAL_LIST_INIT(ROLES_ENGINEERING, list(JOB_CHIEF_ENGINEER, JOB_ORDNANCE_TECH, JOB_MAINT_TECH, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH))
+GLOBAL_LIST_INIT(ROLES_REQUISITION, list(JOB_CHIEF_REQUISITION, JOB_CARGO_TECH, JOB_WO_CHIEF_REQUISITION, JOB_WO_REQUISITION))
+GLOBAL_LIST_INIT(ROLES_MEDICAL, list(JOB_CMO, JOB_RESEARCHER, JOB_DOCTOR, JOB_NURSE, JOB_WO_CMO, JOB_WO_RESEARCHER, JOB_WO_DOCTOR))
+GLOBAL_LIST_INIT(ROLES_MARINES, list(JOB_SQUAD_LEADER, JOB_SQUAD_TEAM_LEADER, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE))
+GLOBAL_LIST_INIT(ROLES_SQUAD_ALL, list(SQUAD_MARINE_1, SQUAD_MARINE_2, SQUAD_MARINE_3, SQUAD_MARINE_4, SQUAD_MARINE_5, SQUAD_MARINE_CRYO, SQUAD_MARINE_INTEL))
+GLOBAL_LIST_INIT(ROLES_WO, list(JOB_WO_CO, JOB_WO_XO, JOB_WO_CORPORATE_LIAISON, JOB_WO_SYNTH, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_WO_PILOT, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH, JOB_WO_CHIEF_REQUISITION, JOB_WO_REQUISITION, JOB_WO_CMO, JOB_WO_DOCTOR, JOB_WO_RESEARCHER, JOB_WO_SQUAD_MARINE, JOB_WO_SQUAD_MEDIC, JOB_WO_SQUAD_ENGINEER, JOB_WO_SQUAD_SMARTGUNNER, JOB_WO_SQUAD_SPECIALIST, JOB_WO_SQUAD_LEADER))
//Groundside roles
-var/global/list/ROLES_XENO = list(JOB_XENOMORPH_QUEEN, JOB_XENOMORPH)
-var/global/list/ROLES_WHITELISTED = list(JOB_SYNTH_SURVIVOR, JOB_CO_SURVIVOR, JOB_PREDATOR)
-var/global/list/ROLES_SPECIAL = list(JOB_SURVIVOR)
+GLOBAL_LIST_INIT(ROLES_XENO, list(JOB_XENOMORPH_QUEEN, JOB_XENOMORPH))
+GLOBAL_LIST_INIT(ROLES_WHITELISTED, list(JOB_SYNTH_SURVIVOR, JOB_CO_SURVIVOR, JOB_PREDATOR))
+GLOBAL_LIST_INIT(ROLES_SPECIAL, list(JOB_SURVIVOR))
-var/global/list/ROLES_USCM = ROLES_CIC + ROLES_POLICE + ROLES_AUXIL_SUPPORT + ROLES_MISC + ROLES_ENGINEERING + ROLES_REQUISITION + ROLES_MEDICAL + ROLES_MARINES - ROLES_WO
-var/global/list/ROLES_GROUND = ROLES_XENO + ROLES_SPECIAL + ROLES_WHITELISTED
+GLOBAL_LIST_INIT(ROLES_USCM, ROLES_CIC + GLOB.ROLES_POLICE + GLOB.ROLES_AUXIL_SUPPORT + GLOB.ROLES_MISC + GLOB.ROLES_ENGINEERING + GLOB.ROLES_REQUISITION + GLOB.ROLES_MEDICAL + GLOB.ROLES_MARINES - ROLES_WO)
+GLOBAL_LIST_INIT(ROLES_GROUND, GLOB.ROLES_XENO + ROLES_SPECIAL + ROLES_WHITELISTED)
-var/global/list/ROLES_DISTRESS_SIGNAL = ROLES_USCM + ROLES_GROUND
-var/global/list/ROLES_FACTION_CLASH = ROLES_USCM + JOB_PREDATOR
+GLOBAL_LIST_INIT(ROLES_DISTRESS_SIGNAL, GLOB.ROLES_USCM + GLOB.ROLES_GROUND)
+GLOBAL_LIST_INIT(ROLES_FACTION_CLASH, ROLES_USCM + JOB_PREDATOR)
-var/global/list/ROLES_UNASSIGNED = list(JOB_SQUAD_MARINE)
-var/global/list/ROLES_WO = list(JOB_WO_CO, JOB_WO_XO, JOB_WO_CORPORATE_LIAISON, JOB_WO_SYNTH, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_WO_PILOT, JOB_WO_CHIEF_ENGINEER, JOB_WO_ORDNANCE_TECH, JOB_WO_CHIEF_REQUISITION, JOB_WO_REQUISITION, JOB_WO_CMO, JOB_WO_DOCTOR, JOB_WO_RESEARCHER, JOB_WO_SQUAD_MARINE, JOB_WO_SQUAD_MEDIC, JOB_WO_SQUAD_ENGINEER, JOB_WO_SQUAD_SMARTGUNNER, JOB_WO_SQUAD_SPECIALIST, JOB_WO_SQUAD_LEADER)
+GLOBAL_LIST_INIT(ROLES_UNASSIGNED, list(JOB_SQUAD_MARINE))
//Role lists used for switch() checks in show_blurb_uscm(). Cosmetic, determines ex. "Engineering, USS Almayer", "2nd Bat. 'Falling Falcons'" etc.
#define BLURB_USCM_COMBAT JOB_CO, JOB_XO, JOB_SO, JOB_WO_CO, JOB_WO_XO, JOB_WO_CHIEF_POLICE, JOB_WO_SO, JOB_WO_CREWMAN, JOB_WO_POLICE, JOB_SEA,\
JOB_SQUAD_LEADER, JOB_SQUAD_TEAM_LEADER, JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN, JOB_SQUAD_MEDIC, JOB_SQUAD_ENGI, JOB_SQUAD_MARINE
@@ -153,7 +153,7 @@ var/global/list/ROLES_WO = list(JOB_WO_CO, JOB_WO_XO, JOB_WO_CORPORATE_LIAISON,
#define WHITELIST_COUNCIL "Council"
#define WHITELIST_LEADER "Leader"
-var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL, WHITELIST_LEADER)
+GLOBAL_LIST_INIT(whitelist_hierarchy, list(WHITELIST_NORMAL, WHITELIST_COUNCIL, WHITELIST_LEADER))
//=================================================
#define WHITELIST_YAUTJA (1<<0)
@@ -186,7 +186,7 @@ var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL,
#define WHITELIST_EVERYTHING (WHITELISTS_GENERAL|WHITELISTS_COUNCIL|WHITELISTS_LEADER)
-#define isCouncil(A) (RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_YAUTJA_COUNCIL) || (RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_SYNTHETIC_COUNCIL) || (RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_COMMANDER_COUNCIL)
+#define isCouncil(A) (GLOB.RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_YAUTJA_COUNCIL) || (GLOB.RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_SYNTHETIC_COUNCIL) || (GLOB.RoleAuthority.roles_whitelist[A.ckey] & WHITELIST_COMMANDER_COUNCIL)
//=================================================
@@ -240,9 +240,17 @@ var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL,
#define FACTION_MONKEY "Monkey" // Nanu
#define FACTION_LIST_MARINE list(FACTION_MARINE)
-#define FACTION_LIST_HUMANOID list(FACTION_MARINE, FACTION_PMC, FACTION_WY, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_UPP, FACTION_FREELANCER, FACTION_SURVIVOR, FACTION_NEUTRAL, FACTION_COLONIST, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_YAUTJA, FACTION_ZOMBIE, FACTION_TWE)
-#define FACTION_LIST_ERT list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_UPP, FACTION_FREELANCER, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_MARSHAL, FACTION_TWE)
+#define FACTION_LIST_HUMANOID list(FACTION_MARINE, FACTION_PMC, FACTION_WY, FACTION_WY_DEATHSQUAD, FACTION_CLF, FACTION_CONTRACTOR, FACTION_MARSHAL, FACTION_UPP, FACTION_FREELANCER, FACTION_SURVIVOR, FACTION_NEUTRAL, FACTION_COLONIST, FACTION_MERCENARY, FACTION_DUTCH, FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO, FACTION_YAUTJA, FACTION_ZOMBIE, FACTION_TWE)
+#define FACTION_LIST_ERT list(FACTION_HEFA, FACTION_GLADIATOR, FACTION_PIRATE, FACTION_PIZZA, FACTION_SOUTO)
#define FACTION_LIST_WY list(FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY)
+#define FACTION_LIST_UPP list(FACTION_UPP)
+#define FACTION_LIST_CLF list(FACTION_CLF)
+#define FACTION_LIST_TWE list(FACTION_TWE)
+#define FACTION_LIST_FREELANCER list(FACTION_FREELANCER)
+#define FACTION_LIST_CONTRACTOR list(FACTION_CONTRACTOR)
+#define FACTION_LIST_MERCENARY list(FACTION_MERCENARY)
+#define FACTION_LIST_MARSHAL list(FACTION_MARSHAL)
+#define FACTION_LIST_DUTCH list(FACTION_DUTCH)
#define FACTION_LIST_MARINE_WY list(FACTION_MARINE, FACTION_PMC, FACTION_WY_DEATHSQUAD, FACTION_WY)
#define FACTION_LIST_MARINE_UPP list(FACTION_MARINE, FACTION_UPP)
#define FACTION_LIST_MARINE_TWE list(FACTION_MARINE, FACTION_TWE)
@@ -265,6 +273,6 @@ var/global/list/whitelist_hierarchy = list(WHITELIST_NORMAL, WHITELIST_COUNCIL,
// global vars to prevent spam of the "one xyz alive" messages
-var/global/last_ares_callout
+GLOBAL_VAR(last_ares_callout)
-var/global/last_qm_callout
+GLOBAL_VAR(last_qm_callout)
diff --git a/code/__DEFINES/objects.dm b/code/__DEFINES/objects.dm
index a6b95c879ae4..292b315360c5 100644
--- a/code/__DEFINES/objects.dm
+++ b/code/__DEFINES/objects.dm
@@ -54,6 +54,8 @@
#define SHOCK 8
#define SAFE 16
+#define CLOSED 2
+
//metal, glass, rod stacks
#define MAX_STACK_AMOUNT_METAL 50
#define MAX_STACK_AMOUNT_GLASS 50
@@ -77,14 +79,14 @@
#define GETPULSE_HAND 0 //less accurate (hand)
#define GETPULSE_TOOL 1 //more accurate (med scanner, sleeper, etc)
-var/list/RESTRICTED_CAMERA_NETWORKS = list( //Those networks can only be accessed by preexisting terminals. AIs and new terminals can't use them.
+GLOBAL_LIST_INIT(RESTRICTED_CAMERA_NETWORKS, list( //Those networks can only be accessed by preexisting terminals. AIs and new terminals can't use them.)
"thunder",
"ERT",
"NUKE",
CAMERA_NET_LADDER,
CAMERA_NET_COLONY,
CAMERA_NET_OVERWATCH,
- )
+ ))
#define STASIS_IN_BAG 1
#define STASIS_IN_CRYO_CELL 2
diff --git a/code/__DEFINES/paygrade_defs/civilian.dm b/code/__DEFINES/paygrade_defs/civilian.dm
new file mode 100644
index 000000000000..ed99a363dedd
--- /dev/null
+++ b/code/__DEFINES/paygrade_defs/civilian.dm
@@ -0,0 +1,35 @@
+// Paygrade shorthand defines, to allow clearer designation.
+
+// Civilians
+/// CIV, Civilian
+#define PAY_SHORT_CIV "CIV"
+
+/// CNUR, Nurse
+#define PAY_SHORT_CNUR "CNUR"
+
+/// CDOC, Doctor
+#define PAY_SHORT_CDOC "CDOC"
+
+/// CCMO, Professor
+#define PAY_SHORT_CCMO "CCMO"
+
+/// CREP, Representative
+#define PAY_SHORT_CREP "CREP"
+
+/// SYN, Synthetic
+#define PAY_SHORT_SYN "SYN"
+
+/// OPR, Operative
+#define PAY_SHORT_OPR "OPR"
+
+/// CPO, Officer
+#define PAY_SHORT_CPO "CPO"
+
+/// CSPO, Senior Officer
+#define PAY_SHORT_CSPO "CSPO"
+
+/// REB, Rebel
+#define PAY_SHORT_REB "REB"
+
+/// REBC, Rebel Commander "REBC"
+#define PAY_SHORT_REBC "REBC"
diff --git a/code/__DEFINES/paygrade_defs/cmb.dm b/code/__DEFINES/paygrade_defs/cmb.dm
new file mode 100644
index 000000000000..8ebd7902dbf8
--- /dev/null
+++ b/code/__DEFINES/paygrade_defs/cmb.dm
@@ -0,0 +1,20 @@
+// Paygrade shorthand defines, to allow clearer designation.
+
+// Colonial Marshal Bureau
+/// IHRO, Interstellar Human Rights Observer
+#define PAY_SHORT_IHRO "IHRO"
+
+/// ICCL, Interstellar Commerce Commission Corporate Liaison
+#define PAY_SHORT_ICCL "ICCL"
+
+/// ICCA, Interstellar Commerce Commission Agent
+#define PAY_SHORT_ICCA "ICCA"
+
+/// CMBM, CMB Marshal
+#define PAY_SHORT_CMBM "CMBM"
+
+/// CMBD, CMB Deputy
+#define PAY_SHORT_CMBD "CMBD"
+
+/// CMBS, CMB Synthetic
+#define PAY_SHORT_CMBS "CMBS"
diff --git a/code/__DEFINES/paygrade_defs/dutch.dm b/code/__DEFINES/paygrade_defs/dutch.dm
new file mode 100644
index 000000000000..299096060f3f
--- /dev/null
+++ b/code/__DEFINES/paygrade_defs/dutch.dm
@@ -0,0 +1,17 @@
+// Paygrade shorthand defines, to allow clearer designation.
+
+// Dutches Dozen
+/// DTC, Dutch's Dozen Standard Mercenary
+#define PAY_SHORT_DTC "DTC"
+
+/// DTCM, Dutch's Dozen Medic
+#define PAY_SHORT_DTCM "DTCM"
+
+/// DTCF, Dutch's Dozen Flamethrower Specialist
+#define PAY_SHORT_DTCF "DTCF"
+
+/// DTCMG, Dutch's Dozen Machinegunner
+#define PAY_SHORT_DTCMG "DTCMG"
+
+/// DTCA, Arnold
+#define PAY_SHORT_DTCA "DTCA"
diff --git a/code/__DEFINES/paygrade_defs/marines.dm b/code/__DEFINES/paygrade_defs/marines.dm
new file mode 100644
index 000000000000..74b659630820
--- /dev/null
+++ b/code/__DEFINES/paygrade_defs/marines.dm
@@ -0,0 +1,80 @@
+// Paygrade shorthand defines, to allow clearer designation.
+
+// USCM MARINES
+/// ME1, Private
+#define PAY_SHORT_ME1 "ME1"
+
+/// ME2, Private First Class
+#define PAY_SHORT_ME2 "ME2"
+
+/// ME3, Lance Corporal
+#define PAY_SHORT_ME3 "ME3"
+
+/// ME4, Corporal
+#define PAY_SHORT_ME4 "ME4"
+
+/// ME5, Sergeant
+#define PAY_SHORT_ME5 "ME5"
+
+/// ME6, Staff Sergeant
+#define PAY_SHORT_ME6 "ME6"
+
+/// ME7, Gunnery Sergeant
+#define PAY_SHORT_ME7 "ME7"
+
+/// ME8, Master Sergeant
+#define PAY_SHORT_ME8 "ME8"
+
+/// ME8E, First Sergeant
+#define PAY_SHORT_ME8E "ME8E"
+
+/// ME9, Master Gunnery Sergeant
+#define PAY_SHORT_ME9 "ME9"
+
+/// ME9E, Sergeant Major
+#define PAY_SHORT_ME9E "ME9E"
+
+/// ME9C, Sergeant Major of the Colonial Marine Corps
+#define PAY_SHORT_ME9C "ME9C"
+
+/// MO1, Second Lieutenant
+#define PAY_SHORT_MO1 "MO1"
+
+/// MO2, First Lieutenant
+#define PAY_SHORT_MO2 "MO2"
+/// MO3, Captain
+
+#define PAY_SHORT_MO3 "MO3"
+/// MO4, Major
+
+#define PAY_SHORT_MO4 "MO4"
+/// MO5, Lieutenant Colonel
+
+#define PAY_SHORT_MO5 "MO5"
+/// MO6, Colonel
+
+#define PAY_SHORT_MO6 "MO6"
+/// MO6E, Senior Colonel
+
+#define PAY_SHORT_MO6E "MO6E"
+/// MO6C, Division Colonel
+
+#define PAY_SHORT_MO6C "MO6C"
+/// MO7, Brigadier General
+
+#define PAY_SHORT_MO7 "MO7"
+/// MO8, Major General
+
+#define PAY_SHORT_MO8 "MO8"
+/// MO9, Lieutenant General
+
+#define PAY_SHORT_MO9 "MO9"
+/// MO10, General
+
+#define PAY_SHORT_MO10 "MO10"
+
+/// MO10C, Assistant Commandant of the Marine Corps
+#define PAY_SHORT_MO10C "MO10C"
+
+/// MO10S, Commandant of the Marine Corps
+#define PAY_SHORT_MO10S "MO10S"
diff --git a/code/__DEFINES/paygrade_defs/navy.dm b/code/__DEFINES/paygrade_defs/navy.dm
new file mode 100644
index 000000000000..d51cccb8fe97
--- /dev/null
+++ b/code/__DEFINES/paygrade_defs/navy.dm
@@ -0,0 +1,74 @@
+// Paygrade shorthand defines, to allow clearer designation.
+
+// USCM NAVY
+/// NE1, Seaman Recruit
+#define PAY_SHORT_NE1 "NE1"
+
+/// NE2M, Seaman Apprentice
+#define PAY_SHORT_NE2 "NE2"
+
+/// NE3, Seaman
+#define PAY_SHORT_NE3 "NE3"
+
+/// NE4, Petty Officer 3rd Class
+#define PAY_SHORT_NE4 "NE4"
+
+/// NE5, Petty Officer 2nd Class
+#define PAY_SHORT_NE5 "NE5"
+
+/// NE6, Petty Officer 1st Class
+#define PAY_SHORT_NE6 "N36"
+
+/// NE7, Chief Petty Officer
+#define PAY_SHORT_NE7 "NE7"
+
+/// NE8, Senior Chief Petty Officer
+#define PAY_SHORT_NE8 "NE8"
+
+/// NE8C, Command Senior Chief Petty Officer
+#define PAY_SHORT_NE8C "NE8C"
+
+/// NE9, Master Chief Petty Officer
+#define PAY_SHORT_NE9 "NE9"
+
+/// NE9C, Command Master Chief Petty Officer
+#define PAY_SHORT_NE9C "NE9C"
+
+/// NO1, Ensign
+#define PAY_SHORT_NO1 "NO1"
+
+/// NO2, Lieutenant Junior Grade
+#define PAY_SHORT_NO2 "NO2"
+
+/// NO3, Lieutenant
+#define PAY_SHORT_NO3 "NO3"
+
+/// NO4, Lieutenant Commander
+#define PAY_SHORT_NO4 "NO4"
+
+/// NO5, Commander
+#define PAY_SHORT_NO5 "NO5"
+
+/// NO6, Captain
+#define PAY_SHORT_NO6 "NO6"
+
+/// NO6E, Commodore
+#define PAY_SHORT_NO6E "NO6E"
+
+/// NO6C, Senior Commodore
+#define PAY_SHORT_NO6C "NO6C"
+
+/// NO7, Rear Admiral (Lower Half)
+#define PAY_SHORT_NO7 "NO7"
+
+/// NO8, Rear Admiral (Upper Half)
+#define PAY_SHORT_NO8 "NO8"
+
+/// NO9, Vice Admiral
+#define PAY_SHORT_NO9 "NO9"
+
+/// NO10, Admiral
+#define PAY_SHORT_NO10 "NO10"
+
+/// NO10C, Chief of Naval Operations
+#define PAY_SHORT_NO10C "NO10C"
diff --git a/code/__DEFINES/paygrade_defs/provost.dm b/code/__DEFINES/paygrade_defs/provost.dm
new file mode 100644
index 000000000000..5b2121642d52
--- /dev/null
+++ b/code/__DEFINES/paygrade_defs/provost.dm
@@ -0,0 +1,14 @@
+// Paygrade shorthand defines, to allow clearer designation.
+
+// PROVOST OFFICE
+/// PvI, Provost Inspector
+#define PAY_SHORT_PVI "PvI"
+
+/// PvM, Provost Marshal
+#define PAY_SHORT_PVM "PvM"
+
+/// PvSM, Provost Sector Marshal
+#define PAY_SHORT_PVSM "PvSM"
+
+/// PvCM, Provost Chief Marshal
+#define PAY_SHORT_PVCM "PvCM"
diff --git a/code/__DEFINES/paygrade_defs/upp.dm b/code/__DEFINES/paygrade_defs/upp.dm
new file mode 100644
index 000000000000..40c0d8441b2e
--- /dev/null
+++ b/code/__DEFINES/paygrade_defs/upp.dm
@@ -0,0 +1,59 @@
+// Paygrade shorthand defines, to allow clearer designation.
+
+// Union of Progressive Peoples
+/// UE,
+#define PAY_SHORT_UEC "UEC"
+
+/// UE1, Private
+#define PAY_SHORT_UE1 "UE1"
+
+/// UE2, Private First Class
+#define PAY_SHORT_UE2 "UE2"
+
+/// UE3, Korporal
+#define PAY_SHORT_UE3 "UE3"
+
+/// UE4, unior Serzhant
+#define PAY_SHORT_UE4 "UE4"
+
+/// UE5, Serzhant
+#define PAY_SHORT_UE5 "UE5"
+
+/// UE6, Master Serzhant
+#define PAY_SHORT_UE6 "UE6"
+
+/// UC1, Junior Kommando
+#define PAY_SHORT_UC1 "UC1"
+
+/// UC2, 2nd Kommando
+#define PAY_SHORT_UC2 "UC2"
+
+/// UC3, 1st Kommando
+#define PAY_SHORT_UC3 "UC3"
+
+/// UO1, Leytenant
+#define PAY_SHORT_UO1 "UO1"
+
+/// UO2, Senior Leytenant
+#define PAY_SHORT_UO2 "UO2"
+
+/// UO3, Kapitan
+#define PAY_SHORT_UO3 "UO3"
+
+/// UO4, Mayjor
+#define PAY_SHORT_UO4 "UO4"
+
+/// UO5, Leytenant Kolonel
+#define PAY_SHORT_UO5 "UO5"
+
+/// UO6, Kolonel
+#define PAY_SHORT_UO6 "UO6"
+
+/// UO7, Mayjor General
+#define PAY_SHORT_UO7 "UO7"
+
+/// UO8, Leytenant General
+#define PAY_SHORT_UO8 "UO8"
+
+/// UO9, Army General
+#define PAY_SHORT_UO9 "UO9"
diff --git a/code/__DEFINES/paygrade_defs/weyland.dm b/code/__DEFINES/paygrade_defs/weyland.dm
new file mode 100644
index 000000000000..1b6c168e9b6e
--- /dev/null
+++ b/code/__DEFINES/paygrade_defs/weyland.dm
@@ -0,0 +1,32 @@
+// Paygrade shorthand defines, to allow clearer designation.
+
+// Weyland Yutani
+/// WYC1, Trainee
+#define PAY_SHORT_WYC1 "WYC1"
+
+/// WYC2, Junior Executive
+#define PAY_SHORT_WYC2 "WYC2"
+
+/// WYC3, Executive
+#define PAY_SHORT_WYC3 "WYC3"
+
+/// WYC4, Senior Executive
+#define PAY_SHORT_WYC4 "WYC4"
+
+/// WYC5, Executive Specialist
+#define PAY_SHORT_WYC5 "WYC5"
+
+/// WYC6, Executive Supervisor
+#define PAY_SHORT_WYC6 "WYC6"
+
+/// WYC7, Assistant Manager
+#define PAY_SHORT_WYC7 "WYC7"
+
+/// WYC8, Division Manager
+#define PAY_SHORT_WYC8 "WYC8"
+
+/// WYC9, Chief Executive
+#define PAY_SHORT_WYC9 "WYC9"
+
+/// WYC10, Director
+#define PAY_SHORT_WYC10 "WYC10"
diff --git a/code/__DEFINES/radio.dm b/code/__DEFINES/radio.dm
index e2bd155fcb0d..cc1831501bad 100644
--- a/code/__DEFINES/radio.dm
+++ b/code/__DEFINES/radio.dm
@@ -61,6 +61,10 @@
#define RADIO_CHANNEL_PMC_CCT "PMC CCT"
#define RADIO_CHANNEL_WY_WO "SpecOps"
+//Listening Devices
+#define RADIO_CHANNEL_BUG_A "Listening Device A"
+#define RADIO_CHANNEL_BUG_B "Listening Device B"
+
//1-Channel ERTs
#define RADIO_CHANNEL_DUTCH_DOZEN "DD"
#define RADIO_CHANNEL_VAI "VAI"
diff --git a/code/__DEFINES/regex.dm b/code/__DEFINES/regex.dm
index f56871ec83f2..a0d9c9a7323b 100644
--- a/code/__DEFINES/regex.dm
+++ b/code/__DEFINES/regex.dm
@@ -6,38 +6,38 @@
// The lazy URL finder. Lazy in that it matches the bare minimum
// Replicates BYOND's own URL parser in functionality.
-var/global/regex/url_find_lazy
+GLOBAL_DATUM(url_find_lazy, /regex)
// REGEX datums used for process_chat_markup.
-var/global/regex/markup_bold
-var/global/regex/markup_italics
-var/global/regex/markup_strike
-var/global/regex/markup_underline
+GLOBAL_DATUM(markup_bold, /regex)
+GLOBAL_DATUM(markup_italics, /regex)
+GLOBAL_DATUM(markup_strike, /regex)
+GLOBAL_DATUM(markup_underline, /regex)
// Global list for mark-up REGEX datums.
// Initialized in the hook, to avoid passing by null value.
-var/global/list/markup_regex = list()
+GLOBAL_LIST_EMPTY(markup_regex)
// Global list for mark-up REGEX tag collection.
-var/global/list/markup_tags = list("/" = list("", ""),
+GLOBAL_LIST_INIT(markup_tags, list("/" = list("", ""),
"*" = list("", ""),
"~" = list("", ""),
- "_" = list("", ""))
+ "_" = list("", "")))
/proc/initialize_global_regex()
- url_find_lazy = new(@"((https?|byond):\/\/[^\s]*)", "g")
+ GLOB.url_find_lazy = new(@"((https?|byond):\/\/[^\s]*)", "g")
- markup_bold = new("((\\W|^)\\*)(\[^\\*\]*)(\\*(\\W|$))", "g")
- markup_italics = new("((\\W|^)\\/)(\[^\\/\]*)(\\/(\\W|$))", "g")
- markup_strike = new("((\\W|^)\\~)(\[^\\~\]*)(\\~(\\W|$))", "g")
- markup_underline = new("((\\W|^)\\_)(\[^\\_\]*)(\\_(\\W|$))", "g")
+ GLOB.markup_bold = new("((\\W|^)\\*)(\[^\\*\]*)(\\*(\\W|$))", "g")
+ GLOB.markup_italics = new("((\\W|^)\\/)(\[^\\/\]*)(\\/(\\W|$))", "g")
+ GLOB.markup_strike = new("((\\W|^)\\~)(\[^\\~\]*)(\\~(\\W|$))", "g")
+ GLOB.markup_underline = new("((\\W|^)\\_)(\[^\\_\]*)(\\_(\\W|$))", "g")
// List needs to be initialized here, due to DM mixing and matching pass-by-value and -reference as it chooses.
- markup_regex = list(
- "/" = markup_italics,
- "*" = markup_bold,
- "~" = markup_strike,
- "_" = markup_underline,
+ GLOB.markup_regex = list(
+ "/" = GLOB.markup_italics,
+ "*" = GLOB.markup_bold,
+ "~" = GLOB.markup_strike,
+ "_" = GLOB.markup_underline,
)
return 1
diff --git a/code/__DEFINES/shuttles.dm b/code/__DEFINES/shuttles.dm
index d283656ccae6..a3299184e4ef 100644
--- a/code/__DEFINES/shuttles.dm
+++ b/code/__DEFINES/shuttles.dm
@@ -100,10 +100,12 @@
#define MOBILE_SHUTTLE_ID_ERT_BIG "ert_boarding_shuttle"
#define MOBILE_TRIJENT_ELEVATOR "trijentshuttle2"
-#define STAT_TRIJENT_LZ1 "trigent_lz1"
-#define STAT_TRIJENT_LZ2 "trigent_lz2"
-#define STAT_TRIJENT_ENGI "trigent_engineering"
-#define STAT_TRIJENT_OMEGA "trigent_omega"
+#define STAT_TRIJENT_EMPTY "trijent_empty"
+#define STAT_TRIJENT_OCCUPIED "trijent_occupied"
+#define STAT_TRIJENT_LZ1 "trijent_lz1"
+#define STAT_TRIJENT_LZ2 "trijent_lz2"
+#define STAT_TRIJENT_ENGI "trijent_engineering"
+#define STAT_TRIJENT_OMEGA "trijent_omega"
#define MOBILE_SHUTTLE_LIFEBOAT_PORT "lifeboat-port"
#define MOBILE_SHUTTLE_LIFEBOAT_STARBOARD "lifeboat-starboard"
@@ -115,6 +117,7 @@
#define ALMAYER_DROPSHIP_LZ1 "almayer-hangar-lz1"
#define ALMAYER_DROPSHIP_LZ2 "almayer-hangar-lz2"
+#define DROPSHIP_FLYBY_ID "special_flight"
#define DROPSHIP_LZ1 "dropship-lz1"
#define DROPSHIP_LZ2 "dropship-lz2"
diff --git a/code/__DEFINES/skills.dm b/code/__DEFINES/skills.dm
index 5dabb4545a32..d33e26c1c3f6 100644
--- a/code/__DEFINES/skills.dm
+++ b/code/__DEFINES/skills.dm
@@ -42,6 +42,8 @@
#define SKILL_SPEC_DEFAULT 0
/// Is trained to use specialist gear, but hasn't picked a kit.
#define SKILL_SPEC_TRAINED 1
+/// Is trained to use specialist gear & HAS picked a kit. (Functionally same as SPEC_ROCKET)
+#define SKILL_SPEC_KITTED 2
/// Can use RPG
#define SKILL_SPEC_ROCKET 2
/// Can use thermal cloaks and custom M4RA rifle
diff --git a/code/__DEFINES/sounds.dm b/code/__DEFINES/sounds.dm
index a6bb381100e7..541d95d28189 100644
--- a/code/__DEFINES/sounds.dm
+++ b/code/__DEFINES/sounds.dm
@@ -27,7 +27,7 @@
#define SOUND_CHANNEL_AMBIENCE 1019
#define SOUND_CHANNEL_WALKMAN 1020
#define SOUND_CHANNEL_SOUNDSCAPE 1021
-#define SOUND_CHANNEL_ADMIN_MIDI 1022
+//#define SOUND_CHANNEL_ADMIN_MIDI 1022
#define SOUND_CHANNEL_LOBBY 1023
#define SOUND_CHANNEL_Z 1024
diff --git a/code/__DEFINES/speech_channels.dm b/code/__DEFINES/speech_channels.dm
index 3f6e4720bde9..5a9a74af8ad0 100644
--- a/code/__DEFINES/speech_channels.dm
+++ b/code/__DEFINES/speech_channels.dm
@@ -1,6 +1,7 @@
// Used to direct channels to speak into.
#define SAY_CHANNEL "Say"
#define COMMS_CHANNEL "Comms"
+#define WHISPER_CHANNEL "Whisper"
#define ME_CHANNEL "Me"
#define OOC_CHANNEL "OOC"
#define LOOC_CHANNEL "LOOC"
diff --git a/code/__DEFINES/status_effects.dm b/code/__DEFINES/status_effects.dm
new file mode 100644
index 000000000000..ecccbd40abeb
--- /dev/null
+++ b/code/__DEFINES/status_effects.dm
@@ -0,0 +1,25 @@
+///if it allows multiple instances of the effect
+#define STATUS_EFFECT_MULTIPLE 0
+///if it allows only one, preventing new instances
+#define STATUS_EFFECT_UNIQUE 1
+///if it allows only one, but new instances replace
+#define STATUS_EFFECT_REPLACE 2
+/// if it only allows one, and new instances just instead refresh the timer
+#define STATUS_EFFECT_REFRESH 3
+
+///Processing flags - used to define the speed at which the status will work
+///This is fast - 0.2s between ticks (I believe!)
+#define STATUS_EFFECT_FAST_PROCESS 0
+///This is slower and better for more intensive status effects - 1s between ticks
+#define STATUS_EFFECT_NORMAL_PROCESS 1
+
+//Incapacitated status effect flags
+/// If the incapacitated status effect will ignore a mob in restraints (handcuffs)
+#define IGNORE_RESTRAINTS (1<<0)
+/// If the incapacitated status effect will ignore a mob in stasis (stasis beds)
+#define IGNORE_STASIS (1<<1)
+/// If the incapacitated status effect will ignore a mob being agressively grabbed
+#define IGNORE_GRAB (1<<2)
+
+/// Time threshold after which we launch ending timer - this should be higher than the slowest processing rate
+#define STATUS_EFFECT_TIME_THRESHOLD (2 SECONDS)
diff --git a/code/__DEFINES/subsystems.dm b/code/__DEFINES/subsystems.dm
index 8a65a4b961ff..9cb67e1e0de1 100644
--- a/code/__DEFINES/subsystems.dm
+++ b/code/__DEFINES/subsystems.dm
@@ -109,36 +109,24 @@
// Subsystems shutdown in the reverse of the order they initialize in
// The numbers just define the ordering, they are meaningless otherwise.
-#define SS_INIT_TICKER_SPAWN 999
+#define SS_INIT_PROFILER 86
#define SS_INIT_INPUT 85
-#define SS_INIT_FAIL_TO_TOPIC 84
#define SS_INIT_TOPIC 83
#define SS_INIT_LOBBYART 82
-#define SS_INIT_RUST 30
#define SS_INIT_INFLUXDRIVER 28
-#define SS_INIT_SUPPLY_SHUTTLE 25
#define SS_INIT_GARBAGE 24
#define SS_INIT_EVENTS 23.5
-#define SS_INIT_JOB 23
+#define SS_INIT_HIJACK 22.6
#define SS_INIT_REDIS 22.5
#define SS_INIT_REAGENTS 22.1
#define SS_INIT_MAPPING 22
#define SS_INIT_NIGHTMARE 21.5
#define SS_INIT_TIMETRACK 21.1
#define SS_INIT_HUMANS 21
-#define SS_INIT_MAP 20
-#define SS_INIT_COMPONENT 19.5
#define SS_INIT_POWER 19
-#define SS_INIT_OBJECT 18
-#define SS_INIT_PIPENET 17.5
-#define SS_INIT_XENOARCH 17
-#define SS_INIT_MORE_INIT 16
-#define SS_INIT_AIR 15
-#define SS_INIT_TELEPORTER 13
#define SS_INIT_INFLUXMCSTATS 12
#define SS_INIT_INFLUXSTATS 11
#define SS_INIT_LIGHTING 10
-#define SS_INIT_DEFCON 9
#define SS_INIT_LAW 6
#define SS_INIT_FZ_TRANSITIONS 5
#define SS_INIT_PROJECTILES 4.1
@@ -152,12 +140,9 @@
#define SS_INIT_RADIO 2
#define SS_INIT_TIMER 100
#define SS_INIT_UNSPECIFIED 0
-#define SS_INIT_EMERGENCY_SHUTTLE -19
#define SS_INIT_ASSETS -20
#define SS_INIT_TICKER -21
#define SS_INIT_VOTE -23
-#define SS_INIT_FINISH -24
-#define SS_INIT_ADMIN -26
#define SS_INIT_DATABASE -27
#define SS_INIT_ENTITYMANAGER -28
#define SS_INIT_PLAYTIME -29
@@ -166,7 +151,6 @@
#define SS_INIT_MINIMAP -34
#define SS_INIT_STATPANELS -98
#define SS_INIT_CHAT -100 //Should be last to ensure chat remains smooth during init.
-#define SS_INIT_EARLYRUNTIMES -500 // Post-init notifier
// Subsystem fire priority, from lowest to highest priority
// If the subsystem isn't listed here it's either DEFAULT or PROCESS (if it's a processing subsystem child)
@@ -177,7 +161,6 @@
#define SS_PRIORITY_SOUND 250
#define SS_PRIORITY_TICKER 200
#define SS_PRIORITY_NIGHTMARE 180
-#define SS_PRIORITY_MAPVIEW 170
#define SS_PRIORITY_QUADTREE 160
#define SS_PRIORITY_CHAT 155
#define SS_PRIORITY_STATPANEL 154
@@ -195,20 +178,19 @@
#define SS_PRIORITY_VOTE 110
#define SS_PRIORITY_FAST_OBJECTS 105
#define SS_PRIORITY_OBJECTS 104
-#define SS_PRIORITY_FACEHUGGERS 100
#define SS_PRIORITY_DECORATOR 99
+#define SS_PRIORITY_EFFECTS 97
+#define SS_PRIORITY_FASTEFFECTS 96
+#define SS_PRIORITY_HIJACK 97
#define SS_PRIORITY_POWER 95
-#define SS_PRIORITY_EFFECTS 92
+#define SS_PRIORITY_OLDEFFECTS 92
#define SS_PRIORITY_MACHINERY 90
#define SS_PRIORITY_FZ_TRANSITIONS 88
-#define SS_PRIORITY_PIPENET 85
#define SS_PRIORITY_ROUND_RECORDING 83
#define SS_PRIORITY_SHUTTLE 80
-#define SS_PRIORITY_TELEPORTER 75
#define SS_PRIORITY_EVENT 65
#define SS_PRIORITY_DISEASE 60
-#define SS_PRIORITY_FAST_MACHINERY 55
-#define SS_PRIORITY_MIDI 40
+#define SS_PRIORITY_DEFENSES 55
#define SS_PRIORITY_ENTITY 37
#define SS_PRIORITY_DEFCON 35
#define SS_PRIORITY_ACID_PILLAR 34
@@ -227,7 +209,6 @@
#define SS_PRIORITY_INFLUXSTATS 8
#define SS_PRIORITY_PLAYTIME 5
#define SS_PRIORITY_PERFLOGGING 4
-#define SS_PRIORITY_CORPSESPAWNER 3
#define SS_PRIORITY_GARBAGE 2
#define SS_PRIORITY_INACTIVITY 1
#define SS_PRIORITY_ADMIN 0
diff --git a/code/__DEFINES/supply.dm b/code/__DEFINES/supply.dm
new file mode 100644
index 000000000000..0369b271207c
--- /dev/null
+++ b/code/__DEFINES/supply.dm
@@ -0,0 +1,17 @@
+//We use the cost to determine the spawn chance this equals out the crates that spawn later in the round.
+#define ASRS_HIGHEST_WEIGHT 0 //warning this weight wont change.
+#define ASRS_VERY_HIGH_WEIGHT 5
+#define ASRS_HIGH_WEIGHT 15
+#define ASRS_MEDIUM_WEIGHT 25
+#define ASRS_LOW_WEIGHT 35
+#define ASRS_VERY_LOW_WEIGHT 50
+#define ASRS_LOWEST_WEIGHT 100
+
+// List of pools of supply packs, rolled individually by the ASRS system
+/// Main pool of ASRS supplies, dispensing military supplies such as ammo
+#define ASRS_POOL_MAIN "Main"
+/// Secondary ASRS pool dispening food related items for MessTech
+#define ASRS_POOL_FOOD "Food"
+
+/// Divider to the amount of xeno forces on the planet to ASRS provided crates. It is used as such sqrt(xenos/ASRS_XENO_CRATES_DIVIDER))
+#define ASRS_XENO_CRATES_DIVIDER 4
diff --git a/code/__DEFINES/surgery.dm b/code/__DEFINES/surgery.dm
index 1bdf2318d250..d63c6da26ac6 100644
--- a/code/__DEFINES/surgery.dm
+++ b/code/__DEFINES/surgery.dm
@@ -38,6 +38,15 @@ unless the surgical tool is completely unsuited to what it's being used for.*/
///A tool that's perfect for the surgery.
#define SURGERY_TOOL_MULT_IDEAL 1
+///The (no) chance of failure for surgery because the correct tools/conditions are used or skill compensates
+#define SURGERY_FAILURE_IMPOSSIBLE 0
+///The chance of failure for surgery because the the tool/ground is SURGERY_TOOL_MULT_BAD_SUBSTITUTE/SURGERY_SURFACE_MULT_UNSUITED and skill can't compensate enough
+#define SURGERY_FAILURE_UNLIKELY 5
+///The chance of failure for surgery because the the tool/ground is SURGERY_TOOL_MULT_AWFUL/SURGERY_SURFACE_MULT_AWFUL and skill can't compensate enough
+#define SURGERY_FAILURE_POSSIBLE 25
+///The chance of failure for surgery because the the tool and ground is some combination worse than awful and skill can't compensate enough
+#define SURGERY_FAILURE_LIKELY 50
+
//When initiating surgeries, these define their order when listed in initiation selector or 'you can't use this tool for anything, but could x, y, or z' messages.
///Appears first in lists. Ex. larva surgery, opening incision. Immediately life-threatening or initiation surgeries.
#define SURGERY_PRIORITY_MAXIMUM 5
@@ -149,7 +158,7 @@ See also /datum/surgery_step/saw_off_limb/failure var/list/cannot_hack, listing
#define SURGERY_TOOLS_SEVER_BONE list(\
/obj/item/tool/surgery/circular_saw = SURGERY_TOOL_MULT_IDEAL,\
/obj/item/weapon/twohanded/fireaxe = SURGERY_TOOL_MULT_SUBOPTIMAL,\
- /obj/item/weapon/claymore/mercsword/machete = SURGERY_TOOL_MULT_SUBOPTIMAL,\
+ /obj/item/weapon/sword/machete = SURGERY_TOOL_MULT_SUBOPTIMAL,\
/obj/item/tool/hatchet = SURGERY_TOOL_MULT_SUBSTITUTE,\
/obj/item/tool/kitchen/knife/butcher = SURGERY_TOOL_MULT_SUBSTITUTE,\
/obj/item/attachable/bayonet = SURGERY_TOOL_MULT_BAD_SUBSTITUTE\
diff --git a/code/__DEFINES/text.dm b/code/__DEFINES/text.dm
index e3724e65f620..0ce7e508daac 100644
--- a/code/__DEFINES/text.dm
+++ b/code/__DEFINES/text.dm
@@ -17,3 +17,10 @@
#define SHOW_MESSAGE_VISIBLE 1
#define SHOW_MESSAGE_AUDIBLE 2
+
+//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
+#define MAX_MESSAGE_LEN 1024
+#define MAX_EMOTE_LEN 256
+#define MAX_PAPER_MESSAGE_LEN 3072
+#define MAX_BOOK_MESSAGE_LEN 9216
+#define MAX_NAME_LEN 26
diff --git a/code/__DEFINES/tgs.dm b/code/__DEFINES/tgs.dm
index 6187a67825a4..c561a64ebf58 100644
--- a/code/__DEFINES/tgs.dm
+++ b/code/__DEFINES/tgs.dm
@@ -1,6 +1,6 @@
// tgstation-server DMAPI
-#define TGS_DMAPI_VERSION "6.5.3"
+#define TGS_DMAPI_VERSION "7.0.1"
// All functions and datums outside this document are subject to change with any version and should not be relied on.
@@ -73,12 +73,12 @@
#define TGS_EVENT_REPO_MERGE_PULL_REQUEST 3
/// Before the repository makes a sychronize operation. Parameters: Absolute repostiory path.
#define TGS_EVENT_REPO_PRE_SYNCHRONIZE 4
-/// Before a BYOND install operation begins. Parameters: [/datum/tgs_version] of the installing BYOND.
-#define TGS_EVENT_BYOND_INSTALL_START 5
-/// When a BYOND install operation fails. Parameters: Error message
-#define TGS_EVENT_BYOND_INSTALL_FAIL 6
-/// When the active BYOND version changes. Parameters: (Nullable) [/datum/tgs_version] of the current BYOND, [/datum/tgs_version] of the new BYOND.
-#define TGS_EVENT_BYOND_ACTIVE_VERSION_CHANGE 7
+/// Before a engine install operation begins. Parameters: Version string of the installing engine.
+#define TGS_EVENT_ENGINE_INSTALL_START 5
+/// When a engine install operation fails. Parameters: Error message
+#define TGS_EVENT_ENGINE_INSTALL_FAIL 6
+/// When the active engine version changes. Parameters: (Nullable) Version string of the current engine, version string of the new engine.
+#define TGS_EVENT_ENGINE_ACTIVE_VERSION_CHANGE 7
/// When the compiler starts running. Parameters: Game directory path, origin commit SHA.
#define TGS_EVENT_COMPILE_START 8
/// When a compile is cancelled. No parameters.
@@ -108,7 +108,7 @@
// #define TGS_EVENT_DREAM_DAEMON_LAUNCH 22
/// After a single submodule update is performed. Parameters: Updated submodule name.
#define TGS_EVENT_REPO_SUBMODULE_UPDATE 23
-/// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, byond version.
+/// After CodeModifications are applied, before DreamMaker is run. Parameters: Game directory path, origin commit sha, version string of the used engine.
#define TGS_EVENT_PRE_DREAM_MAKER 24
/// Whenever a deployment folder is deleted from disk. Parameters: Game directory path.
#define TGS_EVENT_DEPLOYMENT_CLEANUP 25
@@ -122,6 +122,7 @@
/// The watchdog will restart on reboot.
#define TGS_REBOOT_MODE_RESTART 2
+// Note that security levels are currently meaningless in OpenDream
/// DreamDaemon Trusted security level.
#define TGS_SECURITY_TRUSTED 0
/// DreamDaemon Safe security level.
@@ -129,6 +130,18 @@
/// DreamDaemon Ultrasafe security level.
#define TGS_SECURITY_ULTRASAFE 2
+/// DreamDaemon public visibility level.
+#define TGS_VISIBILITY_PUBLIC 0
+/// DreamDaemon private visibility level.
+#define TGS_VISIBILITY_PRIVATE 1
+/// DreamDaemon invisible visibility level.
+#define TGS_VISIBILITY_INVISIBLE 2
+
+/// The Build Your Own Net Dream engine.
+#define TGS_ENGINE_TYPE_BYOND 0
+/// The OpenDream engine.
+#define TGS_ENGINE_TYPE_OPENDREAM 1
+
//REQUIRED HOOKS
/**
@@ -442,6 +455,10 @@
/world/proc/TgsVersion()
return
+/// Returns the running engine type
+/world/proc/TgsEngine()
+ return
+
/// Returns the current [/datum/tgs_version] of the DMAPI being used if it was activated, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsApiVersion()
return
@@ -458,6 +475,10 @@
/world/proc/TgsSecurityLevel()
return
+/// Returns the current BYOND visibility level as a TGS_VISIBILITY_ define if TGS is present, null otherwise. Requires TGS to be using interop API version 5 or higher otherwise the string "___unimplemented" wil be returned. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
+/world/proc/TgsVisibility()
+ return
+
/// Returns a list of active [/datum/tgs_revision_information/test_merge]s if TGS is present, null otherwise. This function may sleep if the call to [/world/proc/TgsNew] is sleeping!
/world/proc/TgsTestMerges()
return
diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm
index b40ae85c3f5f..c2abe21a26ad 100644
--- a/code/__DEFINES/traits.dm
+++ b/code/__DEFINES/traits.dm
@@ -1,22 +1,20 @@
-//shamelessly ripped from TG
#define SIGNAL_ADDTRAIT(trait_ref) "addtrait [trait_ref]"
#define SIGNAL_REMOVETRAIT(trait_ref) "removetrait [trait_ref]"
// trait accessor defines
-//here be dragons
#define ADD_TRAIT(target, trait, source) \
do { \
var/list/_L; \
- if (!target.status_traits) { \
- target.status_traits = list(); \
- _L = target.status_traits; \
+ if (!target._status_traits) { \
+ target._status_traits = list(); \
+ _L = target._status_traits; \
_L[trait] = list(source); \
SEND_SIGNAL(target, SIGNAL_ADDTRAIT(trait), trait); \
if(trait in GLOB.traits_with_elements){ \
target.AddElement(GLOB.traits_with_elements[trait]); \
} \
} else { \
- _L = target.status_traits; \
+ _L = target._status_traits; \
if (_L[trait]) { \
_L[trait] |= list(source); \
} else { \
@@ -30,16 +28,16 @@
} while (0)
#define REMOVE_TRAIT(target, trait, sources) \
do { \
- var/list/_L = target.status_traits; \
+ var/list/_L = target._status_traits; \
var/list/_S; \
if (sources && !islist(sources)) { \
_S = list(sources); \
} else { \
_S = sources\
}; \
- if (_L && _L[trait]) { \
+ if (_L?[trait]) { \
for (var/_T in _L[trait]) { \
- if ((!_S && (_T != TRAIT_SOURCE_QUIRK)) || (_T in _S)) { \
+ if ((!_S && (_T != ROUNDSTART_TRAIT)) || (_T in _S)) { \
_L[trait] -= _T \
} \
};\
@@ -51,13 +49,40 @@
} \
}; \
if (!length(_L)) { \
- target.status_traits = null \
+ target._status_traits = null \
+ }; \
+ } \
+ } while (0)
+#define REMOVE_TRAIT_NOT_FROM(target, trait, sources) \
+ do { \
+ var/list/_traits_list = target._status_traits; \
+ var/list/_sources_list; \
+ if (sources && !islist(sources)) { \
+ _sources_list = list(sources); \
+ } else { \
+ _sources_list = sources\
+ }; \
+ if (_traits_list?[trait]) { \
+ for (var/_trait_source in _traits_list[trait]) { \
+ if (!(_trait_source in _sources_list)) { \
+ _traits_list[trait] -= _trait_source \
+ } \
+ };\
+ if (!length(_traits_list[trait])) { \
+ _traits_list -= trait; \
+ SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \
+ if(trait in GLOB.traits_with_elements) { \
+ target.RemoveElement(GLOB.traits_with_elements[trait]); \
+ } \
+ }; \
+ if (!length(_traits_list)) { \
+ target._status_traits = null \
}; \
} \
} while (0)
#define REMOVE_TRAITS_NOT_IN(target, sources) \
do { \
- var/list/_L = target.status_traits; \
+ var/list/_L = target._status_traits; \
var/list/_S = sources; \
if (_L) { \
for (var/_T in _L) { \
@@ -65,20 +90,20 @@
if (!length(_L[_T])) { \
_L -= _T; \
SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(_T), _T); \
- if(_T in GLOB.traits_with_elements) { \
- target.RemoveElement(GLOB.traits_with_elements[_T]); \
+ if(trait in GLOB.traits_with_elements) { \
+ target.RemoveElement(GLOB.traits_with_elements[trait]); \
}; \
};\
};\
if (!length(_L)) { \
- target.status_traits = null\
+ target._status_traits = null\
};\
}\
} while (0)
#define REMOVE_TRAITS_IN(target, sources) \
do { \
- var/list/_L = target.status_traits; \
+ var/list/_L = target._status_traits; \
var/list/_S = sources; \
if (sources && !islist(sources)) { \
_S = list(sources); \
@@ -97,40 +122,44 @@
};\
};\
if (!length(_L)) { \
- target.status_traits = null\
+ target._status_traits = null\
};\
}\
} while (0)
-/// Will 100% nuke a trait regardless of source. Preferably use this as little as possible
-#define REMOVE_TRAIT_ALLSOURCES(target, trait) \
- do { \
- var/list/_L = target.status_traits; \
- if (_L?[trait]) { \
- if (length(_L)) { \
- _L -= trait; \
- SEND_SIGNAL(target, SIGNAL_REMOVETRAIT(trait), trait); \
- }; \
- else { \
- target.status_traits = null \
- }; \
- } \
- } while (0)
-
-#define HAS_TRAIT(target, trait) (target.status_traits ? (target.status_traits[trait] ? TRUE : FALSE) : FALSE)
-#define HAS_TRAIT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (source in target.status_traits[trait]) : FALSE) : FALSE)
-#define HAS_TRAIT_FROM_ONLY(target, trait, source) (\
- target.status_traits ?\
- (target.status_traits[trait] ?\
- ((source in target.status_traits[trait]) && (length(target.status_traits) == 1))\
- : FALSE)\
- : FALSE)
-#define HAS_TRAIT_NOT_FROM(target, trait, source) (target.status_traits ? (target.status_traits[trait] ? (length(target.status_traits[trait] - source) > 0) : FALSE) : FALSE)
-
+#define HAS_TRAIT(target, trait) (target._status_traits?[trait] ? TRUE : FALSE)
+#define HAS_TRAIT_FROM(target, trait, source) (HAS_TRAIT(target, trait) && (source in target._status_traits[trait]))
+#define HAS_TRAIT_FROM_ONLY(target, trait, source) (HAS_TRAIT(target, trait) && (source in target._status_traits[trait]) && (length(target._status_traits[trait]) == 1))
+#define HAS_TRAIT_NOT_FROM(target, trait, source) (HAS_TRAIT(target, trait) && (length(target._status_traits[trait] - source) > 0))
+/// Returns a list of trait sources for this trait. Only useful for wacko cases and internal futzing
+/// You should not be using this
+#define GET_TRAIT_SOURCES(target, trait) (target._status_traits?[trait] || list())
+/// Returns the amount of sources for a trait. useful if you don't want to have a "thing counter" stuck around all the time
+#define COUNT_TRAIT_SOURCES(target, trait) length(GET_TRAIT_SOURCES(target, trait))
+/// A simple helper for checking traits in a mob's mind
+#define HAS_MIND_TRAIT(target, trait) (HAS_TRAIT(target, trait) || (target.mind ? HAS_TRAIT(target.mind, trait) : FALSE))
/// Example trait
// #define TRAIT_X "t_x"
+
//-- mob traits --
+/// Apply this to make a mob not dense, and remove it when you want it to no longer make them undense, other sorces of undesity will still apply. Always define a unique source when adding a new instance of this!
+#define TRAIT_UNDENSE "undense"
+/// Forces the user to stay unconscious.
+#define TRAIT_KNOCKEDOUT "knockedout"
+/// Prevents voluntary movement.
+#define TRAIT_IMMOBILIZED "immobilized"
+/// Prevents voluntary standing or staying up on its own.
+#define TRAIT_FLOORED "floored"
+/// Forces user to stay standing
+#define TRAIT_FORCED_STANDING "forcedstanding"
+/// Stuns preventing movement and using objects but without further impairement
+#define TRAIT_INCAPACITATED "incapacitated"
+/// Disoriented. Unable to talk properly, and unable to use some skills as Xeno
+#define TRAIT_DAZED "dazed"
+/// Apply this to identify a mob as merged with weeds
+#define TRAIT_MERGED_WITH_WEEDS "merged_with_weeds"
+
// SPECIES TRAITS
/// Knowledge of Yautja technology
#define TRAIT_YAUTJA_TECH "t_yautja_tech"
@@ -194,6 +223,8 @@
#define TRAIT_HARDCORE "t_hardcore"
/// If the mob is able to use the vulture rifle or spotting scope
#define TRAIT_VULTURE_USER "t_vulture_user"
+/// If the mob is currently loading a tutorial
+#define TRAIT_IN_TUTORIAL "t_IN_TUTORIAL"
/// If the mob is cloaked in any form
#define TRAIT_CLOAKED "t_cloaked"
@@ -221,6 +252,9 @@
/// Can lockout blackmarket from ASRS console circuits.
#define TRAIT_TOOL_TRADEBAND "t_tool_tradeband"
+/// Can hack ASRS consoles to access the black market
+#define TRAIT_TOOL_BLACKMARKET_HACKER "t_tool_blackmarket_hacker"
+
// CLOTHING TRAITS
#define TRAIT_CLOTHING_HOOD "t_clothing_hood"
@@ -267,6 +301,7 @@ GLOBAL_LIST_INIT(mob_traits, list(
TRAIT_REAGENT_SCANNER,
TRAIT_ABILITY_BURROWED,
TRAIT_VULTURE_USER,
+ TRAIT_IN_TUTORIAL,
))
/*
@@ -276,6 +311,12 @@ GLOBAL_LIST_INIT(mob_traits, list(
*/
GLOBAL_LIST_INIT(traits_by_type, list(
/mob = list(
+ "TRAIT_KNOCKEDOUT" = TRAIT_KNOCKEDOUT,
+ "TRAIT_IMMOBILIZED" = TRAIT_IMMOBILIZED,
+ "TRAIT_INCAPACITATED" = TRAIT_INCAPACITATED,
+ "TRAIT_FLOORED" = TRAIT_FLOORED,
+ "TRAIT_DAZED" = TRAIT_DAZED,
+ "TRAIT_UNDENSE" = TRAIT_UNDENSE,
"TRAIT_YAUTJA_TECH" = TRAIT_YAUTJA_TECH,
"TRAIT_SUPER_STRONG" = TRAIT_SUPER_STRONG,
"TRAIT_FOREIGN_BIO" = TRAIT_FOREIGN_BIO,
@@ -301,6 +342,8 @@ GLOBAL_LIST_INIT(traits_by_type, list(
"TRAIT_VULTURE_USER" = TRAIT_VULTURE_USER,
"TRAIT_CLOAKED" = TRAIT_CLOAKED,
),
+// /mob/living/carbon/human = list(
+// ),
/mob/living/carbon/xenomorph = list(
"TRAIT_ABILITY_NO_PLASMA_TRANSFER" = TRAIT_ABILITY_NO_PLASMA_TRANSFER,
"TRAIT_ABILITY_OVIPOSITOR" = TRAIT_ABILITY_OVIPOSITOR,
@@ -351,21 +394,25 @@ GLOBAL_LIST(trait_name_map)
/// Example trait source
// #define TRAIT_SOURCE_Y "t_s_y"
#define TRAIT_SOURCE_INHERENT "t_s_inherent"
+/// cannot be removed without admin intervention
+#define ROUNDSTART_TRAIT "roundstart"
//-- mob traits --
+///Status trait coming from lying down through update_canmove()
+#define LYING_TRAIT "lying"
///Status trait coming from species. .human/species_gain()
#define TRAIT_SOURCE_SPECIES "t_s_species"
///Status trait coming from the hive.
#define TRAIT_SOURCE_HIVE "t_s_hive"
///Status trait coming from being buckled.
#define TRAIT_SOURCE_BUCKLE "t_s_buckle"
-///Status trait coming from roundstart quirks (that don't exist yet). Unremovable by REMOVE_TRAIT
-#define TRAIT_SOURCE_QUIRK "t_s_quirk"
///Status trait coming from being assigned as [acting] squad leader.
#define TRAIT_SOURCE_SQUAD_LEADER "t_s_squad_leader"
///Status trait coming from their job
#define TRAIT_SOURCE_JOB "t_s_job"
///Status trait forced by staff
#define TRAIT_SOURCE_ADMIN "t_s_admin"
+/// Status trait coming from a tutorial
+#define TRAIT_SOURCE_TUTORIAL "t_s_tutorials"
///Status trait coming from equipment
#define TRAIT_SOURCE_EQUIPMENT(slot) "t_s_equipment_[slot]"
///Status trait coming from skill
@@ -374,8 +421,13 @@ GLOBAL_LIST(trait_name_map)
#define TRAIT_SOURCE_ATTACHMENT(slot) "t_s_attachment_[slot]"
///Status trait coming from ability
#define TRAIT_SOURCE_ABILITY(ability) "t_s_ability_[ability]"
+#define TRAIT_SOURCE_LIMB(limb) "t_s_limb_[limb]"
///Status trait forced by the xeno action charge
#define TRAIT_SOURCE_XENO_ACTION_CHARGE "t_s_xeno_action_charge"
+///Status trait coming from a xeno nest
+#define XENO_NEST_TRAIT "xeno_nest"
+///Status trait from a generic throw by xeno abilities
+#define XENO_THROW_TRAIT "xeno_throw_trait"
//-- structure traits --
///Status trait coming from being flipped or unflipped.
#define TRAIT_SOURCE_FLIP_TABLE "t_s_flip_table"
@@ -387,3 +439,40 @@ GLOBAL_LIST(trait_name_map)
//Status trait coming from clothing.
#define TRAIT_SOURCE_CLOTHING "t_s_clothing"
+
+/// trait associated to being buckled
+#define BUCKLED_TRAIT "buckled" // Yes the name doesn't conform. /tg/ appears to have changed naming style inbetween
+/// trait source when an effect is coming from a fakedeath effect (refactor this)
+#define FAKEDEATH_TRAIT "fakedeath"
+/// trait source where a condition comes from body state
+#define BODY_TRAIT "body"
+/// Trait associated to lying down (having a [lying_angle] of a different value than zero).
+#define LYING_DOWN_TRAIT "lying-down"
+/// trait associated to a stat value or range of
+#define STAT_TRAIT "stat"
+/// trait effect related to the queen ovipositor
+#define OVIPOSITOR_TRAIT "ovipositor"
+/// trait associated to being held in a chokehold
+#define CHOKEHOLD_TRAIT "chokehold"
+/// trait effect related to active specialist gear
+#define SPECIALIST_GEAR_TRAIT "specialist_gear"
+/// traits associated with usage of snowflake dropship double seats
+#define DOUBLE_SEATS_TRAIT "double_seats"
+/// traits associated with xeno on-ground weeds
+#define XENO_WEED_TRAIT "xeno_weed"
+/// traits associated with actively interacted machinery
+#define INTERACTION_TRAIT "interaction"
+/// traits bound by stunned status effects
+#define STUNNED_TRAIT "stunned"
+/// traits bound by knocked_down status effect
+#define KNOCKEDDOWN_TRAIT "knockeddown"
+/// traits bound by knocked_out status effect
+#define KNOCKEDOUT_TRAIT "knockedout"
+/// traits from being pounced
+#define POUNCED_TRAIT "pounced"
+/// traits from step_triggers on the map
+#define STEP_TRIGGER_TRAIT "step_trigger"
+/// traits from hacked machine interactions
+#define HACKED_TRAIT "hacked"
+/// traits from chloroform usage
+#define CHLOROFORM_TRAIT "chloroform"
diff --git a/code/__DEFINES/tutorial.dm b/code/__DEFINES/tutorial.dm
new file mode 100644
index 000000000000..75dc7f6da21f
--- /dev/null
+++ b/code/__DEFINES/tutorial.dm
@@ -0,0 +1,6 @@
+#define TUTORIAL_ATOM_FROM_TRACKING(path, varname) var##path/##varname = tracking_atoms[##path]
+
+#define TUTORIAL_CATEGORY_BASE "Base" // Shouldn't be used outside of base types
+#define TUTORIAL_CATEGORY_SS13 "Space Station 13"
+#define TUTORIAL_CATEGORY_MARINE "Marine"
+#define TUTORIAL_CATEGORY_XENO "Xenomorph"
diff --git a/code/__DEFINES/typecheck/items.dm b/code/__DEFINES/typecheck/items.dm
index 09153cde25c2..5c4d099b8112 100644
--- a/code/__DEFINES/typecheck/items.dm
+++ b/code/__DEFINES/typecheck/items.dm
@@ -1,10 +1,10 @@
#define iswelder(O) (istype(O, /obj/item/tool/weldingtool))
#define iscoil(O) (istype(O, /obj/item/stack/cable_coil))
#define iswire(O) (istype(O, /obj/item/stack/cable_coil))
-#define isweapon(O) (O && is_type_in_list(O, weapons))
+#define isweapon(O) (O && is_type_in_list(O, GLOB.weapons))
#define isgun(O) (istype(O, /obj/item/weapon/gun))
#define isbanana(O) (istype(O, /obj/item/reagent_container/food/snacks/grown/banana))
-#define istool(O) (O && is_type_in_list(O, common_tools))
+#define istool(O) (O && is_type_in_list(O, GLOB.common_tools))
#define ispowerclamp(O) (istype(O, /obj/item/powerloader_clamp))
#define isstorage(O) (istype(O, /obj/item/storage))
#define isclothing(O) (istype(O, /obj/item/clothing))
@@ -12,13 +12,13 @@
#define isdefenses(O) (istype(O, /obj/structure/machinery/defenses))
//Quick type checks for weapons
-var/global/list/weapons = list(
+GLOBAL_LIST_INIT(weapons, list(
/obj/item/weapon,
/obj/item/attachable/bayonet
-)
+))
//Quick type checks for some tools
-var/global/list/common_tools = list(
+GLOBAL_LIST_INIT(common_tools, list(
/obj/item/stack/cable_coil,
/obj/item/tool/wrench,
/obj/item/tool/weldingtool,
@@ -26,7 +26,7 @@ var/global/list/common_tools = list(
/obj/item/tool/wirecutters,
/obj/item/device/multitool,
/obj/item/tool/crowbar
-)
+))
/obj/item/proc/can_pry()
if(pry_capable > IS_PRY_CAPABLE_SIMPLE || HAS_TRAIT(src, TRAIT_TOOL_CROWBAR))
diff --git a/code/__DEFINES/urls.dm b/code/__DEFINES/urls.dm
index 137095327a2c..5d3fca1a2032 100644
--- a/code/__DEFINES/urls.dm
+++ b/code/__DEFINES/urls.dm
@@ -1,3 +1,7 @@
+// placeholder strings to be replaced
+#define WIKI_PLACEHOLDER "%WIKIURL%"
+#define LAW_PLACEHOLDER "%LAWURL%"
+
// ------ MISC WIKI LINKS ------ //
#define URL_WIKI_LAW "Marine_Law"
#define URL_WIKI_XENO_QUICKSTART "Xeno_Quickstart_Guide"
diff --git a/code/__DEFINES/vehicle.dm b/code/__DEFINES/vehicle.dm
index 9c6685085788..8a1617229926 100644
--- a/code/__DEFINES/vehicle.dm
+++ b/code/__DEFINES/vehicle.dm
@@ -53,5 +53,6 @@
#define VEHICLE_CLASS_LIGHT (1<<2) //light class armor (APC, tank)
#define VEHICLE_CLASS_MEDIUM (1<<3) //medium class armor (tank)
#define VEHICLE_CLASS_HEAVY (1<<4) //heavy class armor (tank)
-
-#define TANK_POPLOCK 90
+// Other vehicle flags
+/// Vehicle can bypass vehicle blockers, typically going further into maps than intended
+#define VEHICLE_BYPASS_BLOCKERS (1<<5)
diff --git a/code/__DEFINES/vendors.dm b/code/__DEFINES/vendors.dm
index 04ee5ffef2b6..086b70a92428 100644
--- a/code/__DEFINES/vendors.dm
+++ b/code/__DEFINES/vendors.dm
@@ -67,3 +67,13 @@
//Whether or not to load ammo boxes depending on ammo loaded into the vendor
//Only relevant in big vendors, like Requisitions or Squad Prep
#define VEND_LOAD_AMMO_BOXES (1<<9)
+/// Vendors with this flag will fill retroactively based on latejoining players,
+/// and expect a scale multiplier instead of amount of items
+#define VEND_STOCK_DYNAMIC (1<<10)
+
+// Redemption Tokens
+#define VEND_TOKEN_ENGINEER "Engineer"
+#define VEND_TOKEN_SPEC "Specialist"
+#define VEND_TOKEN_SYNTH "Synthetic"
+/// Token invalid/unrecognised.
+#define VEND_TOKEN_VOID "Void"
diff --git a/code/__DEFINES/weapon_stats.dm b/code/__DEFINES/weapon_stats.dm
index beac54d98892..3a69002a3b93 100644
--- a/code/__DEFINES/weapon_stats.dm
+++ b/code/__DEFINES/weapon_stats.dm
@@ -18,17 +18,17 @@ Accuracy determines if your bullets will hit whatever you're shooting at. Think
It DOES NOT control where your bullets go, that's scatter and projectile variance.
.../update_projectiles/guns/code.dm
-var/accuracy_mult //Base firearm accuracy when firing from a 2-hand, "secure", wielded, etc, whatever grip.
-var/accuracy_mult_unwielded //Base firearm accuracy when firing from hip. Both of these default to 1, with additions or subtractions from the mult vars.
+ var/accuracy_mult //Base firearm accuracy when firing from a 2-hand, "secure", wielded, etc, whatever grip.
+ var/accuracy_mult_unwielded //Base firearm accuracy when firing from hip. Both of these default to 1, with additions or subtractions from the mult vars.
.../updated_projectiles/ammo_datums.dm
-var/accuracy //This is added to the firearm's base accuracy when the specific ammo is shot.
-var/accuracy_var_low //These two vars are used for the upper and lower bounds of accuracy variance when a bullet is fired. Bullet 'wobble' if you will.
-var/accuracy_var_high
+ var/accuracy //This is added to the firearm's base accuracy when the specific ammo is shot.
+ var/accuracy_var_low //These two vars are used for the upper and lower bounds of accuracy variance when a bullet is fired. Bullet 'wobble' if you will.
+ var/accuracy_var_high
.../updated_projectiles/gun_attachables.dm
-var/accuracy_mult //Attachments ADD an additional multiplier to the base config value. Only ever use accuracy_mult config references.
-var/accuracy_mult_unwielded
+ var/accuracy_mult //Attachments ADD an additional multiplier to the base config value. Only ever use accuracy_mult config references.
+ var/accuracy_mult_unwielded
*/
#define HIT_ACCURACY_TIER_1 5
diff --git a/code/__DEFINES/xeno.dm b/code/__DEFINES/xeno.dm
index b178f0692dd6..d12e4c1c6c5a 100644
--- a/code/__DEFINES/xeno.dm
+++ b/code/__DEFINES/xeno.dm
@@ -174,6 +174,21 @@
/// The time it takes for a pylon to give one larva while activated
#define XENO_PYLON_ACTIVATION_COOLDOWN (5 MINUTES)
+/// The time until you can re-corrupt a comms relay after the last pylon was destroyed
+#define XENO_PYLON_DESTRUCTION_DELAY (5 MINUTES)
+
+/// Evolution boost during hijack
+#define XENO_HIJACK_EVILUTION_BUFF 10
+
+/// For how long the buff lasts
+#define XENO_HIJACK_EVILUTION_TIME (3 MINUTES)
+
+/// Xenos need to have their number to marines ratio lower than this to get larvae from pylons
+#define ENDGAME_LARVA_CAP_MULTIPLIER 0.5
+
+/// What percent of their numbers xeno get from pylons
+#define LARVA_ADDITION_MULTIPLIER 0.10
+
/// The time against away_timer when an AFK xeno larva can be replaced
#define XENO_LEAVE_TIMER_LARVA 80 //80 seconds
/// The time against away_timer when an AFK xeno (not larva) can be replaced
@@ -246,11 +261,6 @@
#define XENO_PLASMA_TIER_8 800 * XENO_UNIVERSAL_PLASMAMULT
#define XENO_PLASMA_TIER_10 1000 * XENO_UNIVERSAL_PLASMAMULT
-// Resource stockpile bands
-#define XENO_CRYSTAL_LOW 50
-#define XENO_CRYSTAL_MEDIUM 100
-#define XENO_CRYSTAL_HIGH 150
-
// Plasma gain bands
#define XENO_PLASMA_GAIN_TIER_1 1
#define XENO_PLASMA_GAIN_TIER_2 1.5
@@ -576,9 +586,7 @@
#define XENO_STRUCTURE_CORE "hive core"
#define XENO_STRUCTURE_CLUSTER "hive cluster"
#define XENO_STRUCTURE_PYLON "hive pylon"
-#define XENO_STRUCTURE_POOL "spawn pool"
#define XENO_STRUCTURE_EGGMORPH "egg morpher"
-#define XENO_STRUCTURE_EVOPOD "evolution pod"
#define XENO_STRUCTURE_RECOVERY "recovery node"
#define XENO_STRUCTURE_NEST "thick resin nest"
diff --git a/code/__HELPERS/#maths.dm b/code/__HELPERS/#maths.dm
index 5419b9cd9624..6ea534a79923 100644
--- a/code/__HELPERS/#maths.dm
+++ b/code/__HELPERS/#maths.dm
@@ -1,22 +1,13 @@
// Credits to Nickr5 for the useful procs I've taken from his library resource.
-var/const/E = 2.71828183
-var/const/Sqrt2 = 1.41421356
-
// List of square roots for the numbers 1-100.
-var/list/sqrtTable = list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
+GLOBAL_LIST_INIT(sqrtTable, list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5,
5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7,
7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
- 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10)
+ 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10))
// MATH DEFINES
-#define Atan2(x, y) (!x && !y ? 0 : \
- (y >= 0 ? \
- arccos(x / sqrt(x*x + y*y)) : \
- -(arccos(x / sqrt(x*x + y*y))) \
- ) \
- )
#define Ceiling(x) (-round(-x))
#define Clamp(val, min_val, max_val) (max(min_val, min(val, max_val)))
#define CLAMP01(x) (clamp(x, 0, 1))
@@ -81,7 +72,7 @@ var/list/sqrtTable = list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4,
// Convert to polar coordinates
var/radius = sqrt(relative_coords[1]**2 + relative_coords[2]**2)
- var/phi = Atan2(relative_coords[1], relative_coords[2])
+ var/phi = arctan(relative_coords[1], relative_coords[2])
// Rotate the point around the axis
phi += degrees
@@ -109,42 +100,6 @@ var/list/sqrtTable = list(1, 1, 1, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4,
return "[round((powerused * 0.000001),0.001)] MW"
return "[round((powerused * 0.000000001),0.0001)] GW"
-///Calculate the angle between two movables and the west|east coordinate
-/proc/get_angle(atom/movable/start, atom/movable/end)//For beams.
- if(!start || !end)
- return 0
- var/dy =(32 * end.y + end.pixel_y) - (32 * start.y + start.pixel_y)
- var/dx =(32 * end.x + end.pixel_x) - (32 * start.x + start.pixel_x)
- if(!dy)
- return (dx >= 0) ? 90 : 270
- . = arctan(dx/dy)
- if(dy < 0)
- . += 180
- else if(dx < 0)
- . += 360
-
-/// Angle between two arbitrary points and horizontal line same as [/proc/get_angle]
-/proc/get_angle_raw(start_x, start_y, start_pixel_x, start_pixel_y, end_x, end_y, end_pixel_x, end_pixel_y)
- var/dy = (32 * end_y + end_pixel_y) - (32 * start_y + start_pixel_y)
- var/dx = (32 * end_x + end_pixel_x) - (32 * start_x + start_pixel_x)
- if(!dy)
- return (dx >= 0) ? 90 : 270
- . = arctan(dx/dy)
- if(dy < 0)
- . += 180
- else if(dx < 0)
- . += 360
-
-///for getting the angle when animating something's pixel_x and pixel_y
-/proc/get_pixel_angle(y, x)
- if(!y)
- return (x >= 0) ? 90 : 270
- . = arctan(x/y)
- if(y < 0)
- . += 180
- else if(x < 0)
- . += 360
-
/**
* Get a list of turfs in a line from `starting_atom` to `ending_atom`.
*
diff --git a/code/__HELPERS/_time.dm b/code/__HELPERS/_time.dm
index b929ae8636b3..8386feff41c2 100644
--- a/code/__HELPERS/_time.dm
+++ b/code/__HELPERS/_time.dm
@@ -15,19 +15,19 @@
#define DECISECONDS_TO_HOURS /36000
-var/midnight_rollovers = 0
-var/rollovercheck_last_timeofday = 0
+GLOBAL_VAR_INIT(midnight_rollovers, 0)
+GLOBAL_VAR_INIT(rollovercheck_last_timeofday, 0)
// Real time that is still reliable even when the round crosses over midnight time reset.
#define REALTIMEOFDAY (world.timeofday + (864000 * MIDNIGHT_ROLLOVER_CHECK))
-#define MIDNIGHT_ROLLOVER_CHECK ( rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : midnight_rollovers )
+#define MIDNIGHT_ROLLOVER_CHECK ( GLOB.rollovercheck_last_timeofday != world.timeofday ? update_midnight_rollover() : GLOB.midnight_rollovers )
/proc/update_midnight_rollover()
- if(world.timeofday < rollovercheck_last_timeofday)
- midnight_rollovers++
+ if(world.timeofday < GLOB.rollovercheck_last_timeofday)
+ GLOB.midnight_rollovers++
- rollovercheck_last_timeofday = world.timeofday
- return midnight_rollovers
+ GLOB.rollovercheck_last_timeofday = world.timeofday
+ return GLOB.midnight_rollovers
///Returns the world time in english. Do not use to get date information - starts at 0 + a random time offset from 10 minutes to 24 hours.
/proc/worldtime2text(format = "hh:mm", time = world.time)
diff --git a/code/__HELPERS/animations.dm b/code/__HELPERS/animations.dm
new file mode 100644
index 000000000000..f85fb763a4a6
--- /dev/null
+++ b/code/__HELPERS/animations.dm
@@ -0,0 +1,2 @@
+/// The duration of the animate call in mob/living/update_transform
+#define UPDATE_TRANSFORM_ANIMATION_TIME (0.2 SECONDS)
diff --git a/code/__HELPERS/chat.dm b/code/__HELPERS/chat.dm
index f7382e151854..20d1a45b31cc 100644
--- a/code/__HELPERS/chat.dm
+++ b/code/__HELPERS/chat.dm
@@ -1,11 +1,12 @@
/**
- * Sends a message to TGS chat channels.
+ * Asynchronously sends a message to TGS chat channels.
*
- * message - The message to send.
+ * message - The [/datum/tgs_message_content] to send.
* channel_tag - Required. If "", the message with be sent to all connected (Game-type for TGS3) channels. Otherwise, it will be sent to TGS4 channels with that tag (Delimited by ','s).
* admin_only - Determines if this communication can only be sent to admin only channels.
*/
-/proc/send2chat(message, channel_tag, admin_only = FALSE)
+/proc/send2chat(datum/tgs_message_content/message, channel_tag, admin_only = FALSE)
+ set waitfor = FALSE
if(channel_tag == null || !world.TgsAvailable())
return
diff --git a/code/__HELPERS/cmp.dm b/code/__HELPERS/cmp.dm
index ff8e31ad3e8a..31308ac5812f 100644
--- a/code/__HELPERS/cmp.dm
+++ b/code/__HELPERS/cmp.dm
@@ -16,12 +16,12 @@
/proc/cmp_name_dsc(atom/a, atom/b)
return sorttext(a.name, b.name)
-var/cmp_field = "name"
+GLOBAL_LIST_INIT(cmp_field, "name")
/proc/cmp_records_asc(datum/data/record/a, datum/data/record/b)
- return sorttext((b ? b.fields[cmp_field] : ""), (a ? a.fields[cmp_field] : a))
+ return sorttext((b ? b.fields[GLOB.cmp_field] : ""), (a ? a.fields[GLOB.cmp_field] : a))
/proc/cmp_records_dsc(datum/data/record/a, datum/data/record/b)
- return sorttext(a.fields[cmp_field], b.fields[cmp_field])
+ return sorttext(a.fields[GLOB.cmp_field], b.fields[GLOB.cmp_field])
/proc/cmp_ckey_asc(client/a, client/b)
return sorttext(b.ckey, a.ckey)
@@ -53,7 +53,6 @@ var/cmp_field = "name"
if (!.)
. = B.qdels - A.qdels
-var/atom/cmp_dist_origin=null
/proc/cmp_typepaths_asc(A, B)
return sorttext("[B]","[A]")
diff --git a/code/__HELPERS/files.dm b/code/__HELPERS/files.dm
index f88fe7168f8d..54bb438cd167 100644
--- a/code/__HELPERS/files.dm
+++ b/code/__HELPERS/files.dm
@@ -46,11 +46,11 @@
PLEASE USE RESPONSIBLY, Some log files canr each sizes of 4MB! */
/client/proc/file_spam_check()
- var/time_to_wait = fileaccess_timer - world.time
+ var/time_to_wait = GLOB.fileaccess_timer - world.time
if(time_to_wait > 0)
to_chat(src, "Error: file_spam_check(): Spam. Please wait [round(time_to_wait/10)] seconds.")
return 1
- fileaccess_timer = world.time + FTPDELAY
+ GLOB.fileaccess_timer = world.time + FTPDELAY
return 0
#undef FTPDELAY
diff --git a/code/__HELPERS/filters.dm b/code/__HELPERS/filters.dm
index aa8d77c81d3a..29e3ec9efb1e 100644
--- a/code/__HELPERS/filters.dm
+++ b/code/__HELPERS/filters.dm
@@ -46,7 +46,7 @@ GLOBAL_LIST_INIT(master_filter_info, list(
"y" = -1,
"size" = 1,
"offset" = 0,
- "color" = COLOUR_HALF_TRANSPARENT_BLACK
+ "color" = COLOR_HALF_TRANSPARENT_BLACK
)
),
"blur" = list(
diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm
index 8d6fb4266776..5ef9ff7e35c3 100644
--- a/code/__HELPERS/game.dm
+++ b/code/__HELPERS/game.dm
@@ -52,9 +52,6 @@
turfs += T
return turfs
-
-//var/debug_mob = 0
-
// Will recursively loop through an atom's contents and check for mobs, then it will loop through every atom in that atom's contents.
// It will keep doing this until it checks every content possible. This will fix any problems with mobs, that are inside objects,
// being unable to hear people due to being in a box within a bag.
@@ -311,11 +308,11 @@
var/mob/dead/observer/cur_obs = candidates[i]
// Generate the messages
- var/cached_message = SPAN_XENONOTICE("You are currently [i-dequeued]\th in the larva queue.")
+ var/cached_message = "You are currently [i-dequeued]\th in the larva queue."
cur_obs.larva_queue_cached_message = cached_message
if(!cache_only)
var/chat_message = dequeued ? replacetext(cached_message, "currently", "now") : cached_message
- to_chat(candidates[i], chat_message)
+ to_chat(candidates[i], SPAN_XENONOTICE(chat_message))
/proc/convert_k2c(temp)
return ((temp - T0C))
diff --git a/code/__HELPERS/icons.dm b/code/__HELPERS/icons.dm
index 99f621919771..97243002740d 100644
--- a/code/__HELPERS/icons.dm
+++ b/code/__HELPERS/icons.dm
@@ -14,8 +14,7 @@ CHANGING ICONS
Several new procs have been added to the /icon datum to simplify working with icons. To use them,
remember you first need to setup an /icon var like so:
-
-var/icon/my_icon = new('iconfile.dmi')
+ var/icon/my_icon = new('iconfile.dmi')
icon/ChangeOpacity(amount = 1)
A very common operation in DM is to try to make an icon more or less transparent. Making an icon more
@@ -329,7 +328,8 @@ world
/// appearance system (overlays/underlays, etc.) is not available.
///
/// Only the first argument is required.
-/proc/getFlatIcon(image/appearance, defdir, deficon, defstate, defblend, start = TRUE, no_anim = FALSE)
+/// appearance_flags indicates whether appearance_flags should be respected (at the cost of about 10-20% perf)
+/proc/getFlatIcon(image/appearance, defdir, deficon, defstate, defblend, start = TRUE, no_anim = FALSE, appearance_flags = FALSE)
// Loop through the underlays, then overlays, sorting them into the layers list
#define PROCESS_OVERLAYS_OR_UNDERLAYS(flat, process, base_layer) \
for (var/i in 1 to process.len) { \
@@ -435,11 +435,21 @@ world
if(layer_image.alpha == 0)
continue
+ // variables only relevant when accounting for appearance_flags:
+ var/apply_color = TRUE
+ var/apply_alpha = TRUE
+
if(layer_image == copy) // 'layer_image' is an /image based on the object being flattened.
curblend = BLEND_OVERLAY
add = icon(layer_image.icon, layer_image.icon_state, base_icon_dir)
else // 'I' is an appearance object.
- add = getFlatIcon(image(layer_image), curdir, curicon, curstate, curblend, FALSE, no_anim)
+ var/image/layer_as_image = image(layer_image)
+ if(appearance_flags)
+ if(layer_as_image.appearance_flags & RESET_COLOR)
+ apply_color = FALSE
+ if(layer_as_image.appearance_flags & RESET_ALPHA)
+ apply_alpha = FALSE
+ add = getFlatIcon(layer_as_image, curdir, curicon, curstate, curblend, FALSE, no_anim, appearance_flags)
if(!add)
continue
@@ -451,9 +461,9 @@ world
if (
addX1 != flatX1 \
- && addX2 != flatX2 \
- && addY1 != flatY1 \
- && addY2 != flatY2 \
+ || addX2 != flatX2 \
+ || addY1 != flatY1 \
+ || addY2 != flatY2 \
)
// Resize the flattened icon so the new icon fits
flat.Crop(
@@ -464,21 +474,34 @@ world
)
flatX1 = addX1
- flatX2 = addY1
- flatY1 = addX2
+ flatX2 = addX2
+ flatY1 = addY1
flatY2 = addY2
+ if(appearance_flags)
+ // apply parent's color/alpha to the added layers if the layer didn't opt
+ if(apply_color && appearance.color)
+ if(islist(appearance.color))
+ add.MapColors(arglist(appearance.color))
+ else
+ add.Blend(appearance.color, ICON_MULTIPLY)
+
+ if(apply_alpha && appearance.alpha < 255)
+ add.Blend(rgb(255, 255, 255, appearance.alpha), ICON_MULTIPLY)
+
// Blend the overlay into the flattened icon
flat.Blend(add, blendMode2iconMode(curblend), layer_image.pixel_x + 2 - flatX1, layer_image.pixel_y + 2 - flatY1)
- if(appearance.color)
- if(islist(appearance.color))
- flat.MapColors(arglist(appearance.color))
- else
- flat.Blend(appearance.color, ICON_MULTIPLY)
+ if(!appearance_flags)
+ // If we didn't apply parent colors individually per layer respecting appearance_flags, then do it just the one time now
+ if(appearance.color)
+ if(islist(appearance.color))
+ flat.MapColors(arglist(appearance.color))
+ else
+ flat.Blend(appearance.color, ICON_MULTIPLY)
- if(appearance.alpha < 255)
- flat.Blend(rgb(255, 255, 255, appearance.alpha), ICON_MULTIPLY)
+ if(appearance.alpha < 255)
+ flat.Blend(rgb(255, 255, 255, appearance.alpha), ICON_MULTIPLY)
if(no_anim)
//Clean up repeated frames
@@ -658,8 +681,9 @@ world
* * moving - whether or not to use a moving state for the given icon
* * sourceonly - if TRUE, only generate the asset and send back the asset url, instead of tags that display the icon to players
* * extra_clases - string of extra css classes to use when returning the icon string
+ * * keyonly - if TRUE, only returns the asset key to use get_asset_url manually. Overrides sourceonly.
*/
-/proc/icon2html(atom/thing, client/target, icon_state, dir = SOUTH, frame = 1, moving = FALSE, sourceonly = FALSE, extra_classes = null)
+/proc/icon2html(atom/thing, client/target, icon_state, dir = SOUTH, frame = 1, moving = FALSE, sourceonly = FALSE, extra_classes = null, keyonly = FALSE)
if (!thing)
return
@@ -690,6 +714,8 @@ world
SSassets.transport.register_asset(name, thing)
for (var/thing2 in targets)
SSassets.transport.send_assets(thing2, name)
+ if(keyonly)
+ return name
if(sourceonly)
return SSassets.transport.get_asset_url(name)
return ""
@@ -708,11 +734,12 @@ world
if (isnull(dir))
dir = thing.dir
- if (ishuman(thing)) // Shitty workaround for a BYOND issue.
+ // Commented out because this is seemingly our source of bad icon operations
+ /* if (ishuman(thing)) // Shitty workaround for a BYOND issue.
var/icon/temp = icon2collapse
icon2collapse = icon()
icon2collapse.Insert(temp, dir = SOUTH)
- dir = SOUTH
+ dir = SOUTH*/
else
if (isnull(dir))
dir = SOUTH
@@ -731,6 +758,8 @@ world
SSassets.transport.register_asset(key, rsc_ref, file_hash, icon_path)
for (var/client_target in targets)
SSassets.transport.send_assets(client_target, key)
+ if(keyonly)
+ return key
if(sourceonly)
return SSassets.transport.get_asset_url(key)
return ""
@@ -852,22 +881,93 @@ world
return image_to_center
//For creating consistent icons for human looking simple animals
-/proc/get_flat_human_icon(icon_id, datum/equipment_preset/preset, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override)
+/proc/get_flat_human_icon(icon_id, equipment_preset_dresscode, datum/preferences/prefs, dummy_key, showDirs = GLOB.cardinals, outfit_override)
var/static/list/humanoid_icon_cache = list()
if(!icon_id || !humanoid_icon_cache[icon_id])
var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(dummy_key)
+
if(prefs)
prefs.copy_all_to(body)
- arm_equipment(body, preset)
+ body.update_body()
+ body.update_hair()
+
+ // Assumption: Is a list
+ if(outfit_override)
+ for(var/obj/item/cur_item as anything in outfit_override)
+ body.equip_to_appropriate_slot(cur_item)
+
+ // Assumption: Is a string or path
+ if(equipment_preset_dresscode)
+ arm_equipment(body, equipment_preset_dresscode)
var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
- for(var/D in showDirs)
- body.setDir(D)
+ for(var/dir in showDirs)
+ body.setDir(dir)
var/icon/partial = getFlatIcon(body)
- out_icon.Insert(partial, dir = D)
+ out_icon.Insert(partial, dir = dir)
humanoid_icon_cache[icon_id] = out_icon
dummy_key ? unset_busy_human_dummy(dummy_key) : qdel(body)
return out_icon
else
return humanoid_icon_cache[icon_id]
+
+/proc/get_flat_human_copy_icon(mob/living/carbon/human/original, equipment_preset_dresscode, showDirs = GLOB.cardinals, outfit_override)
+ var/mob/living/carbon/human/dummy/body = generate_or_wait_for_human_dummy(null)
+
+ if(original)
+ // From /datum/preferences/proc/copy_appearance_to
+ body.age = original.age
+ body.gender = original.gender
+ body.ethnicity = original.ethnicity
+ body.body_type = original.body_type
+
+ body.r_eyes = original.r_eyes
+ body.g_eyes = original.g_eyes
+ body.b_eyes = original.b_eyes
+
+ body.r_hair = original.r_hair
+ body.g_hair = original.g_hair
+ body.b_hair = original.b_hair
+
+ body.r_gradient = original.r_gradient
+ body.g_gradient = original.g_gradient
+ body.b_gradient = original.b_gradient
+ body.grad_style = original.grad_style
+
+ body.r_facial = original.r_facial
+ body.g_facial = original.g_facial
+ body.b_facial = original.b_facial
+
+ body.r_skin = original.r_skin
+ body.g_skin = original.g_skin
+ body.b_skin = original.b_skin
+
+ body.h_style = original.h_style
+ body.f_style = original.f_style
+
+ body.underwear = original.underwear
+ body.undershirt = original.undershirt
+
+ body.update_body()
+ body.update_hair()
+
+ // Assumption: Is a list
+ if(outfit_override)
+ for(var/obj/item/cur_item as anything in outfit_override)
+ body.equip_to_appropriate_slot(cur_item)
+
+ // Assumption: Is a string or path
+ if(equipment_preset_dresscode)
+ arm_equipment(body, equipment_preset_dresscode)
+
+ var/icon/out_icon = icon('icons/effects/effects.dmi', "nothing")
+ for(var/dir in showDirs)
+ body.setDir(dir)
+ var/icon/partial = getFlatIcon(body)
+ out_icon.Insert(partial, dir = dir)
+
+ // log_debug("get_flat_human_copy_icon called on ref=[REF(original)], instance=[original], type=[original.type], with [length(original.overlays)] overlays reduced to [length(body.overlays)] overlays")
+
+ qdel(body)
+ return out_icon
diff --git a/code/__HELPERS/job.dm b/code/__HELPERS/job.dm
index 43902b07cfd9..220236c6f7e3 100644
--- a/code/__HELPERS/job.dm
+++ b/code/__HELPERS/job.dm
@@ -14,39 +14,10 @@
all_jobs += new jobtype
return all_jobs
-
/proc/get_all_centcom_jobs() return list()
-//gets the actual job rank (ignoring alt titles)
-//this is used solely for sechuds
-/obj/proc/GetJobRealName()
- if (!istype(src,/obj/item/card/id)) return
- var/obj/item/card/id/I = src
- if(I.rank in GLOB.joblist) return I.rank
- if(I.assignment in GLOB.joblist) return I.assignment
- return "Unknown"
-
-/proc/FindNameFromID(mob/living/carbon/human/H)
- ASSERT(istype(H))
- var/obj/item/card/id/I = H.wear_id
- if(istype(I)) return I.registered_name
- I = H.get_active_hand()
- if(istype(I)) return I.registered_name
-
/proc/get_all_job_icons() return GLOB.joblist + list("Prisoner")//For all existing HUD icons
-/obj/proc/GetJobName() //Used in secHUD icon generation
- var/obj/item/card/id/I = src
- if(istype(I))
- var/job_icons = get_all_job_icons()
- var/centcom = get_all_centcom_jobs()
-
- if(I.assignment in job_icons) return I.assignment//Check if the job has a hud icon
- if(I.rank in job_icons) return I.rank
- if(I.assignment in centcom) return "Centcom"//Return with the NT logo if it is a Centcom job
- if(I.rank in centcom) return "Centcom"
- return "Unknown" //Return unknown if none of the above apply
-
/proc/get_actual_job_name(mob/M)
if(!M)
return null
diff --git a/code/__HELPERS/level_traits.dm b/code/__HELPERS/level_traits.dm
index 01a972485fa2..8b3d1b0a3809 100644
--- a/code/__HELPERS/level_traits.dm
+++ b/code/__HELPERS/level_traits.dm
@@ -1,4 +1,3 @@
-
#define is_admin_level(z) SSmapping.level_trait(z, ZTRAIT_ADMIN)
#define is_ground_level(z) SSmapping.level_trait(z, ZTRAIT_GROUND)
diff --git a/code/__HELPERS/logging.dm b/code/__HELPERS/logging.dm
index 5ecbff108725..c20db3da303f 100644
--- a/code/__HELPERS/logging.dm
+++ b/code/__HELPERS/logging.dm
@@ -35,27 +35,27 @@
// will get logs that are one big line if the system is Linux and they are using notepad. This solves it by adding CR to every line ending
// in the logs. ascii character 13 = CR
-/var/global/log_end= world.system_type == UNIX ? ascii2text(13) : ""
+GLOBAL_VAR_INIT(log_end, world.system_type == UNIX ? ascii2text(13) : "")
/proc/error(msg)
- world.log << "## ERROR: [msg][log_end]"
+ world.log << "## ERROR: [msg][GLOB.log_end]"
GLOB.STUI.debug.Add("\[[time_stamp()]]DEBUG: [msg]")
GLOB.STUI.processing |= STUI_LOG_DEBUG
#define WARNING(MSG) warning("[MSG] in [__FILE__] at line [__LINE__] src: [src] usr: [usr].")
//print a warning message to world.log
/proc/warning(msg)
- world.log << "## WARNING: [msg][log_end]"
+ world.log << "## WARNING: [msg][GLOB.log_end]"
GLOB.STUI.debug.Add("\[[time_stamp()]]WARNING: [msg]")
GLOB.STUI.processing |= STUI_LOG_DEBUG
//print a testing-mode debug message to world.log
/proc/testing(msg)
- world.log << "## TESTING: [msg][log_end]"
+ world.log << "## TESTING: [msg][GLOB.log_end]"
GLOB.STUI.debug.Add("\[[time_stamp()]]TESTING: [msg]")
GLOB.STUI.processing |= STUI_LOG_DEBUG
/proc/log_admin(text)
var/time = time_stamp()
- admin_log.Add(text)
+ GLOB.admin_log.Add(text)
if (CONFIG_GET(flag/log_admin))
WRITE_LOG(GLOB.world_game_log, "ADMIN: [text]")
LOG_REDIS("admin", "\[[time]\] [text]")
@@ -63,14 +63,14 @@
GLOB.STUI.processing |= STUI_LOG_ADMIN
/proc/log_asset(text)
- asset_log.Add(text)
+ GLOB.asset_log.Add(text)
if (CONFIG_GET(flag/log_asset))
var/time = time_stamp()
WRITE_LOG(GLOB.world_game_log, "ASSET: [text]")
LOG_REDIS("asset", "\[[time]\] [text]")
/proc/log_adminpm(text)
- admin_log.Add(text)
+ GLOB.admin_log.Add(text)
if (CONFIG_GET(flag/log_admin))
WRITE_LOG(GLOB.world_game_log, "ADMIN: [text]")
GLOB.STUI.staff.Add("\[[time_stamp()]]ADMIN: [text]")
diff --git a/code/__HELPERS/mobs.dm b/code/__HELPERS/mobs.dm
index 9aa1bdc3ea2f..663d72fd5079 100644
--- a/code/__HELPERS/mobs.dm
+++ b/code/__HELPERS/mobs.dm
@@ -51,8 +51,10 @@
return f_style
/proc/random_name(gender, species = "Human")
- if(gender==FEMALE) return capitalize(pick(first_names_female)) + " " + capitalize(pick(last_names))
- else return capitalize(pick(first_names_male)) + " " + capitalize(pick(last_names))
+ if(gender==FEMALE)
+ return capitalize(pick(GLOB.first_names_female)) + " " + capitalize(pick(GLOB.last_names))
+ else
+ return capitalize(pick(GLOB.first_names_male)) + " " + capitalize(pick(GLOB.last_names))
/proc/has_species(mob/M, species)
if(!M || !istype(M,/mob/living/carbon/human))
@@ -71,6 +73,7 @@
/mob/proc/change_real_name(mob/M, new_name)
if(!new_name)
return FALSE
+ var/old_name = M.real_name
M.real_name = new_name
M.name = new_name
@@ -81,6 +84,7 @@
// If we are humans, we need to update our voice as well
M.change_mob_voice(new_name)
+ SEND_SIGNAL(src, COMSIG_MOB_REAL_NAME_CHANGED, old_name, new_name)
return TRUE
/mob/proc/change_mind_name(new_mind_name)
diff --git a/code/__HELPERS/sorts/TimSort.dm b/code/__HELPERS/sorts/TimSort.dm
index cfa55f0dfa3c..ae83bd9b0682 100644
--- a/code/__HELPERS/sorts/TimSort.dm
+++ b/code/__HELPERS/sorts/TimSort.dm
@@ -8,10 +8,14 @@
if(toIndex <= 0)
toIndex += L.len + 1
- sortInstance.L = L
- sortInstance.cmp = cmp
- sortInstance.associative = associative
+ var/datum/sortInstance/sort_instance = GLOB.sortInstance
+ if(!sort_instance)
+ sort_instance = new()
- sortInstance.timSort(fromIndex, toIndex)
+ sort_instance.L = L
+ sort_instance.cmp = cmp
+ sort_instance.associative = associative
+
+ sort_instance.timSort(fromIndex, toIndex)
return L
diff --git a/code/__HELPERS/sorts/_Main.dm b/code/__HELPERS/sorts/_Main.dm
index 7bc906be7e63..5d6f5210be47 100644
--- a/code/__HELPERS/sorts/_Main.dm
+++ b/code/__HELPERS/sorts/_Main.dm
@@ -8,8 +8,8 @@
//When we get into galloping mode, we stay there until both runs win less often than MIN_GALLOP consecutive times.
#define MIN_GALLOP 7
- //This is a global instance to allow much of this code to be reused. The interfaces are kept separately
-var/datum/sortInstance/sortInstance = new()
+//This is a global instance to allow much of this code to be reused. The interfaces are kept separately
+GLOBAL_DATUM_INIT(sortInstance, /datum/sortInstance, new())
/datum/sortInstance
//The array being sorted.
var/list/L
diff --git a/code/__HELPERS/status_effects.dm b/code/__HELPERS/status_effects.dm
new file mode 100644
index 000000000000..d06cb687f6a5
--- /dev/null
+++ b/code/__HELPERS/status_effects.dm
@@ -0,0 +1 @@
+#define TRAIT_STATUS_EFFECT(effect_id) "[effect_id]-trait"
diff --git a/code/__HELPERS/text.dm b/code/__HELPERS/text.dm
index d4d9eb320633..967967790b28 100644
--- a/code/__HELPERS/text.dm
+++ b/code/__HELPERS/text.dm
@@ -30,6 +30,11 @@
text = replacetext(text, char, repl_chars[char])
return text
+///Helper for only alphanumeric characters plus common punctuation, spaces, underscore and hyphen _ -.
+/proc/replace_non_alphanumeric_plus(text)
+ var/regex/alphanumeric = regex(@{"[^a-z0-9 ,.?!\-_&]"}, "gi")
+ return alphanumeric.Replace(text, "")
+
/proc/readd_quotes(text)
var/list/repl_chars = list(""" = "\"", "'" = "'")
for(var/char in repl_chars)
@@ -341,8 +346,8 @@
// ---Begin URL caching.
var/list/urls = list()
var/i = 1
- while (url_find_lazy.Find_char(message))
- urls["\ref[urls]-[i]"] = url_find_lazy.match
+ while (GLOB.url_find_lazy.Find_char(message))
+ urls["\ref[urls]-[i]"] = GLOB.url_find_lazy.match
i++
for (var/ref in urls)
@@ -350,9 +355,9 @@
// ---End URL caching
var/regex/tag_markup
- for (var/tag in (markup_tags - ignore_tags))
- tag_markup = markup_regex[tag]
- message = tag_markup.Replace_char(message, "$2[markup_tags[tag][1]]$3[markup_tags[tag][2]]$5")
+ for (var/tag in (GLOB.markup_tags - ignore_tags))
+ tag_markup = GLOB.markup_regex[tag]
+ message = tag_markup.Replace_char(message, "$2[GLOB.markup_tags[tag][1]]$3[GLOB.markup_tags[tag][2]]$5")
// ---Unload URL cache
for (var/ref in urls)
diff --git a/code/__HELPERS/traits.dm b/code/__HELPERS/traits.dm
new file mode 100644
index 000000000000..ba99b2e1e7ff
--- /dev/null
+++ b/code/__HELPERS/traits.dm
@@ -0,0 +1,43 @@
+#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/i in target)
+ if(!isatom(i))
+ continue
+ var/atom/the_atom = i
+ ADD_TRAIT(the_atom,trait,source)
+ else if(isatom(target))
+ var/atom/the_atom2 = target
+ ADD_TRAIT(the_atom2,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/i in target)
+ if(!isatom(i))
+ continue
+ var/atom/the_atom = i
+ REMOVE_TRAIT(the_atom,trait,source)
+ else if(isatom(target))
+ var/atom/the_atom2 = target
+ REMOVE_TRAIT(the_atom2,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 4e4a1b3ff31c..5d0d113b0c55 100644
--- a/code/__HELPERS/type2type.dm
+++ b/code/__HELPERS/type2type.dm
@@ -21,7 +21,7 @@
var/char = copytext(hex, i, i + 1)
switch(char)
if("0")
- //Apparently, switch works with empty statements, yay! If that doesn't work, blame me, though. -- Urist
+ pass()
if("9", "8", "7", "6", "5", "4", "3", "2", "1")
num += text2num(char) * 16 ** power
if("a", "A")
@@ -77,7 +77,6 @@
hex += "E"
if(15.0)
hex += "F"
- else
power--
while(length(hex) < placeholder)
hex = text("0[]", hex)
@@ -165,8 +164,6 @@
return 6
if("SOUTHWEST")
return 10
- else
- return
//Converts an angle (degrees) into an ss13 direction
/proc/angle2dir(degree)
diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm
index 9a6ee4362088..05fa7c69e50f 100644
--- a/code/__HELPERS/unsorted.dm
+++ b/code/__HELPERS/unsorted.dm
@@ -21,16 +21,16 @@
#define between(low, middle, high) (max(min(middle, high), low))
//Offuscate x for coord system
-#define obfuscate_x(x) (x + obfs_x)
+#define obfuscate_x(x) (x + GLOB.obfs_x)
//Offuscate y for coord system
-#define obfuscate_y(y) (y + obfs_y)
+#define obfuscate_y(y) (y + GLOB.obfs_y)
//Deoffuscate x for coord system
-#define deobfuscate_x(x) (x - obfs_x)
+#define deobfuscate_x(x) (x - GLOB.obfs_x)
//Deoffuscate y for coord system
-#define deobfuscate_y(y) (y - obfs_y)
+#define deobfuscate_y(y) (y - GLOB.obfs_y)
#define can_xeno_build(T) (!T.density && !(locate(/obj/structure/fence) in T) && !(locate(/obj/structure/tunnel) in T) && (locate(/obj/effect/alien/weeds) in T))
@@ -99,38 +99,29 @@
var/atom/movable/big_subject = subject
. += (big_subject.bound_height - world.icon_size) / 2
-/proc/Get_Angle(atom/start,atom/end, tile_bound = FALSE)//For beams.
- if(!start || !end) return 0
- if(!start.z || !end.z) return 0 //Atoms are not on turfs.
- var/dx
- var/dy
- if(tile_bound)
- dy=end.y-start.y
- dx=end.x-start.x
- else
- dy = get_pixel_position_y(end) - get_pixel_position_y(start)
- dx = get_pixel_position_x(end) - get_pixel_position_x(start)
- if(!dy)
- return (dx>=0)?90:270
- .=arctan(dx/dy)
- if(dy<0)
- .+=180
- else if(dx<0)
- .+=360
-
-/proc/Get_Compass_Dir(atom/start,atom/end)//get_dir() only considers an object to be north/south/east/west if there is zero deviation. This uses rounding instead.
- if(!start || !end) return 0
- if(!start.z || !end.z) return 0 //Atoms are not on turfs.
- var/dy=end.y-start.y
- var/dx=end.x-start.x
- if(!dy)
- return (dx>=0)?4:8
- var/angle=arctan(dx/dy)
- if(dy<0)
- angle+=180
- else if(dx<0)
- angle+=360
-
+/// Calculate the angle between two atoms. Uses north-clockwise convention: NORTH = 0, EAST = 90, etc.
+/proc/Get_Angle(atom/start, atom/end)//For beams.
+ if(!start || !end)
+ return 0
+ if(!start.z)
+ start = get_turf(start)
+ if(!start)
+ return 0 //Atoms are not on turfs.
+ if(!end.z)
+ end = get_turf(end)
+ if(!end)
+ return 0 //Atoms are not on turfs.
+ var/dy = get_pixel_position_y(end) - get_pixel_position_y(start)
+ var/dx = get_pixel_position_x(end) - get_pixel_position_x(start)
+ return delta_to_angle(dx, dy)
+
+/// Calculate the angle produced by a pair of x and y deltas. Uses north-clockwise convention: NORTH = 0, EAST = 90, etc.
+/proc/delta_to_angle(dx, dy)
+ . = arctan(dy, dx) //y-then-x results in north-clockwise convention: https://en.wikipedia.org/wiki/Atan2#East-counterclockwise,_north-clockwise_and_south-clockwise_conventions,_etc.
+ if(. < 0)
+ . += 360
+
+/proc/angle_to_dir(angle)
switch(angle) //diagonal directions get priority over straight directions in edge cases
if (22.5 to 67.5)
return NORTHEAST
@@ -151,6 +142,8 @@
else
return NORTH
+/proc/Get_Compass_Dir(atom/start, atom/end)//get_dir() only considers an object to be north/south/east/west if there is zero deviation. This uses rounding instead.
+ return angle_to_dir(Get_Angle(get_turf(start), get_turf(end)))
// Among other things, used by flamethrower and boiler spray to calculate if flame/spray can pass through.
// Returns an atom for specific effects (primarily flames and acid spray) that damage things upon contact
@@ -281,9 +274,10 @@
//update the datacore records! This is goig to be a bit costly.
var/mob_ref = WEAKREF(src)
for(var/list/L in list(GLOB.data_core.general, GLOB.data_core.medical, GLOB.data_core.security, GLOB.data_core.locked))
- for(var/datum/data/record/R in L)
- if(R.fields["ref"] == mob_ref)
- R.fields["name"] = newname
+ for(var/datum/data/record/record_entry in L)
+ if(record_entry.fields["ref"] == mob_ref)
+ record_entry.fields["name"] = newname
+ record_entry.name = newname
break
//update our pda and id if we have them on our person
@@ -916,110 +910,127 @@
return FALSE
-var/global/image/busy_indicator_clock
-var/global/image/busy_indicator_medical
-var/global/image/busy_indicator_build
-var/global/image/busy_indicator_friendly
-var/global/image/busy_indicator_hostile
-var/global/image/emote_indicator_highfive
-var/global/image/emote_indicator_fistbump
-var/global/image/emote_indicator_headbutt
-var/global/image/emote_indicator_tailswipe
-var/global/image/emote_indicator_rock_paper_scissors
-var/global/image/emote_indicator_rock
-var/global/image/emote_indicator_paper
-var/global/image/emote_indicator_scissors
-var/global/image/action_red_power_up
-var/global/image/action_green_power_up
-var/global/image/action_blue_power_up
-var/global/image/action_purple_power_up
+GLOBAL_DATUM(busy_indicator_clock, /image)
+GLOBAL_DATUM(busy_indicator_medical, /image)
+GLOBAL_DATUM(busy_indicator_build, /image)
+GLOBAL_DATUM(busy_indicator_friendly, /image)
+GLOBAL_DATUM(busy_indicator_hostile, /image)
+GLOBAL_DATUM(emote_indicator_highfive, /image)
+GLOBAL_DATUM(emote_indicator_fistbump, /image)
+GLOBAL_DATUM(emote_indicator_headbutt, /image)
+GLOBAL_DATUM(emote_indicator_tailswipe, /image)
+GLOBAL_DATUM(emote_indicator_rock_paper_scissors, /image)
+GLOBAL_DATUM(emote_indicator_rock, /image)
+GLOBAL_DATUM(emote_indicator_paper, /image)
+GLOBAL_DATUM(emote_indicator_scissors, /image)
+GLOBAL_DATUM(action_red_power_up, /image)
+GLOBAL_DATUM(action_green_power_up, /image)
+GLOBAL_DATUM(action_blue_power_up, /image)
+GLOBAL_DATUM(action_purple_power_up, /image)
/proc/get_busy_icon(busy_type)
if(busy_type == BUSY_ICON_GENERIC)
- if(!busy_indicator_clock)
- busy_indicator_clock = image('icons/mob/mob.dmi', null, "busy_generic", "pixel_y" = 22)
- busy_indicator_clock.layer = FLY_LAYER
- return busy_indicator_clock
+ if(!GLOB.busy_indicator_clock)
+ GLOB.busy_indicator_clock = image('icons/mob/mob.dmi', null, "busy_generic", "pixel_y" = 22)
+ GLOB.busy_indicator_clock.layer = FLY_LAYER
+ GLOB.busy_indicator_clock.plane = ABOVE_HUD_PLANE
+ return GLOB.busy_indicator_clock
else if(busy_type == BUSY_ICON_MEDICAL)
- if(!busy_indicator_medical)
- busy_indicator_medical = image('icons/mob/mob.dmi', null, "busy_medical", "pixel_y" = 0) //This shows directly on top of the mob, no offset!
- busy_indicator_medical.layer = FLY_LAYER
- return busy_indicator_medical
+ if(!GLOB.busy_indicator_medical)
+ GLOB.busy_indicator_medical = image('icons/mob/mob.dmi', null, "busy_medical", "pixel_y" = 0) //This shows directly on top of the mob, no offset!
+ GLOB.busy_indicator_medical.layer = FLY_LAYER
+ GLOB.busy_indicator_medical.plane = ABOVE_HUD_PLANE
+ return GLOB.busy_indicator_medical
else if(busy_type == BUSY_ICON_BUILD)
- if(!busy_indicator_build)
- busy_indicator_build = image('icons/mob/mob.dmi', null, "busy_build", "pixel_y" = 22)
- busy_indicator_build.layer = FLY_LAYER
- return busy_indicator_build
+ if(!GLOB.busy_indicator_build)
+ GLOB.busy_indicator_build = image('icons/mob/mob.dmi', null, "busy_build", "pixel_y" = 22)
+ GLOB.busy_indicator_build.layer = FLY_LAYER
+ GLOB.busy_indicator_build.plane = ABOVE_HUD_PLANE
+ return GLOB.busy_indicator_build
else if(busy_type == BUSY_ICON_FRIENDLY)
- if(!busy_indicator_friendly)
- busy_indicator_friendly = image('icons/mob/mob.dmi', null, "busy_friendly", "pixel_y" = 22)
- busy_indicator_friendly.layer = FLY_LAYER
- return busy_indicator_friendly
+ if(!GLOB.busy_indicator_friendly)
+ GLOB.busy_indicator_friendly = image('icons/mob/mob.dmi', null, "busy_friendly", "pixel_y" = 22)
+ GLOB.busy_indicator_friendly.layer = FLY_LAYER
+ GLOB.busy_indicator_friendly.plane = ABOVE_HUD_PLANE
+ return GLOB.busy_indicator_friendly
else if(busy_type == BUSY_ICON_HOSTILE)
- if(!busy_indicator_hostile)
- busy_indicator_hostile = image('icons/mob/mob.dmi', null, "busy_hostile", "pixel_y" = 22)
- busy_indicator_hostile.layer = FLY_LAYER
- return busy_indicator_hostile
+ if(!GLOB.busy_indicator_hostile)
+ GLOB.busy_indicator_hostile = image('icons/mob/mob.dmi', null, "busy_hostile", "pixel_y" = 22)
+ GLOB.busy_indicator_hostile.layer = FLY_LAYER
+ GLOB.busy_indicator_hostile.plane = ABOVE_HUD_PLANE
+ return GLOB.busy_indicator_hostile
else if(busy_type == EMOTE_ICON_HIGHFIVE)
- if(!emote_indicator_highfive)
- emote_indicator_highfive = image('icons/mob/mob.dmi', null, "emote_highfive", "pixel_y" = 22)
- emote_indicator_highfive.layer = FLY_LAYER
- return emote_indicator_highfive
+ if(!GLOB.emote_indicator_highfive)
+ GLOB.emote_indicator_highfive = image('icons/mob/mob.dmi', null, "emote_highfive", "pixel_y" = 22)
+ GLOB.emote_indicator_highfive.layer = FLY_LAYER
+ GLOB.emote_indicator_highfive.plane = ABOVE_HUD_PLANE
+ return GLOB.emote_indicator_highfive
else if(busy_type == EMOTE_ICON_FISTBUMP)
- if(!emote_indicator_fistbump)
- emote_indicator_fistbump = image('icons/mob/mob.dmi', null, "emote_fistbump", "pixel_y" = 22)
- emote_indicator_fistbump.layer = FLY_LAYER
- return emote_indicator_fistbump
+ if(!GLOB.emote_indicator_fistbump)
+ GLOB.emote_indicator_fistbump = image('icons/mob/mob.dmi', null, "emote_fistbump", "pixel_y" = 22)
+ GLOB.emote_indicator_fistbump.layer = FLY_LAYER
+ GLOB.emote_indicator_fistbump.plane = ABOVE_HUD_PLANE
+ return GLOB.emote_indicator_fistbump
else if(busy_type == EMOTE_ICON_ROCK_PAPER_SCISSORS)
- if(!emote_indicator_rock_paper_scissors)
- emote_indicator_rock_paper_scissors = image('icons/mob/mob.dmi', null, "emote_rps", "pixel_y" = 22)
- emote_indicator_rock_paper_scissors.layer = FLY_LAYER
- return emote_indicator_rock_paper_scissors
+ if(!GLOB.emote_indicator_rock_paper_scissors)
+ GLOB.emote_indicator_rock_paper_scissors = image('icons/mob/mob.dmi', null, "emote_rps", "pixel_y" = 22)
+ GLOB.emote_indicator_rock_paper_scissors.layer = FLY_LAYER
+ GLOB.emote_indicator_rock_paper_scissors.plane = ABOVE_HUD_PLANE
+ return GLOB.emote_indicator_rock_paper_scissors
else if(busy_type == EMOTE_ICON_ROCK)
- if(!emote_indicator_rock)
- emote_indicator_rock = image('icons/mob/mob.dmi', null, "emote_rock", "pixel_y" = 22)
- emote_indicator_rock.layer = FLY_LAYER
- return emote_indicator_rock
+ if(!GLOB.emote_indicator_rock)
+ GLOB.emote_indicator_rock = image('icons/mob/mob.dmi', null, "emote_rock", "pixel_y" = 22)
+ GLOB.emote_indicator_rock.layer = FLY_LAYER
+ GLOB.emote_indicator_rock.plane = ABOVE_HUD_PLANE
+ return GLOB.emote_indicator_rock
else if(busy_type == EMOTE_ICON_PAPER)
- if(!emote_indicator_paper)
- emote_indicator_paper = image('icons/mob/mob.dmi', null, "emote_paper", "pixel_y" = 22)
- emote_indicator_paper.layer = FLY_LAYER
- return emote_indicator_paper
+ if(!GLOB.emote_indicator_paper)
+ GLOB.emote_indicator_paper = image('icons/mob/mob.dmi', null, "emote_paper", "pixel_y" = 22)
+ GLOB.emote_indicator_paper.layer = FLY_LAYER
+ GLOB.emote_indicator_paper.plane = ABOVE_HUD_PLANE
+ return GLOB.emote_indicator_paper
else if(busy_type == EMOTE_ICON_SCISSORS)
- if(!emote_indicator_scissors)
- emote_indicator_scissors = image('icons/mob/mob.dmi', null, "emote_scissors", "pixel_y" = 22)
- emote_indicator_scissors.layer = FLY_LAYER
- return emote_indicator_scissors
+ if(!GLOB.emote_indicator_scissors)
+ GLOB.emote_indicator_scissors = image('icons/mob/mob.dmi', null, "emote_scissors", "pixel_y" = 22)
+ GLOB.emote_indicator_scissors.layer = FLY_LAYER
+ GLOB.emote_indicator_scissors.plane = ABOVE_HUD_PLANE
+ return GLOB.emote_indicator_scissors
else if(busy_type == EMOTE_ICON_HEADBUTT)
- if(!emote_indicator_headbutt)
- emote_indicator_headbutt = image('icons/mob/mob.dmi', null, "emote_headbutt", "pixel_y" = 22)
- emote_indicator_headbutt.layer = FLY_LAYER
- return emote_indicator_headbutt
+ if(!GLOB.emote_indicator_headbutt)
+ GLOB.emote_indicator_headbutt = image('icons/mob/mob.dmi', null, "emote_headbutt", "pixel_y" = 22)
+ GLOB.emote_indicator_headbutt.layer = FLY_LAYER
+ GLOB.emote_indicator_headbutt.plane = ABOVE_HUD_PLANE
+ return GLOB.emote_indicator_headbutt
else if(busy_type == EMOTE_ICON_TAILSWIPE)
- if(!emote_indicator_tailswipe)
- emote_indicator_tailswipe = image('icons/mob/mob.dmi', null, "emote_tailswipe", "pixel_y" = 22)
- emote_indicator_tailswipe.layer = FLY_LAYER
- return emote_indicator_tailswipe
+ if(!GLOB.emote_indicator_tailswipe)
+ GLOB.emote_indicator_tailswipe = image('icons/mob/mob.dmi', null, "emote_tailswipe", "pixel_y" = 22)
+ GLOB.emote_indicator_tailswipe.layer = FLY_LAYER
+ GLOB.emote_indicator_tailswipe.plane = ABOVE_HUD_PLANE
+ return GLOB.emote_indicator_tailswipe
else if(busy_type == ACTION_RED_POWER_UP)
- if(!action_red_power_up)
- action_red_power_up = image('icons/effects/effects.dmi', null, "anger", "pixel_x" = 16)
- action_red_power_up.layer = FLY_LAYER
- return action_red_power_up
+ if(!GLOB.action_red_power_up)
+ GLOB.action_red_power_up = image('icons/effects/effects.dmi', null, "anger", "pixel_x" = 16)
+ GLOB.action_red_power_up.layer = FLY_LAYER
+ GLOB.action_red_power_up.plane = ABOVE_HUD_PLANE
+ return GLOB.action_red_power_up
else if(busy_type == ACTION_GREEN_POWER_UP)
- if(!action_green_power_up)
- action_green_power_up = image('icons/effects/effects.dmi', null, "vitality", "pixel_x" = 16)
- action_green_power_up.layer = FLY_LAYER
- return action_green_power_up
+ if(!GLOB.action_green_power_up)
+ GLOB.action_green_power_up = image('icons/effects/effects.dmi', null, "vitality", "pixel_x" = 16)
+ GLOB.action_green_power_up.layer = FLY_LAYER
+ GLOB.action_green_power_up.plane = ABOVE_HUD_PLANE
+ return GLOB.action_green_power_up
else if(busy_type == ACTION_BLUE_POWER_UP)
- if(!action_blue_power_up)
- action_blue_power_up = image('icons/effects/effects.dmi', null, "shock", "pixel_x" = 16)
- action_blue_power_up.layer = FLY_LAYER
- return action_blue_power_up
+ if(!GLOB.action_blue_power_up)
+ GLOB.action_blue_power_up = image('icons/effects/effects.dmi', null, "shock", "pixel_x" = 16)
+ GLOB.action_blue_power_up.layer = FLY_LAYER
+ GLOB.action_blue_power_up.plane = ABOVE_HUD_PLANE
+ return GLOB.action_blue_power_up
else if(busy_type == ACTION_PURPLE_POWER_UP)
- if(!action_purple_power_up)
- action_purple_power_up = image('icons/effects/effects.dmi', null, "pain", "pixel_x" = 16)
- action_purple_power_up.layer = FLY_LAYER
- return action_purple_power_up
+ if(!GLOB.action_purple_power_up)
+ GLOB.action_purple_power_up = image('icons/effects/effects.dmi', null, "pain", "pixel_x" = 16)
+ GLOB.action_purple_power_up.layer = FLY_LAYER
+ GLOB.action_purple_power_up.plane = ABOVE_HUD_PLANE
+ return GLOB.action_purple_power_up
/*
@@ -1089,7 +1100,7 @@ var/global/image/action_purple_power_up
target_orig_turf = get_turf(target)
var/obj/user_holding = busy_user.get_active_hand()
var/obj/target_holding
- var/cur_user_lying = busy_user.lying
+ var/cur_user_lying = busy_user.body_position
var/cur_target_lying
var/expected_total_time = delayfraction*numticks
var/time_remaining = expected_total_time
@@ -1097,7 +1108,7 @@ var/global/image/action_purple_power_up
if(has_target && istype(T))
cur_target_zone_sel = T.zone_selected
target_holding = T.get_active_hand()
- cur_target_lying = T.lying
+ cur_target_lying = T.body_position
. = TRUE
for(var/i in 1 to numticks)
@@ -1121,17 +1132,17 @@ var/global/image/action_purple_power_up
)
. = FALSE
break
- if(user_flags & INTERRUPT_KNOCKED_DOWN && busy_user.knocked_down || \
- target_is_mob && (target_flags & INTERRUPT_KNOCKED_DOWN && T.knocked_down)
+ if(user_flags & INTERRUPT_KNOCKED_DOWN && HAS_TRAIT(busy_user, TRAIT_FLOORED) || \
+ target_is_mob && (target_flags & INTERRUPT_KNOCKED_DOWN && HAS_TRAIT(T, TRAIT_FLOORED))
)
. = FALSE
break
- if(user_flags & INTERRUPT_STUNNED && busy_user.stunned || \
- target_is_mob && (target_flags & INTERRUPT_STUNNED && T.stunned)
+ if(user_flags & INTERRUPT_STUNNED && HAS_TRAIT(busy_user, TRAIT_INCAPACITATED)|| \
+ target_is_mob && (target_flags & INTERRUPT_STUNNED && HAS_TRAIT(T, TRAIT_INCAPACITATED))
)
. = FALSE
break
- if(user_flags & INTERRUPT_DAZED && busy_user.dazed)
+ if(user_flags & INTERRUPT_DAZED && HAS_TRAIT(busy_user, TRAIT_DAZED))
. = FALSE
break
if(user_flags & INTERRUPT_EMOTE && !busy_user.flags_emote)
@@ -1201,8 +1212,8 @@ var/global/image/action_purple_power_up
)
. = FALSE
break
- if(user_flags & INTERRUPT_CHANGED_LYING && busy_user.lying != cur_user_lying || \
- target_is_mob && (target_flags & INTERRUPT_CHANGED_LYING && T.lying != cur_target_lying)
+ if(user_flags & INTERRUPT_CHANGED_LYING && busy_user.body_position != cur_user_lying || \
+ target_is_mob && (target_flags & INTERRUPT_CHANGED_LYING && T.body_position != cur_target_lying)
)
. = FALSE
break
@@ -1465,7 +1476,7 @@ var/global/image/action_purple_power_up
/*
Checks if that loc and dir has a item on the wall
*/
-var/list/WALLITEMS = list(
+GLOBAL_LIST_INIT(WALLITEMS, list(
/obj/structure/machinery/power/apc,
/obj/structure/machinery/alarm,
/obj/item/device/radio/intercom,
@@ -1486,10 +1497,11 @@ var/list/WALLITEMS = list(
/obj/structure/mirror,
/obj/structure/closet/fireaxecabinet,
/obj/structure/machinery/computer/cameras/telescreen/entertainment,
- )
+ ))
+
/proc/gotwallitem(loc, dir)
for(var/obj/O in loc)
- for(var/item in WALLITEMS)
+ for(var/item in GLOB.WALLITEMS)
if(istype(O, item))
//Direction works sometimes
if(O.dir == dir)
@@ -1513,7 +1525,7 @@ var/list/WALLITEMS = list(
//Some stuff is placed directly on the wallturf (signs)
for(var/obj/O in get_step(loc, dir))
- for(var/item in WALLITEMS)
+ for(var/item in GLOB.WALLITEMS)
if(istype(O, item))
if(O.pixel_x == 0 && O.pixel_y == 0)
return 1
@@ -1650,7 +1662,7 @@ var/list/WALLITEMS = list(
var/turf/Turf = get_turf(explosive)
if(!(Turf.loc.type in GLOB.explosive_antigrief_exempt_areas))
var/crash_occured = (SSticker?.mode?.is_in_endgame)
- if((Turf.z in SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP, ZTRAIT_RESERVED))) && (security_level < SEC_LEVEL_RED) && !crash_occured)
+ if((Turf.z in SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP, ZTRAIT_RESERVED))) && (GLOB.security_level < SEC_LEVEL_RED) && !crash_occured)
switch(CONFIG_GET(number/explosive_antigrief))
if(ANTIGRIEF_DISABLED)
return FALSE
@@ -2093,3 +2105,15 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars,list(
if(NORTHWEST)
return list(NORTHWEST, NORTH, WEST)
+
+/// Returns TRUE if the target is somewhere that the game should not interact with if possible
+/// In this case, admin Zs and tutorial areas
+/proc/should_block_game_interaction(atom/target)
+ if(is_admin_level(target.z))
+ return TRUE
+
+ var/area/target_area = get_area(target)
+ if(target_area?.block_game_interaction)
+ return TRUE
+
+ return FALSE
diff --git a/code/__odlint.dm b/code/__odlint.dm
new file mode 100644
index 000000000000..f42517133746
--- /dev/null
+++ b/code/__odlint.dm
@@ -0,0 +1,11 @@
+// This file is included right at the start of the DME.
+// Its purpose is to enable multiple lints (pragmas) that are supported by OpenDream to better validate the codebase
+// These are essentially nitpicks the DM compiler should pick up on but doesnt
+
+#ifndef SPACEMAN_DMM
+#ifdef OPENDREAM
+// These are in their own file as you need to do it with an include as a hack to avoid
+// SpacemanDMM evaluating the #pragma lines, even if its outside a block it cares about
+#include "__pragmas.dm"
+#endif
+#endif
diff --git a/code/__pragmas.dm b/code/__pragmas.dm
new file mode 100644
index 000000000000..39c14e1bbc95
--- /dev/null
+++ b/code/__pragmas.dm
@@ -0,0 +1,27 @@
+//1000-1999
+#pragma FileAlreadyIncluded error
+#pragma MissingIncludedFile error
+#pragma MisplacedDirective error
+#pragma UndefineMissingDirective error
+#pragma DefinedMissingParen error
+#pragma ErrorDirective error
+#pragma WarningDirective error
+#pragma MiscapitalizedDirective error
+
+//2000-2999
+#pragma SoftReservedKeyword error
+#pragma DuplicateVariable error
+#pragma DuplicateProcDefinition error
+#pragma TooManyArguments error
+#pragma PointlessParentCall error
+#pragma PointlessBuiltinCall error
+#pragma SuspiciousMatrixCall error
+#pragma MalformedRange error
+#pragma InvalidRange error
+#pragma InvalidSetStatement error
+#pragma InvalidOverride error
+#pragma DanglingVarType error
+#pragma MissingInterpolatedExpression error
+
+//3000-3999
+#pragma EmptyBlock error
diff --git a/code/_byond_version_compat.dm b/code/_byond_version_compat.dm
index 719d85654b5f..26968f0f837c 100644
--- a/code/_byond_version_compat.dm
+++ b/code/_byond_version_compat.dm
@@ -3,7 +3,7 @@
//Update this whenever you need to take advantage of more recent byond features
#define MIN_COMPILER_VERSION 514
#define MIN_COMPILER_BUILD 1588
-#if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM)
+#if (DM_VERSION < MIN_COMPILER_VERSION || DM_BUILD < MIN_COMPILER_BUILD) && !defined(SPACEMAN_DMM) && !defined(OPENDREAM)
//Don't forget to update this part
#error Your version of BYOND is too out-of-date to compile this project. Go to https://secure.byond.com/download and update.
#error You need version 514.1588 or higher
diff --git a/code/_compile_options.dm b/code/_compile_options.dm
index 0f81b0173ac1..20aa2081318c 100644
--- a/code/_compile_options.dm
+++ b/code/_compile_options.dm
@@ -30,7 +30,7 @@
#define CBT
#endif
-#if !defined(CBT) && !defined(SPACEMAN_DMM)
+#if !defined(CBT) && !defined(SPACEMAN_DMM) && !defined(OPENDREAM)
#warn Building with Dream Maker is no longer supported and will result in errors.
#warn In order to build, run BUILD.bat in the bin directory.
#warn Consider switching to VSCode editor instead, where you can press Ctrl+Shift+B to build.
diff --git a/code/_globalvars/bitfields.dm b/code/_globalvars/bitfields.dm
index 53dd40ff6035..59d14f2e0fed 100644
--- a/code/_globalvars/bitfields.dm
+++ b/code/_globalvars/bitfields.dm
@@ -87,6 +87,7 @@ DEFINE_BITFIELD(flags_ammo_behaviour, list(
"AMMO_IGNORE_RESIST" = AMMO_IGNORE_RESIST,
"AMMO_BALLISTIC" = AMMO_BALLISTIC,
"AMMO_IGNORE_COVER" = AMMO_IGNORE_COVER,
+ "AMMO_ANTIVEHICLE" = AMMO_ANTIVEHICLE,
"AMMO_STOPPED_BY_COVER" = AMMO_STOPPED_BY_COVER,
"AMMO_SPECIAL_EMBED" = AMMO_SPECIAL_EMBED,
"AMMO_STRIKES_SURFACE" = AMMO_STRIKES_SURFACE,
@@ -97,7 +98,6 @@ DEFINE_BITFIELD(flags_ammo_behaviour, list(
"AMMO_FLAME" = AMMO_FLAME,
))
-
DEFINE_BITFIELD(projectile_flags, list(
"PROJECTILE_SHRAPNEL" = PROJECTILE_SHRAPNEL,
"PROJECTILE_BULLSEYE" = PROJECTILE_BULLSEYE,
@@ -120,6 +120,7 @@ DEFINE_BITFIELD(flags_gun_features, list(
"GUN_ANTIQUE" = GUN_ANTIQUE,
"GUN_RECOIL_BUILDUP" = GUN_RECOIL_BUILDUP,
"GUN_SUPPORT_PLATFORM" = GUN_SUPPORT_PLATFORM,
+ "GUN_NO_DESCRIPTION" = GUN_NO_DESCRIPTION,
))
DEFINE_BITFIELD(flags_magazine, list(
@@ -150,6 +151,7 @@ DEFINE_BITFIELD(flags_atom, list(
"INITIALIZED" = INITIALIZED,
"ATOM_DECORATED" = ATOM_DECORATED,
"USES_HEARING" = USES_HEARING,
+ "HTML_USE_INITAL_ICON" = HTML_USE_INITAL_ICON,
))
DEFINE_BITFIELD(flags_item, list(
@@ -166,7 +168,6 @@ DEFINE_BITFIELD(flags_item, list(
"ITEM_OVERRIDE_NORTHFACE" = ITEM_OVERRIDE_NORTHFACE,
"CAN_DIG_SHRAPNEL" = CAN_DIG_SHRAPNEL,
"ANIMATED_SURGICAL_TOOL" = ANIMATED_SURGICAL_TOOL,
- "NOTABLEMERGE" = NOTABLEMERGE,
"IGNITING_ITEM" = IGNITING_ITEM,
))
@@ -182,7 +183,7 @@ DEFINE_BITFIELD(flags_inv_hide, list(
"HIDETOPHAIR" = HIDETOPHAIR,
"HIDEALLHAIR" = HIDEALLHAIR,
"HIDETAIL" = HIDETAIL,
- "HIDEFACE" = HIDEFACE
+ "HIDEFACE" = HIDEFACE,
))
DEFINE_BITFIELD(flags_inventory, list(
@@ -328,9 +329,6 @@ DEFINE_BITFIELD(flags_area, list(
DEFINE_BITFIELD(disabilities, list(
"NEARSIGHTED" = NEARSIGHTED,
- "EPILEPSY" = EPILEPSY,
- "COUGHING" = COUGHING,
- "TOURETTES" = TOURETTES,
"NERVOUS" = NERVOUS,
"OPIATE_RECEPTOR_DEFICIENCY" = OPIATE_RECEPTOR_DEFICIENCY,
))
@@ -370,6 +368,13 @@ DEFINE_BITFIELD(mob_flags, list(
"NOBIOSCAN" = NOBIOSCAN,
))
+DEFINE_BITFIELD(mobility_flags, list(
+ "MOVE" = MOBILITY_MOVE,
+ "STAND" = MOBILITY_STAND,
+ "REST" = MOBILITY_REST,
+ "LIEDOWN" = MOBILITY_LIEDOWN
+))
+
DEFINE_BITFIELD(flags, list(
"NO_BLOOD" = NO_BLOOD,
"NO_BREATHE" = NO_BREATHE,
@@ -417,6 +422,7 @@ DEFINE_BITFIELD(toggleable_flags, list(
"MODE_NO_COMBAT_CAS" = MODE_NO_COMBAT_CAS,
"MODE_LZ_PROTECTION" = MODE_LZ_PROTECTION,
"MODE_SHIPSIDE_SD" = MODE_SHIPSIDE_SD,
+ "MODE_HARDCORE_PERMA" = MODE_HARDCORE_PERMA,
"MODE_DISPOSABLE_MOBS" = MODE_DISPOSABLE_MOBS,
"MODE_BYPASS_JOE" = MODE_BYPASS_JOE,
))
@@ -450,7 +456,9 @@ DEFINE_BITFIELD(fire_immunity, list(
"FIRE_IMMUNITY_NO_DAMAGE" = FIRE_IMMUNITY_NO_DAMAGE,
"FIRE_IMMUNITY_NO_IGNITE" = FIRE_IMMUNITY_NO_IGNITE,
"FIRE_IMMUNITY_XENO_FRENZY" = FIRE_IMMUNITY_XENO_FRENZY,
+ "FIRE_VULNERABILITY" = FIRE_VULNERABILITY,
))
+
DEFINE_BITFIELD(vend_flags, list(
"VEND_TO_HAND" = VEND_TO_HAND,
"VEND_UNIFORM_RANKS" = VEND_UNIFORM_RANKS,
@@ -461,4 +469,133 @@ DEFINE_BITFIELD(vend_flags, list(
"VEND_INSTANCED_CATEGORY" = VEND_INSTANCED_CATEGORY,
"VEND_FACTION_THEMES" = VEND_FACTION_THEMES,
"VEND_USE_VENDOR_FLAGS" = VEND_USE_VENDOR_FLAGS,
+ "VEND_LOAD_AMMO_BOXES" = VEND_LOAD_AMMO_BOXES,
+ "VEND_STOCK_DYNAMIC" = VEND_STOCK_DYNAMIC
+))
+
+DEFINE_BITFIELD(vehicle_flags, list(
+ "VEHICLE_CLASS_WEAK" = VEHICLE_CLASS_WEAK,
+ "VEHICLE_CLASS_LIGHT" = VEHICLE_CLASS_LIGHT,
+ "VEHICLE_CLASS_MEDIUM" = VEHICLE_CLASS_MEDIUM,
+ "VEHICLE_CLASS_HEAVY" = VEHICLE_CLASS_HEAVY,
+ "VEHICLE_BYPASS_BLOCKERS" = VEHICLE_BYPASS_BLOCKERS,
+))
+
+DEFINE_BITFIELD(flags_pass, list(
+ "PASS_THROUGH" = PASS_THROUGH,
+ "PASS_AROUND" = PASS_AROUND,
+ "PASS_OVER_THROW_ITEM" = PASS_OVER_THROW_ITEM,
+ "PASS_OVER_THROW_MOB" = PASS_OVER_THROW_MOB,
+ "PASS_OVER_FIRE" = PASS_OVER_FIRE,
+ "PASS_OVER_ACID_SPRAY" = PASS_OVER_ACID_SPRAY,
+ "PASS_UNDER" = PASS_UNDER,
+ "PASS_GLASS" = PASS_GLASS,
+ "PASS_MOB_IS_XENO" = PASS_MOB_IS_XENO,
+ "PASS_MOB_IS_HUMAN" = PASS_MOB_IS_HUMAN,
+ "PASS_MOB_IS_OTHER" = PASS_MOB_IS_OTHER,
+ "PASS_MOB_THRU_XENO" = PASS_MOB_THRU_XENO,
+ "PASS_MOB_THRU_HUMAN" = PASS_MOB_THRU_HUMAN,
+ "PASS_MOB_THRU_OTHER" = PASS_MOB_THRU_OTHER,
+ "PASS_TYPE_CRAWLER" = PASS_TYPE_CRAWLER,
+ "PASS_HIGH_OVER_ONLY" = PASS_HIGH_OVER_ONLY,
+ "PASS_BUILDING_ONLY" = PASS_BUILDING_ONLY,
+ "PASS_CRUSHER_CHARGE" = PASS_CRUSHER_CHARGE,
+))
+
+DEFINE_BITFIELD(flags_can_pass_all, list(
+ "PASS_THROUGH" = PASS_THROUGH,
+ "PASS_AROUND" = PASS_AROUND,
+ "PASS_OVER_THROW_ITEM" = PASS_OVER_THROW_ITEM,
+ "PASS_OVER_THROW_MOB" = PASS_OVER_THROW_MOB,
+ "PASS_OVER_FIRE" = PASS_OVER_FIRE,
+ "PASS_OVER_ACID_SPRAY" = PASS_OVER_ACID_SPRAY,
+ "PASS_UNDER" = PASS_UNDER,
+ "PASS_GLASS" = PASS_GLASS,
+ "PASS_MOB_IS_XENO" = PASS_MOB_IS_XENO,
+ "PASS_MOB_IS_HUMAN" = PASS_MOB_IS_HUMAN,
+ "PASS_MOB_IS_OTHER" = PASS_MOB_IS_OTHER,
+ "PASS_MOB_THRU_XENO" = PASS_MOB_THRU_XENO,
+ "PASS_MOB_THRU_HUMAN" = PASS_MOB_THRU_HUMAN,
+ "PASS_MOB_THRU_OTHER" = PASS_MOB_THRU_OTHER,
+ "PASS_TYPE_CRAWLER" = PASS_TYPE_CRAWLER,
+ "PASS_HIGH_OVER_ONLY" = PASS_HIGH_OVER_ONLY,
+ "PASS_BUILDING_ONLY" = PASS_BUILDING_ONLY,
+ "PASS_CRUSHER_CHARGE" = PASS_CRUSHER_CHARGE,
+))
+
+DEFINE_BITFIELD(flags_can_pass_front, list(
+ "PASS_THROUGH" = PASS_THROUGH,
+ "PASS_AROUND" = PASS_AROUND,
+ "PASS_OVER_THROW_ITEM" = PASS_OVER_THROW_ITEM,
+ "PASS_OVER_THROW_MOB" = PASS_OVER_THROW_MOB,
+ "PASS_OVER_FIRE" = PASS_OVER_FIRE,
+ "PASS_OVER_ACID_SPRAY" = PASS_OVER_ACID_SPRAY,
+ "PASS_UNDER" = PASS_UNDER,
+ "PASS_GLASS" = PASS_GLASS,
+ "PASS_MOB_IS_XENO" = PASS_MOB_IS_XENO,
+ "PASS_MOB_IS_HUMAN" = PASS_MOB_IS_HUMAN,
+ "PASS_MOB_IS_OTHER" = PASS_MOB_IS_OTHER,
+ "PASS_MOB_THRU_XENO" = PASS_MOB_THRU_XENO,
+ "PASS_MOB_THRU_HUMAN" = PASS_MOB_THRU_HUMAN,
+ "PASS_MOB_THRU_OTHER" = PASS_MOB_THRU_OTHER,
+ "PASS_TYPE_CRAWLER" = PASS_TYPE_CRAWLER,
+ "PASS_HIGH_OVER_ONLY" = PASS_HIGH_OVER_ONLY,
+ "PASS_BUILDING_ONLY" = PASS_BUILDING_ONLY,
+ "PASS_CRUSHER_CHARGE" = PASS_CRUSHER_CHARGE,
+))
+
+DEFINE_BITFIELD(flags_can_pass_behind, list(
+ "PASS_THROUGH" = PASS_THROUGH,
+ "PASS_AROUND" = PASS_AROUND,
+ "PASS_OVER_THROW_ITEM" = PASS_OVER_THROW_ITEM,
+ "PASS_OVER_THROW_MOB" = PASS_OVER_THROW_MOB,
+ "PASS_OVER_FIRE" = PASS_OVER_FIRE,
+ "PASS_OVER_ACID_SPRAY" = PASS_OVER_ACID_SPRAY,
+ "PASS_UNDER" = PASS_UNDER,
+ "PASS_GLASS" = PASS_GLASS,
+ "PASS_MOB_IS_XENO" = PASS_MOB_IS_XENO,
+ "PASS_MOB_IS_HUMAN" = PASS_MOB_IS_HUMAN,
+ "PASS_MOB_IS_OTHER" = PASS_MOB_IS_OTHER,
+ "PASS_MOB_THRU_XENO" = PASS_MOB_THRU_XENO,
+ "PASS_MOB_THRU_HUMAN" = PASS_MOB_THRU_HUMAN,
+ "PASS_MOB_THRU_OTHER" = PASS_MOB_THRU_OTHER,
+ "PASS_TYPE_CRAWLER" = PASS_TYPE_CRAWLER,
+ "PASS_HIGH_OVER_ONLY" = PASS_HIGH_OVER_ONLY,
+ "PASS_BUILDING_ONLY" = PASS_BUILDING_ONLY,
+ "PASS_CRUSHER_CHARGE" = PASS_CRUSHER_CHARGE,
+))
+
+DEFINE_BITFIELD(sight, list(
+ "BLIND" = BLIND,
+ "SEE_BLACKNESS" = SEE_BLACKNESS,
+ "SEE_INFRA" = SEE_INFRA,
+ "SEE_MOBS" = SEE_MOBS,
+ "SEE_OBJS" = SEE_OBJS,
+ "SEE_PIXELS" = SEE_PIXELS,
+ "SEE_SELF" = SEE_SELF,
+ "SEE_THRU" = SEE_THRU,
+ "SEE_TURFS" = SEE_TURFS,
+))
+
+DEFINE_BITFIELD(vision_flags, list(
+ "BLIND" = BLIND,
+ "SEE_BLACKNESS" = SEE_BLACKNESS,
+ "SEE_INFRA" = SEE_INFRA,
+ "SEE_MOBS" = SEE_MOBS,
+ "SEE_OBJS" = SEE_OBJS,
+ "SEE_PIXELS" = SEE_PIXELS,
+ "SEE_SELF" = SEE_SELF,
+ "SEE_THRU" = SEE_THRU,
+ "SEE_TURFS" = SEE_TURFS,
+))
+
+DEFINE_BITFIELD(vis_flags, list(
+ "VIS_HIDE" = VIS_HIDE,
+ "VIS_INHERIT_DIR" = VIS_INHERIT_DIR,
+ "VIS_INHERIT_ICON" = VIS_INHERIT_ICON,
+ "VIS_INHERIT_ICON_STATE" = VIS_INHERIT_ICON_STATE,
+ "VIS_INHERIT_ID" = VIS_INHERIT_ID,
+ "VIS_INHERIT_LAYER" = VIS_INHERIT_LAYER,
+ "VIS_INHERIT_PLANE" = VIS_INHERIT_PLANE,
+ "VIS_UNDERLAY" = VIS_UNDERLAY,
))
diff --git a/code/_globalvars/global_lists.dm b/code/_globalvars/global_lists.dm
index 36058a44fc37..6e1b229e562f 100644
--- a/code/_globalvars/global_lists.dm
+++ b/code/_globalvars/global_lists.dm
@@ -1,6 +1,3 @@
-
-var/list/unansweredAhelps = list() //This feels inefficient, but I can't think of a better way. Stores the message indexed by CID
-
GLOBAL_LIST_EMPTY(PressFaxes)
GLOBAL_LIST_EMPTY(WYFaxes) //Departmental faxes
GLOBAL_LIST_EMPTY(USCMFaxes)
@@ -9,20 +6,25 @@ GLOBAL_LIST_EMPTY(CMBFaxes)
GLOBAL_LIST_EMPTY(GeneralFaxes) //Inter-machine faxes
GLOBAL_LIST_EMPTY(fax_contents) //List of fax contents to maintain it even if source paper is deleted
+//datum containing a reference to the flattend map png url, the actual png is stored in the user's cache.
+GLOBAL_LIST_EMPTY(uscm_flat_tacmap_data)
+GLOBAL_LIST_EMPTY(xeno_flat_tacmap_data)
+
+//datum containing the svg overlay coords in array format.
+GLOBAL_LIST_EMPTY(uscm_svg_tacmap_data)
+GLOBAL_LIST_EMPTY(xeno_svg_tacmap_data)
+
GLOBAL_LIST_EMPTY(failed_fultons) //A list of fultoned items which weren't collected and fell back down
GLOBAL_LIST_EMPTY(larva_burst_by_hive)
GLOBAL_LIST_INIT_TYPED(custom_huds_list, /datum/custom_hud, setup_all_huds())
GLOBAL_LIST_INIT_TYPED(custom_human_huds, /datum/custom_hud, setup_human_huds())
-//Since it didn't really belong in any other category, I'm putting this here
-//This is for procs to replace all the goddamn 'in world's that are chilling around the code
-
-var/readied_players = 0 //How many players are readied up in the lobby
+GLOBAL_VAR_INIT(readied_players, 0) //How many players are readied up in the lobby
GLOBAL_LIST_EMPTY_TYPED(other_factions_human_list, /mob/living/carbon/human)
-var/global/list/ai_mob_list = list() //List of all AIs
+GLOBAL_LIST_EMPTY(ai_mob_list) //List of all AIs
GLOBAL_LIST_EMPTY(freed_mob_list) // List of mobs freed for ghosts
@@ -104,12 +106,12 @@ GLOBAL_LIST_INIT_TYPED(resin_mark_meanings, /datum/xeno_mark_define, setup_resin
GLOBAL_REFERENCE_LIST_INDEXED(xeno_datum_list, /datum/caste_datum, caste_type)
//Chem Stuff
-var/global/list/chemical_reactions_filtered_list //List of all /datum/chemical_reaction datums filtered by reaction components. Used during chemical reactions
-var/global/list/chemical_reactions_list //List of all /datum/chemical_reaction datums indexed by reaction id. Used to search for the result instead of the components.
-var/global/list/chemical_reagents_list //List of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
-var/global/list/chemical_properties_list //List of all /datum/chem_property datums indexed by property name
+GLOBAL_LIST(chemical_reactions_filtered_list) //List of all /datum/chemical_reaction datums filtered by reaction components. Used during chemical reactions
+GLOBAL_LIST(chemical_reactions_list) //List of all /datum/chemical_reaction datums indexed by reaction id. Used to search for the result instead of the components.
+GLOBAL_LIST(chemical_reagents_list) //List of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
+GLOBAL_LIST(chemical_properties_list) //List of all /datum/chem_property datums indexed by property name
//List of all id's from classed /datum/reagent datums indexed by class or tier. Used by chemistry generator and chem spawners.
-var/global/list/list/chemical_gen_classes_list = list("C" = list(),"C1" = list(),"C2" = list(),"C3" = list(),"C4" = list(),"C5" = list(),"C6" = list(),"T1" = list(),"T2" = list(),"T3" = list(),"T4" = list(),"tau" = list())
+GLOBAL_LIST_INIT_TYPED(chemical_gen_classes_list, /list, list("C" = list(),"C1" = list(),"C2" = list(),"C3" = list(),"C4" = list(),"C5" = list(),"C6" = list(),"T1" = list(),"T2" = list(),"T3" = list(),"T4" = list(),"tau", list()))
//properties generated in chemicals, helps to make sure the same property doesn't show up 10 times
GLOBAL_LIST_INIT_TYPED(generated_properties, /list, list("positive" = list(), "negative" = list(), "neutral" = list()))
@@ -135,13 +137,12 @@ GLOBAL_LIST_INIT(surgical_patient_types, setup_surgical_patient_types())
GLOBAL_LIST_INIT_TYPED(gear_path_presets_list, /datum/equipment_preset, setup_gear_path_presets())
GLOBAL_LIST_INIT_TYPED(gear_name_presets_list, /datum/equipment_preset, setup_gear_name_presets())
-var/global/list/active_areas = list()
-var/global/list/all_areas = list()
+GLOBAL_LIST_EMPTY(active_areas)
+GLOBAL_LIST_EMPTY(all_areas)
-var/global/list/turfs = list()
-var/global/list/z1turfs = list()
+GLOBAL_LIST_EMPTY(turfs)
-/var/global/list/objects_of_interest // This is used to track the stealing objective for Agents.
+GLOBAL_LIST(objects_of_interest) // This is used to track the stealing objective for Agents.
// Areas exempt from explosive antigrief (not Z-levels)
GLOBAL_LIST_INIT(explosive_antigrief_exempt_areas, list(
@@ -204,23 +205,23 @@ GLOBAL_REFERENCE_LIST_INDEXED(hair_gradient_list, /datum/sprite_accessory/hair_g
GLOBAL_REFERENCE_LIST_INDEXED(yautja_hair_styles_list, /datum/sprite_accessory/yautja_hair, name)
//Backpacks
-var/global/list/backbaglist = list("Backpack", "Satchel")
+GLOBAL_LIST_INIT(backbaglist, list("Backpack", "Satchel"))
//Armor styles
GLOBAL_LIST_INIT(armor_style_list, list("Padded" = 1, "Padless" = 2, "Ridged" = 3, "Carrier" = 4, "Skull" = 5, "Smooth" = 6, "Random"))
// var/global/list/exclude_jobs = list(/datum/job/ai,/datum/job/cyborg)
-var/global/round_should_check_for_win = TRUE
+GLOBAL_VAR_INIT(round_should_check_for_win, TRUE)
-var/global/list/key_mods = list("CTRL", "ALT", "SHIFT")
+GLOBAL_LIST_INIT(key_mods, list("CTRL", "ALT", "SHIFT"))
// A list storing the pass flags for specific types of atoms
-var/global/list/pass_flags_cache = list()
+GLOBAL_LIST_EMPTY(pass_flags_cache)
//Parameterss cache
-var/global/list/paramslist_cache = list()
+GLOBAL_LIST_EMPTY(paramslist_cache)
//Turf Edge info uberlist -- a list whos states contain GLOB.edgeinfo_X keyed as different icon_states
-var/global/list/turf_edgeinfo_cache = list()
+GLOBAL_LIST_EMPTY(turf_edgeinfo_cache)
#define FULL_EDGE 1
#define HALF_EDGE_RIGHT 2
@@ -272,10 +273,10 @@ GLOBAL_LIST_INIT(typecache_living, typecacheof(/mob/living))
GLOBAL_LIST_INIT(emote_list, init_emote_list())
/proc/cached_params_decode(params_data, decode_proc)
- . = paramslist_cache[params_data]
+ . = GLOB.paramslist_cache[params_data]
if(!.)
. = call(decode_proc)(params_data)
- paramslist_cache[params_data] = .
+ GLOB.paramslist_cache[params_data] = .
/proc/key_number_decode(key_number_data)
var/list/L = params2list(key_number_data)
@@ -456,10 +457,10 @@ GLOBAL_LIST_INIT(emote_list, init_emote_list())
/* // Uncomment to debug chemical reaction list.
/client/verb/debug_chemical_list()
- for (var/reaction in chemical_reactions_filtered_list)
- . += "chemical_reactions_filtered_list\[\"[reaction]\"\] = \"[chemical_reactions_filtered_list[reaction]]\"\n"
- if(islist(chemical_reactions_filtered_list[reaction]))
- var/list/L = chemical_reactions_filtered_list[reaction]
+ for (var/reaction in GLOB.chemical_reactions_filtered_list)
+ . += "GLOB.chemical_reactions_filtered_list\[\"[reaction]\"\] = \"[GLOB.chemical_reactions_filtered_list[reaction]]\"\n"
+ if(islist(GLOB.chemical_reactions_filtered_list[reaction]))
+ var/list/L = GLOB.chemical_reactions_filtered_list[reaction]
for(var/t in L)
. += " has: [t]\n"
world << .
@@ -473,22 +474,22 @@ GLOBAL_LIST_EMPTY(timelocks)
//the global list of specialist kits that haven't been claimed yet.
-var/global/list/available_specialist_sets = list(
+GLOBAL_LIST_INIT(available_specialist_sets, list(
"Scout Set",
"Sniper Set",
"Demolitionist Set",
"Heavy Grenadier Set",
"Pyro Set"
- )
+ ))
//Similar thing, but used in /obj/item/spec_kit
-var/global/list/available_specialist_kit_boxes = list(
+GLOBAL_LIST_INIT(available_specialist_kit_boxes, list(
"Pyro" = 2,
"Grenadier" = 2,
"Sniper" = 2,
"Scout" = 2,
"Demo" = 2,
- )
+ ))
/proc/init_global_referenced_datums()
init_keybindings()
diff --git a/code/_globalvars/lists/clans.dm b/code/_globalvars/lists/clans.dm
new file mode 100644
index 000000000000..f04915a37435
--- /dev/null
+++ b/code/_globalvars/lists/clans.dm
@@ -0,0 +1,19 @@
+GLOBAL_LIST_INIT_TYPED(clan_ranks, /datum/yautja_rank, list(
+ CLAN_RANK_UNBLOODED = new /datum/yautja_rank/unblooded(),
+ CLAN_RANK_YOUNG = new /datum/yautja_rank/young(),
+ CLAN_RANK_BLOODED = new /datum/yautja_rank/blooded(),
+ CLAN_RANK_ELITE = new /datum/yautja_rank/elite(),
+ CLAN_RANK_ELDER = new /datum/yautja_rank/elder(),
+ CLAN_RANK_LEADER = new /datum/yautja_rank/leader(),
+ CLAN_RANK_ADMIN = new /datum/yautja_rank/ancient()
+))
+
+GLOBAL_LIST_INIT(clan_ranks_ordered, list(
+ CLAN_RANK_UNBLOODED = CLAN_RANK_UNBLOODED_INT,
+ CLAN_RANK_YOUNG = CLAN_RANK_YOUNG_INT,
+ CLAN_RANK_BLOODED = CLAN_RANK_BLOODED_INT,
+ CLAN_RANK_ELITE = CLAN_RANK_ELITE_INT,
+ CLAN_RANK_ELDER = CLAN_RANK_ELDER_INT,
+ CLAN_RANK_LEADER = CLAN_RANK_LEADER_INT,
+ CLAN_RANK_ADMIN = CLAN_RANK_ADMIN_INT
+))
diff --git a/code/_globalvars/lists/names.dm b/code/_globalvars/lists/names.dm
new file mode 100644
index 000000000000..09ad2b422d3c
--- /dev/null
+++ b/code/_globalvars/lists/names.dm
@@ -0,0 +1,39 @@
+GLOBAL_LIST_INIT(ai_names, file2list("strings/ai.txt"))
+GLOBAL_LIST_INIT(first_names_male, file2list("strings/first_male.txt"))
+GLOBAL_LIST_INIT(first_names_female, file2list("strings/first_female.txt"))
+GLOBAL_LIST_INIT(last_names, file2list("strings/last.txt"))
+GLOBAL_LIST_INIT(clown_names, file2list("strings/clown.txt"))
+GLOBAL_LIST_INIT(operation_titles, file2list("strings/operation_title.txt"))
+GLOBAL_LIST_INIT(operation_prefixes, file2list("strings/operation_prefix.txt"))
+GLOBAL_LIST_INIT(operation_postfixes, file2list("strings/operation_postfix.txt"))
+
+GLOBAL_LIST_INIT(verbs, file2list("strings/verbs.txt"))
+//loaded on startup because of "
+//would include in rsc if ' was used
+
+
+GLOBAL_LIST_INIT(first_names_male_clf, list("Alan","Jack","Bil","Jonathan","John","Shiro","Gareth","Clark","Sam", "Lionel", "Aaron", "Charlie", "Scott", "Winston", "Aidan", "Ellis", "Mason", "Wesley", "Nicholas", "Calvin", "Nishikawa", "Hiroto", "Chiba", "Ouchi", "Furuse", "Takagi", "Oba", "Kishimoto"))
+GLOBAL_LIST_INIT(first_names_female_clf, list("Emma", "Adelynn", "Mary", "Halie", "Chelsea", "Lexie", "Arya", "Alicia", "Selah", "Amber", "Heather", "Myra", "Heidi", "Charlotte", "Oliva", "Lydia", "Tia", "Riko", "Ari", "Machida", "Ueki", "Mihara", "Noda"))
+GLOBAL_LIST_INIT(last_names_clf, list("Hawkins","Rickshaw","Elliot","Billard","Cooper","Fox", "Barlow", "Barrows", "Stewart", "Morgan", "Green", "Stone", "Burr", "Hunt", "Yuko", "Gesshin", "Takanibu", "Tetsuzan", "Tomomi", "Bokkai", "Takesi"))
+
+GLOBAL_LIST_INIT(first_names_male_colonist, list("Alan","Jack","Bil","Jonathan","John","Shiro","Gareth","Clark","Sam", "Lionel", "Aaron", "Charlie", "Scott", "Winston", "Aidan", "Ellis", "Mason", "Wesley", "Nicholas", "Calvin", "Nishikawa", "Hiroto", "Chiba", "Ouchi", "Furuse", "Takagi", "Oba", "Kishimoto"))
+GLOBAL_LIST_INIT(first_names_female_colonist, list("Emma", "Adelynn", "Mary", "Halie", "Chelsea", "Lexie", "Arya", "Alicia", "Selah", "Amber", "Heather", "Myra", "Heidi", "Charlotte", "Ashley", "Raven", "Tori", "Anne", "Madison", "Oliva", "Lydia", "Tia", "Riko", "Ari", "Machida", "Ueki", "Mihara", "Noda"))
+GLOBAL_LIST_INIT(last_names_colonist, list("Hawkins","Rickshaw","Elliot","Billard","Cooper","Fox", "Barlow", "Barrows", "Stewart", "Morgan", "Green", "Stone", "Titan", "Crowe", "Krantz", "Pathillo", "Driggers", "Burr", "Hunt", "Yuko", "Gesshin", "Takanibu", "Tetsuzan", "Tomomi", "Bokkai", "Takesi"))
+
+GLOBAL_LIST_INIT(first_names_male_upp, list("Badai","Mongkeemur","Alexei","Andrei","Artyom","Viktor","Xiangai","Ivan","Choban","Oleg", "Dayan", "Taghi", "Batu", "Arik", "Orda", "Ghazan", "Bala", "Gao", "Zhan", "Ren", "Hou", "Xue", "Serafim", "Luca", "Su", "György", "István", "Mihály", "Vladimir", "Aleksandr", "Fyodor", "Bhodar", "Qazem", "Łukasz", "Miłogost", "Radogost", "Uniegost", "Hostirad", "Hostimil", "Hostisvit", "Lubgost", "Gościsław", "Vseslav", "Bohuměr", "Bronisław", "Česćiměr", "Dobysław", "Horisław", "Jaroměr", "Mirosław", "Mječisław", "Radoměr", "Stanij", "Stanisław", "Wjeleměr", "Wójsław"))
+GLOBAL_LIST_INIT(first_names_female_upp, list("Altani","Cirina","Anastasiya","Saran","Wei","Oksana","Ren","Svena","Tatyana","Yaroslava", "Izabella", "Kata", "Krisztina", "Miruna", "Flori", "Lucia", "Anica", "Li", "Yimu", "Alona", "Hsiau-Li", "Xiaoling", "Erhong", "Baśka", "Angela", "Angelina", "Angja", "Ankica", "Biljana", "Bisera", "Bistra", "Blaga", "Blagica", "Blagorodna", "Verka", "Vladica", "Denica", "Živka", "Zlata", "Jagoda", "Letka", "Ljupka", "Mila", "Mirjana", "Mirka", "Rada", "Radmila", "Slavica", "Slavka", "Snežana", "Stojna", "Ubavka", "Jaromir", "Mscëwòj", "Subisłôw", "Swiãtopôłk", "Ji-Sun", "Chaeyong", "Chaewon", "Saerom", "Seoyeong", "Jiheon", "Hayoung"))
+GLOBAL_LIST_INIT(last_names_upp, list("Azarov","Bogdanov","Barsukov","Golovin","Davydov","Khan","Noica","Barbu","Zhukov","Ivanov","Mihai","Kasputin","Belov", "Belova","Melnikov", "Vasilevsky", "Aleksander", "Halkovich", "Stanislaw", "Proca", "Zaituc", "Arcos", "Kubat", "Kral", "Volf", "Xun", "Jia", "Bachoń", "Wang", "Ji", "Xiang", "Zhang", "Mei", "Ma", "Kim", "Yi", "Ri", "Pak", "Chong", "Baek", "Kwon", "Hwang", "Roh", "Lee", "Song"))
+
+GLOBAL_LIST_INIT(first_names_male_pmc, list("Owen","Luka","Nelson","Branson", "Tyson", "Leo", "Bryant", "Kobe", "Rohan", "Riley", "Aidan", "Watase","Egawa", "Hisakawa", "Koide", "Remy", "Martial", "Magnus", "Heiko", "Lennard"))
+GLOBAL_LIST_INIT(first_names_female_pmc, list("Madison","Jessica","Anna","Juliet", "Olivia", "Lea", "Diane", "Kaori", "Beatrice", "Riley", "Amy", "Natsue","Yumi", "Aiko", "Fujiko", "Jennifer", "Ashley", "Mary", "Hitomi", "Lisa"))
+GLOBAL_LIST_INIT(last_names_pmc, list("Bates","Shaw","Hansen","Black", "Chambers", "Hall", "Gibson", "Weiss", "Waller", "Burton", "Bakin", "Rohan", "Naomichi", "Yakumo", "Yosai", "Gallagher", "Hiles", "Bourdon", "Strassman", "Palau"))
+
+GLOBAL_LIST_INIT(first_names_male_gladiator, list("Augustus", "Maximus", "Octavius", "Septimus", "Titus", "Brutus", "Caesar", "Justinian"))
+GLOBAL_LIST_INIT(first_names_female_gladiator, list("Aelia", "Aquila", "Caecilia", "Camilla", "Claudia", "Flavia", "Martina", "Theodora"))
+
+GLOBAL_LIST_INIT(first_names_male_dutch, list("Raymond", "Jesse", "Jack", "John", "Sam", "Aaron", "Charlie", "Ellis", "Nick", "Francis", "Louis"))
+GLOBAL_LIST_INIT(first_names_female_dutch, list("Chelsea", "Mira", "Jessica", "Catherine", "Eliza", "Emma", "Ashley", "Annie", "Alicia", "Miranda", "Ellen"))
+
+GLOBAL_LIST_INIT(monkey_names, list("Abu", "Aldo", "Bear", "Bingo", "Clyde", "Crystal", "Gordo", "George", "Koko", "Marcel", "Nim", "Rafiki", "Spike", "Banana", "Boots", "Bubbles", "Smiley", "Winston"))
+
+GLOBAL_LIST_INIT(weapon_surnames, list("Adze", "Axe", "Bagh Nakha", "Bo", "Bola", "Bow", "Bowman", "Cannon", "Carbine", "Cestus", "Club", "Culverin", "Dagger", "Dao", "Derringer", "Dha", "Dussack", "Emeici", "Falchion", "Fan", "Flyssa", "Gauntlet", "Hammer", "Halberd", "Harquebus", "Hatchet", "Hwando", "Katar", "Kampilan", "Knuckles", "Lance", "Lancer", "Larim", "Maduvu", "Mace", "Maru", "Mauser", "Messer", "Mine", "Mubucae", "Nyepel", "Onager", "Pata", "Pike", "Ram", "Saber", "Seax", "Shamsir", "Sickle", "Sling", "Spear", "Spears", "Staff", "Sword", "Tekko"))
diff --git a/code/_globalvars/lists/object_lists.dm b/code/_globalvars/lists/object_lists.dm
index 3a417625538b..5cfd0653c24a 100644
--- a/code/_globalvars/lists/object_lists.dm
+++ b/code/_globalvars/lists/object_lists.dm
@@ -23,11 +23,10 @@ GLOBAL_LIST_EMPTY_TYPED(disposal_retrieval_list, /obj/structure/disposaloutlet/r
GLOBAL_LIST_EMPTY_TYPED(disposalpipe_up_list, /obj/structure/disposalpipe/up/almayer)
GLOBAL_LIST_EMPTY_TYPED(disposalpipe_down_list, /obj/structure/disposalpipe/down/almayer)
-GLOBAL_LIST_EMPTY_TYPED(hijack_bustable_windows, /obj/structure/window)
-GLOBAL_LIST_EMPTY_TYPED(hijack_deletable_windows, /obj/structure/machinery/door/window/ultra)
-GLOBAL_LIST_EMPTY_TYPED(hijack_bustable_ladders, /obj/structure/ladder/fragile_almayer)
-
GLOBAL_LIST_EMPTY_TYPED(all_multi_vehicles, /obj/vehicle/multitile)
GLOBAL_LIST_EMPTY_TYPED(lifeboat_almayer_docks, /obj/docking_port/stationary/lifeboat_dock)
GLOBAL_LIST_EMPTY_TYPED(lifeboat_doors, /obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/lifeboat/blastdoor)
+
+GLOBAL_LIST_EMPTY_TYPED(teleporters, /datum/teleporter)
+GLOBAL_LIST_EMPTY(teleporters_by_id)
diff --git a/code/_globalvars/misc.dm b/code/_globalvars/misc.dm
index 646b8ec2c854..0b7a4af0f05f 100644
--- a/code/_globalvars/misc.dm
+++ b/code/_globalvars/misc.dm
@@ -1,3 +1,89 @@
+GLOBAL_VAR_INIT(game_year, 2182)
+
+GLOBAL_VAR_INIT(ooc_allowed, TRUE)
+GLOBAL_VAR_INIT(looc_allowed, TRUE)
+GLOBAL_VAR_INIT(dsay_allowed, TRUE)
+GLOBAL_VAR_INIT(dooc_allowed, TRUE)
+GLOBAL_VAR_INIT(dlooc_allowed, FALSE)
+
+GLOBAL_VAR_INIT(enter_allowed, TRUE)
+
+GLOBAL_LIST_EMPTY(admin_log)
+GLOBAL_LIST_EMPTY(asset_log)
+
+// multiplier for watts per tick <> cell storage (eg: 0.02 means if there is a load of 1000 watts, 20 units will be taken from a cell per second)
+//It's a conversion constant. power_used*CELLRATE = charge_provided, or charge_used/CELLRATE = power_provided
+#define CELLRATE 0.006
+
+// Cap for how fast cells charge, as a percentage-per-tick (0.01 means cellcharge is capped to 1% per second)
+#define CHARGELEVEL 0.001
+
+GLOBAL_VAR(VehicleElevatorConsole)
+GLOBAL_VAR(VehicleGearConsole)
+
+//Spawnpoints.
+GLOBAL_LIST_EMPTY(fallen_list)
+/// This is for dogtags placed on crosses- they will show up at the end-round memorial.
+GLOBAL_LIST_EMPTY(fallen_list_cross)
+
+GLOBAL_LIST_INIT(diagonals, list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST))
+GLOBAL_LIST_INIT(alldirs, list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST))
+GLOBAL_LIST_INIT(reverse_dir, list(2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15, 32, 34, 33, 35, 40, 42, 41, 43, 36, 38, 37, 39, 44, 46, 45, 47, 16, 18, 17, 19, 24, 26, 25, 27, 20, 22, 21, 23, 28, 30, 29, 31, 48, 50, 49, 51, 56, 58, 57, 59, 52, 54, 53, 55, 60, 62, 61, 63))
+
+
+
+GLOBAL_VAR(join_motd)
+GLOBAL_VAR(current_tms)
+
+GLOBAL_LIST_INIT(BorgWireColorToFlag, RandomBorgWires())
+GLOBAL_LIST(BorgIndexToFlag)
+GLOBAL_LIST(BorgIndexToWireColor)
+GLOBAL_LIST(BorgWireColorToIndex)
+GLOBAL_LIST_INIT(AAlarmWireColorToFlag, RandomAAlarmWires())
+GLOBAL_LIST(AAlarmIndexToFlag)
+GLOBAL_LIST(AAlarmIndexToWireColor)
+GLOBAL_LIST(AAlarmWireColorToIndex)
+
+/// 3 minutes in the station.
+#define shuttle_time_in_station 3 MINUTES
+/// 10 minutes to arrive.
+#define shuttle_time_to_arrive 10 MINUTES
+
+ // For FTP requests. (i.e. downloading runtime logs.)
+ // However it'd be ok to use for accessing attack logs and such too, which are even laggier.
+GLOBAL_VAR_INIT(fileaccess_timer, 0)
+
+// Reference list for disposal sort junctions. Filled up by sorting junction's New()
+GLOBAL_LIST_EMPTY(tagger_locations)
+
+//added for Xenoarchaeology, might be useful for other stuff
+GLOBAL_LIST_INIT(alphabet_uppercase, list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"))
+GLOBAL_LIST_INIT(alphabet_lowercase, list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z"))
+
+GLOBAL_LIST_INIT(greek_letters, list("Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omnicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega"))
+GLOBAL_LIST_INIT(nato_phonetic_alphabet, list("Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliett", "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-Ray", "Yankee", "Zulu"))
+
+//Used for autocall procs on ERT
+GLOBAL_VAR_INIT(distress_cancel, FALSE)
+GLOBAL_VAR_INIT(destroy_cancel, FALSE)
+
+// Which lobby art is on display
+// This is updated by the lobby art turf when it initializes
+GLOBAL_VAR_INIT(displayed_lobby_art, -1)
+
+// Last global ID that was assigned to a mob (for round recording purposes)
+GLOBAL_VAR_INIT(last_mob_gid, 0)
+
+GLOBAL_LIST_INIT(almayer_ship_sections, list(
+ "Upper deck Foreship",
+ "Upper deck Midship",
+ "Upper deck Aftship",
+ "Lower deck Foreship",
+ "Lower deck Midship",
+ "Lower deck Aftship"
+))
+
+
GLOBAL_VAR_INIT(internal_tick_usage, 0.2 * world.tick_lag)
/// Global performance feature toggle flags
@@ -14,8 +100,24 @@ GLOBAL_LIST_INIT(pill_icon_mappings, map_pill_icons())
/// In-round override to default OOC color
GLOBAL_VAR(ooc_color_override)
+// tacmap cooldown for xenos and marines
+GLOBAL_VAR_INIT(uscm_canvas_cooldown, 0)
+GLOBAL_VAR_INIT(xeno_canvas_cooldown, 0)
+
+// getFlatIcon cooldown for xenos and marines
+GLOBAL_VAR_INIT(uscm_flatten_map_icon_cooldown, 0)
+GLOBAL_VAR_INIT(xeno_flatten_map_icon_cooldown, 0)
+
+// latest unannounced flat tacmap for xenos and marines
+GLOBAL_VAR(uscm_unannounced_map)
+GLOBAL_VAR(xeno_unannounced_map)
+
+//global tacmaps for action button access
+GLOBAL_DATUM_INIT(uscm_tacmap_status, /datum/tacmap/drawing/status_tab_view, new)
+GLOBAL_DATUM_INIT(xeno_tacmap_status, /datum/tacmap/drawing/status_tab_view/xeno, new)
+
/// List of roles that can be setup for each gamemode
-GLOBAL_LIST_INIT(gamemode_roles, list())
+GLOBAL_LIST_EMPTY(gamemode_roles)
GLOBAL_VAR_INIT(minimum_exterior_lighting_alpha, 255)
@@ -30,3 +132,10 @@ GLOBAL_VAR_INIT(time_offset, setup_offset())
/// The last count of possible candidates in the xeno larva queue (updated via get_alien_candidates)
GLOBAL_VAR(xeno_queue_candidate_count)
+
+//Coordinate obsfucator
+//Used by the rangefinders and linked systems to prevent coords collection/prefiring
+/// A number between -500 and 500.
+GLOBAL_VAR(obfs_x)
+/// A number between -500 and 500.
+GLOBAL_VAR(obfs_y)
diff --git a/code/_onclick/adjacent.dm b/code/_onclick/adjacent.dm
index dd7a528bb8a6..6504db0d9f0c 100644
--- a/code/_onclick/adjacent.dm
+++ b/code/_onclick/adjacent.dm
@@ -94,6 +94,11 @@ Quick adjacency (to turf):
/obj/item/Adjacent(atom/neighbor, recurse = 1)
if(neighbor == loc || (loc && neighbor == loc.loc))
return TRUE
+
+ // Internal storages have special relationships with the object they are connected to and we still want two depth adjacency for storages
+ if(istype(loc?.loc, /obj/item/storage/internal) && recurse > 0)
+ return loc.loc.Adjacent(neighbor, recurse)
+
if(issurface(loc))
return loc.Adjacent(neighbor, recurse) //Surfaces don't count as storage depth.
else if(istype(loc, /obj/item))
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 3b8ba26c07e9..b99d52086e36 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -375,7 +375,7 @@
tX = tX[1]
var/shiftX = C.pixel_x / world.icon_size
var/shiftY = C.pixel_y / world.icon_size
- var/list/actual_view = getviewsize(C ? C.view : world_view_size)
+ var/list/actual_view = getviewsize(C ? C.view : GLOB.world_view_size)
tX = Clamp(origin.x + text2num(tX) + shiftX - round(actual_view[1] / 2) - 1, 1, world.maxx)
tY = Clamp(origin.y + text2num(tY) + shiftY - round(actual_view[2] / 2) - 1, 1, world.maxy)
return locate(tX, tY, tZ)
diff --git a/code/_onclick/click_hold.dm b/code/_onclick/click_hold.dm
index f65dd33c2eea..996f7ed2bf3b 100644
--- a/code/_onclick/click_hold.dm
+++ b/code/_onclick/click_hold.dm
@@ -94,3 +94,12 @@
// Add the hovered atom to the trace
LAZYADD(mouse_trace_history, over_obj)
+
+/client/MouseDrop(datum/over_object, datum/src_location, over_location, src_control, over_control, params)
+ . = ..()
+
+ if(src_location)
+ SEND_SIGNAL(src_location, COMSIG_ATOM_DROPPED_ON, over_object, src)
+
+ if(over_object)
+ SEND_SIGNAL(over_object, COMSIG_ATOM_DROP_ON, src_location, src)
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index c6b642974881..22a24e022a3f 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -9,7 +9,7 @@
"1:2,3:4" is the square (1,3) with pixel offsets (+2, +4); slightly right and slightly above the turf grid.
Pixel offsets are used so you don't perfectly hide the turf under them, that would be crappy.
- The size of the user's screen is defined by client.view (indirectly by world_view_size), in our case "15x15".
+ The size of the user's screen is defined by client.view (indirectly by GLOB.world_view_size), in our case "15x15".
Therefore, the top right corner (except during admin shenanigans) is at "15,15"
*/
diff --git a/code/_onclick/hud/ghost.dm b/code/_onclick/hud/ghost.dm
index a6754747a019..a99129d09bcd 100644
--- a/code/_onclick/hud/ghost.dm
+++ b/code/_onclick/hud/ghost.dm
@@ -48,6 +48,14 @@
var/mob/dead/observer/G = usr
G.reenter_corpse()
+/atom/movable/screen/ghost/toggle_huds
+ name = "Toggle HUDs"
+ icon_state = "ghost_hud_toggle"
+
+/atom/movable/screen/ghost/toggle_huds/Click()
+ var/client/client = usr.client
+ client.toggle_ghost_hud()
+
/datum/hud/ghost/New(mob/owner, ui_style='icons/mob/hud/human_white.dmi', ui_color, ui_alpha = 230)
. = ..()
var/atom/movable/screen/using
@@ -68,6 +76,9 @@
using.screen_loc = ui_ghost_slot4
static_inventory += using
+ using = new /atom/movable/screen/ghost/toggle_huds()
+ using.screen_loc = ui_ghost_slot5
+ static_inventory += using
/datum/hud/ghost/show_hud(version = 0, mob/viewmob)
// don't show this HUD if observing; show the HUD of the observee
diff --git a/code/_onclick/hud/hud.dm b/code/_onclick/hud/hud.dm
index 215e228fdd9d..f5f61424daac 100644
--- a/code/_onclick/hud/hud.dm
+++ b/code/_onclick/hud/hud.dm
@@ -230,6 +230,7 @@
hud_version = display_hud_version
persistent_inventory_update(screenmob)
mymob.update_action_buttons(TRUE)
+ reorganize_alerts(screenmob)
mymob.reload_fullscreens()
// ensure observers get an accurate and up-to-date view
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index d514bdedfcdf..37a858d76699 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -116,6 +116,10 @@
return
var/mob/living/carbon/human/H = mymob
var/mob/screenmob = viewer || H
+
+ if(!screenmob?.client)
+ return
+
if(!gear.len)
inventory_shown = FALSE
return //species without inv slots don't show items.
@@ -181,6 +185,9 @@
var/mob/living/carbon/human/H = mymob
var/mob/screenmob = viewer || H
+ if(!screenmob?.client)
+ return
+
if(H.hud_used)
if(H.hud_used.hud_shown)
if(H.s_store)
diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm
index cfc6c4d034fb..4a23ebd882d3 100644
--- a/code/_onclick/hud/radial.dm
+++ b/code/_onclick/hud/radial.dm
@@ -34,6 +34,12 @@ GLOBAL_LIST_EMPTY(radial_menus)
/atom/movable/screen/radial/slice/clicked(mob/user)
+ if(QDELETED(src))
+ return
+
+ if(!parent)
+ CRASH("clicked() called on a radial slice with a null parent while not deleted/deleting")
+
if(user.client == parent.current_user)
if(next_page)
parent.next_page()
diff --git a/code/_onclick/hud/rendering/plane_master.dm b/code/_onclick/hud/rendering/plane_master.dm
index 91c0e24fae1f..d4181d7e9953 100644
--- a/code/_onclick/hud/rendering/plane_master.dm
+++ b/code/_onclick/hud/rendering/plane_master.dm
@@ -149,6 +149,14 @@
remove_filter("AO")
add_filter("AO", 1, drop_shadow_filter(x = 0, y = -2, size = 4, color = "#04080FAA"))
+/atom/movable/screen/plane_master/nvg_plane
+ name = "NVG plane"
+ plane = NVG_PLANE
+ render_relay_plane = RENDER_PLANE_GAME
+ blend_mode_override = BLEND_MULTIPLY
+ //icon = 'icons/mob/hud/screen1.dmi'
+ //icon_state = "noise"
+
/atom/movable/screen/plane_master/fullscreen
name = "fullscreen alert plane"
plane = FULLSCREEN_PLANE
diff --git a/code/_onclick/hud/screen_objects.dm b/code/_onclick/hud/screen_objects.dm
index aecec79a8d3f..9af7e4f1db1c 100644
--- a/code/_onclick/hud/screen_objects.dm
+++ b/code/_onclick/hud/screen_objects.dm
@@ -30,6 +30,10 @@
/atom/movable/screen/inventory
var/slot_id //The indentifier for the slot. It has nothing to do with ID cards.
+/atom/movable/screen/inventory/Initialize(mapload, ...)
+ . = ..()
+
+ RegisterSignal(src, COMSIG_ATOM_DROPPED_ON, PROC_REF(handle_dropped_on))
/atom/movable/screen/close
name = "close"
@@ -325,6 +329,22 @@
return 1
return 0
+/atom/movable/screen/inventory/proc/handle_dropped_on(atom/dropped_on, atom/dropping, client/user)
+ SIGNAL_HANDLER
+
+ if(slot_id != WEAR_L_HAND && slot_id != WEAR_R_HAND)
+ return
+
+ if(!isstorage(dropping.loc))
+ return
+
+ if(!user.mob.Adjacent(dropping))
+ return
+
+ var/obj/item/storage/store = dropping.loc
+ store.remove_from_storage(dropping, get_turf(user.mob))
+ user.mob.put_in_active_hand(dropping)
+
/atom/movable/screen/throw_catch
name = "throw/catch"
icon = 'icons/mob/hud/human_midnight.dmi'
@@ -503,19 +523,19 @@
if(user.observed_xeno == user.tracked_marker)
user.overwatch(user.tracked_marker, TRUE) //passing in an obj/effect into a proc that expects mob/xenomorph B)
else
- to_chat(user, SPAN_XENONOTICE("You psychically observe the [user.tracked_marker.mark_meaning.name] resin mark in [get_area_name(user.tracked_marker)]."))
+ to_chat(user, SPAN_XENONOTICE("We psychically observe the [user.tracked_marker.mark_meaning.name] resin mark in [get_area_name(user.tracked_marker)]."))
user.overwatch(user.tracked_marker) //this is so scuffed, sorry if this causes errors
return
if(mods["alt"] && user.tracked_marker)
user.stop_tracking_resin_mark()
return
if(!user.hive)
- to_chat(user, SPAN_WARNING("You don't belong to a hive!"))
+ to_chat(user, SPAN_WARNING("We don't belong to a hive!"))
return FALSE
if(!user.hive.living_xeno_queen)
- to_chat(user, SPAN_WARNING("Without a queen your psychic link is broken!"))
+ to_chat(user, SPAN_WARNING("Without a queen our psychic link is broken!"))
return FALSE
- if(user.burrow || user.is_mob_incapacitated() || user.buckled)
+ if(HAS_TRAIT(user, TRAIT_ABILITY_BURROWED) || user.is_mob_incapacitated() || user.buckled)
return FALSE
user.hive.mark_ui.update_all_data()
user.hive.mark_ui.open_mark_menu(user)
@@ -531,10 +551,10 @@
return FALSE
if(mods["shift"])
var/area/current_area = get_area(user)
- to_chat(user, SPAN_NOTICE("You are currently at: [current_area.name]."))
+ to_chat(user, SPAN_NOTICE("We are currently at: [current_area.name]."))
return
if(!user.hive)
- to_chat(user, SPAN_WARNING("You don't belong to a hive!"))
+ to_chat(user, SPAN_WARNING("We don't belong to a hive!"))
return FALSE
if(mods["alt"])
var/list/options = list()
@@ -561,9 +581,9 @@
track_state = options[selected]
return
if(!user.hive.living_xeno_queen)
- to_chat(user, SPAN_WARNING("Your hive doesn't have a living queen!"))
+ to_chat(user, SPAN_WARNING("Our hive doesn't have a living queen!"))
return FALSE
- if(user.burrow || user.is_mob_incapacitated() || user.buckled)
+ if(HAS_TRAIT(user, TRAIT_ABILITY_BURROWED) || user.is_mob_incapacitated() || user.buckled)
return FALSE
user.overwatch(user.hive.living_xeno_queen)
diff --git a/code/_onclick/human.dm b/code/_onclick/human.dm
index cb71e27f9d1a..b09c26ffb92f 100644
--- a/code/_onclick/human.dm
+++ b/code/_onclick/human.dm
@@ -64,7 +64,7 @@
/mob/living/carbon/human/UnarmedAttack(atom/A, proximity, click_parameters)
- if(lying) //No attacks while laying down
+ if(body_position == LYING_DOWN) //No attacks while laying down
return 0
var/obj/item/clothing/gloves/G = gloves // not typecast specifically enough in defines
@@ -88,7 +88,7 @@
/atom/proc/attack_hand(mob/user)
return
-/mob/living/carbon/human/MouseDrop_T(atom/dropping, mob/user)
+/mob/living/carbon/human/MouseDrop_T(atom/dropping, mob/living/user)
if(user != src)
return . = ..()
@@ -99,7 +99,7 @@
if(xeno.stat != DEAD) // If the Xeno is alive, fight back
var/mob/living/carbon/carbon_user = user
if(!carbon_user || !carbon_user.ally_of_hivenumber(xeno.hivenumber))
- user.KnockDown(rand(xeno.caste.tacklestrength_min, xeno.caste.tacklestrength_max))
+ carbon_user.KnockDown(rand(xeno.caste.tacklestrength_min, xeno.caste.tacklestrength_max))
playsound(user.loc, 'sound/weapons/pierce.ogg', 25, TRUE)
user.visible_message(SPAN_WARNING("\The [user] tried to unstrap \the [back_item] from [xeno] but instead gets a tail swipe to the head!"))
return
@@ -153,6 +153,4 @@
target.Move(user.loc, get_dir(target.loc, user.loc))
target.update_transform(TRUE)
- target.update_canmove()
-
diff --git a/code/_onclick/item_attack.dm b/code/_onclick/item_attack.dm
index c6052da33199..8d77920a59cc 100644
--- a/code/_onclick/item_attack.dm
+++ b/code/_onclick/item_attack.dm
@@ -3,6 +3,7 @@
/obj/item/proc/attack_self(mob/user)
SHOULD_CALL_PARENT(TRUE)
SEND_SIGNAL(src, COMSIG_ITEM_ATTACK_SELF, user)
+ SEND_SIGNAL(user, COMSIG_MOB_ITEM_ATTACK_SELF, src)
if(flags_item & CAN_DIG_SHRAPNEL && ishuman(user))
dig_out_shrapnel(user)
@@ -11,6 +12,7 @@
/atom/proc/attackby(obj/item/W, mob/living/user,list/mods)
if(SEND_SIGNAL(src, COMSIG_PARENT_ATTACKBY, W, user, mods) & COMPONENT_NO_AFTERATTACK)
return TRUE
+ SEND_SIGNAL(user, COMSIG_MOB_PARENT_ATTACKBY, src, W)
return FALSE
/atom/movable/attackby(obj/item/W, mob/living/user)
diff --git a/code/_onclick/observer.dm b/code/_onclick/observer.dm
index f87778355755..21dd804f09c4 100644
--- a/code/_onclick/observer.dm
+++ b/code/_onclick/observer.dm
@@ -29,7 +29,7 @@
if(ismob(target) || isVehicle(target))
if(isxeno(target) && SSticker.mode.check_xeno_late_join(src)) //if it's a xeno and all checks are alright, we are gonna try to take their body
var/mob/living/carbon/xenomorph/xeno = target
- if(xeno.stat == DEAD || is_admin_level(xeno.z) || xeno.aghosted)
+ if(xeno.stat == DEAD || should_block_game_interaction(xeno) || xeno.aghosted)
to_chat(src, SPAN_WARNING("You cannot join as [xeno]."))
do_observe(xeno)
return FALSE
diff --git a/code/_onclick/other_mobs.dm b/code/_onclick/other_mobs.dm
index 9c9784286d09..0bfa0a759287 100644
--- a/code/_onclick/other_mobs.dm
+++ b/code/_onclick/other_mobs.dm
@@ -13,7 +13,7 @@
var/obj/structure/S = A
S.do_climb(src, mods)
return TRUE
- else if(!(isitem(A) && get_dist(src, A) <= 1) && client.prefs.toggle_prefs & TOGGLE_MIDDLE_MOUSE_SWAP_HANDS)
+ else if(!(isitem(A) && get_dist(src, A) <= 1) && (client && (client.prefs.toggle_prefs & TOGGLE_MIDDLE_MOUSE_SWAP_HANDS)))
swap_hand()
return TRUE
diff --git a/code/_onclick/ventcrawl.dm b/code/_onclick/ventcrawl.dm
index b079cffe2afe..e1877dcbd0a7 100644
--- a/code/_onclick/ventcrawl.dm
+++ b/code/_onclick/ventcrawl.dm
@@ -7,7 +7,7 @@
return
for(var/atom/A as anything in src)
if(!(is_type_in_list(A, canEnterVentWith)))
- to_chat(src, SPAN_WARNING("You can't be carrying items or have items equipped when vent crawling!"))
+ to_chat(src, SPAN_WARNING("We cannot be carrying items or have items equipped when vent crawling!"))
return FALSE
/mob/living/click(atom/A, list/mods)
@@ -25,7 +25,7 @@
if(Adjacent(V) && !V.welded)
pipes |= V
if(!pipes || !pipes.len)
- to_chat(src, SPAN_WARNING("There are no pipes that you can ventcrawl into within range!"))
+ to_chat(src, SPAN_WARNING("There are no pipes that we can ventcrawl into within range!"))
return
if(pipes.len == 1)
pipe = pipes[1]
@@ -42,11 +42,11 @@
/mob/living/proc/handle_ventcrawl(atom/clicked_on)
if(stat)
- to_chat(src, SPAN_WARNING("You must be conscious to do this!"))
+ to_chat(src, SPAN_WARNING("We must be conscious to do this!"))
return
- if(lying)
- to_chat(src, SPAN_WARNING("You can't vent crawl while you're stunned!"))
+ if(is_mob_incapacitated())
+ to_chat(src, SPAN_WARNING("We can't vent crawl while we are stunned!"))
return
var/obj/structure/pipes/vents/vent_found
@@ -59,11 +59,11 @@
vent_found = locate(/obj/structure/pipes/vents/) in range(1, src)
if(!vent_found)
- to_chat(src, SPAN_WARNING("You must be standing on or beside an air vent to enter it."))
+ to_chat(src, SPAN_WARNING("We must be standing on or beside an air vent to enter it."))
return
if(vent_found.welded)
- to_chat(src, SPAN_WARNING("This vent is closed off, you cannot climb through it."))
+ to_chat(src, SPAN_WARNING("This vent is closed off, we cannot climb through it."))
return
if(!ventcrawl_carry())
@@ -78,17 +78,17 @@
if(length(vent_found.connected_to))
if(src.action_busy)
- to_chat(src, SPAN_WARNING("You are already busy with something."))
+ to_chat(src, SPAN_WARNING("We are already busy with something."))
return
- visible_message(SPAN_NOTICE("[src] begins climbing into [vent_found]."), SPAN_NOTICE("You begin climbing into [vent_found]."))
+ visible_message(SPAN_NOTICE("[src] begins climbing into [vent_found]."), SPAN_NOTICE("We begin climbing into [vent_found]."))
vent_found.animate_ventcrawl()
if(!do_after(src, 45, INTERRUPT_NO_NEEDHAND, BUSY_ICON_GENERIC))
vent_found.animate_ventcrawl_reset()
return
updatehealth()
- if(stat || stunned || dazed || knocked_down || lying || health < 0 || !client || !ventcrawl_carry())
+ if(is_mob_incapacitated(src) || health < 0 || !client || !ventcrawl_carry())
vent_found.animate_ventcrawl_reset()
return
diff --git a/code/_onclick/xeno.dm b/code/_onclick/xeno.dm
index 62d612790930..ad4ba9d72546 100644
--- a/code/_onclick/xeno.dm
+++ b/code/_onclick/xeno.dm
@@ -3,7 +3,7 @@
*/
/mob/living/carbon/xenomorph/UnarmedAttack(atom/target, proximity, click_parameters, tile_attack = FALSE, ignores_resin = FALSE)
- if(lying || burrow) //No attacks while laying down
+ if(body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_ABILITY_BURROWED)) //No attacks while laying down
return FALSE
var/mob/alt
@@ -21,7 +21,7 @@
if (!L.is_xeno_grabbable() || L == src) //Xenos never attack themselves.
continue
- if (L.lying)
+ if (L.body_position == LYING_DOWN)
alt = L
continue
target = L
@@ -73,10 +73,10 @@
playsound(loc, 'sound/weapons/alien_claw_swipe.ogg', 10, 1) //Quiet to limit spam/nuisance.
if(firepatted)
src.visible_message(SPAN_DANGER("\The [src] pats at the fire!"), \
- SPAN_DANGER("You pat the fire!"), null, 5, CHAT_TYPE_XENO_COMBAT)
+ SPAN_DANGER("We pat the fire!"), null, 5, CHAT_TYPE_XENO_COMBAT)
else
src.visible_message(SPAN_DANGER("\The [src] swipes at \the [target]!"), \
- SPAN_DANGER("You swipe at \the [target]!"), null, 5, CHAT_TYPE_XENO_COMBAT)
+ SPAN_DANGER("We swipe at \the [target]!"), null, 5, CHAT_TYPE_XENO_COMBAT)
return TRUE
/mob/living/carbon/xenomorph/RangedAttack(atom/A)
@@ -111,7 +111,7 @@ so that it doesn't double up on the delays) so that it applies the delay immedia
if(alt_pressed && shift_pressed)
if(istype(target, /mob/living/carbon/xenomorph))
var/mob/living/carbon/xenomorph/xeno = target
- if(!QDELETED(xeno) && xeno.stat != DEAD && !is_admin_level(xeno.z) && xeno.check_state(TRUE) && xeno.hivenumber == hivenumber)
+ if(!QDELETED(xeno) && xeno.stat != DEAD && !should_block_game_interaction(xeno) && xeno.check_state(TRUE) && xeno.hivenumber == hivenumber)
overwatch(xeno)
next_move = world.time + 3 // Some minimal delay so this isn't crazy spammy
return TRUE
diff --git a/code/controllers/configuration/configuration.dm b/code/controllers/configuration/configuration.dm
index e8b010669c0e..147f57fcb1aa 100644
--- a/code/controllers/configuration/configuration.dm
+++ b/code/controllers/configuration/configuration.dm
@@ -20,7 +20,8 @@
var/policy
var/static/regex/ic_filter_regex
- var/list/fail_to_topic_whitelisted_ips
+
+ var/is_loaded = FALSE
/datum/controller/configuration/proc/admin_reload()
if(IsAdminAdvancedProcCall())
@@ -53,7 +54,8 @@
loadmaplist(CONFIG_GROUND_MAPS_FILE, GROUND_MAP)
loadmaplist(CONFIG_SHIP_MAPS_FILE, SHIP_MAP)
LoadChatFilter()
- LoadTopicRateWhitelist()
+
+ is_loaded = TRUE
if(Master)
Master.OnConfigLoad()
@@ -333,18 +335,3 @@
/datum/controller/configuration/proc/DelayedMessageAdmins(text)
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(message_admins), text), 0)
-/datum/controller/configuration/proc/LoadTopicRateWhitelist()
- LAZYINITLIST(fail_to_topic_whitelisted_ips)
- if(!fexists("[directory]/topic_rate_limit_whitelist.txt"))
- log_config("Error 404: topic_rate_limit_whitelist.txt not found!")
- return
-
- log_config("Loading config file topic_rate_limit_whitelist.txt...")
-
- for(var/line in file2list("[directory]/topic_rate_limit_whitelist.txt"))
- if(!line)
- continue
- if(findtextEx(line, "#", 1, 2))
- continue
-
- fail_to_topic_whitelisted_ips[line] = 1
diff --git a/code/controllers/configuration/entries/game_options.dm b/code/controllers/configuration/entries/game_options.dm
index 743f9be9fec0..741862b5d65d 100644
--- a/code/controllers/configuration/entries/game_options.dm
+++ b/code/controllers/configuration/entries/game_options.dm
@@ -127,3 +127,8 @@
min_val = 1
config_entry_value = 450
integer = TRUE
+
+/datum/config_entry/number/whiskey_required_players
+ min_val = 0
+ config_entry_value = 140
+ integer = TRUE
diff --git a/code/controllers/configuration/entries/general.dm b/code/controllers/configuration/entries/general.dm
index cc3d00fd951b..385cbcb8d446 100644
--- a/code/controllers/configuration/entries/general.dm
+++ b/code/controllers/configuration/entries/general.dm
@@ -627,3 +627,5 @@ This maintains a list of ip addresses that are able to bypass topic filtering.
protection = CONFIG_ENTRY_HIDDEN|CONFIG_ENTRY_LOCKED
/datum/config_entry/flag/guest_ban
+
+/datum/config_entry/flag/auto_profile
diff --git a/code/controllers/mc/admin.dm b/code/controllers/mc/admin.dm
index 78eb5c5b5a5a..8c5060864747 100644
--- a/code/controllers/mc/admin.dm
+++ b/code/controllers/mc/admin.dm
@@ -96,8 +96,8 @@ INITIALIZE_IMMEDIATE(/obj/effect/statclick)
set category = "Debug.Controllers"
set name = "Debug Role Authority"
- if(!RoleAuthority)
+ if(!GLOB.RoleAuthority)
to_chat(usr, "RoleAuthority not found!")
return
- debug_variables(RoleAuthority)
+ debug_variables(GLOB.RoleAuthority)
message_admins("Admin [key_name_admin(usr)] is debugging the Role Authority.")
diff --git a/code/controllers/shuttle_controller.dm b/code/controllers/shuttle_controller.dm
index e54d045baff4..35031cf7334f 100644
--- a/code/controllers/shuttle_controller.dm
+++ b/code/controllers/shuttle_controller.dm
@@ -28,12 +28,12 @@
shuttle.location = 1
shuttle.warmup_time = 1
shuttle.move_time = ELEVATOR_TRANSIT_DURATION
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/supply/dock)
shuttle.area_offsite = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/supply/station)
shuttle.area_station = A
break
@@ -41,7 +41,7 @@
shuttles["Supply"] = shuttle
process_shuttles += shuttle
- supply_controller.shuttle = shuttle
+ GLOB.supply_controller.shuttle = shuttle
//---ELEVATOR---//
// Elevator I
@@ -50,17 +50,17 @@
shuttle.warmup_time = 10 SECONDS
shuttle.recharge_time = ELEVATOR_RECHARGE
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator1/underground)
shuttle.area_offsite = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator1/ground)
shuttle.area_station = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator1/transit)
shuttle.area_transition = A
break
@@ -76,17 +76,17 @@
shuttle.warmup_time = 10 SECONDS
shuttle.recharge_time = ELEVATOR_RECHARGE
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator2/underground)
shuttle.area_offsite = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator2/ground)
shuttle.area_station = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator2/transit)
shuttle.area_transition = A
break
@@ -102,17 +102,17 @@
shuttle.location = 0
shuttle.warmup_time = 10 SECONDS
shuttle.recharge_time = ELEVATOR_RECHARGE
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator3/underground)
shuttle.area_offsite = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator3/ground)
shuttle.area_station = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator3/transit)
shuttle.area_transition = A
break
@@ -127,17 +127,17 @@
shuttle.location = 0
shuttle.warmup_time = 10 SECONDS
shuttle.recharge_time = ELEVATOR_RECHARGE
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator4/underground)
shuttle.area_offsite = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator4/ground)
shuttle.area_station = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/elevator4/transit)
shuttle.area_transition = A
break
@@ -152,17 +152,17 @@
shuttle.location = 0
shuttle.warmup_time = 10 SECONDS
shuttle.recharge_time = ELEVATOR_RECHARGE
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/tri_trans1/omega)
shuttle.area_offsite = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/tri_trans1/alpha)
shuttle.area_station = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/tri_trans1/away)
shuttle.area_transition = A
break
@@ -178,17 +178,17 @@
shuttle.location = 0
shuttle.warmup_time = 10 SECONDS
shuttle.recharge_time = ELEVATOR_RECHARGE
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/tri_trans2/omega)
shuttle.area_offsite = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/tri_trans2/alpha)
shuttle.area_station = A
break
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.type == /area/shuttle/tri_trans2/away)
shuttle.area_transition = A
break
@@ -216,7 +216,7 @@
//search for the controllers, if we have one.
if(dock_controller_map.len)
- for(var/obj/structure/machinery/embedded_controller/radio/C in machines) //only radio controllers are supported at the moment
+ for(var/obj/structure/machinery/embedded_controller/radio/C in GLOB.machines) //only radio controllers are supported at the moment
if (istype(C.program, /datum/computer/file/embedded_program/docking))
if(dock_controller_map[C.id_tag])
shuttle = dock_controller_map[C.id_tag]
diff --git a/code/controllers/subsystem/admin.dm b/code/controllers/subsystem/admin.dm
deleted file mode 100644
index 8aab64b04881..000000000000
--- a/code/controllers/subsystem/admin.dm
+++ /dev/null
@@ -1,40 +0,0 @@
-SUBSYSTEM_DEF(admin)
- name = "Admin"
- wait = 5 MINUTES
- flags = SS_NO_INIT | SS_KEEP_TIMING
- runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY
- var/list/currentrun = list()
- var/times_repeated = 0
-
-/datum/controller/subsystem/admin/stat_entry(msg)
- msg = "P:[unansweredAhelps.len]"
- return ..()
-
-/datum/controller/subsystem/admin/fire(resumed = FALSE)
- if (!resumed)
- currentrun = unansweredAhelps.Copy()
-
- if(!currentrun.len)
- times_repeated = 0
- return
-
- var/msg = "Unheard Ahelps (Repeated [times_repeated] times):"
-
- while (currentrun.len)
- var/ahelp_msg = currentrun[currentrun.len]
- currentrun.len--
-
- if (!ahelp_msg)
- continue
-
- msg += unansweredAhelps[ahelp_msg] + "\n"
-
- if (MC_TICK_CHECK)
- return
-
- for(var/client/C in GLOB.admins)
- if(C && C.admin_holder && (C.admin_holder.rights & R_MOD))
- if(C.prefs.toggles_sound & SOUND_ADMINHELP)
- sound_to(C, 'sound/effects/adminhelp_new.ogg')
- to_chat(C, msg)
- times_repeated++
diff --git a/code/controllers/subsystem/atoms.dm b/code/controllers/subsystem/atoms.dm
index 23da8cc8c9eb..3d544dca1390 100644
--- a/code/controllers/subsystem/atoms.dm
+++ b/code/controllers/subsystem/atoms.dm
@@ -131,7 +131,7 @@ SUBSYSTEM_DEF(atoms)
switch(result)
if (INITIALIZE_HINT_NORMAL)
- // pass
+ pass()
if(INITIALIZE_HINT_LATELOAD)
if(arguments[1]) //mapload
late_loaders += A
diff --git a/code/controllers/subsystem/cellauto.dm b/code/controllers/subsystem/cellauto.dm
index bcdd9d241ccf..b543ddd43c26 100644
--- a/code/controllers/subsystem/cellauto.dm
+++ b/code/controllers/subsystem/cellauto.dm
@@ -1,4 +1,4 @@
-var/list/cellauto_cells = list()
+GLOBAL_LIST_EMPTY(cellauto_cells)
SUBSYSTEM_DEF(cellauto)
name = "Cellular Automata"
@@ -9,12 +9,12 @@ SUBSYSTEM_DEF(cellauto)
var/list/currentrun = list()
/datum/controller/subsystem/cellauto/stat_entry(msg)
- msg = "C: [cellauto_cells.len]"
+ msg = "C: [GLOB.cellauto_cells.len]"
return ..()
/datum/controller/subsystem/cellauto/fire(resumed = FALSE)
if (!resumed)
- currentrun = cellauto_cells.Copy()
+ currentrun = GLOB.cellauto_cells.Copy()
while(currentrun.len)
var/datum/automata_cell/C = currentrun[currentrun.len]
diff --git a/code/controllers/subsystem/communications.dm b/code/controllers/subsystem/communications.dm
index a5c5271c8d7d..b8b037c33381 100644
--- a/code/controllers/subsystem/communications.dm
+++ b/code/controllers/subsystem/communications.dm
@@ -66,77 +66,83 @@ Frequency range: 1200 to 1600
Radiochat range: 1441 to 1489 (most devices refuse to be tune to other frequency, even during mapmaking)
*/
-var/const/MIN_FREE_FREQ = 1201 // -------------------------------------------------
+#define MIN_FREE_FREQ 1201 // -------------------------------------------------
//Misc channels
-var/const/YAUT_FREQ = 1205
-var/const/DUT_FREQ = 1210
-var/const/CMB_FREQ = 1220
-var/const/VAI_FREQ = 1215
-var/const/RMC_FREQ = 1216
+#define YAUT_FREQ 1205
+#define DUT_FREQ 1210
+#define VAI_FREQ 1215
+#define RMC_FREQ 1216
+#define CMB_FREQ 1220
//WY Channels (1230-1249)
-var/const/WY_FREQ = 1231
-var/const/PMC_CMD_FREQ = 1232
-var/const/PMC_FREQ = 1233
-var/const/PMC_ENGI_FREQ = 1234
-var/const/PMC_MED_FREQ = 1235
-var/const/PMC_CCT_FREQ = 1236
-var/const/WY_WO_FREQ = 1239
+#define WY_FREQ 1231
+#define PMC_CMD_FREQ 1232
+#define PMC_FREQ 1233
+#define PMC_ENGI_FREQ 1234
+#define PMC_MED_FREQ 1235
+#define PMC_CCT_FREQ 1236
+#define WY_WO_FREQ 1239
//UPP Channels (1250-1269)
-var/const/UPP_FREQ = 1251
-var/const/UPP_CMD_FREQ = 1252
-var/const/UPP_ENGI_FREQ = 1253
-var/const/UPP_MED_FREQ = 1254
-var/const/UPP_CCT_FREQ = 1255
-var/const/UPP_KDO_FREQ = 1259
+#define UPP_FREQ 1251
+#define UPP_CMD_FREQ 1252
+#define UPP_ENGI_FREQ 1253
+#define UPP_MED_FREQ 1254
+#define UPP_CCT_FREQ 1255
+#define UPP_KDO_FREQ 1259
//CLF Channels (1270-1289)
-var/const/CLF_FREQ = 1271
-var/const/CLF_CMD_FREQ = 1272
-var/const/CLF_ENGI_FREQ = 1273
-var/const/CLF_MED_FREQ = 1274
-var/const/CLF_CCT_FREQ = 1275
+#define CLF_FREQ 1271
+#define CLF_CMD_FREQ 1272
+#define CLF_ENGI_FREQ 1273
+#define CLF_MED_FREQ 1274
+#define CLF_CCT_FREQ 1275
-var/const/MIN_FREQ = 1460 // ------------------------------------------------------
-var/const/PUB_FREQ = 1461
-var/const/MAX_FREQ = 1468 // ------------------------------------------------------
+//Listening Bugs (1290-1291)
+#define BUG_A_FREQ 1290
+#define BUG_B_FREQ 1291
+
+//General Radio
+#define MIN_FREQ 1460 // ------------------------------------------------------
+#define PUB_FREQ 1461
+#define MAX_FREQ 1468 // ------------------------------------------------------
//USCM High Command (USCM 1470-1499)
-var/const/HC_FREQ = 1471
-var/const/SOF_FREQ = 1472
-var/const/PVST_FREQ = 1473
+#define HC_FREQ 1471
+#define SOF_FREQ 1472
+#define PVST_FREQ 1473
+#define CBRN_FREQ 1474
//Ship department channels
-var/const/SENTRY_FREQ = 1480
-var/const/COMM_FREQ = 1481
-var/const/MED_FREQ = 1482
-var/const/ENG_FREQ = 1483
-var/const/SEC_FREQ = 1484
-var/const/REQ_FREQ = 1485
-var/const/JTAC_FREQ = 1486
-var/const/INTEL_FREQ = 1487
-
-var/const/DS1_FREQ = 1488
-var/const/DS2_FREQ = 1489
+#define SENTRY_FREQ 1480
+#define COMM_FREQ 1481
+#define MED_FREQ 1482
+#define ENG_FREQ 1483
+#define SEC_FREQ 1484
+#define REQ_FREQ 1485
+#define JTAC_FREQ 1486
+#define INTEL_FREQ 1487
+
+#define DS1_FREQ 1488
+#define DS2_FREQ 1489
//Marine Squad channels
-var/const/ALPHA_FREQ = 1491
-var/const/BRAVO_FREQ = 1492
-var/const/CHARLIE_FREQ = 1493
-var/const/DELTA_FREQ = 1494
-var/const/ECHO_FREQ = 1495
-var/const/CRYO_FREQ = 1496
+#define ALPHA_FREQ 1491
+#define BRAVO_FREQ 1492
+#define CHARLIE_FREQ 1493
+#define DELTA_FREQ 1494
+#define ECHO_FREQ 1495
+#define CRYO_FREQ 1496
//Civilian channels
-var/const/COLONY_FREQ = 1469
+#define COLONY_FREQ 1469
-var/const/AI_FREQ = 1500
+#define AI_FREQ 1500
-var/const/MAX_FREE_FREQ = 1599 // -------------------------------------------------
+#define MAX_FREE_FREQ 1599 // -------------------------------------------------
-var/list/radiochannels = list(
+GLOBAL_LIST_INIT(radiochannels, list(
RADIO_CHANNEL_YAUTJA = YAUT_FREQ,
RADIO_CHANNEL_VAI = VAI_FREQ,
RADIO_CHANNEL_CMB = CMB_FREQ,
@@ -162,6 +168,7 @@ var/list/radiochannels = list(
SQUAD_MARINE_5 = ECHO_FREQ,
SQUAD_MARINE_CRYO = CRYO_FREQ,
SQUAD_SOF = SOF_FREQ,
+ SQUAD_CBRN = CBRN_FREQ,
RADIO_CHANNEL_ALAMO = DS1_FREQ,
RADIO_CHANNEL_NORMANDY = DS2_FREQ,
@@ -189,7 +196,10 @@ var/list/radiochannels = list(
RADIO_CHANNEL_CLF_ENGI = CLF_ENGI_FREQ,
RADIO_CHANNEL_CLF_MED = CLF_MED_FREQ,
RADIO_CHANNEL_CLF_CCT = CLF_CCT_FREQ,
-)
+
+ RADIO_CHANNEL_BUG_A = BUG_A_FREQ,
+ RADIO_CHANNEL_BUG_B = BUG_B_FREQ,
+))
// Response Teams
#define ERT_FREQS list(VAI_FREQ, DUT_FREQ, YAUT_FREQ, CMB_FREQ, RMC_FREQ)
@@ -203,6 +213,9 @@ var/list/radiochannels = list(
// PMC Frequencies
#define PMC_FREQS list(PMC_FREQ, PMC_CMD_FREQ, PMC_ENGI_FREQ, PMC_MED_FREQ, PMC_CCT_FREQ, WY_WO_FREQ, WY_FREQ)
+//Listening Device Frequencies
+#define BUG_FREQS list(BUG_A_FREQ, BUG_B_FREQ)
+
//Depts - used for colors in headset.dm, as well as deciding what the marine comms tower can listen into
#define DEPT_FREQS list(COMM_FREQ, MED_FREQ, ENG_FREQ, SEC_FREQ, SENTRY_FREQ, ALPHA_FREQ, BRAVO_FREQ, CHARLIE_FREQ, DELTA_FREQ, ECHO_FREQ, CRYO_FREQ, REQ_FREQ, JTAC_FREQ, INTEL_FREQ, WY_FREQ)
@@ -215,17 +228,17 @@ var/list/radiochannels = list(
//This is done for performance, so we don't send signals to lots of machines unnecessarily.
//This filter is special because devices belonging to default also receive signals sent to any other filter.
-var/const/RADIO_DEFAULT = "radio_default"
-
-var/const/RADIO_TO_AIRALARM = "radio_airalarm" //air alarms
-var/const/RADIO_FROM_AIRALARM = "radio_airalarm_rcvr" //devices interested in receiving signals from air alarms
-var/const/RADIO_CHAT = "radio_telecoms"
-var/const/RADIO_SIGNALS = "radio_signals"
-var/const/RADIO_ATMOSIA = "radio_atmos"
-var/const/RADIO_NAVBEACONS = "radio_navbeacon"
-var/const/RADIO_AIRLOCK = "radio_airlock"
-var/const/RADIO_MULEBOT = "radio_mulebot"
-var/const/RADIO_MAGNETS = "radio_magnet"
+#define RADIO_DEFAULT "radio_default"
+
+#define RADIO_TO_AIRALARM "radio_airalarm" //air alarms
+#define RADIO_FROM_AIRALARM "radio_airalarm_rcvr" //devices interested in receiving signals from air alarms
+#define RADIO_CHAT "radio_telecoms"
+#define RADIO_SIGNALS "radio_signals"
+#define RADIO_ATMOSIA "radio_atmos"
+#define RADIO_NAVBEACONS "radio_navbeacon"
+#define RADIO_AIRLOCK "radio_airlock"
+#define RADIO_MULEBOT "radio_mulebot"
+#define RADIO_MAGNETS "radio_magnet"
//callback used by objects to react to incoming radio signals
/obj/proc/receive_signal(datum/signal/signal, receive_method, receive_param)
@@ -262,10 +275,13 @@ SUBSYSTEM_DEF(radio)
"[DELTA_FREQ]" = "deltaradio",
"[ECHO_FREQ]" = "echoradio",
"[CRYO_FREQ]" = "cryoradio",
+ "[CBRN_FREQ]" = "hcradio",
"[SOF_FREQ]" = "hcradio",
"[HC_FREQ]" = "hcradio",
"[PVST_FREQ]" = "pvstradio",
"[COLONY_FREQ]" = "deptradio",
+ "[BUG_A_FREQ]" = "airadio",
+ "[BUG_B_FREQ]" = "aiprivradio",
)
/datum/controller/subsystem/radio/proc/add_object(obj/device as obj, new_frequency as num, filter = null as text|null)
diff --git a/code/controllers/subsystem/disease.dm b/code/controllers/subsystem/disease.dm
index 25200cce11ed..b98187ca252c 100644
--- a/code/controllers/subsystem/disease.dm
+++ b/code/controllers/subsystem/disease.dm
@@ -1,22 +1,19 @@
-var/list/active_diseases = list()
-
-
SUBSYSTEM_DEF(disease)
name = "Disease"
wait = 2 SECONDS
flags = SS_NO_INIT | SS_KEEP_TIMING
priority = SS_PRIORITY_DISEASE
- var/list/currentrun = list()
+ var/list/datum/disease/all_diseases = list()
+ var/list/datum/disease/currentrun = list()
/datum/controller/subsystem/disease/stat_entry(msg)
- msg = "P:[active_diseases.len]"
+ msg = "P:[all_diseases.len]"
return ..()
-
/datum/controller/subsystem/disease/fire(resumed = FALSE)
if (!resumed)
- currentrun = active_diseases.Copy()
+ currentrun = all_diseases.Copy()
while (currentrun.len)
var/datum/disease/D = currentrun[currentrun.len]
diff --git a/code/controllers/subsystem/fail_to_topic.dm b/code/controllers/subsystem/fail_to_topic.dm
deleted file mode 100644
index 45674683a443..000000000000
--- a/code/controllers/subsystem/fail_to_topic.dm
+++ /dev/null
@@ -1,81 +0,0 @@
-SUBSYSTEM_DEF(fail_to_topic)
- name = "Fail to Topic"
- init_order = SS_INIT_FAIL_TO_TOPIC
- flags = SS_BACKGROUND
- runlevels = ALL
-
- var/list/rate_limiting = list()
- var/list/fail_counts = list()
- var/list/active_bans = list()
- var/list/currentrun = list()
-
- var/rate_limit
- var/max_fails
- var/enabled = FALSE
-
-/datum/controller/subsystem/fail_to_topic/Initialize(timeofday)
- rate_limit = ((CONFIG_GET(number/topic_rate_limit)) SECONDS)
- max_fails = CONFIG_GET(number/topic_max_fails)
- enabled = CONFIG_GET(flag/topic_enabled)
-
- if (world.system_type == UNIX && enabled)
- enabled = FALSE
- WARNING("fail_to_topic subsystem disabled. UNIX is not supported.")
- return SS_INIT_NO_NEED
-
- if (!enabled)
- can_fire = FALSE
- return SS_INIT_NO_NEED
-
- return SS_INIT_SUCCESS
-
-/datum/controller/subsystem/fail_to_topic/fire(resumed = FALSE)
- if(!resumed)
- currentrun = rate_limiting.Copy()
- //cache for sanic speed (lists are references anyways)
- var/list/current_run = currentrun
-
- while(current_run.len)
- var/ip = current_run[current_run.len]
- var/last_attempt = current_run[ip]
- current_run.len--
-
- // last_attempt list housekeeping
- if(world.time - last_attempt > rate_limit)
- rate_limiting -= ip
- fail_counts -= ip
-
- if(MC_TICK_CHECK)
- return
-
-/datum/controller/subsystem/fail_to_topic/proc/IsRateLimited(ip)
- if(!enabled)
- return FALSE
-
- var/last_attempt = rate_limiting[ip]
-
- if (config.fail_to_topic_whitelisted_ips[ip])
- return FALSE
-
- if (active_bans[ip])
- return TRUE
-
- rate_limiting[ip] = world.time
-
- if (isnull(last_attempt))
- return FALSE
-
- if (world.time - last_attempt > rate_limit)
- fail_counts -= ip
- return FALSE
- else
- var/failures = fail_counts[ip]
-
- if (isnull(failures))
- fail_counts[ip] = 1
- return TRUE
- else if (failures > max_fails)
- return TRUE
- else
- fail_counts[ip] = failures + 1
- return TRUE
diff --git a/code/controllers/subsystem/fast_machinery.dm b/code/controllers/subsystem/fast_machinery.dm
deleted file mode 100644
index 8211b3b5e310..000000000000
--- a/code/controllers/subsystem/fast_machinery.dm
+++ /dev/null
@@ -1,27 +0,0 @@
-var/list/fast_machines = list()
-
-
-SUBSYSTEM_DEF(fast_machinery)
- name = "Fast Machinery"
- wait = 0.7 SECONDS
- priority = SS_PRIORITY_FAST_MACHINERY
- flags = SS_NO_INIT
- var/list/currentrun = list()
-
-/datum/controller/subsystem/fast_machinery/stat_entry(msg)
- msg = "FP:[fast_machines.len]"
- return ..()
-
-/datum/controller/subsystem/fast_machinery/fire(resumed = FALSE)
- if(!resumed)
- currentrun = fast_machines.Copy()
- while(currentrun.len)
- var/obj/structure/machinery/M = currentrun[currentrun.len]
- currentrun.len--
-
- if(QDELETED(M))
- continue
-
- M.process()
- if(MC_TICK_CHECK)
- return
diff --git a/code/controllers/subsystem/fz_transitions.dm b/code/controllers/subsystem/fz_transitions.dm
index fd41ce1ccb55..d12ab1358535 100644
--- a/code/controllers/subsystem/fz_transitions.dm
+++ b/code/controllers/subsystem/fz_transitions.dm
@@ -1,6 +1,6 @@
-var/list/projectors = list()
-var/list/clones = list()
-var/list/clones_t = list()
+GLOBAL_LIST_EMPTY(projectors)
+GLOBAL_LIST_EMPTY(clones)
+GLOBAL_LIST_EMPTY(clones_t)
SUBSYSTEM_DEF(fz_transitions)
name = "Z-Transitions"
@@ -10,18 +10,18 @@ SUBSYSTEM_DEF(fz_transitions)
flags = SS_KEEP_TIMING
/datum/controller/subsystem/fz_transitions/stat_entry(msg)
- msg = "P:[projectors.len]|C:[clones.len]|T:[clones_t.len]"
+ msg = "P:[GLOB.projectors.len]|C:[GLOB.clones.len]|T:[GLOB.clones_t.len]"
return ..()
/datum/controller/subsystem/fz_transitions/Initialize()
for(var/obj/effect/projector/P in world)
- projectors.Add(P)
+ GLOB.projectors.Add(P)
return SS_INIT_SUCCESS
/datum/controller/subsystem/fz_transitions/fire(resumed = FALSE)
- for(var/obj/effect/projector/P in projectors)
+ for(var/obj/effect/projector/P in GLOB.projectors)
if(!P || !P.loc)
- projectors -= P
+ GLOB.projectors -= P
continue
if(!P.loc.clone)
P.loc.create_clone(P.vector_x, P.vector_y)
@@ -36,13 +36,13 @@ SUBSYSTEM_DEF(fz_transitions)
O.clone.proj_y = P.vector_y
- for(var/atom/movable/clone/C in clones)
+ for(var/atom/movable/clone/C in GLOB.clones)
if(C.mstr == null || !istype(C.mstr.loc, /turf))
C.mstr.destroy_clone() //Kill clone if master has been destroyed or picked up
else
if(C != C.mstr)
C.mstr.update_clone() //NOTE: Clone updates are also forced by player movement to reduce latency
- for(var/atom/T in clones_t)
+ for(var/atom/T in GLOB.clones_t)
if(T.clone && T.icon_state) //Just keep the icon updated for explosions etc.
T.clone.icon_state = T.icon_state
diff --git a/code/controllers/subsystem/game_decorator.dm b/code/controllers/subsystem/game_decorator.dm
new file mode 100644
index 000000000000..dd53b647d1a8
--- /dev/null
+++ b/code/controllers/subsystem/game_decorator.dm
@@ -0,0 +1,35 @@
+// Essentially the same as decorators but that apply to the whole game state instead of individual atoms
+SUBSYSTEM_DEF(game_decorator)
+ name = "Game Decorator"
+ init_order = SS_INIT_DECORATOR
+ flags = SS_NO_FIRE
+
+/datum/controller/subsystem/game_decorator/Initialize()
+ . = ..()
+ for(var/decorator_type in subtypesof(/datum/game_decorator))
+ var/datum/game_decorator/decorator = new decorator_type()
+ if(!decorator.is_active_decor())
+ continue
+ if(!decorator.defer_decoration)
+ decorator.decorate()
+ CHECK_TICK
+
+ return SS_INIT_SUCCESS
+
+/datum/game_decorator
+ var/defer_decoration = TRUE //! So map decoration is done post-setup after nightmare and spawners
+
+/datum/game_decorator/New()
+ if(defer_decoration && is_active_decor())
+ RegisterSignal(SSdcs, COMSIG_GLOB_MODE_POSTSETUP, PROC_REF(defered_decoration))
+
+/datum/game_decorator/proc/is_active_decor()
+ return FALSE
+
+/datum/game_decorator/proc/defered_decoration(dcs)
+ SIGNAL_HANDLER
+ decorate()
+
+/datum/game_decorator/proc/decorate()
+ set waitfor = FALSE
+ return
diff --git a/code/controllers/subsystem/hijack.dm b/code/controllers/subsystem/hijack.dm
new file mode 100644
index 000000000000..ed9eba2bc6c3
--- /dev/null
+++ b/code/controllers/subsystem/hijack.dm
@@ -0,0 +1,429 @@
+SUBSYSTEM_DEF(hijack)
+ name = "Hijack"
+ wait = 2 SECONDS
+ flags = SS_KEEP_TIMING
+ priority = SS_PRIORITY_HIJACK
+ init_order = SS_INIT_HIJACK
+
+ ///Required progress to evacuate safely via lifeboats
+ var/required_progress = 100
+
+ ///Current progress towards evacuating safely via lifeboats
+ var/current_progress = 0
+
+ /// How much progress is required to early launch
+ var/early_launch_required_progress = 25
+
+ ///The estimated time left to get to the safe evacuation point
+ var/estimated_time_left = 0
+
+ ///Areas that are marked as having progress, assoc list that is progress_area = boolean, the boolean indicating if it was progressing or not on the last fire()
+ var/list/area/progress_areas = list()
+
+ ///The areas that need cycled through currently
+ var/list/area/current_run = list()
+
+ ///The progress of the current run that needs to be added at the end of the current run
+ var/current_run_progress_additive = 0
+
+ ///Holds what the current_run_progress_additive should be multiplied by at the end of the current run
+ var/current_run_progress_multiplicative = 1
+
+ ///Holds the progress change from last run
+ var/last_run_progress_change = 0
+
+ ///Holds the next % point progress should be announced, increments on itself
+ var/announce_checkpoint = 25
+
+ ///What stage of evacuation we are currently on
+ var/evac_status = EVACUATION_STATUS_NOT_INITIATED
+
+ ///What stage of hijack are we currently on
+ var/hijack_status = HIJACK_OBJECTIVES_NOT_STARTED
+
+ ///Whether or not evacuation has been disabled by admins
+ var/evac_admin_denied = FALSE
+
+ /// If TRUE, self destruct has been unlocked and is possible with a hold of reactor
+ var/sd_unlocked = FALSE
+
+ /// Admin var to manually prevent self destruct from occurring
+ var/admin_sd_blocked = FALSE
+
+ /// Maximum amount of fusion generators that can be overloaded at once for a time benefit
+ var/maximum_overload_generators = 18
+
+ /// How many generators are currently overloaded
+ var/overloaded_generators = 0
+
+ /// How long the manual self destruct will take on the high end
+ var/sd_max_time = 15 MINUTES
+
+ /// How long the manual self destruct will take on the low end
+ var/sd_min_time = 5 MINUTES
+
+ /// How much time left until SD detonates
+ var/sd_time_remaining = 0
+
+ /// Roughly what % of the SD countdown remains
+ var/percent_completion_remaining = 100
+
+ /// If the engine room has been heated, occurs at 33% SD completion
+ var/engine_room_heated = FALSE
+
+ /// If the engine room has been superheated, occurs at 66% SD completion
+ var/engine_room_superheated = FALSE
+
+ /// If the self destruct has/is detonating
+ var/sd_detonated = FALSE
+
+ /// If a generator has ever been overloaded in the past this round
+ var/generator_ever_overloaded = FALSE
+
+ /// If ARES has announced the 50% point yet for SD
+ var/ares_sd_announced = FALSE
+
+/datum/controller/subsystem/hijack/Initialize(timeofday)
+ RegisterSignal(SSdcs, COMSIG_GLOB_GENERATOR_SET_OVERLOADING, PROC_REF(on_generator_overload))
+ return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/hijack/stat_entry(msg)
+ if(!SSticker?.mode?.is_in_endgame)
+ msg = " Not Hijack"
+ return ..()
+
+ if(current_progress >= required_progress)
+ msg = " Complete"
+ return ..()
+
+ msg = " Progress: [current_progress]% | Last run: [last_run_progress_change]"
+ return ..()
+
+/datum/controller/subsystem/hijack/fire(resumed = FALSE)
+ if(!SSticker?.mode?.is_in_endgame)
+ return
+
+ if(hijack_status < HIJACK_OBJECTIVES_STARTED)
+ hijack_status = HIJACK_OBJECTIVES_STARTED
+
+ if(current_progress >= required_progress)
+ if(hijack_status < HIJACK_OBJECTIVES_COMPLETE)
+ hijack_status = HIJACK_OBJECTIVES_COMPLETE
+
+ if(sd_unlocked && overloaded_generators)
+ sd_time_remaining -= wait
+ if(!engine_room_heated && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.66)))
+ heat_engine_room()
+
+ if(!ares_sd_announced && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.5)))
+ announce_sd_halfway()
+
+ if(!engine_room_superheated && (sd_time_remaining <= (max((1 - round(overloaded_generators / maximum_overload_generators, 0.01)) * sd_max_time, sd_min_time) * 0.33)))
+ superheat_engine_room()
+
+ if((sd_time_remaining <= 0) && !sd_detonated)
+ detonate_sd()
+
+ return
+
+ if(!resumed)
+ current_run = progress_areas.Copy()
+
+ for(var/area/almayer/cycled_area as anything in current_run)
+ current_run -= cycled_area
+
+ if(progress_areas[cycled_area] != cycled_area.power_equip)
+ progress_areas[cycled_area] = !progress_areas[cycled_area]
+ announce_area_power_change(cycled_area)
+
+ if(progress_areas[cycled_area])
+ switch(cycled_area.hijack_evacuation_type)
+ if(EVACUATION_TYPE_ADDITIVE)
+ current_run_progress_additive += cycled_area.hijack_evacuation_weight
+ if(EVACUATION_TYPE_MULTIPLICATIVE)
+ current_run_progress_multiplicative *= cycled_area.hijack_evacuation_weight
+
+ if (MC_TICK_CHECK)
+ return
+
+ last_run_progress_change = current_run_progress_additive * current_run_progress_multiplicative
+ current_progress += last_run_progress_change
+
+ if(last_run_progress_change)
+ estimated_time_left = ((required_progress - current_progress) / last_run_progress_change) * wait
+ else
+ estimated_time_left = INFINITY
+
+ if(current_progress >= announce_checkpoint)
+ announce_progress()
+ announce_checkpoint += initial(announce_checkpoint)
+
+ current_run_progress_additive = 0
+ current_run_progress_multiplicative = 1
+
+///Called when the xeno dropship crashes into the Almayer and announces the current status of various objectives to marines
+/datum/controller/subsystem/hijack/proc/announce_status_on_crash()
+ var/message = ""
+
+ for(var/area/cycled_area as anything in progress_areas)
+ message += "[cycled_area] - [cycled_area.power_equip ? "Online" : "Offline"]\n"
+ progress_areas[cycled_area] = cycled_area.power_equip
+
+ message += "\nDue to low orbit, extra fuel is required for non-surface evacuations.\nMaintain fueling functionality for optimal evacuation conditions."
+
+ marine_announcement(message, HIJACK_ANNOUNCE)
+
+///Called when an area power status is changed to announce that it has been changed
+/datum/controller/subsystem/hijack/proc/announce_area_power_change(area/changed_area)
+ var/message = "[changed_area] - [changed_area.power_equip ? "Online" : "Offline"]"
+
+ marine_announcement(message, HIJACK_ANNOUNCE)
+
+///Called to announce to xenos the state of evacuation progression
+/datum/controller/subsystem/hijack/proc/announce_progress()
+ var/announce = announce_checkpoint / initial(announce_checkpoint)
+
+ var/marine_warning_areas = ""
+ var/xeno_warning_areas = ""
+
+ for(var/area/cycled_area as anything in progress_areas)
+ if(cycled_area.power_equip)
+ xeno_warning_areas += "[cycled_area], "
+ continue
+ marine_warning_areas += "[cycled_area], "
+
+ if(xeno_warning_areas)
+ xeno_warning_areas = copytext(xeno_warning_areas, 1, -2)
+
+ if(marine_warning_areas)
+ marine_warning_areas = copytext(marine_warning_areas, 1, -2)
+
+ var/datum/hive_status/hive
+ for(var/hivenumber in GLOB.hive_datum)
+ hive = GLOB.hive_datum[hivenumber]
+ if(!length(hive.totalXenos))
+ continue
+
+ switch(announce)
+ if(1)
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls are a quarter of the way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+ if(2)
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls are half way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+ if(3)
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls are three quarters of the way towards their goals. Disable the following areas: [xeno_warning_areas]"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+ if(4)
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls have completed their goals!"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+
+ switch(announce)
+ if(1)
+ marine_announcement("Emergency fuel replenishment is at 25 percent. Lifeboat emergency early launch is now available.[marine_warning_areas ? "\nTo increase speed, restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE)
+ if(2)
+ marine_announcement("Emergency fuel replenishment is at 50 percent.[marine_warning_areas ? "\nTo increase speed, restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE)
+ if(3)
+ marine_announcement("Emergency fuel replenishment is at 75 percent.[marine_warning_areas ? "\nTo increase speed, restore power to the following areas: [marine_warning_areas]" : " All fueling areas operational."]", HIJACK_ANNOUNCE)
+ if(4)
+ marine_announcement("Emergency fuel replenishment is at 100 percent. Safe utilization of lifeboats and pods is now possible.", HIJACK_ANNOUNCE)
+ if(!admin_sd_blocked)
+ addtimer(CALLBACK(src, PROC_REF(unlock_self_destruct)), 8 SECONDS)
+
+/// Passes the ETA for status panels
+/datum/controller/subsystem/hijack/proc/get_evac_eta()
+ switch(hijack_status)
+ if(HIJACK_OBJECTIVES_STARTED)
+ if(estimated_time_left == INFINITY)
+ return "Never"
+ return "[duration2text_sec(estimated_time_left)]"
+
+ if(HIJACK_OBJECTIVES_COMPLETE)
+ return "Complete"
+
+/datum/controller/subsystem/hijack/proc/get_sd_eta()
+ if(sd_detonated)
+ return "Complete"
+
+ if(overloaded_generators <= 0)
+ return "Never"
+
+ return "[duration2text_sec(sd_time_remaining)]"
+
+//~~~~~~~~~~~~~~~~~~~~~~~~ EVAC STUFF ~~~~~~~~~~~~~~~~~~~~~~~~//
+
+/// Initiates evacuation by announcing and then prepping all lifepods/lifeboats
+/datum/controller/subsystem/hijack/proc/initiate_evacuation()
+ if(evac_status == EVACUATION_STATUS_NOT_INITIATED && !(evac_admin_denied & FLAGS_EVACUATION_DENY))
+ evac_status = EVACUATION_STATUS_INITIATED
+ ai_announcement("Attention. Emergency. All personnel must evacuate immediately.", 'sound/AI/evacuate.ogg')
+
+ for(var/obj/structure/machinery/status_display/cycled_status_display in GLOB.machines)
+ if(is_mainship_level(cycled_status_display.z))
+ cycled_status_display.set_picture("evac")
+ for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
+ shuttle.prepare_evac()
+ activate_lifeboats()
+ return TRUE
+
+/// Cancels evacuation, tells lifepods/lifeboats and status_displays
+/datum/controller/subsystem/hijack/proc/cancel_evacuation()
+ if(evac_status == EVACUATION_STATUS_INITIATED)
+ evac_status = EVACUATION_STATUS_NOT_INITIATED
+ deactivate_lifeboats()
+ ai_announcement("Evacuation has been cancelled.", 'sound/AI/evacuate_cancelled.ogg')
+
+ for(var/obj/structure/machinery/status_display/cycled_status_display in GLOB.machines)
+ if(is_mainship_level(cycled_status_display.z))
+ cycled_status_display.set_sec_level_picture()
+
+ for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
+ shuttle.cancel_evac()
+ return TRUE
+
+/// Opens the lifeboat doors and gets them ready to launch
+/datum/controller/subsystem/hijack/proc/activate_lifeboats()
+ for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
+ var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
+ if(lifeboat && lifeboat.available)
+ lifeboat.status = LIFEBOAT_ACTIVE
+ lifeboat_dock.open_dock()
+
+/// Turns off ability to manually take off lifeboats
+/datum/controller/subsystem/hijack/proc/deactivate_lifeboats()
+ for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
+ var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
+ if(lifeboat && lifeboat.available)
+ lifeboat.status = LIFEBOAT_INACTIVE
+
+
+/// Once refueling is done, marines can optionally hold SD for a time for a stalemate instead of a xeno minor
+/datum/controller/subsystem/hijack/proc/unlock_self_destruct()
+ sd_time_remaining = sd_max_time
+ sd_unlocked = TRUE
+ marine_announcement("Fuel reserves full. Manual detonation of fuel reserves by overloading the on-board fusion reactors now possible.", HIJACK_ANNOUNCE)
+
+/datum/controller/subsystem/hijack/proc/on_generator_overload(obj/structure/machinery/power/fusion_engine/source, new_overloading)
+ SIGNAL_HANDLER
+
+ if(!generator_ever_overloaded)
+ generator_ever_overloaded = TRUE
+ var/datum/hive_status/hive
+ for(var/hivenumber in GLOB.hive_datum)
+ hive = GLOB.hive_datum[hivenumber]
+ if(!length(hive.totalXenos))
+ continue
+
+ xeno_announcement(SPAN_XENOANNOUNCE("The talls may be attempting to take their ship down with them in Engineering, stop them!"), hive.hivenumber, XENO_HIJACK_ANNOUNCE)
+
+ adjust_generator_overload_count(new_overloading ? 1 : -1)
+
+/datum/controller/subsystem/hijack/proc/adjust_generator_overload_count(amount = 1)
+ var/generator_overload_percent = round(overloaded_generators / maximum_overload_generators, 0.01)
+ var/old_required_time = sd_min_time + ((1 - generator_overload_percent) * (sd_max_time - sd_min_time))
+ percent_completion_remaining = sd_time_remaining / old_required_time
+ overloaded_generators = clamp(overloaded_generators + amount, 0, maximum_overload_generators)
+ generator_overload_percent = round(overloaded_generators / maximum_overload_generators, 0.01)
+ var/new_required_time = sd_min_time + ((1 - generator_overload_percent) * (sd_max_time - sd_min_time))
+ sd_time_remaining = percent_completion_remaining * new_required_time
+
+/datum/controller/subsystem/hijack/proc/heat_engine_room()
+ engine_room_heated = TRUE
+ var/area/engine_room = GLOB.areas_by_type[/area/almayer/engineering/lower/engine_core]
+ engine_room.firealert()
+ engine_room.temperature = T90C
+ for(var/mob/current_mob as anything in GLOB.mob_list)
+ var/area/mob_area = get_area(current_mob)
+ if(istype(mob_area, /area/almayer/engineering/lower/engine_core))
+ to_chat(current_mob, SPAN_BOLDWARNING("You feel the heat of the room increase as the fusion engines whirr louder."))
+
+/datum/controller/subsystem/hijack/proc/superheat_engine_room()
+ engine_room_superheated = TRUE
+ var/area/engine_room = GLOB.areas_by_type[/area/almayer/engineering/lower/engine_core]
+ engine_room.firealert()
+ engine_room.temperature = T120C //slowly deals burn at this temp
+ for(var/mob/current_mob as anything in GLOB.mob_list)
+ var/area/mob_area = get_area(current_mob)
+ if(istype(mob_area, /area/almayer/engineering/lower/engine_core))
+ to_chat(current_mob, SPAN_BOLDWARNING("The room feels incredibly hot, you can't take much more of this!"))
+
+/datum/controller/subsystem/hijack/proc/announce_sd_halfway()
+ ares_sd_announced = TRUE
+ marine_announcement("ALERT: Fusion reactor meltdown has reached fifty percent.", HIJACK_ANNOUNCE)
+
+/datum/controller/subsystem/hijack/proc/detonate_sd()
+ set waitfor = FALSE
+ sd_detonated = TRUE
+ var/creak_picked = pick('sound/effects/creak1.ogg', 'sound/effects/creak2.ogg', 'sound/effects/creak3.ogg')
+ for(var/mob/current_mob as anything in GLOB.mob_list)
+ var/turf/current_turf = get_turf(current_mob)
+ if(!current_mob?.loc || !current_mob.client || !current_turf || !is_mainship_level(current_turf.z))
+ continue
+
+ to_chat(current_mob, SPAN_BOLDWARNING("The ship's deck worryingly creaks underneath you."))
+ playsound_client(current_mob.client, creak_picked, vol = 50)
+
+ sleep(7 SECONDS)
+ shakeship(2, 10, TRUE)
+
+ marine_announcement("ALERT: Fusion reactors dangerously overloaded. Runaway meltdown in reactor core imminent.", HIJACK_ANNOUNCE)
+ sleep(5 SECONDS)
+
+ var/sound_picked = pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg')
+ for(var/client/player as anything in GLOB.clients)
+ playsound_client(player, sound_picked, 90)
+
+ var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s).
+ var/list/dead_mobs = list() //Everyone who only needs to see the cinematic.
+ for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting.
+ var/turf/current_turf = get_turf(current_mob)
+ if(!current_mob?.loc || !current_turf)
+ continue
+
+ if(current_mob.stat == DEAD)
+ dead_mobs |= current_mob
+ continue
+
+ if(is_mainship_level(current_turf.z))
+ alive_mobs |= current_mob
+ shake_camera(current_mob, 110, 4)
+
+
+ sleep(10 SECONDS)
+ /*Hardcoded for now, since this was never really used for anything else.
+ Would ideally use a better system for showing cutscenes.*/
+ var/atom/movable/screen/cinematic/explosion/explosive_cinematic = new()
+
+ for(var/mob/current_mob as anything in (alive_mobs + dead_mobs))
+ if(current_mob?.loc && current_mob.client)
+ current_mob.client.add_to_screen(explosive_cinematic) //They may have disconnected in the mean time.
+
+ sleep(1.5 SECONDS) //Extra 1.5 seconds to look at the ship.
+ flick("intro_nuke", explosive_cinematic)
+
+ sleep(3.5 SECONDS)
+ for(var/mob/current_mob as anything in alive_mobs)
+ var/turf/current_mob_turf = get_turf(current_mob)
+ if(!current_mob?.loc || !current_mob_turf) //Who knows, maybe they escaped, or don't exist anymore.
+ continue
+
+ if(is_mainship_level(current_mob_turf.z))
+ if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge))
+ continue
+
+ current_mob.death(create_cause_data("nuclear explosion"))
+ else
+ current_mob.client.remove_from_screen(explosive_cinematic) //those who managed to escape the z level at last second shouldn't have their view obstructed.
+
+ flick("ship_destroyed", explosive_cinematic)
+ explosive_cinematic.icon_state = "summary_destroyed"
+
+ for(var/client/player as anything in GLOB.clients)
+ playsound_client(player, 'sound/effects/explosionfar.ogg', 90)
+
+
+ sleep(0.5 SECONDS)
+ if(SSticker.mode)
+ SSticker.mode.check_win()
+
+ if(!SSticker.mode) //Just a safety, just in case a mode isn't running, somehow.
+ to_world(SPAN_ROUNDBODY("Resetting in 30 seconds!"))
+ sleep(30 SECONDS)
+ log_game("Rebooting due to nuclear detonation.")
+ world.Reboot()
diff --git a/code/controllers/subsystem/htmlui.dm b/code/controllers/subsystem/htmlui.dm
deleted file mode 100644
index 5dc885abc625..000000000000
--- a/code/controllers/subsystem/htmlui.dm
+++ /dev/null
@@ -1,57 +0,0 @@
-// What in the name of god is this?
-// You'd think it'd be some form of process for the HTML interface module.
-// But it isn't?
-// It's some form of proc queue but ???
-// Does anything even *use* this?
-
-SUBSYSTEM_DEF(html_ui)
- name = "HTMLUI"
- wait = 1.7 SECONDS
- flags = SS_NO_INIT
- runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY
- var/list/update = list()
-
-/datum/controller/subsystem/html_ui/fire(resumed = FALSE)
- if (update.len)
- var/list/L = list()
- var/key
-
- for (var/datum/procqueue_item/item in update)
- key = "[item.ref]_[item.procname]"
-
- if (item.args)
- key += "("
- var/first = 1
- for (var/a in item.args)
- if (!first)
- key += ","
- key += "[a]"
- first = 0
- key += ")"
-
- if (!(key in L))
- if (item.args)
- call(item.ref, item.procname)(arglist(item.args))
- else
- call(item.ref, item.procname)()
-
- L.Add(key)
-
- update.Cut()
-
-
-/datum/controller/subsystem/html_ui/proc/queue(ref, procname, ...)
- var/datum/procqueue_item/item = new
- item.ref = ref
- item.procname = procname
-
- if (args.len > 2)
- item.args = args.Copy(3)
-
- update.Insert(1, item)
-
-
-/datum/procqueue_item
- var/ref
- var/procname
- var/list/args
diff --git a/code/controllers/subsystem/inactivity.dm b/code/controllers/subsystem/inactivity.dm
index dd547e1f406b..6b8542444040 100644
--- a/code/controllers/subsystem/inactivity.dm
+++ b/code/controllers/subsystem/inactivity.dm
@@ -1,20 +1,26 @@
-#define INACTIVITY_KICK 6000 //10 minutes in ticks (approx.)
+#define INACTIVITY_KICK 10 MINUTES
SUBSYSTEM_DEF(inactivity)
name = "Inactivity"
- wait = INACTIVITY_KICK
+ wait = 1 MINUTES
flags = SS_NO_INIT | SS_BACKGROUND
priority = SS_PRIORITY_INACTIVITY
runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY
/datum/controller/subsystem/inactivity/fire(resumed = FALSE)
- if (CONFIG_GET(flag/kick_inactive))
- for(var/i in GLOB.clients)
- var/client/C = i
- if(C.admin_holder && C.admin_holder.rights & R_ADMIN) //Skip admins.
- continue
- if (C.is_afk(INACTIVITY_KICK))
- if (!istype(C.mob, /mob/dead))
- log_access("AFK: [key_name(C)]")
- to_chat(C, SPAN_WARNING("You have been inactive for more than 10 minutes and have been disconnected."))
- qdel(C)
+ if(list_clear_nulls(GLOB.clients))
+ debug_log("Removed nulls from GLOB.clients!")
+ if(list_clear_nulls(GLOB.player_list))
+ debug_log("Removed nulls from GLOB.player_list!")
+
+ if (!CONFIG_GET(flag/kick_inactive))
+ return
+
+ for(var/client/current as anything in GLOB.clients)
+ if(current.admin_holder && current.admin_holder.rights & R_MOD) //Skip admins.
+ continue
+ if(current.is_afk(INACTIVITY_KICK))
+ if(!istype(current.mob, /mob/dead))
+ log_access("AFK: [key_name(current)]")
+ to_chat(current, SPAN_WARNING("You have been inactive for more than [INACTIVITY_KICK / 600] minutes and have been disconnected."))
+ qdel(current)
diff --git a/code/controllers/subsystem/influxstats.dm b/code/controllers/subsystem/influxstats.dm
index 01015b83191d..066c94cc2593 100644
--- a/code/controllers/subsystem/influxstats.dm
+++ b/code/controllers/subsystem/influxstats.dm
@@ -104,7 +104,7 @@ SUBSYSTEM_DEF(influxstats)
/datum/controller/subsystem/influxstats/proc/run_job_statistics()
var/list/team_job_stats = list()
- var/list/squad_job_stats = ROLES_SQUAD_ALL.Copy()
+ var/list/squad_job_stats = GLOB.ROLES_SQUAD_ALL.Copy()
for(var/squad in squad_job_stats)
squad_job_stats[squad] = list()
diff --git a/code/controllers/subsystem/init/earlyruntimes.dm b/code/controllers/subsystem/init/earlyruntimes.dm
deleted file mode 100644
index 8e43b94a0735..000000000000
--- a/code/controllers/subsystem/init/earlyruntimes.dm
+++ /dev/null
@@ -1,14 +0,0 @@
-/// Just messages the unwary coder to tell them there are errors that likely escaped their debugguer.
-SUBSYSTEM_DEF(earlyruntimes)
- name = "Early Runtimes"
- init_order = SS_INIT_EARLYRUNTIMES
- flags = SS_NO_FIRE
-
-/datum/controller/subsystem/earlyruntimes/stat_entry(msg)
- msg = " Early Runtimes: [init_runtimes_count || 0] | All runtimes: [total_runtimes || 0]"
- return ..()
-
-/datum/controller/subsystem/earlyruntimes/Initialize()
- if(init_runtimes_count)
- return SS_INIT_FAILURE
- return SS_INIT_SUCCESS
diff --git a/code/controllers/subsystem/init/landmarks.dm b/code/controllers/subsystem/init/landmarks.dm
index 59bba7c7922b..31b71c074a5d 100644
--- a/code/controllers/subsystem/init/landmarks.dm
+++ b/code/controllers/subsystem/init/landmarks.dm
@@ -1,4 +1,4 @@
-var/list/item_pool_landmarks = list()
+GLOBAL_LIST_EMPTY(item_pool_landmarks)
SUBSYSTEM_DEF(landmark_init)
name = "Landmark Init"
@@ -9,7 +9,7 @@ SUBSYSTEM_DEF(landmark_init)
// List of all the datums we need to loop through
var/list/datum/item_pool_holder/pools = list()
- for (var/obj/effect/landmark/item_pool_spawner/L in item_pool_landmarks)
+ for (var/obj/effect/landmark/item_pool_spawner/L in GLOB.item_pool_landmarks)
var/curr_pool_name = L.pool_name
@@ -48,8 +48,8 @@ SUBSYSTEM_DEF(landmark_init)
continue
if (pool.quota > pool.turfs.len)
- log_debug("Item pool [pool.pool_name] wants to spawn more items than it has landmarks for. Spawning [turfs.len] instances of [pool.type_to_spawn] instead. Code: ITEM_POOL_4")
- message_admins("Item pool [pool.pool_name] wants to spawn more items than it has landmarks for. Spawning [turfs.len] instances of [pool.type_to_spawn] instead. Tell the devs. Code: ITEM_POOL_4")
+ log_debug("Item pool [pool.pool_name] wants to spawn more items than it has landmarks for. Spawning [pool.turfs.len] instances of [pool.type_to_spawn] instead. Code: ITEM_POOL_4")
+ message_admins("Item pool [pool.pool_name] wants to spawn more items than it has landmarks for. Spawning [pool.turfs.len] instances of [pool.type_to_spawn] instead. Tell the devs. Code: ITEM_POOL_4")
pool.quota = pool.turfs.len
// Quota times, pick a random turf, spawn an item there, then remove that turf from the list.
diff --git a/code/controllers/subsystem/init/law.dm b/code/controllers/subsystem/init/law.dm
index 52fbbbeadf5d..c7ade815972c 100644
--- a/code/controllers/subsystem/init/law.dm
+++ b/code/controllers/subsystem/init/law.dm
@@ -8,20 +8,24 @@ SUBSYSTEM_DEF(law_init)
var/list/minor_law = list()
var/list/major_law = list()
var/list/capital_law = list()
+ var/list/precautionary_law = list()
/datum/controller/subsystem/law_init/Initialize()
- for(var/L in subtypesof(/datum/law/optional_law))
- optional_law += new L
+ for(var/law in subtypesof(/datum/law/optional_law))
+ optional_law += new law
- for(var/L in subtypesof(/datum/law/minor_law))
- minor_law += new L
+ for(var/law in subtypesof(/datum/law/minor_law))
+ minor_law += new law
- for(var/L in subtypesof(/datum/law/major_law))
- major_law += new L
+ for(var/law in subtypesof(/datum/law/major_law))
+ major_law += new law
- for(var/L in subtypesof(/datum/law/capital_law))
- capital_law += new L
+ for(var/law in subtypesof(/datum/law/capital_law))
+ capital_law += new law
- laws = optional_law + minor_law + major_law + capital_law
+ for(var/law in subtypesof(/datum/law/precautionary_charge))
+ precautionary_law += new law
+
+ laws = optional_law + minor_law + major_law + capital_law + precautionary_law
return SS_INIT_SUCCESS
diff --git a/code/controllers/subsystem/interior.dm b/code/controllers/subsystem/interior.dm
index 389e95fe6022..8abc3179f191 100644
--- a/code/controllers/subsystem/interior.dm
+++ b/code/controllers/subsystem/interior.dm
@@ -42,7 +42,7 @@ SUBSYSTEM_DEF(interior)
continue
if(x >= bounds[1].x && x <= bounds[2].x && y >= bounds[1].y && y <= bounds[2].y)
return current_interior
- return FALSE
+ return
/// Checks if an atom is in an interior
/datum/controller/subsystem/interior/proc/in_interior(loc)
@@ -51,10 +51,16 @@ SUBSYSTEM_DEF(interior)
if(!isturf(loc))
loc = get_turf(loc)
- var/datum/turf_reservation/interior/reservation = SSmapping.used_turfs[loc]
+ var/datum/weakref/reservation_weakref = SSmapping.used_turfs[loc]
+
+ if(!reservation_weakref)
+ return
+
+ var/datum/turf_reservation/interior/reservation = reservation_weakref.resolve()
if(!istype(reservation))
return FALSE
+
return TRUE
#undef INTERIOR_BORDER_SIZE
diff --git a/code/controllers/subsystem/item_cleanup.dm b/code/controllers/subsystem/item_cleanup.dm
index 35d1fc2859e9..26958eb8742b 100644
--- a/code/controllers/subsystem/item_cleanup.dm
+++ b/code/controllers/subsystem/item_cleanup.dm
@@ -1,4 +1,4 @@
-var/global/list/item_cleanup_list = list()
+GLOBAL_LIST_EMPTY(item_cleanup_list)
SUBSYSTEM_DEF(item_cleanup)
name = "Item Cleanup"
@@ -34,9 +34,9 @@ SUBSYSTEM_DEF(item_cleanup)
break
//We transfer items from the global garbage list onto the next iteration list
- while(!isnull(item_cleanup_list) && item_cleanup_list.len > 0)
- addToListNoDupe(items_to_clean_up, item_cleanup_list[item_cleanup_list.len])
- item_cleanup_list -= item_cleanup_list[item_cleanup_list.len]
+ while(!isnull(GLOB.item_cleanup_list) && GLOB.item_cleanup_list.len > 0)
+ addToListNoDupe(items_to_clean_up, GLOB.item_cleanup_list[GLOB.item_cleanup_list.len])
+ GLOB.item_cleanup_list -= GLOB.item_cleanup_list[GLOB.item_cleanup_list.len]
log_debug("item_cleanup deleted [deleted] garbage out of total [total_items]")
@@ -57,9 +57,9 @@ SUBSYSTEM_DEF(item_cleanup)
qdel(o)
/proc/add_to_garbage(atom/a)
- addToListNoDupe(item_cleanup_list, a)
+ addToListNoDupe(GLOB.item_cleanup_list, a)
/proc/remove_from_garbage(atom/a)
- item_cleanup_list -= a
+ GLOB.item_cleanup_list -= a
if(SSitem_cleanup)
SSitem_cleanup.items_to_clean_up -= a
diff --git a/code/controllers/subsystem/machinery.dm b/code/controllers/subsystem/machinery.dm
index 7f86689874ff..6a0f938475a1 100644
--- a/code/controllers/subsystem/machinery.dm
+++ b/code/controllers/subsystem/machinery.dm
@@ -1,8 +1,8 @@
-var/list/machines = list()
-var/list/processing_machines = list()
+GLOBAL_LIST_EMPTY(machines)
+GLOBAL_LIST_EMPTY(processing_machines)
-var/list/datum/powernet/powernets = list() //Holds all powernet datums in use or pooled
-var/list/datum/powernet/powernets_by_name = list() //Holds all powernet datums in use or pooled
+GLOBAL_LIST_EMPTY(powernets) //Holds all powernet datums in use or pooled
+GLOBAL_LIST_EMPTY(powernets_by_name) //Holds all powernet datums in use or pooled
SUBSYSTEM_DEF(machinery)
@@ -19,12 +19,12 @@ SUBSYSTEM_DEF(machinery)
return SS_INIT_SUCCESS
/datum/controller/subsystem/machinery/stat_entry(msg)
- msg = "M:[global.processing_machines.len]"
+ msg = "M:[GLOB.processing_machines.len]"
return ..()
/datum/controller/subsystem/machinery/fire(resumed = FALSE)
if (!resumed)
- currentrunmachines = processing_machines.Copy()
+ currentrunmachines = GLOB.processing_machines.Copy()
while (currentrunmachines.len)
var/obj/structure/machinery/M = currentrunmachines[currentrunmachines.len]
diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm
index afecabd74be0..0f4a63ff65e8 100644
--- a/code/controllers/subsystem/mapping.dm
+++ b/code/controllers/subsystem/mapping.dm
@@ -6,9 +6,13 @@ SUBSYSTEM_DEF(mapping)
var/list/datum/map_config/configs
var/list/datum/map_config/next_map_configs
+ ///Name of all maps
var/list/map_templates = list()
-
+ ///Name of all shuttles
var/list/shuttle_templates = list()
+ var/list/all_shuttle_templates = list()
+ ///map_id of all tents
+ var/list/tent_type_templates = list()
var/list/areas_in_z = list()
@@ -29,9 +33,7 @@ SUBSYSTEM_DEF(mapping)
/datum/controller/subsystem/mapping/proc/HACK_LoadMapConfig()
if(!configs)
configs = load_map_configs(ALL_MAPTYPES, error_if_missing = FALSE)
- for(var/i in GLOB.clients)
- var/client/C = i
- winset(C, null, "mainwindow.title='[CONFIG_GET(string/title)] - [SSmapping.configs[SHIP_MAP].map_name]'")
+ world.name = "[CONFIG_GET(string/title)] - [SSmapping.configs[SHIP_MAP].map_name]"
/datum/controller/subsystem/mapping/Initialize(timeofday)
HACK_LoadMapConfig()
@@ -59,6 +61,11 @@ SUBSYSTEM_DEF(mapping)
if(MC.perf_mode)
GLOB.perf_flags |= MC.perf_mode
+ if(configs[GROUND_MAP])
+ send2chat(new /datum/tgs_message_content("<@&[CONFIG_GET(string/new_round_alert_role_id)]> Round restarted! Map is [configs[GROUND_MAP].map_name]"), CONFIG_GET(string/new_round_alert_channel))
+ else
+ send2chat(new /datum/tgs_message_content("<@&[CONFIG_GET(string/new_round_alert_role_id)]> Round started!"), CONFIG_GET(string/new_round_alert_channel))
+
return SS_INIT_SUCCESS
/datum/controller/subsystem/mapping/proc/wipe_reservations(wipe_safety_delay = 100)
@@ -202,6 +209,7 @@ SUBSYSTEM_DEF(mapping)
map_templates[T.name] = T
preloadShuttleTemplates()
+ preload_tent_templates()
/proc/generateMapList(filename)
. = list()
@@ -240,8 +248,14 @@ SUBSYSTEM_DEF(mapping)
var/datum/map_template/shuttle/S = new shuttle_type()
shuttle_templates[S.shuttle_id] = S
+ all_shuttle_templates[item] = S
map_templates[S.shuttle_id] = S
+/datum/controller/subsystem/mapping/proc/preload_tent_templates()
+ for(var/template in subtypesof(/datum/map_template/tent))
+ var/datum/map_template/tent/new_tent = new template()
+ tent_type_templates[new_tent.map_id] = new_tent
+
/datum/controller/subsystem/mapping/proc/RequestBlockReservation(width, height, z, type = /datum/turf_reservation, turf_type_override)
UNTIL(initialized && !clearing_reserved_turfs)
var/datum/turf_reservation/reserve = new type
diff --git a/code/controllers/subsystem/midi.dm b/code/controllers/subsystem/midi.dm
deleted file mode 100644
index 158d67cf25ac..000000000000
--- a/code/controllers/subsystem/midi.dm
+++ /dev/null
@@ -1,45 +0,0 @@
-/datum/midi_record
- var/target
- var/midi
-
-SUBSYSTEM_DEF(midi)
- name = "Midi"
- wait = 2 SECONDS
- flags = SS_NO_INIT|SS_BACKGROUND
- runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY
- priority = SS_PRIORITY_MIDI
-
- var/list/datum/midi_record/prepped_midis = list()
-
- var/list/datum/midi_record/currentrun = list()
-
-
-/datum/controller/subsystem/midi/stat_entry(msg)
- msg = "MR:[prepped_midis.len]"
- return ..()
-
-
-/datum/controller/subsystem/midi/fire(resumed = FALSE)
- if (!resumed)
- currentrun = prepped_midis
- prepped_midis = list()
-
- while (currentrun.len)
- var/datum/midi_record/E = currentrun[currentrun.len]
- currentrun.len--
-
- if (!E)
- continue
-
- E.target << E.midi
-
- if (MC_TICK_CHECK)
- return
-
-/datum/controller/subsystem/midi/proc/queue(target, midi)
- if(!prepped_midis)
- prepped_midis = list()
- var/datum/midi_record/MR = new()
- MR.target = target
- MR.midi = midi
- prepped_midis.Add(MR)
diff --git a/code/controllers/subsystem/minimap.dm b/code/controllers/subsystem/minimap.dm
index 6f5b9303a91f..a808e7e3fd85 100644
--- a/code/controllers/subsystem/minimap.dm
+++ b/code/controllers/subsystem/minimap.dm
@@ -1,3 +1,6 @@
+#define CANVAS_COOLDOWN_TIME 4 MINUTES
+#define FLATTEN_MAP_COOLDOWN_TIME 3 MINUTES
+
/**
* # Minimaps subsystem
*
@@ -256,8 +259,6 @@ SUBSYSTEM_DEF(minimaps)
removal_cbs[target] = CALLBACK(src, PROC_REF(removeimage), blip, target)
RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(remove_marker))
-
-
/**
* removes an image from raw tracked lists, invoked by callback
*/
@@ -322,7 +323,7 @@ SUBSYSTEM_DEF(minimaps)
minimaps_by_z["[z_level]"].images_assoc["[flag]"] -= source
/**
- * Fetches a /atom/movable/screen/minimap instance or creates on if none exists
+ * Fetches a /atom/movable/screen/minimap instance or creates one if none exists
* Note this does not destroy them when the map is unused, might be a potential thing to do?
* Arguments:
* * zlevel: zlevel to fetch map for
@@ -338,6 +339,172 @@ SUBSYSTEM_DEF(minimaps)
hashed_minimaps[hash] = map
return map
+/**
+ * Fetches the datum containing an announced flattend map png reference.
+ *
+ * Arguments:
+ * * faction: FACTION_MARINE or XENO_HIVE_NORMAL
+ */
+/proc/get_tacmap_data_png(faction)
+ var/list/map_list
+
+ if(faction == FACTION_MARINE)
+ map_list = GLOB.uscm_flat_tacmap_data
+ else if(faction == XENO_HIVE_NORMAL)
+ map_list = GLOB.xeno_flat_tacmap_data
+ else
+ return null
+
+ var/map_length = length(map_list)
+
+ if(map_length == 0)
+ return null
+
+ return map_list[map_length]
+
+/**
+ * Fetches the datum containing the latest unannounced flattend map png reference.
+ *
+ * Arguments:
+ * * faction: FACTION_MARINE or XENO_HIVE_NORMAL
+ */
+/proc/get_unannounced_tacmap_data_png(faction)
+ if(faction == FACTION_MARINE)
+ return GLOB.uscm_unannounced_map
+ else if(faction == XENO_HIVE_NORMAL)
+ return GLOB.xeno_unannounced_map
+
+ return null
+
+/**
+ * Fetches the last set of svg coordinates for the tacmap drawing.
+ *
+ * Arguments:
+ * * faction: which faction get the map for: FACTION_MARINE or XENO_HIVE_NORMAL
+ */
+/proc/get_tacmap_data_svg(faction)
+ var/list/map_list
+
+ if(faction == FACTION_MARINE)
+ map_list = GLOB.uscm_svg_tacmap_data
+ else if(faction == XENO_HIVE_NORMAL)
+ map_list = GLOB.xeno_svg_tacmap_data
+ else
+ return null
+
+ var/map_length = length(map_list)
+
+ if(map_length == 0)
+ return null
+
+ return map_list[map_length]
+
+/**
+ * Re-sends relevant flattened tacmaps to a single client.
+ *
+ * Arguments:
+ * * user: The mob that is either an observer, marine, or xeno
+ */
+/proc/resend_current_map_png(mob/user)
+ if(!user.client)
+ return
+
+ var/is_observer = user.faction == FACTION_NEUTRAL && isobserver(user)
+ if(is_observer || user.faction == FACTION_MARINE)
+ // Send marine maps
+ var/datum/flattened_tacmap/latest = get_tacmap_data_png(FACTION_MARINE)
+ if(latest)
+ SSassets.transport.send_assets(user.client, latest.asset_key)
+ var/datum/flattened_tacmap/unannounced = get_unannounced_tacmap_data_png(FACTION_MARINE)
+ if(unannounced && (!latest || latest.asset_key != unannounced.asset_key))
+ SSassets.transport.send_assets(user.client, unannounced.asset_key)
+
+ var/mob/living/carbon/xenomorph/xeno = user
+ if(is_observer || istype(xeno) && xeno.hivenumber == XENO_HIVE_NORMAL)
+ // Send xeno maps
+ var/datum/flattened_tacmap/latest = get_tacmap_data_png(XENO_HIVE_NORMAL)
+ if(latest)
+ SSassets.transport.send_assets(user.client, latest.asset_key)
+ var/datum/flattened_tacmap/unannounced = get_unannounced_tacmap_data_png(XENO_HIVE_NORMAL)
+ if(unannounced && (!latest || latest.asset_key != unannounced.asset_key))
+ SSassets.transport.send_assets(user.client, unannounced.asset_key)
+
+/**
+ * Flattens the current map and then distributes it for the specified faction as an unannounced map.
+ *
+ * Arguments:
+ * * faction: Which faction to distribute the map to: FACTION_MARINE or XENO_HIVE_NORMAL
+ * Return:
+ * * Returns a boolean value, TRUE if the operation was successful, FALSE if it was not (on cooldown generally).
+ */
+/datum/tacmap/drawing/proc/distribute_current_map_png(faction)
+ if(faction == FACTION_MARINE)
+ if(!COOLDOWN_FINISHED(GLOB, uscm_flatten_map_icon_cooldown))
+ return FALSE
+ COOLDOWN_START(GLOB, uscm_flatten_map_icon_cooldown, FLATTEN_MAP_COOLDOWN_TIME)
+ else if(faction == XENO_HIVE_NORMAL)
+ if(!COOLDOWN_FINISHED(GLOB, xeno_flatten_map_icon_cooldown))
+ return FALSE
+ COOLDOWN_START(GLOB, xeno_flatten_map_icon_cooldown, FLATTEN_MAP_COOLDOWN_TIME)
+ else
+ return FALSE
+
+ var/icon/flat_map = getFlatIcon(map_holder.map, appearance_flags = TRUE)
+ if(!flat_map)
+ to_chat(usr, SPAN_WARNING("A critical error has occurred! Contact a coder.")) // tf2heavy: "Oh, this is bad!"
+ return FALSE
+
+ // Send to only relevant clients
+ var/list/faction_clients = list()
+ for(var/client/client as anything in GLOB.clients)
+ if(!client || !client.mob)
+ continue
+ var/mob/client_mob = client.mob
+ if(client_mob.faction == faction)
+ faction_clients += client
+ else if(client_mob.faction == FACTION_NEUTRAL && isobserver(client_mob))
+ faction_clients += client
+ else if(isxeno(client_mob))
+ var/mob/living/carbon/xenomorph/xeno = client_mob
+ if(xeno.hivenumber == faction)
+ faction_clients += client
+
+ // This may be unnecessary to do this way if the asset url is always the same as the lookup key
+ var/flat_tacmap_key = icon2html(flat_map, faction_clients, keyonly = TRUE)
+ if(!flat_tacmap_key)
+ to_chat(usr, SPAN_WARNING("A critical error has occurred! Contact a coder."))
+ return FALSE
+ var/flat_tacmap_png = SSassets.transport.get_asset_url(flat_tacmap_key)
+ var/datum/flattened_tacmap/new_flat = new(flat_tacmap_png, flat_tacmap_key)
+
+ if(faction == FACTION_MARINE)
+ GLOB.uscm_unannounced_map = new_flat
+ else //if(faction == XENO_HIVE_NORMAL)
+ GLOB.xeno_unannounced_map = new_flat
+
+ return TRUE
+
+/**
+ * Globally stores svg coords for a given faction.
+ *
+ * Arguments:
+ * * faction: which faction to save the data for: FACTION_MARINE or XENO_HIVE_NORMAL
+ * * svg_coords: an array of coordinates corresponding to an svg.
+ * * ckey: the ckey of the user who submitted this
+ */
+/datum/tacmap/drawing/proc/store_current_svg_coords(faction, svg_coords, ckey)
+ var/datum/svg_overlay/svg_store_overlay = new(svg_coords, ckey)
+
+ if(faction == FACTION_MARINE)
+ GLOB.uscm_svg_tacmap_data += svg_store_overlay
+ else if(faction == XENO_HIVE_NORMAL)
+ GLOB.xeno_svg_tacmap_data += svg_store_overlay
+ else
+ qdel(svg_store_overlay)
+ debug_log("SVG coordinates for [faction] are not implemented!")
+
+#define can_draw(faction, user) ((faction == FACTION_MARINE && skillcheck(user, SKILL_LEADERSHIP, SKILL_LEAD_EXPERT)) || (faction == XENO_HIVE_NORMAL && isqueen(user)))
+
/datum/controller/subsystem/minimaps/proc/fetch_tacmap_datum(zlevel, flags)
var/hash = "[zlevel]-[flags]"
if(hashed_tacmaps[hash])
@@ -442,7 +609,7 @@ SUBSYSTEM_DEF(minimaps)
marker_flags = MINIMAP_FLAG_USCM
/datum/action/minimap/observer
- minimap_flags = MINIMAP_FLAG_XENO|MINIMAP_FLAG_USCM|MINIMAP_FLAG_UPP|MINIMAP_FLAG_CLF|MINIMAP_FLAG_UPP
+ minimap_flags = MINIMAP_FLAG_ALL
marker_flags = NONE
hidden = TRUE
@@ -452,17 +619,58 @@ SUBSYSTEM_DEF(minimaps)
var/targeted_ztrait = ZTRAIT_GROUND
var/atom/owner
+ /// tacmap holder for holding the minimap
var/datum/tacmap_holder/map_holder
+/datum/tacmap/drawing
+ /// A url that will point to the wiki map for the current map as a fall back image
+ var/static/wiki_map_fallback
+
+ /// color selection for the tactical map canvas, defaults to black.
+ var/toolbar_color_selection = "black"
+ var/toolbar_updated_selection = "black"
+
+ /// boolean value to keep track if the canvas has been updated or not, the value is used in tgui state.
+ var/updated_canvas = FALSE
+ /// current flattend map
+ var/datum/flattened_tacmap/new_current_map
+ /// previous flattened map
+ var/datum/flattened_tacmap/old_map
+ /// current svg
+ var/datum/svg_overlay/current_svg
+
+ var/action_queue_change = 0
+
+ /// The last time the map has been flattened - used as a key to trick react into updating the canvas
+ var/last_update_time = 0
+ /// A temporary lock out time before we can open the new canvas tab to allow the tacmap time to fire
+ var/tacmap_ready_time = 0
+
/datum/tacmap/New(atom/source, minimap_type)
allowed_flags = minimap_type
owner = source
+/datum/tacmap/drawing/status_tab_view/New()
+ var/datum/tacmap/drawing/status_tab_view/uscm_tacmap
+ allowed_flags = MINIMAP_FLAG_USCM
+ owner = uscm_tacmap
+
+/datum/tacmap/drawing/status_tab_view/xeno/New()
+ var/datum/tacmap/drawing/status_tab_view/xeno/xeno_tacmap
+ allowed_flags = MINIMAP_FLAG_XENO
+ owner = xeno_tacmap
+
/datum/tacmap/Destroy()
map_holder = null
owner = null
return ..()
+/datum/tacmap/drawing/Destroy()
+ new_current_map = null
+ old_map = null
+ current_svg = null
+ return ..()
+
/datum/tacmap/tgui_interact(mob/user, datum/tgui/ui)
if(!map_holder)
var/level = SSmapping.levels_by_trait(targeted_ztrait)
@@ -476,11 +684,234 @@ SUBSYSTEM_DEF(minimaps)
ui = new(user, src, "TacticalMap")
ui.open()
+/datum/tacmap/drawing/tgui_interact(mob/user, datum/tgui/ui)
+ var/mob/living/carbon/xenomorph/xeno = user
+ var/is_xeno = istype(xeno)
+ var/faction = is_xeno ? xeno.hivenumber : user.faction
+ if(faction == FACTION_NEUTRAL && isobserver(user))
+ faction = allowed_flags == MINIMAP_FLAG_XENO ? XENO_HIVE_NORMAL : FACTION_MARINE
+
+ new_current_map = get_unannounced_tacmap_data_png(faction)
+ old_map = get_tacmap_data_png(faction)
+ current_svg = get_tacmap_data_svg(faction)
+
+ var/use_live_map = faction == FACTION_MARINE && skillcheck(user, SKILL_LEADERSHIP, SKILL_LEAD_EXPERT) || is_xeno
+
+ if(use_live_map && !map_holder)
+ var/level = SSmapping.levels_by_trait(targeted_ztrait)
+ if(!level[1])
+ return
+ map_holder = SSminimaps.fetch_tacmap_datum(level[1], allowed_flags)
+
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ if(!wiki_map_fallback)
+ var/wiki_url = CONFIG_GET(string/wikiurl)
+ var/obj/item/map/current_map/new_map = new
+ if(wiki_url && new_map.html_link)
+ wiki_map_fallback ="[wiki_url]/[new_map.html_link]"
+ else
+ debug_log("Failed to determine fallback wiki map! Attempted '[wiki_url]/[new_map.html_link]'")
+ qdel(new_map)
+
+ // Ensure we actually have the map image sent
+ resend_current_map_png(user)
+
+ if(use_live_map)
+ tacmap_ready_time = SSminimaps.next_fire + 2 SECONDS
+ addtimer(CALLBACK(src, PROC_REF(on_tacmap_fire), faction), SSminimaps.next_fire - world.time + 1 SECONDS)
+ user.client.register_map_obj(map_holder.map)
+
+ ui = new(user, src, "TacticalMap")
+ ui.open()
+
+/datum/tacmap/drawing/ui_data(mob/user)
+ var/list/data = list()
+
+ data["newCanvasFlatImage"] = new_current_map?.flat_tacmap
+ data["oldCanvasFlatImage"] = old_map?.flat_tacmap
+ data["svgData"] = current_svg?.svg_data
+
+ data["actionQueueChange"] = action_queue_change
+
+ data["toolbarColorSelection"] = toolbar_color_selection
+ data["toolbarUpdatedSelection"] = toolbar_updated_selection
+
+ if(isxeno(user))
+ data["canvasCooldown"] = max(GLOB.xeno_canvas_cooldown - world.time, 0)
+ else
+ data["canvasCooldown"] = max(GLOB.uscm_canvas_cooldown - world.time, 0)
+
+ data["updatedCanvas"] = updated_canvas
+
+ data["lastUpdateTime"] = last_update_time
+ data["tacmapReady"] = world.time > tacmap_ready_time
+
+ return data
+
/datum/tacmap/ui_static_data(mob/user)
var/list/data = list()
- data["mapRef"] = map_holder.map_ref
+
+ data["mapRef"] = map_holder?.map_ref
+ data["canDraw"] = FALSE
+ data["canViewTacmap"] = TRUE
+ data["canViewCanvas"] = FALSE
+ data["isXeno"] = FALSE
+
+ return data
+
+/datum/tacmap/drawing/ui_static_data(mob/user)
+ var/list/data = list()
+
+ data["canvasCooldownDuration"] = CANVAS_COOLDOWN_TIME
+ data["mapRef"] = map_holder?.map_ref
+ data["canDraw"] = FALSE
+ data["mapFallback"] = wiki_map_fallback
+
+ var/mob/living/carbon/xenomorph/xeno = user
+ var/is_xeno = istype(xeno)
+ var/faction = is_xeno ? xeno.hivenumber : user.faction
+
+ data["isXeno"] = is_xeno
+ data["canViewTacmap"] = is_xeno
+ data["canViewCanvas"] = faction == FACTION_MARINE || faction == XENO_HIVE_NORMAL
+
+ if(can_draw(faction, user))
+ data["canDraw"] = TRUE
+ data["canViewTacmap"] = TRUE
+
+ return data
+
+/datum/tacmap/drawing/status_tab_view/ui_static_data(mob/user)
+ var/list/data = list()
+
+ data["canvasCooldownDuration"] = CANVAS_COOLDOWN_TIME
+ data["mapFallback"] = wiki_map_fallback
+ data["canDraw"] = FALSE
+ data["canViewTacmap"] = FALSE
+ data["canViewCanvas"] = TRUE
+ data["isXeno"] = FALSE
+
+ return data
+
+/datum/tacmap/drawing/status_tab_view/xeno/ui_static_data(mob/user)
+ var/list/data = list()
+
+ data["canvasCooldownDuration"] = CANVAS_COOLDOWN_TIME
+ data["mapFallback"] = wiki_map_fallback
+ data["canDraw"] = FALSE
+ data["canViewTacmap"] = FALSE
+ data["canViewCanvas"] = TRUE
+ data["isXeno"] = TRUE
+
return data
+/datum/tacmap/drawing/ui_close(mob/user)
+ . = ..()
+ action_queue_change = 0
+ updated_canvas = FALSE
+ toolbar_color_selection = "black"
+ toolbar_updated_selection = "black"
+
+/datum/tacmap/drawing/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/user = ui.user
+ var/mob/living/carbon/xenomorph/xeno = user
+ var/faction = istype(xeno) ? xeno.hivenumber : user.faction
+ var/is_observer = isobserver(user)
+ if(faction == FACTION_NEUTRAL && is_observer)
+ faction = allowed_flags == MINIMAP_FLAG_XENO ? XENO_HIVE_NORMAL : FACTION_MARINE
+ var/drawing_allowed = !is_observer && can_draw(faction, user)
+
+ switch (action)
+ if ("menuSelect")
+ if(params["selection"] != "Canvas")
+ if(updated_canvas)
+ updated_canvas = FALSE
+ toolbar_updated_selection = toolbar_color_selection // doing this if it == canvas can cause a latency issue with the stroke.
+ else
+ if(!drawing_allowed)
+ msg_admin_niche("[key_name(user)] made an unauthorized attempt to 'menuSelect' the 'new canvas' panel of the [faction] tacmap!")
+ return FALSE
+ distribute_current_map_png(faction)
+ last_update_time = world.time
+ // An attempt to get the image to load on first try in the interface, but doesn't seem always reliable
+
+ new_current_map = get_unannounced_tacmap_data_png(faction)
+ old_map = get_tacmap_data_png(faction)
+ current_svg = get_tacmap_data_svg(faction)
+
+ if("updateCanvas")
+ toolbar_updated_selection = "export"
+ updated_canvas = TRUE
+ action_queue_change += 1
+
+ if("clearCanvas")
+ toolbar_updated_selection = "clear"
+ updated_canvas = FALSE
+ action_queue_change += 1
+
+ if("undoChange")
+ toolbar_updated_selection = "undo"
+ updated_canvas = FALSE
+ action_queue_change += 1
+
+ if("selectColor")
+ var/newColor = params["color"]
+ if(newColor)
+ toolbar_color_selection = newColor
+ toolbar_updated_selection = newColor
+ action_queue_change += 1
+
+ if("onDraw")
+ updated_canvas = FALSE
+
+ if("selectAnnouncement")
+ if(!drawing_allowed)
+ msg_admin_niche("[key_name(user)] made an unauthorized attempt to 'selectAnnouncement' the [faction] tacmap!")
+ return FALSE
+
+ if(!istype(params["image"], /list)) // potentially very serious?
+ return FALSE
+
+ var/cooldown_satisfied = FALSE
+ if(faction == FACTION_MARINE)
+ cooldown_satisfied = COOLDOWN_FINISHED(GLOB, uscm_canvas_cooldown)
+ else if(faction == XENO_HIVE_NORMAL)
+ cooldown_satisfied = COOLDOWN_FINISHED(GLOB, xeno_canvas_cooldown)
+ if(!cooldown_satisfied)
+ msg_admin_niche("[key_name(user)] attempted to 'selectAnnouncement' the [faction] tacmap while it is still on cooldown!")
+ return FALSE
+
+ if(faction == FACTION_MARINE)
+ GLOB.uscm_flat_tacmap_data += new_current_map
+ COOLDOWN_START(GLOB, uscm_canvas_cooldown, CANVAS_COOLDOWN_TIME)
+ for(var/datum/squad/current_squad in GLOB.RoleAuthority.squads)
+ current_squad.send_maptext("Tactical map update in progress...", "Tactical Map:")
+ var/mob/living/carbon/human/human_leader = user
+ human_leader.visible_message(SPAN_BOLDNOTICE("Tactical map update in progress..."))
+ playsound_client(human_leader.client, "sound/effects/sos-morse-code.ogg")
+ notify_ghosts(header = "Tactical Map", message = "The USCM tactical map has been updated.", ghost_sound = "sound/effects/sos-morse-code.ogg", notify_volume = 80, action = NOTIFY_USCM_TACMAP, enter_link = "uscm_tacmap=1", enter_text = "View", source = owner)
+ else if(faction == XENO_HIVE_NORMAL)
+ GLOB.xeno_flat_tacmap_data += new_current_map
+ COOLDOWN_START(GLOB, xeno_canvas_cooldown, CANVAS_COOLDOWN_TIME)
+ xeno_maptext("The Queen has updated our hive mind map", "We sense something unusual...", faction)
+ var/mutable_appearance/appearance = mutable_appearance(icon('icons/mob/hud/actions_xeno.dmi'), "toggle_queen_zoom")
+ notify_ghosts(header = "Tactical Map", message = "The Xenomorph tactical map has been updated.", ghost_sound = "sound/voice/alien_distantroar_3.ogg", notify_volume = 50, action = NOTIFY_XENO_TACMAP, enter_link = "xeno_tacmap=1", enter_text = "View", source = user, alert_overlay = appearance)
+
+ store_current_svg_coords(faction, params["image"], user)
+ current_svg = get_tacmap_data_svg(faction)
+ old_map = get_tacmap_data_png(faction)
+
+ toolbar_updated_selection = toolbar_color_selection
+ message_admins("[key_name(user)] has updated the tactical map for [faction].")
+ updated_canvas = FALSE
+
+ return TRUE
+
/datum/tacmap/ui_status(mob/user)
if(!(isatom(owner)))
return UI_INTERACTIVE
@@ -493,7 +924,7 @@ SUBSYSTEM_DEF(minimaps)
else
return UI_CLOSE
-/datum/tacmap/xeno/ui_status(mob/user)
+/datum/tacmap/drawing/xeno/ui_status(mob/user)
if(!isxeno(user))
return UI_CLOSE
@@ -516,3 +947,75 @@ SUBSYSTEM_DEF(minimaps)
/datum/tacmap_holder/Destroy()
map = null
return ..()
+
+/datum/flattened_tacmap
+ var/flat_tacmap
+ var/asset_key
+ var/time
+
+/datum/flattened_tacmap/New(flat_tacmap, asset_key)
+ src.flat_tacmap = flat_tacmap
+ src.asset_key = asset_key
+ src.time = time_stamp()
+
+/datum/svg_overlay
+ var/svg_data
+ var/ckey
+ var/name
+ var/time
+
+/datum/svg_overlay/New(svg_data, mob/user)
+ src.svg_data = svg_data
+ src.ckey = user?.persistent_ckey
+ src.name = user?.real_name
+ src.time = time_stamp()
+
+/// Callback when timer indicates the tacmap is flattenable now
+/datum/tacmap/drawing/proc/on_tacmap_fire(faction)
+ distribute_current_map_png(faction)
+ last_update_time = world.time
+
+/// Gets the MINIMAP_FLAG for the provided faction or hivenumber if one exists
+/proc/get_minimap_flag_for_faction(faction)
+ switch(faction)
+ if(XENO_HIVE_NORMAL)
+ return MINIMAP_FLAG_XENO
+ if(FACTION_MARINE)
+ return MINIMAP_FLAG_USCM
+ if(FACTION_UPP)
+ return MINIMAP_FLAG_UPP
+ if(FACTION_WY)
+ return MINIMAP_FLAG_USCM
+ if(FACTION_CLF)
+ return MINIMAP_FLAG_CLF
+ if(FACTION_PMC)
+ return MINIMAP_FLAG_PMC
+ if(FACTION_YAUTJA)
+ return MINIMAP_FLAG_YAUTJA
+ if(XENO_HIVE_CORRUPTED)
+ return MINIMAP_FLAG_XENO_CORRUPTED
+ if(XENO_HIVE_ALPHA)
+ return MINIMAP_FLAG_XENO_ALPHA
+ if(XENO_HIVE_BRAVO)
+ return MINIMAP_FLAG_XENO_BRAVO
+ if(XENO_HIVE_CHARLIE)
+ return MINIMAP_FLAG_XENO_CHARLIE
+ if(XENO_HIVE_DELTA)
+ return MINIMAP_FLAG_XENO_DELTA
+ if(XENO_HIVE_FERAL)
+ return MINIMAP_FLAG_XENO_FERAL
+ if(XENO_HIVE_TAMED)
+ return MINIMAP_FLAG_XENO_TAMED
+ if(XENO_HIVE_MUTATED)
+ return MINIMAP_FLAG_XENO_MUTATED
+ if(XENO_HIVE_FORSAKEN)
+ return MINIMAP_FLAG_XENO_FORSAKEN
+ if(XENO_HIVE_YAUTJA)
+ return MINIMAP_FLAG_YAUTJA
+ if(XENO_HIVE_RENEGADE)
+ return MINIMAP_FLAG_XENO_RENEGADE
+ return 0
+
+#undef CANVAS_COOLDOWN_TIME
+#undef FLATTEN_MAP_COOLDOWN_TIME
+#undef can_draw
diff --git a/code/controllers/subsystem/nanoui.dm b/code/controllers/subsystem/nanoui.dm
index 1f33227a7fee..85ad0d32aaf4 100644
--- a/code/controllers/subsystem/nanoui.dm
+++ b/code/controllers/subsystem/nanoui.dm
@@ -5,6 +5,12 @@ SUBSYSTEM_DEF(nano)
priority = SS_PRIORITY_NANOUI
runlevels = RUNLEVELS_DEFAULT|RUNLEVEL_LOBBY
var/list/currentrun = list()
+ var/datum/nanomanager/nanomanager
+
+/datum/controller/subsystem/nano/New()
+ . = ..()
+
+ nanomanager = new()
/datum/controller/subsystem/nano/stat_entry(msg)
msg = "P:[nanomanager.processing_uis.len]"
diff --git a/code/controllers/subsystem/power.dm b/code/controllers/subsystem/power.dm
index 16f4f2ab6127..9908a60420b2 100644
--- a/code/controllers/subsystem/power.dm
+++ b/code/controllers/subsystem/power.dm
@@ -1,4 +1,4 @@
-var/list/power_machines = list()
+GLOBAL_LIST_EMPTY(power_machines)
SUBSYSTEM_DEF(power)
name = "Power"
@@ -12,7 +12,7 @@ SUBSYSTEM_DEF(power)
var/list/currentrun_areas = list()
/datum/controller/subsystem/power/stat_entry(msg)
- msg = "PN:[powernets.len]|PM:[power_machines.len]|A:[active_areas.len]"
+ msg = "PN:[GLOB.powernets.len]|PM:[GLOB.power_machines.len]|A:[GLOB.active_areas.len]"
return ..()
@@ -23,9 +23,9 @@ SUBSYSTEM_DEF(power)
/datum/controller/subsystem/power/fire(resumed = FALSE)
if (!resumed)
- currentrun_powerents = global.powernets.Copy()
- currentrun_areas = active_areas.Copy()
- currentrun_power_machines = global.power_machines.Copy()
+ currentrun_powerents = GLOB.powernets.Copy()
+ currentrun_areas = GLOB.active_areas.Copy()
+ currentrun_power_machines = GLOB.power_machines.Copy()
// First we reset the powernets.
// This is done first because we want the power machinery to have acted last on the powernet between intervals.
@@ -49,7 +49,7 @@ SUBSYSTEM_DEF(power)
var/obj/structure/machinery/M = X
if (M.process() == PROCESS_KILL)
//M.inMachineList = FALSE
- power_machines.Remove(M)
+ GLOB.power_machines.Remove(M)
continue
if (MC_TICK_CHECK)
diff --git a/code/controllers/subsystem/processing/defprocess.dm b/code/controllers/subsystem/processing/defprocess.dm
new file mode 100644
index 000000000000..3701a0617a7a
--- /dev/null
+++ b/code/controllers/subsystem/processing/defprocess.dm
@@ -0,0 +1,5 @@
+PROCESSING_SUBSYSTEM_DEF(defprocess)
+ name = "Defenses Processing"
+ priority = SS_PRIORITY_DEFENSES
+ flags = SS_NO_INIT
+ wait = 0.7 SECONDS
diff --git a/code/controllers/subsystem/processing/effects.dm b/code/controllers/subsystem/processing/effects.dm
index 5dc9c5f7b9c2..095d557c1ad3 100644
--- a/code/controllers/subsystem/processing/effects.dm
+++ b/code/controllers/subsystem/processing/effects.dm
@@ -1,5 +1,4 @@
PROCESSING_SUBSYSTEM_DEF(effects)
name = "Effects"
wait = 1 SECONDS
- flags = SS_NO_INIT | SS_KEEP_TIMING
priority = SS_PRIORITY_EFFECTS
diff --git a/code/controllers/subsystem/processing/fasteffects.dm b/code/controllers/subsystem/processing/fasteffects.dm
new file mode 100644
index 000000000000..29d3857916f9
--- /dev/null
+++ b/code/controllers/subsystem/processing/fasteffects.dm
@@ -0,0 +1,4 @@
+PROCESSING_SUBSYSTEM_DEF(fasteffects)
+ name = "Fast Effects"
+ wait = 0.2 SECONDS
+ priority = SS_PRIORITY_FASTEFFECTS
diff --git a/code/controllers/subsystem/processing/oldeffects.dm b/code/controllers/subsystem/processing/oldeffects.dm
new file mode 100644
index 000000000000..d2b217f5fc9d
--- /dev/null
+++ b/code/controllers/subsystem/processing/oldeffects.dm
@@ -0,0 +1,5 @@
+PROCESSING_SUBSYSTEM_DEF(oldeffects)
+ name = "Old Effects"
+ wait = 1 SECONDS
+ flags = SS_NO_INIT | SS_KEEP_TIMING
+ priority = SS_PRIORITY_OLDEFFECTS
diff --git a/code/controllers/subsystem/profiler.dm b/code/controllers/subsystem/profiler.dm
new file mode 100644
index 000000000000..f9ba79046c2c
--- /dev/null
+++ b/code/controllers/subsystem/profiler.dm
@@ -0,0 +1,74 @@
+#define PROFILER_FILENAME "profiler.json"
+#define SENDMAPS_FILENAME "sendmaps.json"
+
+SUBSYSTEM_DEF(profiler)
+ name = "Profiler"
+ init_order = SS_INIT_PROFILER
+ runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
+ wait = 300 SECONDS
+ var/fetch_cost = 0
+ var/write_cost = 0
+
+/datum/controller/subsystem/profiler/stat_entry(msg)
+ msg += "F:[round(fetch_cost,1)]ms"
+ msg += "|W:[round(write_cost,1)]ms"
+ return msg
+
+/datum/controller/subsystem/profiler/Initialize()
+ if(CONFIG_GET(flag/auto_profile))
+ StartProfiling()
+ else
+ StopProfiling() //Stop the early start profiler
+ return SS_INIT_SUCCESS
+
+/datum/controller/subsystem/profiler/OnConfigLoad()
+ if(CONFIG_GET(flag/auto_profile))
+ StartProfiling()
+ can_fire = TRUE
+ else
+ StopProfiling()
+ can_fire = FALSE
+
+/datum/controller/subsystem/profiler/fire()
+ DumpFile()
+
+/datum/controller/subsystem/profiler/Shutdown()
+ if(CONFIG_GET(flag/auto_profile))
+ DumpFile(allow_yield = FALSE)
+ world.Profile(PROFILE_CLEAR, type = "sendmaps")
+ return ..()
+
+/datum/controller/subsystem/profiler/proc/StartProfiling()
+ world.Profile(PROFILE_START)
+ world.Profile(PROFILE_START, type = "sendmaps")
+
+/datum/controller/subsystem/profiler/proc/StopProfiling()
+ world.Profile(PROFILE_STOP)
+ world.Profile(PROFILE_STOP, type = "sendmaps")
+
+/datum/controller/subsystem/profiler/proc/DumpFile(allow_yield = TRUE)
+ var/timer = TICK_USAGE_REAL
+ var/current_profile_data = world.Profile(PROFILE_REFRESH, format = "json")
+ var/current_sendmaps_data = world.Profile(PROFILE_REFRESH, type = "sendmaps", format="json")
+ fetch_cost = MC_AVERAGE(fetch_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+ if(allow_yield)
+ CHECK_TICK
+
+ if(!length(current_profile_data)) //Would be nice to have explicit proc to check this
+ stack_trace("Warning, profiling stopped manually before dump.")
+ var/prof_file = file("[GLOB.log_directory]/[PROFILER_FILENAME]")
+ if(fexists(prof_file))
+ fdel(prof_file)
+ if(!length(current_sendmaps_data)) //Would be nice to have explicit proc to check this
+ stack_trace("Warning, sendmaps profiling stopped manually before dump.")
+ var/sendmaps_file = file("[GLOB.log_directory]/[SENDMAPS_FILENAME]")
+ if(fexists(sendmaps_file))
+ fdel(sendmaps_file)
+
+ timer = TICK_USAGE_REAL
+ WRITE_FILE(prof_file, current_profile_data)
+ WRITE_FILE(sendmaps_file, current_sendmaps_data)
+ write_cost = MC_AVERAGE(write_cost, TICK_DELTA_TO_MS(TICK_USAGE_REAL - timer))
+
+#undef PROFILER_FILENAME
+#undef SENDMAPS_FILENAME
diff --git a/code/controllers/subsystem/reagents.dm b/code/controllers/subsystem/reagents.dm
index 5a310801b191..187479509385 100644
--- a/code/controllers/subsystem/reagents.dm
+++ b/code/controllers/subsystem/reagents.dm
@@ -17,33 +17,33 @@ SUBSYSTEM_DEF(reagents)
/datum/controller/subsystem/reagents/proc/prepare_properties()
//Chemical Properties - Initialises all /datum/chem_property into a list indexed by property name
var/paths = typesof(/datum/chem_property)
- chemical_properties_list = list()
+ GLOB.chemical_properties_list = list()
//Some filters
- chemical_properties_list["negative"] = list()
- chemical_properties_list["neutral"] = list()
- chemical_properties_list["positive"] = list()
- chemical_properties_list["rare"] = list()
+ GLOB.chemical_properties_list["negative"] = list()
+ GLOB.chemical_properties_list["neutral"] = list()
+ GLOB.chemical_properties_list["positive"] = list()
+ GLOB.chemical_properties_list["rare"] = list()
//Save
for(var/path in paths)
var/datum/chem_property/prop = new path()
if(!prop.name)
continue
- chemical_properties_list[prop.name] = prop
+ GLOB.chemical_properties_list[prop.name] = prop
if(prop.starter)
//Add a separate instance to the chemical property database
var/datum/chem_property/chem = new path()
chem.level = 0
- chemical_data.research_property_data += chem
+ GLOB.chemical_data.research_property_data += chem
if(prop.rarity > PROPERTY_DISABLED)
//Filters for the generator picking properties
if(prop.rarity == PROPERTY_RARE || prop.rarity == PROPERTY_LEGENDARY)
- chemical_properties_list["rare"][prop.name] = prop
+ GLOB.chemical_properties_list["rare"][prop.name] = prop
else if(isNegativeProperty(prop))
- chemical_properties_list["negative"][prop.name] = prop
+ GLOB.chemical_properties_list["negative"][prop.name] = prop
else if(isNeutralProperty(prop))
- chemical_properties_list["neutral"][prop.name] = prop
+ GLOB.chemical_properties_list["neutral"][prop.name] = prop
else if(isPositiveProperty(prop))
- chemical_properties_list["positive"][prop.name] = prop
+ GLOB.chemical_properties_list["positive"][prop.name] = prop
/datum/controller/subsystem/reagents/proc/prepare_reagents()
//I dislike having these here but map-objects are initialised before world/New() is called. >_>
@@ -51,11 +51,11 @@ SUBSYSTEM_DEF(reagents)
//Chemical Reagents - Initialises all /datum/reagent into a list indexed by reagent id
//Generated chemicals should be initialized last, hence the substract then readd.
var/list/paths = subtypesof(/datum/reagent) - typesof(/datum/reagent/generated) - subtypesof(/datum/reagent/generated) + subtypesof(/datum/reagent/generated)
- chemical_reagents_list = list()
+ GLOB.chemical_reagents_list = list()
for(var/path in paths)
var/datum/reagent/chem = new path()
chem.save_chemclass()
- chemical_reagents_list[chem.id] = chem
+ GLOB.chemical_reagents_list[chem.id] = chem
//Chemical Reactions - Initialises all /datum/chemical_reaction into a list
// It is filtered into multiple lists within a list.
@@ -63,11 +63,11 @@ SUBSYSTEM_DEF(reagents)
// chemical_reaction_list["phoron"] is a list of all reactions relating to phoron
var/list/regular_paths = subtypesof(/datum/chemical_reaction) - typesof(/datum/chemical_reaction/generated)
var/list/generated_paths = subtypesof(/datum/chemical_reaction/generated) //Generated chemicals should be initialized last
- chemical_reactions_filtered_list = list()
- chemical_reactions_list = list()
+ GLOB.chemical_reactions_filtered_list = list()
+ GLOB.chemical_reactions_list = list()
for(paths in list(regular_paths, generated_paths))
for(var/path in paths)
var/datum/chemical_reaction/react = new path()
- chemical_reactions_list[react.id] = react
+ GLOB.chemical_reactions_list[react.id] = react
react.add_to_filtered_list()
diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm
index 972f61aa530f..2da87df90995 100644
--- a/code/controllers/subsystem/shuttle.dm
+++ b/code/controllers/subsystem/shuttle.dm
@@ -1,11 +1,11 @@
-var/global/datum/controller/shuttle_controller/shuttle_controller
-
SUBSYSTEM_DEF(oldshuttle)
name = "Old Shuttle"
wait = 5.5 SECONDS
init_order = SS_INIT_SHUTTLE
priority = SS_PRIORITY_SHUTTLE
+ var/datum/controller/shuttle_controller/shuttle_controller
+
/datum/controller/subsystem/oldshuttle/Initialize()
if(GLOB.perf_flags & PERF_TOGGLE_SHUTTLES)
can_fire = FALSE
diff --git a/code/controllers/subsystem/shuttles.dm b/code/controllers/subsystem/shuttles.dm
index 34104736949a..3e59744cff31 100644
--- a/code/controllers/subsystem/shuttles.dm
+++ b/code/controllers/subsystem/shuttles.dm
@@ -504,7 +504,7 @@ SUBSYSTEM_DEF(shuttle)
/datum/controller/subsystem/shuttle/tgui_interact(mob/user, datum/tgui/ui)
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
- ui = new(user, src, "ShuttleManipulator", name, 800, 600)
+ ui = new(user, src, "ShuttleManipulator", name, 850, 600)
ui.open()
diff --git a/code/controllers/subsystem/smoke_system.dm b/code/controllers/subsystem/smoke_system.dm
deleted file mode 100644
index 2010687fcba2..000000000000
--- a/code/controllers/subsystem/smoke_system.dm
+++ /dev/null
@@ -1,31 +0,0 @@
-var/list/active_smoke_effects = list()
-
-
-SUBSYSTEM_DEF(smoke_effects)
- name = "Smoke Effects"
- wait = 1 SECONDS
- flags = SS_NO_INIT | SS_KEEP_TIMING
- priority = SS_PRIORITY_OBJECTS
-
- var/list/currentrun = list()
-
-/datum/controller/subsystem/smoke_effects/stat_entry(msg)
- msg = "P:[active_smoke_effects.len]"
- return ..()
-
-
-/datum/controller/subsystem/smoke_effects/fire(resumed = FALSE)
- if(!resumed)
- currentrun = active_smoke_effects.Copy()
-
- while(currentrun.len)
- var/obj/effect/particle_effect/smoke/E = currentrun[currentrun.len]
- currentrun.len--
-
- if(!E || QDELETED(E))
- continue
-
- E.process()
-
- if(MC_TICK_CHECK)
- return
diff --git a/code/controllers/subsystem/sound.dm b/code/controllers/subsystem/sound.dm
index 1935294394e7..4fdfd7935349 100644
--- a/code/controllers/subsystem/sound.dm
+++ b/code/controllers/subsystem/sound.dm
@@ -41,5 +41,5 @@ SUBSYSTEM_DEF(sound)
if(VI?.ready)
var/list/bounds = VI.get_middle_coords()
if(bounds.len >= 2)
- hearers |= SSquadtree.players_in_range(RECT(bounds[1], bounds[2], VI.map_template.height, VI.map_template.width), bounds[3])
+ hearers |= SSquadtree.players_in_range(RECT(bounds[1], bounds[2], VI.map_template.width, VI.map_template.height), bounds[3])
template_queue[template] = hearers
diff --git a/code/controllers/subsystem/stamina.dm b/code/controllers/subsystem/stamina.dm
deleted file mode 100644
index 84d5b4038cd0..000000000000
--- a/code/controllers/subsystem/stamina.dm
+++ /dev/null
@@ -1,25 +0,0 @@
-var/global/list/active_staminas = list()
-
-SUBSYSTEM_DEF(stamina)
- name = "Stamina"
- wait = 2 SECONDS
- priority = SS_PRIORITY_STAMINA
- flags = SS_NO_INIT
- var/list/currentrun = list()
-
-
-/datum/controller/subsystem/stamina/fire(resumed = FALSE)
- if (!resumed)
- currentrun = active_staminas.Copy()
-
- while (currentrun.len)
- var/datum/stamina/S = currentrun[currentrun.len]
- currentrun.len--
-
- if (!S || QDELETED(S))
- continue
-
- S.process()
-
- if (MC_TICK_CHECK)
- return
diff --git a/code/controllers/subsystem/statpanel.dm b/code/controllers/subsystem/statpanel.dm
index 9a94eb3371f9..b65ca1e758a2 100644
--- a/code/controllers/subsystem/statpanel.dm
+++ b/code/controllers/subsystem/statpanel.dm
@@ -44,6 +44,9 @@ SUBSYSTEM_DEF(statpanels)
var/client/target = currentrun[length(currentrun)]
currentrun.len--
+ if(!target)
+ continue
+
if(!target.stat_panel.is_ready())
continue
@@ -313,14 +316,39 @@ SUBSYSTEM_DEF(statpanels)
for(index in 1 to length(to_make))
var/atom/thing = to_make[index]
+ // var/start_time = REALTIMEOFDAY
var/generated_string
- /* We're cheap and won't render all overlays. It's expensive and updates with onmob changes!
- if(ismob(thing) || length(thing.overlays) > 2)
- generated_string = costly_icon2html(thing, parent, sourceonly=TRUE)
+ // We're cheap and won't render all overlays. It's expensive and updates with onmob changes!
+ //if(ismob(thing) || length(thing.overlays) > 2)
+ //generated_string = costly_icon2html(thing, parent, sourceonly=TRUE)
+ if(ishuman(thing))
+ var/mob/living/carbon/human/human_thing = thing
+ var/icon
+
+ // Ensure they have their armor since its going to be the majority of their appearance
+ var/list/armor = list()
+ var/obj/item/uniform = human_thing.get_item_by_slot(WEAR_BODY)
+ if(uniform)
+ armor += new uniform.type
+ var/obj/item/hat = human_thing.get_item_by_slot(WEAR_HEAD)
+ if(hat)
+ armor += new hat.type
+ var/obj/item/suit = human_thing.get_item_by_slot(WEAR_JACKET)
+ if(suit)
+ armor += new suit.type
+ var/obj/item/gloves = human_thing.get_item_by_slot(WEAR_HANDS)
+ if(gloves)
+ armor += new gloves.type
+ var/obj/item/shoes = human_thing.get_item_by_slot(WEAR_FEET)
+ if(shoes)
+ armor += new shoes.type
+
+ // If we don't succeed making a flat human icon below, allowing the human to pass into icon2html will throw a bad icon operation because of a workaround in icon2html for humans...
+ icon = get_flat_human_copy_icon(human_thing, showDirs = list(SOUTH), outfit_override = armor)
+ generated_string = icon2html(icon, parent, sourceonly=TRUE)
+ // log_debug("object_window_info called on ref=[REF(thing)], instance=[thing], type=[thing.type], finished in [(REALTIMEOFDAY-start_time) / 10]s")
else
generated_string = icon2html(thing, parent, sourceonly=TRUE)
- */
- generated_string = icon2html(thing, parent, sourceonly=TRUE)
newly_seen[thing] = generated_string
if(TICK_CHECK)
@@ -383,8 +411,10 @@ SUBSYSTEM_DEF(statpanels)
set name = "Open Statbrowser Options"
set hidden = TRUE
+ if (!current_fontsize)
+ current_fontsize = 12
- var/datum/statbrowser_options/SM = statbrowser_options
- if(!SM)
- SM = statbrowser_options = new(src, current_fontsize)
- SM.tgui_interact()
+ var/datum/statbrowser_options/options_panel = statbrowser_options
+ if(!options_panel)
+ options_panel = statbrowser_options = new(src, current_fontsize)
+ options_panel.tgui_interact()
diff --git a/code/controllers/subsystem/stats_collector.dm b/code/controllers/subsystem/stats_collector.dm
deleted file mode 100644
index de66e3b2c6b1..000000000000
--- a/code/controllers/subsystem/stats_collector.dm
+++ /dev/null
@@ -1,17 +0,0 @@
-/// Collects simple round statistics periodically
-SUBSYSTEM_DEF(stats_collector)
- name = "Round Stats"
- wait = 30 SECONDS
- priority = SS_PRIORITY_PAGER_STATUS
- runlevels = RUNLEVELS_DEFAULT | RUNLEVEL_LOBBY
- flags = SS_KEEP_TIMING | SS_NO_INIT
-
- var/stat_ticks = 0
- var/players_counter = 0
-
-/datum/controller/subsystem/stats_collector/fire(resumed = FALSE)
- players_counter += length(GLOB.clients)
- stat_ticks++
-
-/datum/controller/subsystem/stats_collector/proc/get_avg_players()
- return players_counter / stat_ticks
diff --git a/code/controllers/subsystem/techtree.dm b/code/controllers/subsystem/techtree.dm
index 04ac2591bc15..5f22373228f0 100644
--- a/code/controllers/subsystem/techtree.dm
+++ b/code/controllers/subsystem/techtree.dm
@@ -34,17 +34,6 @@ SUBSYSTEM_DEF(techtree)
var/datum/space_level/zpos = SSmapping.add_new_zlevel(tree.name, list(ZTRAIT_TECHTREE))
tree.zlevel = zpos
- var/zlevel = zpos.z_value
- var/turf/z_min = locate(1, 1, zlevel)
- var/turf/z_max = locate(world.maxx, world.maxy, zlevel)
-
-
-
- for(var/t in block(z_min, z_max))
- var/turf/Tu = t
- Tu.ChangeTurf(/turf/closed/void, list(/turf/closed/void))
- new /area/techtree(Tu)
-
for(var/tier in tree.tree_tiers)
tree.unlocked_techs += tier
tree.all_techs += tier
diff --git a/code/controllers/subsystem/teleporter.dm b/code/controllers/subsystem/teleporter.dm
deleted file mode 100644
index b753bdb0d519..000000000000
--- a/code/controllers/subsystem/teleporter.dm
+++ /dev/null
@@ -1,10 +0,0 @@
-// Master teleporter controller.
-SUBSYSTEM_DEF(teleporter)
- name = "Teleporter"
- wait = 5 SECONDS
- init_order = SS_INIT_TELEPORTER
- priority = SS_PRIORITY_TELEPORTER
- flags = SS_NO_FIRE|SS_NO_INIT
-
- var/list/teleporters_by_id = list() // Associative list of teleporters by ID, master list of teleporters to process
- var/list/teleporters = list() // Process list (identical contents to teleporters_by_id)
diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm
index 88627669aa3b..2e11ba8a96cb 100644
--- a/code/controllers/subsystem/ticker.dm
+++ b/code/controllers/subsystem/ticker.dm
@@ -46,6 +46,7 @@ SUBSYSTEM_DEF(ticker)
var/totalPlayers = 0 //used for pregame stats on statpanel
var/totalPlayersReady = 0 //used for pregame stats on statpanel
+ var/tutorial_disabled = FALSE //zonenote
/datum/controller/subsystem/ticker/Initialize(timeofday)
load_mode()
@@ -97,9 +98,9 @@ SUBSYSTEM_DEF(ticker)
if(!roundend_check_paused && mode.check_finished(force_ending) || force_ending)
current_state = GAME_STATE_FINISHED
- ooc_allowed = TRUE
+ GLOB.ooc_allowed = TRUE
mode.declare_completion(force_ending)
- REDIS_PUBLISH("byond.round", "type" = "round-complete")
+ REDIS_PUBLISH("byond.round", "type" = "round-complete", "round_name" = GLOB.round_statistics.round_name)
flash_clients()
addtimer(CALLBACK(
SSvote,
@@ -135,8 +136,8 @@ SUBSYSTEM_DEF(ticker)
REDIS_PUBLISH("byond.round", "type" = "round-start")
for(var/client/C in GLOB.admins)
- remove_verb(C, roundstart_mod_verbs)
- admin_verbs_minor_event -= roundstart_mod_verbs
+ remove_verb(C, GLOB.roundstart_mod_verbs)
+ GLOB.admin_verbs_minor_event -= GLOB.roundstart_mod_verbs
return TRUE
@@ -173,14 +174,14 @@ SUBSYSTEM_DEF(ticker)
if(!mode.can_start(bypass_checks))
to_chat(world, "Reverting to pre-game lobby.")
QDEL_NULL(mode)
- RoleAuthority.reset_roles()
+ GLOB.RoleAuthority.reset_roles()
return FALSE
CHECK_TICK
if(!mode.pre_setup() && !bypass_checks)
QDEL_NULL(mode)
to_chat(world, "Error in pre-setup for [GLOB.master_mode]. Reverting to pre-game lobby.")
- RoleAuthority.reset_roles()
+ GLOB.RoleAuthority.reset_roles()
return FALSE
CHECK_TICK
@@ -194,7 +195,7 @@ SUBSYSTEM_DEF(ticker)
if(CONFIG_GET(flag/autooocmute))
- ooc_allowed = FALSE
+ GLOB.ooc_allowed = FALSE
round_start_time = world.time
@@ -213,7 +214,7 @@ SUBSYSTEM_DEF(ticker)
var/roles_to_roll = null
if(length(mode.roles_to_roll))
roles_to_roll = mode.roles_to_roll
- RoleAuthority.setup_candidates_and_roles(roles_to_roll) //Distribute jobs
+ GLOB.RoleAuthority.setup_candidates_and_roles(roles_to_roll) //Distribute jobs
if(mode.flags_round_type & MODE_NEW_SPAWN)
create_characters() // Create and equip characters
else
@@ -235,7 +236,7 @@ SUBSYSTEM_DEF(ticker)
setup_economy()
- shuttle_controller?.setup_shuttle_docks()
+ SSoldshuttle.shuttle_controller?.setup_shuttle_docks()
PostSetup()
return TRUE
@@ -251,15 +252,15 @@ SUBSYSTEM_DEF(ticker)
// Switch back to default automatically
save_mode(CONFIG_GET(string/gamemode_default))
- if(round_statistics)
- to_chat_spaced(world, html = FONT_SIZE_BIG(SPAN_ROLE_BODY("Welcome to [round_statistics.round_name]")))
+ if(GLOB.round_statistics)
+ to_chat_spaced(world, html = FONT_SIZE_BIG(SPAN_ROLE_BODY("Welcome to [GLOB.round_statistics.round_name]")))
- supply_controller.process() //Start the supply shuttle regenerating points -- TLE
+ GLOB.supply_controller.start_processing()
for(var/i in GLOB.closet_list) //Set up special equipment for lockers and vendors, depending on gamemode
var/obj/structure/closet/C = i
INVOKE_ASYNC(C, TYPE_PROC_REF(/obj/structure/closet, select_gamemode_equipment), mode.type)
- for(var/obj/structure/machinery/vending/V in machines)
+ for(var/obj/structure/machinery/vending/V in GLOB.machines)
INVOKE_ASYNC(V, TYPE_PROC_REF(/obj/structure/machinery/vending, select_gamemode_equipment), mode.type)
SEND_GLOBAL_SIGNAL(COMSIG_GLOB_POST_SETUP)
@@ -376,7 +377,7 @@ SUBSYSTEM_DEF(ticker)
world.Reboot(TRUE)
/datum/controller/subsystem/ticker/proc/create_characters()
- if(!RoleAuthority)
+ if(!GLOB.RoleAuthority)
return
for(var/mob/new_player/player in GLOB.player_list)
@@ -386,7 +387,7 @@ SUBSYSTEM_DEF(ticker)
INVOKE_ASYNC(src, PROC_REF(spawn_and_equip_char), player)
/datum/controller/subsystem/ticker/proc/spawn_and_equip_char(mob/new_player/player)
- var/datum/job/J = RoleAuthority.roles_for_mode[player.job]
+ var/datum/job/J = GLOB.RoleAuthority.roles_for_mode[player.job]
if(J.job_options && player?.client?.prefs?.pref_special_job_options[J.title])
J.handle_job_options(player.client.prefs.pref_special_job_options[J.title])
if(J.handle_spawn_and_equip)
@@ -424,7 +425,7 @@ SUBSYSTEM_DEF(ticker)
if(player.job == JOB_CO)
captainless = FALSE
if(player.job)
- RoleAuthority.equip_role(player, RoleAuthority.roles_by_name[player.job], late_join = FALSE)
+ GLOB.RoleAuthority.equip_role(player, GLOB.RoleAuthority.roles_by_name[player.job], late_join = FALSE)
EquipCustomItems(player)
if(player.client)
var/client/C = player.client
@@ -478,7 +479,6 @@ SUBSYSTEM_DEF(ticker)
winset(C, null, "mainwindow.icon=[SSticker.mode.taskbar_icon]")
-
/datum/controller/subsystem/ticker/proc/hijack_ocurred()
if(mode)
mode.is_in_endgame = TRUE
diff --git a/code/controllers/subsystem/vote.dm b/code/controllers/subsystem/vote.dm
index 3882228a5ab1..104bb838bbcf 100644
--- a/code/controllers/subsystem/vote.dm
+++ b/code/controllers/subsystem/vote.dm
@@ -273,10 +273,11 @@ SUBSYSTEM_DEF(vote)
question = "Gamemode vote"
randomize_entries = TRUE
for(var/mode_type in config.gamemode_cache)
- var/datum/game_mode/M = initial(mode_type)
+ var/datum/game_mode/M = mode_type
if(initial(M.config_tag))
var/vote_cycle_met = !initial(M.vote_cycle) || (text2num(SSperf_logging?.round?.id) % initial(M.vote_cycle) == 0)
- if(initial(M.votable) && vote_cycle_met)
+ var/min_players_met = length(GLOB.clients) >= M.required_players
+ if(initial(M.votable) && vote_cycle_met && min_players_met)
choices += initial(M.config_tag)
if("groundmap")
question = "Ground map vote"
@@ -359,7 +360,7 @@ SUBSYSTEM_DEF(vote)
log_vote(text)
var/vp = CONFIG_GET(number/vote_period)
SEND_SOUND(world, sound(vote_sound, channel = SOUND_CHANNEL_VOX, volume = vote_sound_vol))
- to_chat(world, SPAN_CENTERBOLD("
[text] Type vote or click here to place your votes. You have [DisplayTimeText(vp)] to vote.
"))
+ to_chat(world, SPAN_CENTERBOLD("
[text] Type vote or click here to place your votes. You have [DisplayTimeText(vp)] to vote.
"))
time_remaining = round(vp/10)
for(var/c in GLOB.clients)
var/client/C = c
diff --git a/code/controllers/subsystem/weather.dm b/code/controllers/subsystem/weather.dm
index 325c45fe2300..a3fdfe509a96 100644
--- a/code/controllers/subsystem/weather.dm
+++ b/code/controllers/subsystem/weather.dm
@@ -1,4 +1,4 @@
-var/list/weather_notify_objects = list()
+GLOBAL_LIST_EMPTY(weather_notify_objects)
SUBSYSTEM_DEF(weather)
name = "Weather"
@@ -46,7 +46,7 @@ SUBSYSTEM_DEF(weather)
/datum/controller/subsystem/weather/proc/setup_weather_areas()
weather_areas = list()
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(A.weather_enabled && map_holder.should_affect_area(A))
weather_areas += A
diff --git a/code/controllers/subsystem/x_evolution.dm b/code/controllers/subsystem/x_evolution.dm
index be787b37de80..2232147d2eb8 100644
--- a/code/controllers/subsystem/x_evolution.dm
+++ b/code/controllers/subsystem/x_evolution.dm
@@ -11,6 +11,7 @@ SUBSYSTEM_DEF(xevolution)
var/time_ratio_modifier = 0.4
var/list/boost_power = list()
+ var/list/overridden_power = list()
var/force_boost_power = FALSE // Debugging only
/datum/controller/subsystem/xevolution/Initialize(start_timeofday)
@@ -18,6 +19,7 @@ SUBSYSTEM_DEF(xevolution)
for(var/hivenumber in GLOB.hive_datum)
HS = GLOB.hive_datum[hivenumber]
boost_power[HS.hivenumber] = 1
+ overridden_power[HS.hivenumber] = FALSE
return SS_INIT_SUCCESS
/datum/controller/subsystem/xevolution/fire(resumed = FALSE)
@@ -27,6 +29,9 @@ SUBSYSTEM_DEF(xevolution)
if(!HS)
continue
+ if(overridden_power[HS.hivenumber])
+ continue
+
if(!HS.dynamic_evolution)
boost_power[HS.hivenumber] = HS.evolution_rate + HS.evolution_bonus
HS.hive_ui.update_burrowed_larva()
@@ -54,6 +59,12 @@ SUBSYSTEM_DEF(xevolution)
/datum/controller/subsystem/xevolution/proc/get_evolution_boost_power(hivenumber)
return boost_power[hivenumber]
+/datum/controller/subsystem/xevolution/proc/override_power(hivenumber, power, override)
+ var/datum/hive_status/hive_status = GLOB.hive_datum[hivenumber]
+ boost_power[hivenumber] = power
+ overridden_power[hivenumber] = override
+ hive_status.hive_ui.update_burrowed_larva()
+
#undef EVOLUTION_INCREMENT_TIME
#undef BOOST_POWER_MIN
#undef BOOST_POWER_MAX
diff --git a/code/controllers/subsystem/xenocon.dm b/code/controllers/subsystem/xenocon.dm
deleted file mode 100644
index d16e59bd9813..000000000000
--- a/code/controllers/subsystem/xenocon.dm
+++ /dev/null
@@ -1,18 +0,0 @@
-SUBSYSTEM_DEF(xenocon)
- name = "XENOCON"
- wait = 5 SECONDS
- priority = SS_PRIORITY_INACTIVITY
- flags = SS_NO_INIT
- var/rewarded = FALSE
-
-/datum/controller/subsystem/xenocon/fire(resumed = FALSE)
- if(rewarded)
- return
-
- var/datum/hive_status/hive
- for(var/hivenumber in GLOB.hive_datum)
- hive = GLOB.hive_datum[hivenumber]
- if(hive.xenocon_points >= XENOCON_THRESHOLD)
- var/datum/emergency_call/em_call = new /datum/emergency_call/xenos/platoon()
- em_call.activate()
- rewarded = TRUE
diff --git a/code/datums/ASRS.dm b/code/datums/ASRS.dm
index 86a7363f07ea..57eff892fa58 100644
--- a/code/datums/ASRS.dm
+++ b/code/datums/ASRS.dm
@@ -2,133 +2,116 @@
//These are non orderable packs that get in automaticly though the ARSR system.
//Note these should never show up to buy and some will only show up later in the round.
//BIG NOTE: Don't add living things to crates, that's bad, it will break the shuttle.
-//We use the cost to determine the spawn chance this equals out the crates that spawn later in the round.
-#define ASRS_HIGHEST_WEIGHT 0 //warning this weight wont change.
-#define ASRS_VERY_HIGH_WEIGHT 5
-#define ASRS_HIGH_WEIGHT 15
-#define ASRS_MEDIUM_WEIGHT 25
-#define ASRS_LOW_WEIGHT 35
-#define ASRS_VERY_LOW_WEIGHT 50
-#define ASRS_LOWEST_WEIGHT 100
+
+
+/datum/supply_packs_asrs
+ /// How likely we are to select this pack over others
+ var/cost = ASRS_MEDIUM_WEIGHT
+ /// Which pool of ASRS automatically dispensed supplies this belongs to
+ var/pool = ASRS_POOL_MAIN
+ /// What supply pack would this dispense
+ var/datum/supply_packs/reference_package
//===================================
// Rounds
-/datum/supply_packs/ammo_rounds_box_rifle/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_rounds_box_rifle
+ reference_package = /datum/supply_packs/ammo_rounds_box_rifle
cost = ASRS_MEDIUM_WEIGHT
-/datum/supply_packs/ammo_rounds_box_rifle_ap/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_rounds_box_rifle_ap
+ reference_package = /datum/supply_packs/ammo_rounds_box_rifle_ap
cost = ASRS_LOW_WEIGHT
-/datum/supply_packs/ammo_rounds_box_xm88/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_rounds_box_xm88
+ reference_package = /datum/supply_packs/ammo_rounds_box_xm88
cost = ASRS_LOW_WEIGHT
//===================================
// Magazines
-/datum/supply_packs/gun/ammo_hpr/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/gun/ammo_hpr
+ reference_package = /datum/supply_packs/ammo_hpr
cost = ASRS_LOWEST_WEIGHT
-/datum/supply_packs/ammo_m4a3_mag_box/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_m4a3_mag_box
+ reference_package = /datum/supply_packs/ammo_m4a3_mag_box
cost = ASRS_LOW_WEIGHT
-/datum/supply_packs/ammo_m4a3_mag_box_ap/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_m4a3_mag_box_ap
+ reference_package = /datum/supply_packs/ammo_m4a3_mag_box_ap
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/ammo_mag_box/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_mag_box
+ reference_package = /datum/supply_packs/ammo_mag_box
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/ammo_mag_box_ap/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_mag_box_ap
+ reference_package = /datum/supply_packs/ammo_mag_box_ap
-/datum/supply_packs/ammo_m4ra_mag_box/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_m4ra_mag_box
+ reference_package = /datum/supply_packs/ammo_m4ra_mag_box
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/ammo_m4ra_mag_box_ap/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_m4ra_mag_box_ap
+ reference_package = /datum/supply_packs/ammo_m4ra_mag_box_ap
-/datum/supply_packs/ammo_shell_box/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_shell_box
+ reference_package = /datum/supply_packs/ammo_shell_box
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/ammo_shell_box_buck/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_shell_box_buck
+ reference_package = /datum/supply_packs/ammo_shell_box_buck
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/ammo_shell_box_flechette/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_shell_box_flechette
+ reference_package = /datum/supply_packs/ammo_shell_box_flechette
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/ammo_smartgun/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_smartgun
+ reference_package = /datum/supply_packs/ammo_smartgun
-/datum/supply_packs/ammo_napalm/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_napalm
+ reference_package = /datum/supply_packs/ammo_napalm
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/ammo_napalm_gel/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_napalm_gel
+ reference_package = /datum/supply_packs/ammo_napalm_gel
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/ammo_flamer_mixed/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_flamer_mixed
+ reference_package = /datum/supply_packs/ammo_flamer_mixed
cost = ASRS_VERY_LOW_WEIGHT
//===================================
// Mortar ammo
-/datum/supply_packs/ammo_mortar_he/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_mortar_he
+ reference_package = /datum/supply_packs/ammo_mortar_he
-/datum/supply_packs/ammo_mortar_incend/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_mortar_incend
+ reference_package = /datum/supply_packs/ammo_mortar_incend
-/datum/supply_packs/ammo_mortar_flare/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/ammo_mortar_flare
+ reference_package = /datum/supply_packs/ammo_mortar_flare
//===================================
// Misc supplies
-/datum/supply_packs/flares/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/flares
+ reference_package = /datum/supply_packs/flares
cost = ASRS_LOW_WEIGHT
-/datum/supply_packs/mre/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/mre
+ reference_package = /datum/supply_packs/mre
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/flashlights/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/flashlights
+ reference_package = /datum/supply_packs/flashlights
cost = ASRS_VERY_LOW_WEIGHT
-/datum/supply_packs/batteries/asrs
- buyable = 0
- group = "ASRS"
+/datum/supply_packs_asrs/batteries
+ reference_package = /datum/supply_packs/batteries
cost = ASRS_VERY_LOW_WEIGHT
+
+// ============================
+// FOOD POOL - for Mess Tech gradual supplies throughout the round
+/datum/supply_packs_asrs/ingredient
+ reference_package = /datum/supply_packs/ingredient
+ pool = ASRS_POOL_FOOD
diff --git a/code/datums/_atmos_setup.dm b/code/datums/_atmos_setup.dm
index be4dc62faeff..3075e98ac464 100644
--- a/code/datums/_atmos_setup.dm
+++ b/code/datums/_atmos_setup.dm
@@ -14,18 +14,18 @@
#define PIPE_COLOR_YELLOW "#ffcc00"
#define PIPE_COLOR_PURPLE "#5c1ec0"
-var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "purple" = PIPE_COLOR_PURPLE)
+GLOBAL_LIST_INIT(pipe_colors, list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_RED, "blue" = PIPE_COLOR_BLUE, "cyan" = PIPE_COLOR_CYAN, "green" = PIPE_COLOR_GREEN, "yellow" = PIPE_COLOR_YELLOW, "purple" = PIPE_COLOR_PURPLE))
/proc/pipe_color_lookup(color)
- for(var/C in pipe_colors)
- if(color == pipe_colors[C])
+ for(var/C in GLOB.pipe_colors)
+ if(color == GLOB.pipe_colors[C])
return "[C]"
/proc/pipe_color_check(color)
if(!color)
return 1
- for(var/C in pipe_colors)
- if(color == pipe_colors[C])
+ for(var/C in GLOB.pipe_colors)
+ if(color == GLOB.pipe_colors[C])
return 1
return 0
@@ -89,10 +89,10 @@ var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_
var/image/I = image('icons/obj/pipes/pipes.dmi', icon_state = state)
pipe_icons[cache_name] = I
- for(var/pipe_color in pipe_colors)
+ for(var/pipe_color in GLOB.pipe_colors)
I = image('icons/obj/pipes/pipes.dmi', icon_state = state)
- I.color = pipe_colors[pipe_color]
- pipe_icons[state + "[pipe_colors[pipe_color]]"] = I
+ I.color = GLOB.pipe_colors[pipe_color]
+ pipe_icons[state + "[GLOB.pipe_colors[pipe_color]]"] = I
pipe = new ('icons/obj/pipes/heat.dmi')
for(var/state in pipe.IconStates())
@@ -122,10 +122,10 @@ var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_
if(findtext(state, "core") || findtext(state, "4way"))
var/image/I = image('icons/obj/pipes/manifold.dmi', icon_state = state)
manifold_icons[state] = I
- for(var/pipe_color in pipe_colors)
+ for(var/pipe_color in GLOB.pipe_colors)
I = image('icons/obj/pipes/manifold.dmi', icon_state = state)
- I.color = pipe_colors[pipe_color]
- manifold_icons[state + pipe_colors[pipe_color]] = I
+ I.color = GLOB.pipe_colors[pipe_color]
+ manifold_icons[state + GLOB.pipe_colors[pipe_color]] = I
/datum/pipe_icon_manager/proc/gen_device_icons()
if(!device_icons)
@@ -170,13 +170,13 @@ var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_
var/cache_name = state
- for(var/D in cardinal)
+ for(var/D in GLOB.cardinals)
var/image/I = image('icons/obj/pipes/pipe_underlays.dmi', icon_state = state, dir = D)
underlays[cache_name + "[D]"] = I
- for(var/pipe_color in pipe_colors)
+ for(var/pipe_color in GLOB.pipe_colors)
I = image('icons/obj/pipes/pipe_underlays.dmi', icon_state = state, dir = D)
- I.color = pipe_colors[pipe_color]
- underlays[state + "[D]" + "[pipe_colors[pipe_color]]"] = I
+ I.color = GLOB.pipe_colors[pipe_color]
+ underlays[state + "[D]" + "[GLOB.pipe_colors[pipe_color]]"] = I
/*
Leaving the old icon manager code commented out for now, as we may want to rewrite the new code to cleanly
@@ -202,7 +202,7 @@ var/global/list/pipe_colors = list("grey" = PIPE_COLOR_GREY, "red" = PIPE_COLOR_
if(state == "")
continue
- for(var/D in cardinal)
+ for(var/D in GLOB.cardinals)
var/image/I = image('icons/atmos/pipe_underlays.dmi', icon_state = state, dir = D)
switch(state)
if("intact")
diff --git a/code/datums/_ndatabase/code/brsql_adapter.dm b/code/datums/_ndatabase/code/brsql_adapter.dm
index 345ddfe005f3..251267a04fdb 100644
--- a/code/datums/_ndatabase/code/brsql_adapter.dm
+++ b/code/datums/_ndatabase/code/brsql_adapter.dm
@@ -101,8 +101,8 @@
SSdatabase.create_parametric_query(query_updatetable, qpars, CB)
/datum/db/adapter/brsql_adapter/insert_table(table_name, list/values, datum/callback/CB, sync = FALSE)
- if(!sync)
- set waitfor = 0
+ set waitfor = FALSE
+
var/length = values.len
var/list/qpars = list()
var/query_inserttable = getquery_insert_table(table_name, values, qpars)
@@ -530,7 +530,7 @@
if(first && !is_id)
if(!items_first)
update_items+=","
- update_items+="`[table_name]`.[esfield]=`__prep_update`.[esfield]"
+ update_items+="`[table_name]`.[esfield]=`subquery`.[esfield]"
items_first = FALSE
local_first = FALSE
calltext += "SELECT [local_text]"
@@ -539,9 +539,7 @@
issue_log += "No ID passed to update query."
return "" // AAAAAAAAAAAAAH FUCK DON'T JUST KILL THE ENTIRE FUCKING TABLE BRUH
return {"
- WITH __prep_update as (
- [calltext]
- ) UPDATE `[connection.database]`.`[table_name]` INNER JOIN `__prep_update` ON `[table_name]`.id = `__prep_update`.id SET [update_items]
+ UPDATE `[connection.database]`.`[table_name]` JOIN (WITH `__prep_update` AS ( [calltext] ) SELECT * FROM `__prep_update`) subquery ON `[table_name]`.id = subquery.id SET [update_items]
"}
/datum/db/adapter/brsql_adapter/proc/getquery_delete_table(table_name, list/ids)
diff --git a/code/datums/_ndatabase/code/interfaces/connection_settings.dm b/code/datums/_ndatabase/code/interfaces/connection_settings.dm
index 4092ee712ba9..0c990b2b9cbc 100644
--- a/code/datums/_ndatabase/code/interfaces/connection_settings.dm
+++ b/code/datums/_ndatabase/code/interfaces/connection_settings.dm
@@ -33,5 +33,3 @@
if(!typestr)
typestr = /datum/db/connection_settings/native
return new typestr(config)
-
-var/global/datum/db/connection_settings/connection_settings
diff --git a/code/datums/_ndatabase/code/native_adapter.dm b/code/datums/_ndatabase/code/native_adapter.dm
index a5e4d41fb6a0..1c23a6ceab8f 100644
--- a/code/datums/_ndatabase/code/native_adapter.dm
+++ b/code/datums/_ndatabase/code/native_adapter.dm
@@ -83,8 +83,7 @@
SSdatabase.create_query(query_gettable, CB)
/datum/db/adapter/native_adapter/update_table(table_name, list/values, datum/callback/CB, sync = FALSE)
- if(!sync)
- set waitfor = 0
+ set waitfor = FALSE
for(var/list/vals in values)
var/list/qpars = list()
diff --git a/code/datums/_ndatabase/subsystems/database_query_manager.dm b/code/datums/_ndatabase/subsystems/database_query_manager.dm
index 7eef5842e2dd..596d55121920 100644
--- a/code/datums/_ndatabase/subsystems/database_query_manager.dm
+++ b/code/datums/_ndatabase/subsystems/database_query_manager.dm
@@ -19,8 +19,7 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-var/datum/controller/subsystem/database_query_manager/SSdatabase
-
+GLOBAL_REAL(SSdatabase, /datum/controller/subsystem/database_query_manager)
/datum/controller/subsystem/database_query_manager
name = "Database QM"
wait = 1
diff --git a/code/datums/_ndatabase/subsystems/entity_manager.dm b/code/datums/_ndatabase/subsystems/entity_manager.dm
index 667f2a855563..833bc6926e09 100644
--- a/code/datums/_ndatabase/subsystems/entity_manager.dm
+++ b/code/datums/_ndatabase/subsystems/entity_manager.dm
@@ -19,7 +19,7 @@
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
// SOFTWARE.
-var/datum/controller/subsystem/entity_manager/SSentity_manager
+GLOBAL_REAL(SSentity_manager, /datum/controller/subsystem/entity_manager)
/datum/controller/subsystem/entity_manager
name = "Entity Manager"
diff --git a/code/datums/action.dm b/code/datums/action.dm
index 47b302e09aac..3a597ad262b1 100644
--- a/code/datums/action.dm
+++ b/code/datums/action.dm
@@ -11,9 +11,9 @@
var/cost = 0 // By default an action has no cost -> will be utilized by skill actions/xeno actions
var/action_flags = 0 // Check out __game.dm for flags
/// Whether the action is hidden from its owner
- /// Useful for when you want to preserve action state while preventing
- /// a mob from using said action
- var/hidden = FALSE
+ var/hidden = FALSE //Preserve action state while preventing mob from using action
+ ///Hide the action from the owner without preventing them from using it (incase of keybind listen_signal)
+ var/player_hidden = FALSE
var/unique = TRUE
/// A signal on the mob that will cause the action to activate
var/listen_signal
@@ -187,8 +187,10 @@
I.ui_action_click(owner, holder_item)
/datum/action/item_action/can_use_action()
- if(ishuman(owner) && !owner.is_mob_incapacitated() && !owner.lying)
- return TRUE
+ if(ishuman(owner) && !owner.is_mob_incapacitated())
+ var/mob/living/carbon/human/human = owner
+ if(human.body_position == STANDING_UP)
+ return TRUE
/datum/action/item_action/update_button_icon()
button.overlays.Cut()
@@ -225,7 +227,7 @@
var/atom/movable/screen/action_button/B = A.button
if(reload_screen)
client.add_to_screen(B)
- if(A.hidden)
+ if(A.hidden || A.player_hidden)
B.screen_loc = null
continue
button_number++
diff --git a/code/datums/agents/tools/chloroform.dm b/code/datums/agents/tools/chloroform.dm
index 464533309bcc..b1c666ac9ec8 100644
--- a/code/datums/agents/tools/chloroform.dm
+++ b/code/datums/agents/tools/chloroform.dm
@@ -47,10 +47,9 @@
/obj/item/weapon/chloroform/proc/grab_stun(mob/living/M, mob/living/user)
M.anchored = TRUE
- M.frozen = TRUE
- M.density = FALSE
+ ADD_TRAIT(M, TRAIT_IMMOBILIZED, CHLOROFORM_TRAIT)
+ ADD_TRAIT(M, TRAIT_UNDENSE, CHLOROFORM_TRAIT)
M.able_to_speak = FALSE
- M.update_canmove()
M.drop_inv_item_on_ground(M.wear_mask, force = TRUE)
@@ -79,10 +78,10 @@
/obj/item/weapon/chloroform/proc/remove_stun(mob/living/M)
animate(M, pixel_x = 0, pixel_y = 0, time = 0.2 SECONDS, easing = QUAD_EASING)
M.anchored = FALSE
- M.density = TRUE
M.able_to_speak = TRUE
M.layer = MOB_LAYER
- M.unfreeze()
+ REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, CHLOROFORM_TRAIT)
+ REMOVE_TRAIT(M, TRAIT_UNDENSE, CHLOROFORM_TRAIT)
QDEL_NULL(mask_item)
diff --git a/code/datums/agents/tools/tracker.dm b/code/datums/agents/tools/tracker.dm
index 1d6d6d4801b4..2f3063afb78c 100644
--- a/code/datums/agents/tools/tracker.dm
+++ b/code/datums/agents/tools/tracker.dm
@@ -12,7 +12,7 @@
overlays.Cut()
if(active && tracked_object)
- overlays += icon(icon, "+tracker_arrow", get_dir(src, tracked_object))
+ overlays += icon(icon, "+tracker_arrow", Get_Compass_Dir(src, tracked_object))
/obj/item/device/tracker/attack_self(mob/user)
if(!skillcheckexplicit(user, SKILL_ANTAG, SKILL_ANTAG_AGENT))
@@ -48,12 +48,12 @@
return ..()
/obj/item/device/tracker/proc/select_object(mob/user)
- if(!LAZYLEN(objects_of_interest))
+ if(!LAZYLEN(GLOB.objects_of_interest))
to_chat(user, SPAN_WARNING("There are nothing of interest to track."))
return
var/list/object_choices = list()
- for(var/obj/O in objects_of_interest)
+ for(var/obj/O in GLOB.objects_of_interest)
var/z_level_to_compare_from = O.z
if(istype(O.loc, /obj/structure/surface))
z_level_to_compare_from = O.loc.z
diff --git a/code/datums/ammo/ammo.dm b/code/datums/ammo/ammo.dm
new file mode 100644
index 000000000000..7a4006deee73
--- /dev/null
+++ b/code/datums/ammo/ammo.dm
@@ -0,0 +1,247 @@
+/datum/ammo
+ var/name = "generic bullet"
+ //Icon state when a human is permanently killed with it by execution/suicide.
+ var/headshot_state = null
+ var/icon = 'icons/obj/items/weapons/projectiles.dmi'
+ var/icon_state = "bullet"
+ /// The icon that is displayed when the bullet bounces off something.
+ var/ping = "ping_b"
+ /// When it deals damage.
+ var/sound_hit
+ /// When it's blocked by human armor.
+ var/sound_armor
+ /// When it misses someone.
+ var/sound_miss
+ /// When it bounces off something.
+ var/sound_bounce
+ /// When the bullet is absorbed by a xeno_shield
+ var/sound_shield_hit
+ /// Snipers use this to simulate poor accuracy at close ranges
+ var/accurate_range_min = 0
+ /// How much the ammo scatters when burst fired, added to gun scatter, along with other mods
+ var/scatter = 0
+ var/stamina_damage = 0
+ /// This is the base damage of the bullet as it is fired
+ var/damage = 0
+ /// BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
+ var/damage_type = BRUTE
+ /// How much armor it ignores before calculations take place
+ var/penetration = 0
+ /// The % chance it will imbed in a human
+ var/shrapnel_chance = 0
+ /// The shrapnel type the ammo will embed, if the chance rolls
+ var/shrapnel_type = 0
+ /// Type path of the extra projectiles
+ var/bonus_projectiles_type
+ /// How many extra projectiles it shoots out. Works kind of like firing on burst, but all of the projectiles travel together
+ var/bonus_projectiles_amount = 0
+ /// Stun,knockdown,knockout,irradiate,stutter,eyeblur,drowsy,agony
+ var/debilitate[] = null
+ /// how much armor breaking will be done per point of penetration. This is for weapons that penetrate with their shape (like needle bullets)
+ var/pen_armor_punch = 0.5
+ /// how much armor breaking is done by sheer weapon force. This is for big blunt weapons
+ var/damage_armor_punch = 0.5
+ /// if we should play a special sound when firing.
+ var/sound_override = null
+ var/flags_ammo_behavior = NO_FLAGS
+
+ /// This is added to the bullet's base accuracy.
+ var/accuracy = HIT_ACCURACY_TIER_1
+ /// How much the accuracy varies when fired. // This REDUCES the lower bound of accuracy variance by 2%, to 96%.
+ var/accuracy_var_low = PROJECTILE_VARIANCE_TIER_9
+ /// This INCREASES the upper bound of accuracy variance by 2%, to 107%.
+ var/accuracy_var_high = PROJECTILE_VARIANCE_TIER_9
+ /// For most guns, this is where the bullet dramatically looses accuracy. Not for snipers though.
+ var/accurate_range = 6
+ /// This will de-increment a counter on the bullet.
+ var/max_range = 22
+ /// Same as with accuracy variance.
+ var/damage_var_low = PROJECTILE_VARIANCE_TIER_9
+ /// This INCREASES the upper bound of damage variance by 2%, to 107%.
+ var/damage_var_high = PROJECTILE_VARIANCE_TIER_9
+ /// How much damage the bullet loses per turf traveled after the effective range
+ var/damage_falloff = DAMAGE_FALLOFF_TIER_10
+ /// How much damage the bullet loses per turf away before the effective range
+ var/damage_buildup = DAMAGE_BUILDUP_TIER_1
+ /// What minimum range the ammo deals full damage, builds up the closer you get. 0 for no minimum. Added onto gun range as a modifier.
+ var/effective_range_min = EFFECTIVE_RANGE_OFF
+ /// What maximum range the ammo deals full damage, tapers off using damage_falloff after hitting this value. 0 for no maximum. Added onto gun range as a modifier.
+ var/effective_range_max = EFFECTIVE_RANGE_OFF
+ /// How fast the projectile moves.
+ var/shell_speed = AMMO_SPEED_TIER_1
+
+ var/handful_type = /obj/item/ammo_magazine/handful
+ var/handful_color
+ /// custom handful sprite, for shotgun shells or etc.
+ var/handful_state = "bullet"
+ /// so handfuls say 'buckshot shells' not 'shell'
+ var/multiple_handful_name
+
+ /// Does this apply xenomorph behaviour delegate?
+ var/apply_delegate = TRUE
+
+ /// An assoc list in the format list(/datum/element/bullet_trait_to_give = list(...args))
+ /// that will be given to a projectile with the current ammo datum
+ var/list/list/traits_to_give
+
+ var/flamer_reagent_type = /datum/reagent/napalm/ut
+
+ /// The flicker that plays when a bullet hits a target. Usually red. Can be nulled so it doesn't show up at all.
+ var/hit_effect_color = "#FF0000"
+
+/datum/ammo/New()
+ set_bullet_traits()
+
+/datum/ammo/proc/on_bullet_generation(obj/projectile/generated_projectile, mob/bullet_generator) //NOT used on New(), applied to the projectiles.
+ return
+
+/// Populate traits_to_give in this proc
+/datum/ammo/proc/set_bullet_traits()
+ return
+
+/datum/ammo/can_vv_modify()
+ return FALSE
+
+/datum/ammo/proc/do_at_half_range(obj/projectile/P)
+ SHOULD_NOT_SLEEP(TRUE)
+ return
+
+/datum/ammo/proc/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE)
+ return
+
+/datum/ammo/proc/do_at_max_range(obj/projectile/P)
+ SHOULD_NOT_SLEEP(TRUE)
+ return
+
+/datum/ammo/proc/on_shield_block(mob/M, obj/projectile/P) //Does it do something special when shield blocked? Ie. a flare or grenade that still blows up.
+ return
+
+/datum/ammo/proc/on_hit_turf(turf/T, obj/projectile/P) //Special effects when hitting dense turfs.
+ SHOULD_NOT_SLEEP(TRUE)
+ return
+
+/datum/ammo/proc/on_hit_mob(mob/M, obj/projectile/P, mob/user) //Special effects when hitting mobs.
+ SHOULD_NOT_SLEEP(TRUE)
+ return
+
+///Special effects when pointblanking mobs. Ultimately called from /living/attackby(). Return TRUE to end the PB attempt.
+/datum/ammo/proc/on_pointblank(mob/living/L, obj/projectile/P, mob/living/user, obj/item/weapon/gun/fired_from)
+ return
+
+/datum/ammo/proc/on_hit_obj(obj/O, obj/projectile/P) //Special effects when hitting objects.
+ SHOULD_NOT_SLEEP(TRUE)
+ return
+
+/datum/ammo/proc/on_near_target(turf/T, obj/projectile/P) //Special effects when passing near something. Range of things that triggers it is controlled by other ammo flags.
+ return 0 //return 0 means it flies even after being near something. Return 1 means it stops
+
+/datum/ammo/proc/knockback(mob/living/living_mob, obj/projectile/fired_projectile, max_range = 2)
+ if(!living_mob || living_mob == fired_projectile.firer)
+ return
+ if(fired_projectile.distance_travelled > max_range || living_mob.body_position == LYING_DOWN)
+ return //Two tiles away or more, basically.
+
+ if(living_mob.mob_size >= MOB_SIZE_BIG)
+ return //Big xenos are not affected.
+
+ shake_camera(living_mob, 3, 4)
+ knockback_effects(living_mob, fired_projectile)
+ slam_back(living_mob, fired_projectile)
+
+/datum/ammo/proc/slam_back(mob/living/living_mob, obj/projectile/fired_projectile)
+ /// Either knockback or slam them into an obstacle.
+ var/direction = Get_Compass_Dir(fired_projectile.z ? fired_projectile : fired_projectile.firer, living_mob) //More precise than get_dir.
+ if(!direction) //Same tile.
+ return
+ if(!step(living_mob, direction))
+ living_mob.animation_attack_on(get_step(living_mob, direction))
+ playsound(living_mob.loc, "punch", 25, 1)
+ living_mob.visible_message(SPAN_DANGER("[living_mob] slams into an obstacle!"),
+ isxeno(living_mob) ? SPAN_XENODANGER("You slam into an obstacle!") : SPAN_HIGHDANGER("You slam into an obstacle!"), null, 4, CHAT_TYPE_TAKING_HIT)
+ living_mob.apply_damage(MELEE_FORCE_TIER_2)
+
+///The applied effects for knockback(), overwrite to change slow/stun amounts for different ammo datums
+/datum/ammo/proc/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
+ if(iscarbonsizexeno(living_mob))
+ var/mob/living/carbon/xenomorph/target = living_mob
+ target.Stun(0.7) // Previous comment said they believed 0.7 was 0.9s and that the balance team approved this. Geez...
+ target.KnockDown(0.7)
+ target.apply_effect(1, SUPERSLOW)
+ target.apply_effect(2, SLOW)
+ to_chat(target, SPAN_XENODANGER("You are shaken by the sudden impact!"))
+ else
+ living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
+
+/datum/ammo/proc/slowdown(mob/living/living_mob, obj/projectile/fired_projectile)
+ if(iscarbonsizexeno(living_mob))
+ var/mob/living/carbon/xenomorph/target = living_mob
+ target.apply_effect(1, SUPERSLOW)
+ target.apply_effect(2, SLOW)
+ to_chat(target, SPAN_XENODANGER("You are slowed by the sudden impact!"))
+ else
+ living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
+
+/datum/ammo/proc/pushback(mob/living/target_mob, obj/projectile/fired_projectile, max_range = 2)
+ if(!target_mob || target_mob == fired_projectile.firer || fired_projectile.distance_travelled > max_range || target_mob.body_position == LYING_DOWN)
+ return
+
+ if(target_mob.mob_size >= MOB_SIZE_BIG)
+ return //too big to push
+
+ to_chat(target_mob, isxeno(target_mob) ? SPAN_XENODANGER("You are pushed back by the sudden impact!") : SPAN_HIGHDANGER("You are pushed back by the sudden impact!"))
+ slam_back(target_mob, fired_projectile, max_range)
+
+/datum/ammo/proc/burst(atom/target, obj/projectile/P, damage_type = BRUTE, range = 1, damage_div = 2, show_message = SHOW_MESSAGE_VISIBLE) //damage_div says how much we divide damage
+ if(!target || !P) return
+ for(var/mob/living/carbon/M in orange(range,target))
+ if(P.firer == M)
+ continue
+ if(show_message)
+ var/msg = "You are hit by backlash from \a [P.name]!"
+ M.visible_message(SPAN_DANGER("[M] is hit by backlash from \a [P.name]!"),isxeno(M) ? SPAN_XENODANGER("[msg]"):SPAN_HIGHDANGER("[msg]"))
+ var/damage = P.damage/damage_div
+
+ var/mob/living/carbon/xenomorph/XNO = null
+
+ if(isxeno(M))
+ XNO = M
+ var/total_explosive_resistance = XNO.caste.xeno_explosion_resistance + XNO.armor_explosive_buff
+ damage = armor_damage_reduction(GLOB.xeno_explosive, damage, total_explosive_resistance , 60, 0, 0.5, XNO.armor_integrity)
+ var/armor_punch = armor_break_calculation(GLOB.xeno_explosive, damage, total_explosive_resistance, 60, 0, 0.5, XNO.armor_integrity)
+ XNO.apply_armorbreak(armor_punch)
+
+ M.apply_damage(damage,damage_type)
+
+ if(XNO && XNO.xeno_shields.len)
+ P.play_shielded_hit_effect(M)
+ else
+ P.play_hit_effect(M)
+
+/datum/ammo/proc/fire_bonus_projectiles(obj/projectile/original_P)
+ set waitfor = 0
+
+ var/turf/curloc = get_turf(original_P.shot_from)
+ var/initial_angle = Get_Angle(curloc, original_P.target_turf)
+
+ for(var/i in 1 to bonus_projectiles_amount) //Want to run this for the number of bonus projectiles.
+ var/final_angle = initial_angle
+
+ var/obj/projectile/P = new /obj/projectile(curloc, original_P.weapon_cause_data)
+ P.generate_bullet(GLOB.ammo_list[bonus_projectiles_type]) //No bonus damage or anything.
+ P.accuracy = round(P.accuracy * original_P.accuracy/initial(original_P.accuracy)) //if the gun changes the accuracy of the main projectile, it also affects the bonus ones.
+ original_P.give_bullet_traits(P)
+
+ var/total_scatter_angle = P.scatter
+ final_angle += rand(-total_scatter_angle, total_scatter_angle)
+ var/turf/new_target = get_angle_target_turf(curloc, final_angle, 30)
+
+ P.fire_at(new_target, original_P.firer, original_P.shot_from, P.ammo.max_range, P.ammo.shell_speed, original_P.original) //Fire!
+
+/datum/ammo/proc/drop_flame(turf/T, datum/cause_data/cause_data) // ~Art updated fire 20JAN17
+ if(!istype(T))
+ return
+ if(locate(/obj/flamer_fire) in T)
+ return
+
+ var/datum/reagent/R = new flamer_reagent_type()
+ new /obj/flamer_fire(T, cause_data, R)
diff --git a/code/datums/ammo/bullet/bullet.dm b/code/datums/ammo/bullet/bullet.dm
new file mode 100644
index 000000000000..dadb644201df
--- /dev/null
+++ b/code/datums/ammo/bullet/bullet.dm
@@ -0,0 +1,81 @@
+/*
+//======
+ Default Ammo
+//======
+*/
+//Only when things screw up do we use this as a placeholder.
+/datum/ammo/bullet
+ name = "default bullet"
+ icon_state = "bullet"
+ headshot_state = HEADSHOT_OVERLAY_LIGHT
+ flags_ammo_behavior = AMMO_BALLISTIC
+ sound_hit = "ballistic_hit"
+ sound_armor = "ballistic_armor"
+ sound_miss = "ballistic_miss"
+ sound_bounce = "ballistic_bounce"
+ sound_shield_hit = "ballistic_shield_hit"
+
+ accurate_range_min = 0
+ damage = 10
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_1
+ shrapnel_type = /obj/item/shard/shrapnel
+ shell_speed = AMMO_SPEED_TIER_4
+
+/datum/ammo/bullet/proc/handle_battlefield_execution(datum/ammo/firing_ammo, mob/living/hit_mob, obj/projectile/firing_projectile, mob/living/user, obj/item/weapon/gun/fired_from)
+ SIGNAL_HANDLER
+
+ if(!user || hit_mob == user || user.zone_selected != "head" || user.a_intent != INTENT_HARM || !ishuman_strict(hit_mob))
+ return
+
+ if(!skillcheck(user, SKILL_EXECUTION, SKILL_EXECUTION_TRAINED))
+ to_chat(user, SPAN_DANGER("You don't know how to execute someone correctly."))
+ return
+
+ var/mob/living/carbon/human/execution_target = hit_mob
+
+ if(execution_target.status_flags & PERMANENTLY_DEAD)
+ to_chat(user, SPAN_DANGER("[execution_target] has already been executed!"))
+ return
+
+ INVOKE_ASYNC(src, PROC_REF(attempt_battlefield_execution), src, execution_target, firing_projectile, user, fired_from)
+
+ return COMPONENT_CANCEL_AMMO_POINT_BLANK
+
+/datum/ammo/bullet/proc/attempt_battlefield_execution(datum/ammo/firing_ammo, mob/living/carbon/human/execution_target, obj/projectile/firing_projectile, mob/living/user, obj/item/weapon/gun/fired_from)
+ user.affected_message(execution_target,
+ SPAN_HIGHDANGER("You aim \the [fired_from] at [execution_target]'s head!"),
+ SPAN_HIGHDANGER("[user] aims \the [fired_from] directly at your head!"),
+ SPAN_DANGER("[user] aims \the [fired_from] at [execution_target]'s head!"))
+
+ user.next_move += 1.1 SECONDS //PB has no click delay; readding it here to prevent people accidentally queuing up multiple executions.
+
+ if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE) || !user.Adjacent(execution_target))
+ fired_from.delete_bullet(firing_projectile, TRUE)
+ return
+
+ if(!(fired_from.flags_gun_features & GUN_SILENCED))
+ playsound(user, fired_from.fire_sound, fired_from.firesound_volume, FALSE)
+ else
+ playsound(user, fired_from.fire_sound, 25, FALSE)
+
+ shake_camera(user, 1, 2)
+
+ execution_target.apply_damage(damage * 3, BRUTE, "head", no_limb_loss = TRUE, permanent_kill = TRUE) //Apply gobs of damage and make sure they can't be revived later...
+ execution_target.apply_damage(200, OXY) //...fill out the rest of their health bar with oxyloss...
+ execution_target.death(create_cause_data("execution", user)) //...make certain they're properly dead...
+ shake_camera(execution_target, 3, 4)
+ execution_target.update_headshot_overlay(headshot_state) //...and add a gory headshot overlay.
+
+ execution_target.visible_message(SPAN_HIGHDANGER(uppertext("[execution_target] WAS EXECUTED!")), \
+ SPAN_HIGHDANGER("You WERE EXECUTED!"))
+
+ user.count_niche_stat(STATISTICS_NICHE_EXECUTION, 1, firing_projectile.weapon_cause_data?.cause_name)
+
+ var/area/execution_area = get_area(execution_target)
+
+ msg_admin_attack(FONT_SIZE_HUGE("[key_name(usr)] has battlefield executed [key_name(execution_target)] in [get_area(usr)] ([usr.loc.x],[usr.loc.y],[usr.loc.z])."), usr.loc.x, usr.loc.y, usr.loc.z)
+ log_attack("[key_name(usr)] battlefield executed [key_name(execution_target)] at [execution_area.name].")
+
+ if(flags_ammo_behavior & AMMO_EXPLOSIVE)
+ execution_target.gib()
+
diff --git a/code/datums/ammo/bullet/lever_action.dm b/code/datums/ammo/bullet/lever_action.dm
new file mode 100644
index 000000000000..2770231b6811
--- /dev/null
+++ b/code/datums/ammo/bullet/lever_action.dm
@@ -0,0 +1,72 @@
+/*
+//======
+ Lever Action
+//======
+*/
+
+/datum/ammo/bullet/lever_action
+ name = "lever-action bullet"
+
+ damage = 80
+ penetration = 0
+ accuracy = HIT_ACCURACY_TIER_1
+ shell_speed = AMMO_SPEED_TIER_6
+ accurate_range = 14
+ handful_state = "lever_action_bullet"
+
+//unused and not working. need to refactor MD code. Unobtainable.
+//intended mechanic is to have xenos hit with it show up very frequently on any MDs around
+/datum/ammo/bullet/lever_action/tracker
+ name = "tracking lever-action bullet"
+ icon_state = "redbullet"
+ damage = 70
+ penetration = ARMOR_PENETRATION_TIER_3
+ accuracy = HIT_ACCURACY_TIER_1
+ handful_state = "tracking_lever_action_bullet"
+
+/datum/ammo/bullet/lever_action/tracker/on_hit_mob(mob/M, obj/projectile/P, mob/user)
+ //SEND_SIGNAL(user, COMSIG_BULLET_TRACKING, user, M)
+ M.visible_message(SPAN_DANGER("You hear a faint beep under [M]'s [M.mob_size > MOB_SIZE_HUMAN ? "chitin" : "skin"]."))
+
+/datum/ammo/bullet/lever_action/training
+ name = "lever-action blank"
+ icon_state = "blank"
+ damage = 70 //blanks CAN hurt you if shot very close
+ penetration = 0
+ accuracy = HIT_ACCURACY_TIER_1
+ damage_falloff = DAMAGE_FALLOFF_BLANK //not much, though (comparatively)
+ shell_speed = AMMO_SPEED_TIER_5
+ handful_state = "training_lever_action_bullet"
+
+//unused, and unobtainable... for now
+/datum/ammo/bullet/lever_action/marksman
+ name = "marksman lever-action bullet"
+ shrapnel_chance = 0
+ damage_falloff = 0
+ accurate_range = 12
+ damage = 70
+ penetration = ARMOR_PENETRATION_TIER_6
+ shell_speed = AMMO_SPEED_TIER_6
+ handful_state = "marksman_lever_action_bullet"
+
+/datum/ammo/bullet/lever_action/xm88
+ name = ".458 SOCOM round"
+
+ damage = 80
+ penetration = ARMOR_PENETRATION_TIER_2
+ accuracy = HIT_ACCURACY_TIER_1
+ shell_speed = AMMO_SPEED_TIER_6
+ accurate_range = 14
+ handful_state = "boomslang_bullet"
+
+/datum/ammo/bullet/lever_action/xm88/pen20
+ penetration = ARMOR_PENETRATION_TIER_4
+
+/datum/ammo/bullet/lever_action/xm88/pen30
+ penetration = ARMOR_PENETRATION_TIER_6
+
+/datum/ammo/bullet/lever_action/xm88/pen40
+ penetration = ARMOR_PENETRATION_TIER_8
+
+/datum/ammo/bullet/lever_action/xm88/pen50
+ penetration = ARMOR_PENETRATION_TIER_10
diff --git a/code/datums/ammo/bullet/pistol.dm b/code/datums/ammo/bullet/pistol.dm
new file mode 100644
index 000000000000..8be63b0a15af
--- /dev/null
+++ b/code/datums/ammo/bullet/pistol.dm
@@ -0,0 +1,265 @@
+/*
+//======
+ Pistol Ammo
+//======
+*/
+
+// Used by M4A3, M4A3 Custom and B92FS
+/datum/ammo/bullet/pistol
+ name = "pistol bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+ accuracy = -HIT_ACCURACY_TIER_3
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ damage = 40
+ penetration= ARMOR_PENETRATION_TIER_2
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
+
+/datum/ammo/bullet/pistol/tiny
+ name = "light pistol bullet"
+
+/datum/ammo/bullet/pistol/tranq
+ name = "tranquilizer bullet"
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST
+ stamina_damage = 30
+ damage = 15
+
+//2020 rebalance: is supposed to counter runners and lurkers, dealing high damage to the only castes with no armor.
+//Limited by its lack of versatility and lower supply, so marines finally have an answer for flanker castes that isn't just buckshot.
+
+/datum/ammo/bullet/pistol/hollow
+ name = "hollowpoint pistol bullet"
+
+ damage = 55 //hollowpoint is strong
+ penetration = 0 //hollowpoint can't pierce armor!
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_3 //hollowpoint causes shrapnel
+
+// Used by M4A3 AP and mod88
+/datum/ammo/bullet/pistol/ap
+ name = "armor-piercing pistol bullet"
+
+ damage = 25
+ accuracy = HIT_ACCURACY_TIER_2
+ penetration= ARMOR_PENETRATION_TIER_8
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
+
+/datum/ammo/bullet/pistol/ap/penetrating
+ name = "wall-penetrating pistol bullet"
+ shrapnel_chance = 0
+
+ damage = 30
+ penetration = ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/bullet/pistol/ap/penetrating/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
+ ))
+
+/datum/ammo/bullet/pistol/ap/toxin
+ name = "toxic pistol bullet"
+ var/acid_per_hit = 10
+ var/organic_damage_mult = 3
+
+/datum/ammo/bullet/pistol/ap/toxin/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
+
+/datum/ammo/bullet/pistol/ap/toxin/on_hit_turf(turf/T, obj/projectile/P)
+ . = ..()
+ if(T.flags_turf & TURF_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/pistol/ap/toxin/on_hit_obj(obj/O, obj/projectile/P)
+ . = ..()
+ if(O.flags_obj & OBJ_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/pistol/le
+ name = "armor-shredding pistol bullet"
+
+ damage = 15
+ penetration = ARMOR_PENETRATION_TIER_4
+ pen_armor_punch = 3
+
+/datum/ammo/bullet/pistol/rubber
+ name = "rubber pistol bullet"
+ sound_override = 'sound/weapons/gun_c99.ogg'
+
+ damage = 0
+ stamina_damage = 25
+ shrapnel_chance = 0
+
+// Reskinned rubber bullet used for the ES-4 CL pistol.
+/datum/ammo/bullet/pistol/rubber/stun
+ name = "stun pistol bullet"
+ sound_override = null
+
+// Used by M1911, Deagle and KT-42
+/datum/ammo/bullet/pistol/heavy
+ name = "heavy pistol bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+ accuracy = -HIT_ACCURACY_TIER_3
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ damage = 55
+ penetration = ARMOR_PENETRATION_TIER_3
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
+
+/datum/ammo/bullet/pistol/heavy/super //Commander's variant
+ name = ".50 heavy pistol bullet"
+ damage = 60
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_6
+ penetration = ARMOR_PENETRATION_TIER_4
+
+/datum/ammo/bullet/pistol/heavy/super/highimpact
+ name = ".50 high-impact pistol bullet"
+ penetration = ARMOR_PENETRATION_TIER_1
+ debilitate = list(0,1.5,0,0,0,1,0,0)
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+/datum/ammo/bullet/pistol/heavy/super/highimpact/ap
+ name = ".50 high-impact armor piercing pistol bullet"
+ penetration = ARMOR_PENETRATION_TIER_10
+ damage = 45
+
+/datum/ammo/bullet/pistol/heavy/super/highimpact/upp
+ name = "high-impact pistol bullet"
+ sound_override = 'sound/weapons/gun_DE50.ogg'
+ penetration = ARMOR_PENETRATION_TIER_6
+ debilitate = list(0,1.5,0,0,0,1,0,0)
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+/datum/ammo/bullet/pistol/heavy/super/highimpact/New()
+ ..()
+ RegisterSignal(src, COMSIG_AMMO_POINT_BLANK, PROC_REF(handle_battlefield_execution))
+
+/datum/ammo/bullet/pistol/heavy/super/highimpact/on_hit_mob(mob/M, obj/projectile/P)
+ knockback(M, P, 4)
+
+/datum/ammo/bullet/pistol/deagle
+ name = ".50 heavy pistol bullet"
+ damage = 45
+ headshot_state = HEADSHOT_OVERLAY_HEAVY
+ accuracy = -HIT_ACCURACY_TIER_3
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ penetration = ARMOR_PENETRATION_TIER_6
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_5
+
+/datum/ammo/bullet/pistol/incendiary
+ name = "incendiary pistol bullet"
+ damage_type = BURN
+ shrapnel_chance = 0
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ accuracy = HIT_ACCURACY_TIER_3
+ damage = 20
+
+/datum/ammo/bullet/pistol/incendiary/set_bullet_traits()
+ ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+// Used by the hipower
+// I know that the 'high power' in the name is supposed to mean its 'impressive' magazine capacity
+// but this is CM, half our guns have baffling misconceptions and mistakes (how do you grab the type-71?) so it's on-brand.
+// maybe in the far flung future of 2280 someone screwed up the design.
+
+/datum/ammo/bullet/pistol/highpower
+ name = "high-powered pistol bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+
+ accuracy = HIT_ACCURACY_TIER_3
+ damage = 36
+ penetration = ARMOR_PENETRATION_TIER_5
+ damage_falloff = DAMAGE_FALLOFF_TIER_7
+
+// Used by VP78 and Auto 9
+/datum/ammo/bullet/pistol/squash
+ name = "squash-head pistol bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+ debilitate = list(0,0,0,0,0,0,0,2)
+
+ accuracy = HIT_ACCURACY_TIER_4
+ damage = 45
+ penetration= ARMOR_PENETRATION_TIER_6
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
+ damage_falloff = DAMAGE_FALLOFF_TIER_6 //"VP78 - the only pistol viable as a primary."-Vampmare, probably.
+
+/datum/ammo/bullet/pistol/squash/toxin
+ name = "toxic squash-head pistol bullet"
+ var/acid_per_hit = 10
+ var/organic_damage_mult = 3
+
+/datum/ammo/bullet/pistol/squash/toxin/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
+
+/datum/ammo/bullet/pistol/squash/toxin/on_hit_turf(turf/T, obj/projectile/P)
+ . = ..()
+ if(T.flags_turf & TURF_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/pistol/squash/toxin/on_hit_obj(obj/O, obj/projectile/P)
+ . = ..()
+ if(O.flags_obj & OBJ_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/pistol/squash/penetrating
+ name = "wall-penetrating squash-head pistol bullet"
+ shrapnel_chance = 0
+ penetration = ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/bullet/pistol/squash/penetrating/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
+ ))
+
+/datum/ammo/bullet/pistol/squash/incendiary
+ name = "incendiary squash-head pistol bullet"
+ damage_type = BURN
+ shrapnel_chance = 0
+ flags_ammo_behavior = AMMO_BALLISTIC
+ accuracy = HIT_ACCURACY_TIER_3
+ damage = 35
+
+/datum/ammo/bullet/pistol/squash/incendiary/set_bullet_traits()
+ ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+
+/datum/ammo/bullet/pistol/mankey
+ name = "live monkey"
+ icon_state = "monkey1"
+ ping = null //no bounce off.
+ damage_type = BURN
+ debilitate = list(4,4,0,0,0,0,0,0)
+ flags_ammo_behavior = AMMO_IGNORE_ARMOR
+
+ damage = 15
+ damage_var_high = PROJECTILE_VARIANCE_TIER_5
+ shell_speed = AMMO_SPEED_TIER_2
+
+/datum/ammo/bullet/pistol/mankey/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/pistol/mankey/on_hit_mob(mob/M,obj/projectile/P)
+ if(P && P.loc && !M.stat && !istype(M,/mob/living/carbon/human/monkey))
+ P.visible_message(SPAN_DANGER("The [src] chimpers furiously!"))
+ new /mob/living/carbon/human/monkey(P.loc)
+
+/datum/ammo/bullet/pistol/smart
+ name = "smartpistol bullet"
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ accuracy = HIT_ACCURACY_TIER_8
+ damage = 30
+ penetration = 20
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
+
diff --git a/code/datums/ammo/bullet/revolver.dm b/code/datums/ammo/bullet/revolver.dm
new file mode 100644
index 000000000000..633bf3e2f7ff
--- /dev/null
+++ b/code/datums/ammo/bullet/revolver.dm
@@ -0,0 +1,180 @@
+/*
+//======
+ Revolver Ammo
+//======
+*/
+
+/datum/ammo/bullet/revolver
+ name = "revolver bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+
+ damage = 55
+ penetration = ARMOR_PENETRATION_TIER_1
+ accuracy = HIT_ACCURACY_TIER_1
+
+/datum/ammo/bullet/revolver/marksman
+ name = "marksman revolver bullet"
+
+ shrapnel_chance = 0
+ damage_falloff = 0
+ accurate_range = 12
+ penetration = ARMOR_PENETRATION_TIER_7
+
+/datum/ammo/bullet/revolver/heavy
+ name = "heavy revolver bullet"
+
+ damage = 35
+ penetration = ARMOR_PENETRATION_TIER_4
+ accuracy = HIT_ACCURACY_TIER_3
+
+/datum/ammo/bullet/revolver/heavy/on_hit_mob(mob/entity, obj/projectile/bullet)
+ slowdown(entity, bullet)
+ pushback(entity, bullet, 4)
+
+/datum/ammo/bullet/revolver/incendiary
+ name = "incendiary revolver bullet"
+ damage = 40
+
+/datum/ammo/bullet/revolver/incendiary/set_bullet_traits()
+ ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/revolver/marksman/toxin
+ name = "toxic revolver bullet"
+ var/acid_per_hit = 10
+ var/organic_damage_mult = 3
+
+/datum/ammo/bullet/revolver/marksman/toxin/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
+
+/datum/ammo/bullet/revolver/marksman/toxin/on_hit_turf(turf/T, obj/projectile/P)
+ . = ..()
+ if(T.flags_turf & TURF_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/revolver/marksman/toxin/on_hit_obj(obj/O, obj/projectile/P)
+ . = ..()
+ if(O.flags_obj & OBJ_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/revolver/penetrating
+ name = "wall-penetrating revolver bullet"
+ shrapnel_chance = 0
+
+ penetration = ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/bullet/revolver/penetrating/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
+ ))
+
+/datum/ammo/bullet/revolver/upp
+ name = "heavy revolver bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+ penetration = ARMOR_PENETRATION_TIER_4
+ damage = 70
+
+
+/datum/ammo/bullet/revolver/upp/shrapnel
+ name = "shrapnel shot"
+ headshot_state = HEADSHOT_OVERLAY_HEAVY //Gol-dang shotgun blow your fething head off.
+ debilitate = list(0,0,0,0,0,0,0,0)
+ icon_state = "shrapnelshot"
+ handful_state = "shrapnel"
+ bonus_projectiles_type = /datum/ammo/bullet/revolver/upp/shrapnel_bits
+
+ max_range = 6
+ damage = 40 // + TIER_4 * 3
+ damage_falloff = DAMAGE_FALLOFF_TIER_7
+ penetration = ARMOR_PENETRATION_TIER_8
+ bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3
+ shrapnel_chance = 100
+ shrapnel_type = /obj/item/shard/shrapnel/upp
+ //roughly 90 or so damage with the additional shrapnel, around 130 in total with primary round
+
+/datum/ammo/bullet/revolver/upp/shrapnel/on_hit_mob(mob/M, obj/projectile/P)
+ pushback(M, P, 1)
+
+/datum/ammo/bullet/revolver/upp/shrapnel_bits
+ name = "small shrapnel"
+ icon_state = "shrapnelshot_bit"
+
+ max_range = 6
+ damage = 30
+ penetration = ARMOR_PENETRATION_TIER_4
+ scatter = SCATTER_AMOUNT_TIER_1
+ bonus_projectiles_amount = 0
+ shrapnel_type = /obj/item/shard/shrapnel/upp/bits
+
+/datum/ammo/bullet/revolver/small
+ name = "small revolver bullet"
+ headshot_state = HEADSHOT_OVERLAY_LIGHT
+
+ damage = 45
+
+ penetration = ARMOR_PENETRATION_TIER_3
+
+/datum/ammo/bullet/revolver/small/hollowpoint
+ name = "small hollowpoint revolver bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+
+ damage = 75 // way too strong because it's hard to make a good balance between HP and normal with this system, but the damage falloff is really strong
+ penetration = 0
+ damage_falloff = DAMAGE_FALLOFF_TIER_6
+
+/datum/ammo/bullet/revolver/mateba
+ name = ".454 heavy revolver bullet"
+
+ damage = 60
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_6
+ penetration = ARMOR_PENETRATION_TIER_4
+
+/datum/ammo/bullet/revolver/mateba/highimpact
+ name = ".454 heavy high-impact revolver bullet"
+ debilitate = list(0,2,0,0,0,1,0,0)
+ penetration = ARMOR_PENETRATION_TIER_1
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+/datum/ammo/bullet/revolver/mateba/highimpact/ap
+ name = ".454 heavy high-impact armor piercing revolver bullet"
+ penetration = ARMOR_PENETRATION_TIER_10
+ damage = 45
+
+/datum/ammo/bullet/revolver/mateba/highimpact/New()
+ ..()
+ RegisterSignal(src, COMSIG_AMMO_POINT_BLANK, PROC_REF(handle_battlefield_execution))
+
+/datum/ammo/bullet/revolver/mateba/highimpact/on_hit_mob(mob/M, obj/projectile/P)
+ knockback(M, P, 4)
+
+/datum/ammo/bullet/revolver/mateba/highimpact/explosive //if you ever put this in normal gameplay, i am going to scream
+ name = ".454 heavy explosive revolver bullet"
+ damage = 100
+ damage_var_low = PROJECTILE_VARIANCE_TIER_10
+ damage_var_high = PROJECTILE_VARIANCE_TIER_1
+ penetration = ARMOR_PENETRATION_TIER_10
+ flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_BALLISTIC
+
+/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_mob(mob/M, obj/projectile/P)
+ ..()
+ cell_explosion(get_turf(M), 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
+
+/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_obj(obj/O, obj/projectile/P)
+ ..()
+ cell_explosion(get_turf(O), 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
+
+/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_turf(turf/T, obj/projectile/P)
+ ..()
+ cell_explosion(T, 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
+
+/datum/ammo/bullet/revolver/webley //Mateba round without the knockdown.
+ name = ".455 Webley bullet"
+ damage = 60
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_6
+ penetration = ARMOR_PENETRATION_TIER_2
diff --git a/code/datums/ammo/bullet/rifle.dm b/code/datums/ammo/bullet/rifle.dm
new file mode 100644
index 000000000000..0be6f1db8ff4
--- /dev/null
+++ b/code/datums/ammo/bullet/rifle.dm
@@ -0,0 +1,211 @@
+/*
+//======
+ Rifle Ammo
+//======
+*/
+
+/datum/ammo/bullet/rifle
+ name = "rifle bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+
+ damage = 40
+ penetration = ARMOR_PENETRATION_TIER_1
+ accurate_range = 16
+ accuracy = HIT_ACCURACY_TIER_4
+ scatter = SCATTER_AMOUNT_TIER_10
+ shell_speed = AMMO_SPEED_TIER_6
+ effective_range_max = 7
+ damage_falloff = DAMAGE_FALLOFF_TIER_7
+ max_range = 24 //So S8 users don't have their bullets magically disappaer at 22 tiles (S8 can see 24 tiles)
+
+/datum/ammo/bullet/rifle/holo_target
+ name = "holo-targeting rifle bullet"
+ damage = 30
+ var/holo_stacks = 10
+
+/datum/ammo/bullet/rifle/holo_target/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ M.AddComponent(/datum/component/bonus_damage_stack, holo_stacks, world.time)
+
+/datum/ammo/bullet/rifle/holo_target/hunting
+ name = "holo-targeting hunting bullet"
+ damage = 25
+ holo_stacks = 15
+
+/datum/ammo/bullet/rifle/explosive
+ name = "explosive rifle bullet"
+
+ damage = 25
+ accurate_range = 22
+ accuracy = 0
+ shell_speed = AMMO_SPEED_TIER_4
+ damage_falloff = DAMAGE_FALLOFF_TIER_9
+
+/datum/ammo/bullet/rifle/explosive/on_hit_mob(mob/M, obj/projectile/P)
+ cell_explosion(get_turf(M), 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
+
+/datum/ammo/bullet/rifle/explosive/on_hit_obj(obj/O, obj/projectile/P)
+ cell_explosion(get_turf(O), 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
+
+/datum/ammo/bullet/rifle/explosive/on_hit_turf(turf/T, obj/projectile/P)
+ if(T.density)
+ cell_explosion(T, 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
+
+/datum/ammo/bullet/rifle/ap
+ name = "armor-piercing rifle bullet"
+
+ damage = 30
+ penetration = ARMOR_PENETRATION_TIER_8
+
+// Basically AP but better. Focused at taking out armour temporarily
+/datum/ammo/bullet/rifle/ap/toxin
+ name = "toxic rifle bullet"
+ var/acid_per_hit = 7
+ var/organic_damage_mult = 3
+
+/datum/ammo/bullet/rifle/ap/toxin/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
+
+/datum/ammo/bullet/rifle/ap/toxin/on_hit_turf(turf/T, obj/projectile/P)
+ . = ..()
+ if(T.flags_turf & TURF_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/rifle/ap/toxin/on_hit_obj(obj/O, obj/projectile/P)
+ . = ..()
+ if(O.flags_obj & OBJ_ORGANIC)
+ P.damage *= organic_damage_mult
+
+
+/datum/ammo/bullet/rifle/ap/penetrating
+ name = "wall-penetrating rifle bullet"
+ shrapnel_chance = 0
+
+ damage = 35
+ penetration = ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/bullet/rifle/ap/penetrating/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
+ ))
+
+/datum/ammo/bullet/rifle/le
+ name = "armor-shredding rifle bullet"
+
+ damage = 20
+ penetration = ARMOR_PENETRATION_TIER_4
+ pen_armor_punch = 5
+
+/datum/ammo/bullet/rifle/heap
+ name = "high-explosive armor-piercing rifle bullet"
+
+ headshot_state = HEADSHOT_OVERLAY_HEAVY
+ damage = 55//big damage, doesn't actually blow up because thats stupid.
+ penetration = ARMOR_PENETRATION_TIER_8
+
+/datum/ammo/bullet/rifle/rubber
+ name = "rubber rifle bullet"
+ sound_override = 'sound/weapons/gun_c99.ogg'
+
+ damage = 0
+ stamina_damage = 15
+ shrapnel_chance = 0
+
+/datum/ammo/bullet/rifle/incendiary
+ name = "incendiary rifle bullet"
+ damage_type = BURN
+ shrapnel_chance = 0
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ damage = 30
+ shell_speed = AMMO_SPEED_TIER_4
+ accuracy = -HIT_ACCURACY_TIER_2
+ damage_falloff = DAMAGE_FALLOFF_TIER_10
+
+/datum/ammo/bullet/rifle/incendiary/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/rifle/m4ra
+ name = "A19 high velocity bullet"
+ shrapnel_chance = 0
+ damage_falloff = 0
+ flags_ammo_behavior = AMMO_BALLISTIC
+ accurate_range_min = 4
+
+ damage = 55
+ scatter = -SCATTER_AMOUNT_TIER_8
+ penetration= ARMOR_PENETRATION_TIER_7
+ shell_speed = AMMO_SPEED_TIER_6
+
+/datum/ammo/bullet/rifle/m4ra/incendiary
+ name = "A19 high velocity incendiary bullet"
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ damage = 40
+ accuracy = HIT_ACCURACY_TIER_4
+ scatter = -SCATTER_AMOUNT_TIER_8
+ penetration= ARMOR_PENETRATION_TIER_5
+ shell_speed = AMMO_SPEED_TIER_6
+
+/datum/ammo/bullet/rifle/m4ra/incendiary/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/rifle/m4ra/impact
+ name = "A19 high velocity impact bullet"
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ damage = 40
+ accuracy = -HIT_ACCURACY_TIER_2
+ scatter = -SCATTER_AMOUNT_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_10
+ shell_speed = AMMO_SPEED_TIER_6
+
+/datum/ammo/bullet/rifle/m4ra/impact/on_hit_mob(mob/M, obj/projectile/P)
+ knockback(M, P, 32) // Can knockback basically at max range
+
+/datum/ammo/bullet/rifle/m4ra/impact/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
+ if(iscarbonsizexeno(living_mob))
+ var/mob/living/carbon/xenomorph/target = living_mob
+ to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!"))
+ target.KnockDown(0.5) // purely for visual effect, noone actually cares
+ target.Stun(0.5)
+ target.apply_effect(2, SUPERSLOW)
+ target.apply_effect(5, SLOW)
+ else
+ if(!isyautja(living_mob)) //Not predators.
+ living_mob.apply_effect(1, SUPERSLOW)
+ living_mob.apply_effect(2, SLOW)
+ to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!"))
+ living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
+
+/datum/ammo/bullet/rifle/mar40
+ name = "heavy rifle bullet"
+
+ damage = 55
+
+/datum/ammo/bullet/rifle/type71
+ name = "heavy rifle bullet"
+
+ damage = 55
+ penetration = ARMOR_PENETRATION_TIER_3
+
+/datum/ammo/bullet/rifle/type71/ap
+ name = "heavy armor-piercing rifle bullet"
+
+ damage = 40
+ penetration = ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/bullet/rifle/type71/heap
+ name = "heavy high-explosive armor-piercing rifle bullet"
+
+ headshot_state = HEADSHOT_OVERLAY_HEAVY
+ damage = 65
+ penetration = ARMOR_PENETRATION_TIER_10
diff --git a/code/datums/ammo/bullet/shotgun.dm b/code/datums/ammo/bullet/shotgun.dm
new file mode 100644
index 000000000000..96ac4cb6ba04
--- /dev/null
+++ b/code/datums/ammo/bullet/shotgun.dm
@@ -0,0 +1,366 @@
+/*
+//======
+ Shotgun Ammo
+//======
+*/
+
+/datum/ammo/bullet/shotgun
+ headshot_state = HEADSHOT_OVERLAY_HEAVY
+
+/datum/ammo/bullet/shotgun/slug
+ name = "shotgun slug"
+ handful_state = "slug_shell"
+
+ accurate_range = 6
+ max_range = 8
+ damage = 70
+ penetration = ARMOR_PENETRATION_TIER_4
+ damage_armor_punch = 2
+ handful_state = "slug_shell"
+
+/datum/ammo/bullet/shotgun/slug/on_hit_mob(mob/M,obj/projectile/P)
+ knockback(M, P, 6)
+
+/datum/ammo/bullet/shotgun/slug/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
+ if(iscarbonsizexeno(living_mob))
+ var/mob/living/carbon/xenomorph/target = living_mob
+ to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!"))
+ target.KnockDown(0.5) // If you ask me the KD should be left out, but players like their visual cues
+ target.Stun(0.5)
+ target.apply_effect(1, SUPERSLOW)
+ target.apply_effect(3, SLOW)
+ else
+ if(!isyautja(living_mob)) //Not predators.
+ living_mob.apply_effect(1, SUPERSLOW)
+ living_mob.apply_effect(2, SLOW)
+ to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!"))
+ living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
+
+/datum/ammo/bullet/shotgun/beanbag
+ name = "beanbag slug"
+ headshot_state = HEADSHOT_OVERLAY_LIGHT //It's not meant to kill people... but if you put it in your mouth, it will.
+ handful_state = "beanbag_slug"
+ icon_state = "beanbag"
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST
+ sound_override = 'sound/weapons/gun_shotgun_riot.ogg'
+
+ max_range = 12
+ shrapnel_chance = 0
+ damage = 0
+ stamina_damage = 45
+ accuracy = HIT_ACCURACY_TIER_3
+ shell_speed = AMMO_SPEED_TIER_3
+ handful_state = "beanbag_slug"
+
+/datum/ammo/bullet/shotgun/beanbag/on_hit_mob(mob/M, obj/projectile/P)
+ if(!M || M == P.firer) return
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ shake_camera(H, 2, 1)
+
+
+/datum/ammo/bullet/shotgun/incendiary
+ name = "incendiary slug"
+ handful_state = "incendiary_slug"
+ damage_type = BURN
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ accuracy = -HIT_ACCURACY_TIER_2
+ max_range = 12
+ damage = 55
+ penetration= ARMOR_PENETRATION_TIER_1
+ handful_state = "incendiary_slug"
+
+/datum/ammo/bullet/shotgun/incendiary/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/shotgun/incendiary/on_hit_mob(mob/M,obj/projectile/P)
+ burst(get_turf(M),P,damage_type)
+ knockback(M,P)
+
+/datum/ammo/bullet/shotgun/incendiary/on_hit_obj(obj/O,obj/projectile/P)
+ burst(get_turf(P),P,damage_type)
+
+/datum/ammo/bullet/shotgun/incendiary/on_hit_turf(turf/T,obj/projectile/P)
+ burst(get_turf(T),P,damage_type)
+
+
+/datum/ammo/bullet/shotgun/flechette
+ name = "flechette shell"
+ icon_state = "flechette"
+ handful_state = "flechette_shell"
+ bonus_projectiles_type = /datum/ammo/bullet/shotgun/flechette_spread
+
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
+ max_range = 12
+ damage = 30
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_7
+ bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3
+ handful_state = "flechette_shell"
+ multiple_handful_name = TRUE
+
+/datum/ammo/bullet/shotgun/flechette_spread
+ name = "additional flechette"
+ icon_state = "flechette"
+
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
+ max_range = 12
+ damage = 30
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_7
+ scatter = SCATTER_AMOUNT_TIER_5
+
+/datum/ammo/bullet/shotgun/buckshot
+ name = "buckshot shell"
+ icon_state = "buckshot"
+ handful_state = "buckshot_shell"
+ multiple_handful_name = TRUE
+ bonus_projectiles_type = /datum/ammo/bullet/shotgun/spread
+
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_5
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_5
+ accurate_range = 4
+ max_range = 4
+ damage = 65
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_1
+ bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3
+ shell_speed = AMMO_SPEED_TIER_2
+ damage_armor_punch = 0
+ pen_armor_punch = 0
+ handful_state = "buckshot_shell"
+ multiple_handful_name = TRUE
+
+/datum/ammo/bullet/shotgun/buckshot/incendiary
+ name = "incendiary buckshot shell"
+ handful_state = "incen_buckshot"
+ handful_type = /obj/item/ammo_magazine/handful/shotgun/buckshot/incendiary
+
+/datum/ammo/bullet/shotgun/buckshot/incendiary/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/shotgun/buckshot/on_hit_mob(mob/M,obj/projectile/P)
+ knockback(M,P)
+
+//buckshot variant only used by the masterkey shotgun attachment.
+/datum/ammo/bullet/shotgun/buckshot/masterkey
+ bonus_projectiles_type = /datum/ammo/bullet/shotgun/spread/masterkey
+
+ damage = 55
+
+/datum/ammo/bullet/shotgun/spread
+ name = "additional buckshot"
+ icon_state = "buckshot"
+
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
+ accurate_range = 4
+ max_range = 6
+ damage = 65
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_1
+ shell_speed = AMMO_SPEED_TIER_2
+ scatter = SCATTER_AMOUNT_TIER_1
+ damage_armor_punch = 0
+ pen_armor_punch = 0
+
+/datum/ammo/bullet/shotgun/spread/masterkey
+ damage = 20
+
+/*
+ 8 GAUGE SHOTGUN AMMO
+*/
+
+/datum/ammo/bullet/shotgun/heavy/buckshot
+ name = "heavy buckshot shell"
+ icon_state = "buckshot"
+ handful_state = "heavy_buckshot"
+ multiple_handful_name = TRUE
+ bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/buckshot/spread
+ bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3
+ accurate_range = 3
+ max_range = 3
+ damage = 75
+ penetration = 0
+ shell_speed = AMMO_SPEED_TIER_2
+ damage_armor_punch = 0
+ pen_armor_punch = 0
+
+/datum/ammo/bullet/shotgun/heavy/buckshot/on_hit_mob(mob/M,obj/projectile/P)
+ knockback(M,P)
+
+/datum/ammo/bullet/shotgun/heavy/buckshot/spread
+ name = "additional heavy buckshot"
+ max_range = 4
+ scatter = SCATTER_AMOUNT_TIER_1
+ bonus_projectiles_amount = 0
+
+//basically the same
+/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath
+ name = "dragon's breath shell"
+ handful_state = "heavy_dragonsbreath"
+ multiple_handful_name = TRUE
+ damage_type = BURN
+ damage = 60
+ accurate_range = 3
+ max_range = 4
+ bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/spread
+
+/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/spread
+ name = "additional dragon's breath"
+ bonus_projectiles_amount = 0
+ accurate_range = 4
+ max_range = 5 //make use of the ablaze property
+ shell_speed = AMMO_SPEED_TIER_4 // so they hit before the main shell stuns
+
+
+/datum/ammo/bullet/shotgun/heavy/slug
+ name = "heavy shotgun slug"
+ handful_state = "heavy_slug"
+
+ accurate_range = 7
+ max_range = 8
+ damage = 90 //ouch.
+ penetration = ARMOR_PENETRATION_TIER_6
+ damage_armor_punch = 2
+
+/datum/ammo/bullet/shotgun/heavy/slug/on_hit_mob(mob/M,obj/projectile/P)
+ knockback(M, P, 7)
+
+/datum/ammo/bullet/shotgun/heavy/slug/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
+ if(iscarbonsizexeno(living_mob))
+ var/mob/living/carbon/xenomorph/target = living_mob
+ to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!"))
+ target.KnockDown(0.5) // If you ask me the KD should be left out, but players like their visual cues
+ target.Stun(0.5)
+ target.apply_effect(2, SUPERSLOW)
+ target.apply_effect(5, SLOW)
+ else
+ if(!isyautja(living_mob)) //Not predators.
+ living_mob.apply_effect(1, SUPERSLOW)
+ living_mob.apply_effect(2, SLOW)
+ to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!"))
+ living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
+
+/datum/ammo/bullet/shotgun/heavy/beanbag
+ name = "heavy beanbag slug"
+ icon_state = "beanbag"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+ handful_state = "heavy_beanbag"
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST
+ sound_override = 'sound/weapons/gun_shotgun_riot.ogg'
+
+ max_range = 7
+ shrapnel_chance = 0
+ damage = 0
+ stamina_damage = 100
+ accuracy = HIT_ACCURACY_TIER_2
+ shell_speed = AMMO_SPEED_TIER_2
+
+/datum/ammo/bullet/shotgun/heavy/beanbag/on_hit_mob(mob/M, obj/projectile/P)
+ if(!M || M == P.firer)
+ return
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ shake_camera(H, 2, 1)
+
+/datum/ammo/bullet/shotgun/heavy/flechette
+ name = "heavy flechette shell"
+ icon_state = "flechette"
+ handful_state = "heavy_flechette"
+ multiple_handful_name = TRUE
+ bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/flechette_spread
+
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_3
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_3
+ max_range = 12
+ damage = 45
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_10
+ bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_2
+
+/datum/ammo/bullet/shotgun/heavy/flechette_spread
+ name = "additional heavy flechette"
+ icon_state = "flechette"
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
+ max_range = 12
+ damage = 45
+ damage_var_low = PROJECTILE_VARIANCE_TIER_8
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_10
+ scatter = SCATTER_AMOUNT_TIER_4
+
+//Enormous shell for Van Bandolier's superheavy double-barreled hunting gun.
+/datum/ammo/bullet/shotgun/twobore
+ name = "two bore bullet"
+ icon_state = "autocannon"
+ handful_state = "twobore"
+
+ accurate_range = 8 //Big low-velocity projectile; this is for blasting dangerous game at close range.
+ max_range = 14 //At this range, it's lost all its damage anyway.
+ damage = 300 //Hits like a buckshot PB.
+ penetration = ARMOR_PENETRATION_TIER_3
+ damage_falloff = DAMAGE_FALLOFF_TIER_1 * 3 //It has a lot of energy, but the 26mm bullet drops off fast.
+ effective_range_max = EFFECTIVE_RANGE_MAX_TIER_2 //Full damage up to this distance, then falloff for each tile beyond.
+ var/hit_messages = list()
+
+/datum/ammo/bullet/shotgun/twobore/on_hit_mob(mob/living/M, obj/projectile/P)
+ var/mob/shooter = P.firer
+ if(shooter && ismob(shooter) && HAS_TRAIT(shooter, TRAIT_TWOBORE_TRAINING) && M.stat != DEAD && prob(40)) //Death is handled by periodic life() checks so this should have a chance to fire on a killshot.
+ if(!length(hit_messages)) //Pick and remove lines, refill on exhaustion.
+ hit_messages = list("Got you!", "Aha!", "Bullseye!", "It's curtains for you, Sonny Jim!", "Your head will look fantastic on my wall!", "I have you now!", "You miserable coward! Come and fight me like a man!", "Tally ho!")
+ var/message = pick_n_take(hit_messages)
+ shooter.say(message)
+
+ if(P.distance_travelled > 8)
+ knockback(M, P, 12)
+
+ else if(!M || M == P.firer || M.body_position == LYING_DOWN) //These checks are included in knockback and would be redundant above.
+ return
+
+ shake_camera(M, 3, 4)
+ M.KnockDown(2) // If you ask me the KD should be left out, but players like their visual cues
+ M.Stun(2)
+ M.apply_effect(4, SLOW)
+ if(iscarbonsizexeno(M))
+ to_chat(M, SPAN_XENODANGER("The impact knocks you off your feet!"))
+ else //This will hammer a Yautja as hard as a human.
+ to_chat(M, SPAN_HIGHDANGER("The impact knocks you off your feet!"))
+
+ step(M, get_dir(P.firer, M))
+
+/datum/ammo/bullet/shotgun/twobore/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
+ if(iscarbonsizexeno(living_mob))
+ var/mob/living/carbon/xenomorph/target = living_mob
+ to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!"))
+ target.KnockDown(0.5) // If you ask me the KD should be left out, but players like their visual cues
+ target.Stun(0.5)
+ target.apply_effect(2, SUPERSLOW)
+ target.apply_effect(5, SLOW)
+ else
+ if(!isyautja(living_mob)) //Not predators.
+ living_mob.apply_effect(1, SUPERSLOW)
+ living_mob.apply_effect(2, SLOW)
+ to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!"))
+ living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
diff --git a/code/datums/ammo/bullet/smg.dm b/code/datums/ammo/bullet/smg.dm
new file mode 100644
index 000000000000..e24b3021da97
--- /dev/null
+++ b/code/datums/ammo/bullet/smg.dm
@@ -0,0 +1,147 @@
+/*
+//======
+ SMG Ammo
+//======
+*/
+//2020 SMG/ammo rebalance. default ammo actually has penetration so it can be useful, by 4khan: should be meh against t3s, better under 15 armor. Perfectly does this right now (oct 2020)
+//has reduced falloff compared to the m39. this means it is best for kiting castes (mostly t2s and below admittedly)
+//while the m39 ap is better for shredding them at close range, but has reduced velocity, so it's better for just running in and erasing armor-centric castes (defender, crusher)
+// which i think is really interesting and good balance, giving both ammo types a reason to exist even against ravagers.
+//i feel it is necessary to reflavor the default bullet, because otherwise, people won't be able to notice it has less falloff and faster bullet speed. even with a changelog,
+//way too many people don't read the changelog, and after one or two months the changelog entry is all but archive, so there needs to be an ingame description of what the ammo does
+//in comparison to armor-piercing rounds.
+
+/datum/ammo/bullet/smg
+ name = "submachinegun bullet"
+ damage = 34
+ accurate_range = 4
+ effective_range_max = 4
+ penetration = ARMOR_PENETRATION_TIER_1
+ shell_speed = AMMO_SPEED_TIER_6
+ damage_falloff = DAMAGE_FALLOFF_TIER_5
+ scatter = SCATTER_AMOUNT_TIER_6
+ accuracy = HIT_ACCURACY_TIER_3
+
+/datum/ammo/bullet/smg/m39
+ name = "high-velocity submachinegun bullet" //i don't want all smgs to inherit 'high velocity'
+
+/datum/ammo/bullet/smg/ap
+ name = "armor-piercing submachinegun bullet"
+
+ damage = 26
+ penetration = ARMOR_PENETRATION_TIER_6
+ shell_speed = AMMO_SPEED_TIER_4
+
+/datum/ammo/bullet/smg/heap
+ name = "high-explosive armor-piercing submachinegun bullet"
+
+ damage = 45
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+ penetration = ARMOR_PENETRATION_TIER_6
+ shell_speed = AMMO_SPEED_TIER_4
+
+/datum/ammo/bullet/smg/ap/toxin
+ name = "toxic submachinegun bullet"
+ var/acid_per_hit = 5
+ var/organic_damage_mult = 3
+
+/datum/ammo/bullet/smg/ap/toxin/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
+
+/datum/ammo/bullet/smg/ap/toxin/on_hit_turf(turf/T, obj/projectile/P)
+ . = ..()
+ if(T.flags_turf & TURF_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/smg/ap/toxin/on_hit_obj(obj/O, obj/projectile/P)
+ . = ..()
+ if(O.flags_obj & OBJ_ORGANIC)
+ P.damage *= organic_damage_mult
+
+/datum/ammo/bullet/smg/nail
+ name = "7x45mm plasteel nail"
+ icon_state = "nail-projectile"
+
+ damage = 25
+ penetration = ARMOR_PENETRATION_TIER_5
+ damage_falloff = DAMAGE_FALLOFF_TIER_6
+ accurate_range = 5
+ shell_speed = AMMO_SPEED_TIER_4
+
+/datum/ammo/bullet/smg/incendiary
+ name = "incendiary submachinegun bullet"
+ damage_type = BURN
+ shrapnel_chance = 0
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ damage = 25
+ accuracy = -HIT_ACCURACY_TIER_2
+
+/datum/ammo/bullet/smg/incendiary/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/smg/ap/penetrating
+ name = "wall-penetrating submachinegun bullet"
+ shrapnel_chance = 0
+
+ damage = 30
+ penetration = ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/bullet/smg/ap/penetrating/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
+ ))
+
+/datum/ammo/bullet/smg/le
+ name = "armor-shredding submachinegun bullet"
+
+ scatter = SCATTER_AMOUNT_TIER_10
+ damage = 20
+ penetration = ARMOR_PENETRATION_TIER_4
+ shell_speed = AMMO_SPEED_TIER_3
+ damage_falloff = DAMAGE_FALLOFF_TIER_10
+ pen_armor_punch = 4
+
+/datum/ammo/bullet/smg/rubber
+ name = "rubber submachinegun bullet"
+ sound_override = 'sound/weapons/gun_c99.ogg'
+
+ damage = 0
+ stamina_damage = 10
+ shrapnel_chance = 0
+
+/datum/ammo/bullet/smg/mp27
+ name = "simple submachinegun bullet"
+ damage = 40
+ accurate_range = 5
+ effective_range_max = 7
+ penetration = 0
+ shell_speed = AMMO_SPEED_TIER_6
+ damage_falloff = DAMAGE_FALLOFF_TIER_6
+ scatter = SCATTER_AMOUNT_TIER_6
+ accuracy = HIT_ACCURACY_TIER_2
+
+// less damage than the m39, but better falloff, range, and AP
+
+/datum/ammo/bullet/smg/ppsh
+ name = "crude submachinegun bullet"
+ damage = 26
+ accurate_range = 7
+ effective_range_max = 7
+ penetration = ARMOR_PENETRATION_TIER_2
+ damage_falloff = DAMAGE_FALLOFF_TIER_7
+ scatter = SCATTER_AMOUNT_TIER_5
+
+/datum/ammo/bullet/smg/pps43
+ name = "simple submachinegun bullet"
+ damage = 35
+ accurate_range = 7
+ effective_range_max = 10
+ penetration = ARMOR_PENETRATION_TIER_4
+ damage_falloff = DAMAGE_FALLOFF_TIER_6
+ scatter = SCATTER_AMOUNT_TIER_6
diff --git a/code/datums/ammo/bullet/sniper.dm b/code/datums/ammo/bullet/sniper.dm
new file mode 100644
index 000000000000..a82f00631608
--- /dev/null
+++ b/code/datums/ammo/bullet/sniper.dm
@@ -0,0 +1,170 @@
+/*
+//======
+ Sniper Ammo
+//======
+*/
+
+/datum/ammo/bullet/sniper
+ name = "sniper bullet"
+ headshot_state = HEADSHOT_OVERLAY_HEAVY
+ damage_falloff = 0
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER
+ accurate_range_min = 4
+
+ accuracy = HIT_ACCURACY_TIER_8
+ accurate_range = 32
+ max_range = 32
+ scatter = 0
+ damage = 70
+ penetration= ARMOR_PENETRATION_TIER_10
+ shell_speed = AMMO_SPEED_TIER_6
+ damage_falloff = 0
+
+/datum/ammo/bullet/sniper/on_hit_mob(mob/M,obj/projectile/P)
+ if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
+ var/mob/living/L = M
+ L.apply_armoured_damage(damage*2, ARMOR_BULLET, BRUTE, null, penetration)
+ to_chat(P.firer, SPAN_WARNING("Bullseye!"))
+
+/datum/ammo/bullet/sniper/incendiary
+ name = "incendiary sniper bullet"
+ damage_type = BRUTE
+ shrapnel_chance = 0
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER
+
+ //Removed accuracy = 0, accuracy_var_high = Variance Tier 6, and scatter = 0. -Kaga
+ damage = 60
+ penetration = ARMOR_PENETRATION_TIER_4
+
+/datum/ammo/bullet/sniper/incendiary/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/sniper/incendiary/on_hit_mob(mob/M,obj/projectile/P)
+ if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
+ var/mob/living/L = M
+ var/blind_duration = 5
+ if(isxeno(M))
+ var/mob/living/carbon/xenomorph/target = M
+ if(target.mob_size >= MOB_SIZE_BIG)
+ blind_duration = 2
+ L.AdjustEyeBlur(blind_duration)
+ L.adjust_fire_stacks(10)
+ to_chat(P.firer, SPAN_WARNING("Bullseye!"))
+
+/datum/ammo/bullet/sniper/flak
+ name = "flak sniper bullet"
+ damage_type = BRUTE
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER
+
+ accuracy = HIT_ACCURACY_TIER_8
+ scatter = SCATTER_AMOUNT_TIER_8
+ damage = 55
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8 //Documenting old code: This converts to a variance of 96-109% damage. -Kaga
+ penetration = 0
+
+/datum/ammo/bullet/sniper/flak/on_hit_mob(mob/M,obj/projectile/P)
+ if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
+ var/slow_duration = 7
+ var/mob/living/L = M
+ if(isxeno(M))
+ var/mob/living/carbon/xenomorph/target = M
+ if(target.mob_size >= MOB_SIZE_BIG)
+ slow_duration = 4
+ M.adjust_effect(slow_duration, SUPERSLOW)
+ L.apply_armoured_damage(damage, ARMOR_BULLET, BRUTE, null, penetration)
+ to_chat(P.firer, SPAN_WARNING("Bullseye!"))
+ else
+ burst(get_turf(M),P,damage_type, 2 , 2)
+ burst(get_turf(M),P,damage_type, 1 , 2 , 0)
+
+/datum/ammo/bullet/sniper/flak/on_near_target(turf/T, obj/projectile/P)
+ burst(T,P,damage_type, 2 , 2)
+ burst(T,P,damage_type, 1 , 2, 0)
+ return 1
+
+/datum/ammo/bullet/sniper/crude
+ name = "crude sniper bullet"
+ damage = 42
+ penetration = ARMOR_PENETRATION_TIER_6
+
+/datum/ammo/bullet/sniper/crude/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ pushback(M, P, 3)
+
+/datum/ammo/bullet/sniper/upp
+ name = "armor-piercing sniper bullet"
+ damage = 80
+ penetration = ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/bullet/sniper/anti_materiel
+ name = "anti-materiel sniper bullet"
+
+ shrapnel_chance = 0 // This isn't leaving any shrapnel.
+ accuracy = HIT_ACCURACY_TIER_8
+ damage = 125
+ shell_speed = AMMO_SPEED_TIER_6
+
+/datum/ammo/bullet/sniper/anti_materiel/on_hit_mob(mob/M,obj/projectile/P)
+ if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
+ var/mob/living/L = M
+ var/size_damage_mod = 0.8
+ if(isxeno(M))
+ var/mob/living/carbon/xenomorph/target = M
+ if(target.mob_size >= MOB_SIZE_XENO)
+ size_damage_mod += 0.6
+ if(target.mob_size >= MOB_SIZE_BIG)
+ size_damage_mod += 0.6
+ L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration)
+ // 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga
+ to_chat(P.firer, SPAN_WARNING("Bullseye!"))
+
+/datum/ammo/bullet/sniper/anti_materiel/vulture
+ damage = 400 // Fully intended to vaporize anything smaller than a mini cooper
+ accurate_range_min = 10
+ handful_state = "vulture_bullet"
+ sound_hit = 'sound/bullets/bullet_vulture_impact.ogg'
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER|AMMO_ANTIVEHICLE
+
+/datum/ammo/bullet/sniper/anti_materiel/vulture/on_hit_mob(mob/hit_mob, obj/projectile/bullet)
+ . = ..()
+ knockback(hit_mob, bullet, 30)
+ hit_mob.apply_effect(3, SLOW)
+
+/datum/ammo/bullet/sniper/anti_materiel/vulture/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating/heavy)
+ ))
+
+/datum/ammo/bullet/sniper/elite
+ name = "supersonic sniper bullet"
+
+ shrapnel_chance = 0 // This isn't leaving any shrapnel.
+ accuracy = HIT_ACCURACY_TIER_8
+ damage = 150
+ shell_speed = AMMO_SPEED_TIER_6 + AMMO_SPEED_TIER_2
+
+/datum/ammo/bullet/sniper/elite/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
+ ))
+
+/datum/ammo/bullet/sniper/elite/on_hit_mob(mob/M,obj/projectile/P)
+ if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
+ var/mob/living/L = M
+ var/size_damage_mod = 0.5
+ if(isxeno(M))
+ var/mob/living/carbon/xenomorph/target = M
+ if(target.mob_size >= MOB_SIZE_XENO)
+ size_damage_mod += 0.5
+ if(target.mob_size >= MOB_SIZE_BIG)
+ size_damage_mod += 1
+ L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration)
+ else
+ L.apply_armoured_damage(damage, ARMOR_BULLET, BRUTE, null, penetration)
+ // 150% damage to runners (225), 300% against Big xenos (450), and 200% against all others (300). -Kaga
+ to_chat(P.firer, SPAN_WARNING("Bullseye!"))
diff --git a/code/datums/ammo/bullet/special_ammo.dm b/code/datums/ammo/bullet/special_ammo.dm
new file mode 100644
index 000000000000..3d53c6b0c0d0
--- /dev/null
+++ b/code/datums/ammo/bullet/special_ammo.dm
@@ -0,0 +1,179 @@
+/*
+//======
+ Special Ammo
+//======
+*/
+
+/datum/ammo/bullet/smartgun
+ name = "smartgun bullet"
+ icon_state = "redbullet"
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ max_range = 12
+ accuracy = HIT_ACCURACY_TIER_4
+ damage = 30
+ penetration = 0
+
+/datum/ammo/bullet/smartgun/armor_piercing
+ name = "armor-piercing smartgun bullet"
+ icon_state = "bullet"
+
+ accurate_range = 12
+ accuracy = HIT_ACCURACY_TIER_2
+ damage = 20
+ penetration = ARMOR_PENETRATION_TIER_8
+ damage_armor_punch = 1
+
+/datum/ammo/bullet/smartgun/dirty
+ name = "irradiated smartgun bullet"
+ debilitate = list(0,0,0,3,0,0,0,1)
+
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_7
+ accurate_range = 32
+ accuracy = HIT_ACCURACY_TIER_3
+ damage = 40
+ penetration = 0
+
+/datum/ammo/bullet/smartgun/dirty/armor_piercing
+ debilitate = list(0,0,0,3,0,0,0,1)
+
+ accurate_range = 22
+ accuracy = HIT_ACCURACY_TIER_3
+ damage = 30
+ penetration = ARMOR_PENETRATION_TIER_7
+ damage_armor_punch = 3
+
+/datum/ammo/bullet/smartgun/holo_target //Royal marines smartgun bullet has only diff between regular ammo is this one does holostacks
+ name = "holo-targeting smartgun bullet"
+ damage = 30
+ ///Stuff for the HRP holotargetting stacks
+ var/holo_stacks = 15
+
+/datum/ammo/bullet/smartgun/holo_target/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ M.AddComponent(/datum/component/bonus_damage_stack, holo_stacks, world.time)
+
+/datum/ammo/bullet/smartgun/holo_target/ap
+ name = "armor-piercing smartgun bullet"
+ icon_state = "bullet"
+
+ accurate_range = 12
+ accuracy = HIT_ACCURACY_TIER_2
+ damage = 20
+ penetration = ARMOR_PENETRATION_TIER_8
+ damage_armor_punch = 1
+
+/datum/ammo/bullet/smartgun/m56_fpw
+ name = "\improper M56 FPW bullet"
+ icon_state = "redbullet"
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ max_range = 7
+ accuracy = HIT_ACCURACY_TIER_7
+ damage = 35
+ penetration = ARMOR_PENETRATION_TIER_1
+
+/datum/ammo/bullet/turret
+ name = "autocannon bullet"
+ icon_state = "redbullet" //Red bullets to indicate friendly fire restriction
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_COVER
+
+ accurate_range = 22
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_8
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_8
+ max_range = 22
+ damage = 30
+ penetration = ARMOR_PENETRATION_TIER_7
+ damage_armor_punch = 0
+ pen_armor_punch = 0
+ shell_speed = 2*AMMO_SPEED_TIER_6
+ accuracy = HIT_ACCURACY_TIER_5
+
+/datum/ammo/bullet/turret/dumb
+ icon_state = "bullet"
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+/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
+
+ accurate_range = 12
+ damage = 35
+ penetration= ARMOR_PENETRATION_TIER_10 //Bumped the penetration to serve a different role from sentries, MGs are a bit more offensive
+ accuracy = HIT_ACCURACY_TIER_3
+
+/datum/ammo/bullet/machinegun/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff)
+ ))
+
+/datum/ammo/bullet/machinegun/doorgun
+ flags_ammo_behavior = AMMO_BALLISTIC | AMMO_IGNORE_COVER
+
+/datum/ammo/bullet/machinegun/auto // for M2C, automatic variant for M56D, stats for bullet should always be moderately overtuned to fulfill its ultra-offense + flank-push purpose
+ name = "heavy machinegun bullet"
+
+ accurate_range = 10
+ damage = 50
+ penetration = ARMOR_PENETRATION_TIER_6
+ accuracy = -HIT_ACCURACY_TIER_2 // 75 accuracy
+ shell_speed = AMMO_SPEED_TIER_2
+ max_range = 15
+ effective_range_max = 7
+ damage_falloff = DAMAGE_FALLOFF_TIER_8
+
+/datum/ammo/bullet/machinegun/auto/set_bullet_traits()
+ return
+
+/datum/ammo/bullet/minigun
+ name = "minigun bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+
+ accuracy = -HIT_ACCURACY_TIER_3
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
+ accurate_range = 12
+ damage = 35
+ penetration = ARMOR_PENETRATION_TIER_6
+
+/datum/ammo/bullet/minigun/New()
+ ..()
+ if(SSticker.mode && MODE_HAS_FLAG(MODE_FACTION_CLASH))
+ damage = 15
+ else if(SSticker.current_state < GAME_STATE_PLAYING)
+ RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PRESETUP, PROC_REF(setup_hvh_damage))
+
+/datum/ammo/bullet/minigun/proc/setup_hvh_damage()
+ if(MODE_HAS_FLAG(MODE_FACTION_CLASH))
+ damage = 15
+
+/datum/ammo/bullet/minigun/tank
+ accuracy = -HIT_ACCURACY_TIER_1
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_8
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_8
+ accurate_range = 12
+
+/datum/ammo/bullet/m60
+ name = "M60 bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+
+ accuracy = HIT_ACCURACY_TIER_2
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_8
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
+ accurate_range = 12
+ damage = 45 //7.62x51 is scary
+ penetration= ARMOR_PENETRATION_TIER_6
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
+
+/datum/ammo/bullet/pkp
+ name = "machinegun bullet"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+
+ accuracy = HIT_ACCURACY_TIER_1
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_8
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
+ accurate_range = 14
+ damage = 35
+ penetration= ARMOR_PENETRATION_TIER_6
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
diff --git a/code/datums/ammo/bullet/tank.dm b/code/datums/ammo/bullet/tank.dm
new file mode 100644
index 000000000000..70a953c6e273
--- /dev/null
+++ b/code/datums/ammo/bullet/tank.dm
@@ -0,0 +1,74 @@
+/*
+//======
+ Tank Ammo
+//======
+*/
+
+/datum/ammo/bullet/tank/flak
+ name = "flak autocannon bullet"
+ icon_state = "autocannon"
+ damage_falloff = 0
+ flags_ammo_behavior = AMMO_BALLISTIC
+ accurate_range_min = 4
+
+ accuracy = HIT_ACCURACY_TIER_8
+ scatter = 0
+ damage = 60
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_6
+ accurate_range = 32
+ max_range = 32
+ shell_speed = AMMO_SPEED_TIER_6
+
+/datum/ammo/bullet/tank/flak/on_hit_mob(mob/M,obj/projectile/P)
+ burst(get_turf(M),P,damage_type, 2 , 3)
+ burst(get_turf(M),P,damage_type, 1 , 3 , 0)
+
+/datum/ammo/bullet/tank/flak/on_near_target(turf/T, obj/projectile/P)
+ burst(get_turf(T),P,damage_type, 2 , 3)
+ burst(get_turf(T),P,damage_type, 1 , 3, 0)
+ return 1
+
+/datum/ammo/bullet/tank/flak/on_hit_obj(obj/O,obj/projectile/P)
+ burst(get_turf(P),P,damage_type, 2 , 3)
+ burst(get_turf(P),P,damage_type, 1 , 3 , 0)
+
+/datum/ammo/bullet/tank/flak/on_hit_turf(turf/T,obj/projectile/P)
+ burst(get_turf(T),P,damage_type, 2 , 3)
+ burst(get_turf(T),P,damage_type, 1 , 3 , 0)
+
+/datum/ammo/bullet/tank/dualcannon
+ name = "dualcannon bullet"
+ icon_state = "autocannon"
+ damage_falloff = 0
+ flags_ammo_behavior = AMMO_BALLISTIC
+
+ accuracy = HIT_ACCURACY_TIER_8
+ scatter = 0
+ damage = 50
+ damage_var_high = PROJECTILE_VARIANCE_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_3
+ accurate_range = 10
+ max_range = 12
+ shell_speed = AMMO_SPEED_TIER_5
+
+/datum/ammo/bullet/tank/dualcannon/on_hit_mob(mob/M,obj/projectile/P)
+ for(var/mob/living/carbon/L in get_turf(M))
+ if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO)
+ shake_camera(L, 1, 1)
+
+/datum/ammo/bullet/tank/dualcannon/on_near_target(turf/T, obj/projectile/P)
+ for(var/mob/living/carbon/L in T)
+ if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO)
+ shake_camera(L, 1, 1)
+ return 1
+
+/datum/ammo/bullet/tank/dualcannon/on_hit_obj(obj/O,obj/projectile/P)
+ for(var/mob/living/carbon/L in get_turf(O))
+ if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO)
+ shake_camera(L, 1, 1)
+
+/datum/ammo/bullet/tank/dualcannon/on_hit_turf(turf/T,obj/projectile/P)
+ for(var/mob/living/carbon/L in T)
+ if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO)
+ shake_camera(L, 1, 1)
diff --git a/code/datums/ammo/energy.dm b/code/datums/ammo/energy.dm
new file mode 100644
index 000000000000..27d2b7d4e0c5
--- /dev/null
+++ b/code/datums/ammo/energy.dm
@@ -0,0 +1,232 @@
+/*
+//======
+ Energy Ammo
+//======
+*/
+
+/datum/ammo/energy
+ ping = null //no bounce off. We can have one later.
+ sound_hit = "energy_hit"
+ sound_miss = "energy_miss"
+ sound_bounce = "energy_bounce"
+
+ damage_type = BURN
+ flags_ammo_behavior = AMMO_ENERGY
+
+ accuracy = HIT_ACCURACY_TIER_4
+
+/datum/ammo/energy/emitter //Damage is determined in emitter.dm
+ name = "emitter bolt"
+ icon_state = "emitter"
+ flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_ARMOR
+
+ accurate_range = 6
+ max_range = 6
+
+/datum/ammo/energy/taser
+ name = "taser bolt"
+ icon_state = "stun"
+ damage_type = OXY
+ flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST|AMMO_ALWAYS_FF //Not that ignoring will do much right now.
+
+ stamina_damage = 45
+ accuracy = HIT_ACCURACY_TIER_8
+ shell_speed = AMMO_SPEED_TIER_1 // Slightly faster
+ hit_effect_color = "#FFFF00"
+
+/datum/ammo/energy/taser/on_hit_mob(mob/M, obj/projectile/P)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ H.disable_special_items() // Disables scout cloak
+
+/datum/ammo/energy/taser/precise
+ name = "precise taser bolt"
+ flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST|AMMO_MP
+
+/datum/ammo/energy/rxfm_eva
+ name = "laser blast"
+ icon_state = "laser_new"
+ flags_ammo_behavior = AMMO_LASER
+ accurate_range = 14
+ max_range = 22
+ damage = 45
+ stamina_damage = 25 //why not
+ shell_speed = AMMO_SPEED_TIER_3
+
+/datum/ammo/energy/rxfm_eva/on_hit_mob(mob/living/M, obj/projectile/P)
+ ..()
+ if(prob(10)) //small chance for one to ignite on hit
+ M.fire_act()
+
+/datum/ammo/energy/laz_uzi
+ name = "laser bolt"
+ icon_state = "laser_new"
+ flags_ammo_behavior = AMMO_ENERGY
+ damage = 40
+ accurate_range = 5
+ effective_range_max = 7
+ max_range = 10
+ shell_speed = AMMO_SPEED_TIER_4
+ scatter = SCATTER_AMOUNT_TIER_6
+ accuracy = HIT_ACCURACY_TIER_3
+ damage_falloff = DAMAGE_FALLOFF_TIER_8
+
+/datum/ammo/energy/yautja
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+ accurate_range = 12
+ shell_speed = AMMO_SPEED_TIER_3
+ damage_type = BURN
+ flags_ammo_behavior = AMMO_IGNORE_RESIST
+
+/datum/ammo/energy/yautja/pistol
+ name = "plasma pistol bolt"
+ icon_state = "ion"
+
+ damage = 40
+ shell_speed = AMMO_SPEED_TIER_2
+
+/datum/ammo/energy/yautja/pistol/incendiary
+ damage = 10
+
+/datum/ammo/energy/yautja/pistol/incendiary/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/shrapnel/plasma
+ name = "plasma wave"
+ shrapnel_chance = 0
+ penetration = ARMOR_PENETRATION_TIER_10
+ accuracy = HIT_ACCURACY_TIER_MAX
+ damage = 15
+ icon_state = "shrapnel_plasma"
+ damage_type = BURN
+
+/datum/ammo/bullet/shrapnel/plasma/on_hit_mob(mob/living/hit_mob, obj/projectile/hit_projectile)
+ hit_mob.Stun(2)
+
+/datum/ammo/energy/yautja/caster
+ name = "root caster bolt"
+ icon_state = "ion"
+
+/datum/ammo/energy/yautja/caster/stun
+ name = "low power stun bolt"
+ debilitate = list(2,2,0,0,0,1,0,0)
+
+ damage = 0
+ flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST
+
+/datum/ammo/energy/yautja/caster/bolt
+ name = "plasma bolt"
+ icon_state = "pulse1"
+ flags_ammo_behavior = AMMO_IGNORE_RESIST
+ shell_speed = AMMO_SPEED_TIER_6
+ damage = 35
+
+/datum/ammo/energy/yautja/caster/bolt/stun
+ name = "high power stun bolt"
+ var/stun_time = 2
+
+ damage = 0
+ flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST
+
+/datum/ammo/energy/yautja/caster/bolt/stun/on_hit_mob(mob/M, obj/projectile/P)
+ var/mob/living/carbon/C = M
+ var/stun_time = src.stun_time
+ if(istype(C))
+ if(isyautja(C) || ispredalien(C))
+ return
+ to_chat(C, SPAN_DANGER("An electric shock ripples through your body, freezing you in place!"))
+ log_attack("[key_name(C)] was stunned by a high power stun bolt from [key_name(P.firer)] at [get_area(P)]")
+
+ if(ishuman(C))
+ stun_time++
+ C.apply_effect(stun_time, WEAKEN)
+ C.apply_effect(stun_time, STUN)
+ ..()
+
+/datum/ammo/energy/yautja/caster/sphere
+ name = "plasma eradicator"
+ icon_state = "bluespace"
+ flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_HITS_TARGET_TURF
+ shell_speed = AMMO_SPEED_TIER_4
+ accuracy = HIT_ACCURACY_TIER_8
+
+ damage = 55
+
+ accurate_range = 8
+ max_range = 8
+
+ var/vehicle_slowdown_time = 5 SECONDS
+
+/datum/ammo/energy/yautja/caster/sphere/on_hit_mob(mob/M, obj/projectile/P)
+ cell_explosion(P, 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+
+/datum/ammo/energy/yautja/caster/sphere/on_hit_turf(turf/T, obj/projectile/P)
+ cell_explosion(P, 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+
+/datum/ammo/energy/yautja/caster/sphere/on_hit_obj(obj/O, obj/projectile/P)
+ if(istype(O, /obj/vehicle/multitile))
+ var/obj/vehicle/multitile/multitile_vehicle = O
+ multitile_vehicle.next_move = world.time + vehicle_slowdown_time
+ playsound(multitile_vehicle, 'sound/effects/meteorimpact.ogg', 35)
+ multitile_vehicle.at_munition_interior_explosion_effect(cause_data = create_cause_data("Plasma Eradicator", P.firer))
+ multitile_vehicle.interior_crash_effect()
+ multitile_vehicle.ex_act(150, P.dir, P.weapon_cause_data, 100)
+ cell_explosion(get_turf(P), 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+
+/datum/ammo/energy/yautja/caster/sphere/do_at_max_range(obj/projectile/P)
+ cell_explosion(get_turf(P), 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+
+
+/datum/ammo/energy/yautja/caster/sphere/stun
+ name = "plasma immobilizer"
+ damage = 0
+ flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST
+ accurate_range = 20
+ max_range = 20
+
+ var/stun_range = 4 // Big
+ var/stun_time = 6
+
+/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_mob(mob/M, obj/projectile/P)
+ do_area_stun(P)
+
+/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_turf(turf/T,obj/projectile/P)
+ do_area_stun(P)
+
+/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_obj(obj/O,obj/projectile/P)
+ do_area_stun(P)
+
+/datum/ammo/energy/yautja/caster/sphere/stun/do_at_max_range(obj/projectile/P)
+ do_area_stun(P)
+
+/datum/ammo/energy/yautja/caster/sphere/stun/proc/do_area_stun(obj/projectile/P)
+ playsound(P, 'sound/weapons/wave.ogg', 75, 1, 25)
+ for (var/mob/living/carbon/M in view(src.stun_range, get_turf(P)))
+ var/stun_time = src.stun_time
+ log_attack("[key_name(M)] was stunned by a plasma immobilizer from [key_name(P.firer)] at [get_area(P)]")
+ if (isyautja(M))
+ stun_time -= 2
+ if(ispredalien(M))
+ continue
+ to_chat(M, SPAN_DANGER("A powerful electric shock ripples through your body, freezing you in place!"))
+ M.apply_effect(stun_time, STUN)
+ M.apply_effect(stun_time, WEAKEN)
+
+/datum/ammo/energy/yautja/rifle/bolt
+ name = "plasma rifle bolt"
+ icon_state = "ion"
+ damage_type = BURN
+ debilitate = list(0,2,0,0,0,0,0,0)
+ flags_ammo_behavior = AMMO_IGNORE_RESIST
+
+ damage = 55
+ penetration = ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/energy/yautja/rifle/bolt/on_hit_mob(mob/hit_mob, obj/projectile/hit_projectile)
+ if(isxeno(hit_mob))
+ var/mob/living/carbon/xenomorph/xeno = hit_mob
+ xeno.apply_damage(damage * 0.75, BURN)
+ xeno.interference = 30
diff --git a/code/datums/ammo/misc.dm b/code/datums/ammo/misc.dm
new file mode 100644
index 000000000000..3aaba8443efb
--- /dev/null
+++ b/code/datums/ammo/misc.dm
@@ -0,0 +1,294 @@
+/*
+//======
+ Misc Ammo
+//======
+*/
+
+/datum/ammo/alloy_spike
+ name = "alloy spike"
+ headshot_state = HEADSHOT_OVERLAY_MEDIUM
+ ping = "ping_s"
+ icon_state = "MSpearFlight"
+ sound_hit = "alloy_hit"
+ sound_armor = "alloy_armor"
+ sound_bounce = "alloy_bounce"
+
+ accuracy = HIT_ACCURACY_TIER_8
+ accurate_range = 12
+ max_range = 12
+ damage = 30
+ penetration= ARMOR_PENETRATION_TIER_10
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_7
+ shrapnel_type = /obj/item/shard/shrapnel
+
+/datum/ammo/flamethrower
+ name = "flame"
+ icon_state = "pulse0"
+ damage_type = BURN
+ flags_ammo_behavior = AMMO_IGNORE_ARMOR|AMMO_HITS_TARGET_TURF
+
+ max_range = 6
+ damage = 35
+
+/datum/ammo/flamethrower/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/flamethrower/on_hit_mob(mob/M, obj/projectile/P)
+ drop_flame(get_turf(M), P.weapon_cause_data)
+
+/datum/ammo/flamethrower/on_hit_obj(obj/O, obj/projectile/P)
+ drop_flame(get_turf(O), P.weapon_cause_data)
+
+/datum/ammo/flamethrower/on_hit_turf(turf/T, obj/projectile/P)
+ drop_flame(T, P.weapon_cause_data)
+
+/datum/ammo/flamethrower/do_at_max_range(obj/projectile/P)
+ drop_flame(get_turf(P), P.weapon_cause_data)
+
+/datum/ammo/flamethrower/tank_flamer
+ flamer_reagent_type = /datum/reagent/napalm/blue
+
+/datum/ammo/flamethrower/sentry_flamer
+ flags_ammo_behavior = AMMO_IGNORE_ARMOR|AMMO_IGNORE_COVER|AMMO_FLAME
+ flamer_reagent_type = /datum/reagent/napalm/blue
+
+ accuracy = HIT_ACCURACY_TIER_8
+ accurate_range = 6
+ max_range = 12
+ shell_speed = AMMO_SPEED_TIER_3
+
+/datum/ammo/flamethrower/sentry_flamer/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/flamethrower/sentry_flamer/glob
+ max_range = 14
+ accurate_range = 10
+ var/datum/effect_system/smoke_spread/phosphorus/smoke
+
+/datum/ammo/flamethrower/sentry_flamer/glob/New()
+ . = ..()
+ smoke = new()
+
+/datum/ammo/flamethrower/sentry_flamer/glob/drop_flame(turf/T, datum/cause_data/cause_data)
+ if(!istype(T))
+ return
+ smoke.set_up(1, 0, T, new_cause_data = cause_data)
+ smoke.start()
+
+/datum/ammo/flamethrower/sentry_flamer/glob/Destroy()
+ qdel(smoke)
+ return ..()
+
+/datum/ammo/flamethrower/sentry_flamer/mini
+ name = "normal fire"
+
+/datum/ammo/flamethrower/sentry_flamer/mini/drop_flame(turf/T, datum/cause_data/cause_data)
+ if(!istype(T))
+ return
+ var/datum/reagent/napalm/ut/R = new()
+ R.durationfire = BURN_TIME_INSTANT
+ new /obj/flamer_fire(T, cause_data, R, 0)
+
+/datum/ammo/flare
+ name = "flare"
+ ping = null //no bounce off.
+ damage_type = BURN
+ flags_ammo_behavior = AMMO_HITS_TARGET_TURF
+ icon_state = "flare"
+
+ damage = 15
+ accuracy = HIT_ACCURACY_TIER_3
+ max_range = 14
+ shell_speed = AMMO_SPEED_TIER_3
+
+ var/flare_type = /obj/item/device/flashlight/flare/on/gun
+ handful_type = /obj/item/device/flashlight/flare
+
+/datum/ammo/flare/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/flare/on_hit_mob(mob/M,obj/projectile/P)
+ drop_flare(get_turf(M), P, P.firer)
+
+/datum/ammo/flare/on_hit_obj(obj/O,obj/projectile/P)
+ drop_flare(get_turf(P), P, P.firer)
+
+/datum/ammo/flare/on_hit_turf(turf/T, obj/projectile/P)
+ if(T.density && isturf(P.loc))
+ drop_flare(P.loc, P, P.firer)
+ else
+ drop_flare(T, P, P.firer)
+
+/datum/ammo/flare/do_at_max_range(obj/projectile/P, mob/firer)
+ drop_flare(get_turf(P), P, P.firer)
+
+/datum/ammo/flare/proc/drop_flare(turf/T, obj/projectile/fired_projectile, mob/firer)
+ var/obj/item/device/flashlight/flare/G = new flare_type(T)
+ var/matrix/rotation = matrix()
+ rotation.Turn(fired_projectile.angle - 90)
+ G.apply_transform(rotation)
+ G.visible_message(SPAN_WARNING("\A [G] bursts into brilliant light nearby!"))
+ return G
+
+/datum/ammo/flare/signal
+ name = "signal flare"
+ icon_state = "flare_signal"
+ flare_type = /obj/item/device/flashlight/flare/signal/gun
+ handful_type = /obj/item/device/flashlight/flare/signal
+
+/datum/ammo/flare/signal/drop_flare(turf/T, obj/projectile/fired_projectile, mob/firer)
+ var/obj/item/device/flashlight/flare/signal/gun/signal_flare = ..()
+ signal_flare.activate_signal(firer)
+ if(istype(fired_projectile.shot_from, /obj/item/weapon/gun/flare))
+ var/obj/item/weapon/gun/flare/flare_gun_fired_from = fired_projectile.shot_from
+ flare_gun_fired_from.last_signal_flare_name = signal_flare.name
+
+/datum/ammo/flare/starshell
+ name = "starshell ash"
+ icon_state = "starshell_bullet"
+ max_range = 5
+ flare_type = /obj/item/device/flashlight/flare/on/starshell_ash
+
+/datum/ammo/flare/starshell/set_bullet_traits()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff, /datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/souto
+ name = "Souto Can"
+ ping = null //no bounce off.
+ damage_type = BRUTE
+ shrapnel_type = /obj/item/reagent_container/food/drinks/cans/souto/classic
+ flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_IGNORE_ARMOR|AMMO_IGNORE_RESIST|AMMO_BALLISTIC|AMMO_STOPPED_BY_COVER|AMMO_SPECIAL_EMBED
+ var/obj/item/reagent_container/food/drinks/cans/souto/can_type
+ icon_state = "souto_classic"
+
+ max_range = 12
+ shrapnel_chance = 10
+ accuracy = HIT_ACCURACY_TIER_8 + HIT_ACCURACY_TIER_8
+ accurate_range = 12
+ shell_speed = AMMO_SPEED_TIER_1
+
+/datum/ammo/souto/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE)
+ if(ishuman(embedded_mob) && !isyautja(embedded_mob))
+ if(istype(target_organ))
+ target_organ.embed(new can_type)
+
+/datum/ammo/souto/on_hit_mob(mob/M, obj/projectile/P)
+ if(!M || M == P.firer) return
+ if(M.throw_mode && !M.get_active_hand()) //empty active hand and we're in throw mode. If so we catch the can.
+ if(!M.is_mob_incapacitated()) // People who are not able to catch cannot catch.
+ if(P.contents.len == 1)
+ for(var/obj/item/reagent_container/food/drinks/cans/souto/S in P.contents)
+ M.put_in_active_hand(S)
+ for(var/mob/O in viewers(GLOB.world_view_size, P)) //find all people in view.
+ O.show_message(SPAN_DANGER("[M] catches [S]!"), SHOW_MESSAGE_VISIBLE) //Tell them the can was caught.
+ return //Can was caught.
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.species.name == "Human") //no effect on synths or preds.
+ H.apply_effect(6, STUN)
+ H.apply_effect(8, WEAKEN)
+ H.apply_effect(15, DAZE)
+ H.apply_effect(15, SLOW)
+ shake_camera(H, 2, 1)
+ if(P.contents.len)
+ drop_can(P.loc, P) //We make a can at the location.
+
+/datum/ammo/souto/on_hit_obj(obj/O,obj/projectile/P)
+ drop_can(P.loc, P) //We make a can at the location.
+
+/datum/ammo/souto/on_hit_turf(turf/T, obj/projectile/P)
+ drop_can(P.loc, P) //We make a can at the location.
+
+/datum/ammo/souto/do_at_max_range(obj/projectile/P)
+ drop_can(P.loc, P) //We make a can at the location.
+
+/datum/ammo/souto/on_shield_block(mob/M, obj/projectile/P)
+ drop_can(P.loc, P) //We make a can at the location.
+
+/datum/ammo/souto/proc/drop_can(loc, obj/projectile/P)
+ if(P.contents.len)
+ for(var/obj/item/I in P.contents)
+ I.forceMove(loc)
+ randomize_projectile(P)
+
+/datum/ammo/souto/proc/randomize_projectile(obj/projectile/P)
+ shrapnel_type = pick(typesof(/obj/item/reagent_container/food/drinks/cans/souto)-/obj/item/reagent_container/food/drinks/cans/souto)
+
+/datum/ammo/grenade_container
+ name = "grenade shell"
+ ping = null
+ damage_type = BRUTE
+ var/nade_type = /obj/item/explosive/grenade/high_explosive
+ icon_state = "grenade"
+ flags_ammo_behavior = AMMO_IGNORE_COVER|AMMO_SKIPS_ALIENS
+
+ damage = 15
+ accuracy = HIT_ACCURACY_TIER_3
+ max_range = 6
+
+/datum/ammo/grenade_container/on_hit_mob(mob/M,obj/projectile/P)
+ drop_nade(P)
+
+/datum/ammo/grenade_container/on_hit_obj(obj/O,obj/projectile/P)
+ drop_nade(P)
+
+/datum/ammo/grenade_container/on_hit_turf(turf/T,obj/projectile/P)
+ drop_nade(P)
+
+/datum/ammo/grenade_container/do_at_max_range(obj/projectile/P)
+ drop_nade(P)
+
+/datum/ammo/grenade_container/proc/drop_nade(obj/projectile/P)
+ var/turf/T = get_turf(P)
+ var/obj/item/explosive/grenade/G = new nade_type(T)
+ G.visible_message(SPAN_WARNING("\A [G] lands on [T]!"))
+ G.det_time = 10
+ G.cause_data = P.weapon_cause_data
+ G.activate()
+
+/datum/ammo/grenade_container/rifle
+ flags_ammo_behavior = NO_FLAGS
+
+/datum/ammo/grenade_container/smoke
+ name = "smoke grenade shell"
+ nade_type = /obj/item/explosive/grenade/smokebomb
+ icon_state = "smoke_shell"
+
+/datum/ammo/hugger_container
+ name = "hugger shell"
+ ping = null
+ damage_type = BRUTE
+ var/hugger_hive = XENO_HIVE_NORMAL
+ icon_state = "smoke_shell"
+
+ damage = 15
+ accuracy = HIT_ACCURACY_TIER_3
+ max_range = 6
+
+/datum/ammo/hugger_container/on_hit_mob(mob/M,obj/projectile/P)
+ spawn_hugger(get_turf(P))
+
+/datum/ammo/hugger_container/on_hit_obj(obj/O,obj/projectile/P)
+ spawn_hugger(get_turf(P))
+
+/datum/ammo/hugger_container/on_hit_turf(turf/T,obj/projectile/P)
+ spawn_hugger(get_turf(P))
+
+/datum/ammo/hugger_container/do_at_max_range(obj/projectile/P)
+ spawn_hugger(get_turf(P))
+
+/datum/ammo/hugger_container/proc/spawn_hugger(turf/T)
+ var/obj/item/clothing/mask/facehugger/child = new(T)
+ child.hivenumber = hugger_hive
+ INVOKE_ASYNC(child, TYPE_PROC_REF(/obj/item/clothing/mask/facehugger, leap_at_nearest_target))
diff --git a/code/datums/ammo/rocket.dm b/code/datums/ammo/rocket.dm
new file mode 100644
index 000000000000..66a9f65bdcdd
--- /dev/null
+++ b/code/datums/ammo/rocket.dm
@@ -0,0 +1,298 @@
+/*
+//======
+ Rocket Ammo
+//======
+*/
+
+/datum/ammo/rocket
+ name = "high explosive rocket"
+ icon_state = "missile"
+ ping = null //no bounce off.
+ sound_bounce = "rocket_bounce"
+ damage_falloff = 0
+ flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_STRIKES_SURFACE
+ var/datum/effect_system/smoke_spread/smoke
+
+ accuracy = HIT_ACCURACY_TIER_2
+ accurate_range = 7
+ max_range = 7
+ damage = 15
+ shell_speed = AMMO_SPEED_TIER_2
+
+/datum/ammo/rocket/New()
+ ..()
+ smoke = new()
+
+/datum/ammo/rocket/Destroy()
+ qdel(smoke)
+ smoke = null
+ . = ..()
+
+/datum/ammo/rocket/on_hit_mob(mob/M, obj/projectile/P)
+ cell_explosion(get_turf(M), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ smoke.set_up(1, get_turf(M))
+ if(ishuman_strict(M)) // No yautya or synths. Makes humans gib on direct hit.
+ M.ex_act(350, P.dir, P.weapon_cause_data, 100)
+ smoke.start()
+
+/datum/ammo/rocket/on_hit_obj(obj/O, obj/projectile/P)
+ cell_explosion(get_turf(O), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ smoke.set_up(1, get_turf(O))
+ smoke.start()
+
+/datum/ammo/rocket/on_hit_turf(turf/T, obj/projectile/P)
+ cell_explosion(T, 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ smoke.set_up(1, T)
+ smoke.start()
+
+/datum/ammo/rocket/do_at_max_range(obj/projectile/P)
+ cell_explosion(get_turf(P), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ smoke.set_up(1, get_turf(P))
+ smoke.start()
+
+/datum/ammo/rocket/ap
+ name = "anti-armor rocket"
+ damage_falloff = 0
+ flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET
+
+ accuracy = HIT_ACCURACY_TIER_8
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_9
+ accurate_range = 6
+ max_range = 6
+ damage = 10
+ penetration= ARMOR_PENETRATION_TIER_10
+
+/datum/ammo/rocket/ap/on_hit_mob(mob/M, obj/projectile/P)
+ var/turf/T = get_turf(M)
+ M.ex_act(150, P.dir, P.weapon_cause_data, 100)
+ M.apply_effect(2, PARALYZE)
+ if(ishuman_strict(M)) // No yautya or synths. Makes humans gib on direct hit.
+ M.ex_act(300, P.dir, P.weapon_cause_data, 100)
+ cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ smoke.set_up(1, T)
+ smoke.start()
+
+/datum/ammo/rocket/ap/on_hit_obj(obj/O, obj/projectile/P)
+ var/turf/T = get_turf(O)
+ O.ex_act(150, P.dir, P.weapon_cause_data, 100)
+ cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ smoke.set_up(1, T)
+ smoke.start()
+
+/datum/ammo/rocket/ap/on_hit_turf(turf/T, obj/projectile/P)
+ var/hit_something = 0
+ for(var/mob/M in T)
+ M.ex_act(150, P.dir, P.weapon_cause_data, 100)
+ M.apply_effect(4, PARALYZE)
+ hit_something = 1
+ continue
+ if(!hit_something)
+ for(var/obj/O in T)
+ if(O.density)
+ O.ex_act(150, P.dir, P.weapon_cause_data, 100)
+ hit_something = 1
+ continue
+ if(!hit_something)
+ T.ex_act(150, P.dir, P.weapon_cause_data, 200)
+
+ cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ smoke.set_up(1, T)
+ smoke.start()
+
+/datum/ammo/rocket/ap/do_at_max_range(obj/projectile/P)
+ var/turf/T = get_turf(P)
+ var/hit_something = 0
+ for(var/mob/M in T)
+ M.ex_act(250, P.dir, P.weapon_cause_data, 100)
+ M.apply_effect(2, WEAKEN)
+ M.apply_effect(2, PARALYZE)
+ hit_something = 1
+ continue
+ if(!hit_something)
+ for(var/obj/O in T)
+ if(O.density)
+ O.ex_act(250, P.dir, P.weapon_cause_data, 100)
+ hit_something = 1
+ continue
+ if(!hit_something)
+ T.ex_act(250, P.dir, P.weapon_cause_data)
+ cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ smoke.set_up(1, T)
+ smoke.start()
+
+/datum/ammo/rocket/ap/anti_tank
+ name = "anti-tank rocket"
+ damage = 100
+ var/vehicle_slowdown_time = 5 SECONDS
+ shrapnel_chance = 5
+ shrapnel_type = /obj/item/large_shrapnel/at_rocket_dud
+
+/datum/ammo/rocket/ap/anti_tank/on_hit_obj(obj/O, obj/projectile/P)
+ if(istype(O, /obj/vehicle/multitile))
+ var/obj/vehicle/multitile/M = O
+ M.next_move = world.time + vehicle_slowdown_time
+ playsound(M, 'sound/effects/meteorimpact.ogg', 35)
+ M.at_munition_interior_explosion_effect(cause_data = create_cause_data("Anti-Tank Rocket"))
+ M.interior_crash_effect()
+ var/turf/T = get_turf(M.loc)
+ M.ex_act(150, P.dir, P.weapon_cause_data, 100)
+ smoke.set_up(1, T)
+ smoke.start()
+ return
+ return ..()
+
+
+/datum/ammo/rocket/ltb
+ name = "cannon round"
+ icon_state = "ltb"
+ flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_STRIKES_SURFACE
+
+ accuracy = HIT_ACCURACY_TIER_3
+ accurate_range = 32
+ max_range = 32
+ damage = 25
+ shell_speed = AMMO_SPEED_TIER_3
+
+/datum/ammo/rocket/ltb/on_hit_mob(mob/M, obj/projectile/P)
+ cell_explosion(get_turf(M), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ cell_explosion(get_turf(M), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+
+/datum/ammo/rocket/ltb/on_hit_obj(obj/O, obj/projectile/P)
+ cell_explosion(get_turf(O), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ cell_explosion(get_turf(O), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+
+/datum/ammo/rocket/ltb/on_hit_turf(turf/T, obj/projectile/P)
+ cell_explosion(get_turf(T), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ cell_explosion(get_turf(T), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+
+/datum/ammo/rocket/ltb/do_at_max_range(obj/projectile/P)
+ cell_explosion(get_turf(P), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+ cell_explosion(get_turf(P), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
+
+/datum/ammo/rocket/wp
+ name = "white phosphorous rocket"
+ flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE|AMMO_STRIKES_SURFACE
+ damage_type = BURN
+
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ accurate_range = 8
+ damage = 90
+ max_range = 8
+
+/datum/ammo/rocket/wp/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/rocket/wp/drop_flame(turf/T, datum/cause_data/cause_data)
+ playsound(T, 'sound/weapons/gun_flamethrower3.ogg', 75, 1, 7)
+ if(!istype(T)) return
+ smoke.set_up(1, T)
+ smoke.start()
+ var/datum/reagent/napalm/blue/R = new()
+ new /obj/flamer_fire(T, cause_data, R, 3)
+
+ var/datum/effect_system/smoke_spread/phosphorus/landingSmoke = new /datum/effect_system/smoke_spread/phosphorus
+ landingSmoke.set_up(3, 0, T, null, 6, cause_data)
+ landingSmoke.start()
+ landingSmoke = null
+
+/datum/ammo/rocket/wp/on_hit_mob(mob/M, obj/projectile/P)
+ drop_flame(get_turf(M), P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/on_hit_obj(obj/O, obj/projectile/P)
+ drop_flame(get_turf(O), P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/on_hit_turf(turf/T, obj/projectile/P)
+ drop_flame(T, P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/do_at_max_range(obj/projectile/P)
+ drop_flame(get_turf(P), P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/upp
+ name = "extreme-intensity incendiary rocket"
+ flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE|AMMO_STRIKES_SURFACE
+ damage_type = BURN
+
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ accurate_range = 8
+ damage = 150
+ max_range = 10
+
+/datum/ammo/rocket/wp/upp/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/rocket/wp/upp/drop_flame(turf/T, datum/cause_data/cause_data)
+ playsound(T, 'sound/weapons/gun_flamethrower3.ogg', 75, 1, 7)
+ if(!istype(T)) return
+ smoke.set_up(1, T)
+ smoke.start()
+ var/datum/reagent/napalm/upp/R = new()
+ new /obj/flamer_fire(T, cause_data, R, 3)
+
+/datum/ammo/rocket/wp/upp/on_hit_mob(mob/M, obj/projectile/P)
+ drop_flame(get_turf(M), P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/upp/on_hit_obj(obj/O, obj/projectile/P)
+ drop_flame(get_turf(O), P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/upp/on_hit_turf(turf/T, obj/projectile/P)
+ drop_flame(T, P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/upp/do_at_max_range(obj/projectile/P)
+ drop_flame(get_turf(P), P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/quad
+ name = "thermobaric rocket"
+ flags_ammo_behavior = AMMO_ROCKET|AMMO_STRIKES_SURFACE
+
+ damage = 100
+ max_range = 32
+ shell_speed = AMMO_SPEED_TIER_3
+
+/datum/ammo/rocket/wp/quad/on_hit_mob(mob/M, obj/projectile/P)
+ drop_flame(get_turf(M), P.weapon_cause_data)
+ explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/quad/on_hit_obj(obj/O, obj/projectile/P)
+ drop_flame(get_turf(O), P.weapon_cause_data)
+ explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/quad/on_hit_turf(turf/T, obj/projectile/P)
+ drop_flame(T, P.weapon_cause_data)
+ explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data)
+
+/datum/ammo/rocket/wp/quad/do_at_max_range(obj/projectile/P)
+ drop_flame(get_turf(P), P.weapon_cause_data)
+ explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data)
+
+/datum/ammo/rocket/custom
+ name = "custom rocket"
+
+/datum/ammo/rocket/custom/proc/prime(atom/A, obj/projectile/P)
+ var/obj/item/weapon/gun/launcher/rocket/launcher = P.shot_from
+ var/obj/item/ammo_magazine/rocket/custom/rocket = launcher.current_mag
+ if(rocket.locked && rocket.warhead && rocket.warhead.detonator)
+ if(rocket.fuel && rocket.fuel.reagents.get_reagent_amount(rocket.fuel_type) >= rocket.fuel_requirement)
+ rocket.forceMove(P.loc)
+ rocket.warhead.cause_data = P.weapon_cause_data
+ rocket.warhead.prime()
+ qdel(rocket)
+ smoke.set_up(1, get_turf(A))
+ smoke.start()
+
+/datum/ammo/rocket/custom/on_hit_mob(mob/M, obj/projectile/P)
+ prime(M, P)
+
+/datum/ammo/rocket/custom/on_hit_obj(obj/O, obj/projectile/P)
+ prime(O, P)
+
+/datum/ammo/rocket/custom/on_hit_turf(turf/T, obj/projectile/P)
+ prime(T, P)
+
+/datum/ammo/rocket/custom/do_at_max_range(obj/projectile/P)
+ prime(null, P)
diff --git a/code/datums/ammo/shrapnel.dm b/code/datums/ammo/shrapnel.dm
new file mode 100644
index 000000000000..e27caa4b277d
--- /dev/null
+++ b/code/datums/ammo/shrapnel.dm
@@ -0,0 +1,157 @@
+/*
+//======
+ Shrapnel
+//======
+*/
+/datum/ammo/bullet/shrapnel
+ name = "shrapnel"
+ icon_state = "buckshot"
+ accurate_range_min = 5
+ flags_ammo_behavior = AMMO_BALLISTIC|AMMO_STOPPED_BY_COVER
+
+ accuracy = HIT_ACCURACY_TIER_3
+ accurate_range = 32
+ max_range = 8
+ damage = 25
+ damage_var_low = -PROJECTILE_VARIANCE_TIER_6
+ damage_var_high = PROJECTILE_VARIANCE_TIER_6
+ penetration = ARMOR_PENETRATION_TIER_4
+ shell_speed = AMMO_SPEED_TIER_2
+ shrapnel_chance = 5
+
+/datum/ammo/bullet/shrapnel/on_hit_obj(obj/O, obj/projectile/P)
+ if(istype(O, /obj/structure/barricade))
+ var/obj/structure/barricade/B = O
+ B.health -= rand(2, 5)
+ B.update_health(1)
+
+/datum/ammo/bullet/shrapnel/rubber
+ name = "rubber pellets"
+ icon_state = "rubber_pellets"
+ flags_ammo_behavior = AMMO_STOPPED_BY_COVER
+
+ damage = 0
+ stamina_damage = 25
+ shrapnel_chance = 0
+
+
+/datum/ammo/bullet/shrapnel/hornet_rounds
+ name = ".22 hornet round"
+ icon_state = "hornet_round"
+ flags_ammo_behavior = AMMO_BALLISTIC
+ damage = 20
+ shrapnel_chance = 0
+ shell_speed = AMMO_SPEED_TIER_3//she fast af boi
+ penetration = ARMOR_PENETRATION_TIER_5
+
+/datum/ammo/bullet/shrapnel/hornet_rounds/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ M.AddComponent(/datum/component/bonus_damage_stack, 10, world.time)
+
+/datum/ammo/bullet/shrapnel/incendiary
+ name = "flaming shrapnel"
+ icon_state = "beanbag" // looks suprisingly a lot like flaming shrapnel chunks
+ flags_ammo_behavior = AMMO_STOPPED_BY_COVER
+
+ shell_speed = AMMO_SPEED_TIER_1
+ damage = 20
+ penetration = ARMOR_PENETRATION_TIER_4
+
+/datum/ammo/bullet/shrapnel/incendiary/set_bullet_traits()
+ . = ..()
+ LAZYADD(traits_to_give, list(
+ BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
+ ))
+
+/datum/ammo/bullet/shrapnel/metal
+ name = "metal shrapnel"
+ icon_state = "shrapnelshot_bit"
+ flags_ammo_behavior = AMMO_STOPPED_BY_COVER|AMMO_BALLISTIC
+ shell_speed = AMMO_SPEED_TIER_1
+ damage = 30
+ shrapnel_chance = 15
+ accuracy = HIT_ACCURACY_TIER_8
+ penetration = ARMOR_PENETRATION_TIER_4
+
+/datum/ammo/bullet/shrapnel/light // weak shrapnel
+ name = "light shrapnel"
+ icon_state = "shrapnel_light"
+
+ damage = 10
+ penetration = ARMOR_PENETRATION_TIER_1
+ shell_speed = AMMO_SPEED_TIER_1
+ shrapnel_chance = 0
+
+/datum/ammo/bullet/shrapnel/light/human
+ name = "human bone fragments"
+ icon_state = "shrapnel_human"
+
+ shrapnel_chance = 50
+ shrapnel_type = /obj/item/shard/shrapnel/bone_chips/human
+
+/datum/ammo/bullet/shrapnel/light/human/var1 // sprite variants
+ icon_state = "shrapnel_human1"
+
+/datum/ammo/bullet/shrapnel/light/human/var2 // sprite variants
+ icon_state = "shrapnel_human2"
+
+/datum/ammo/bullet/shrapnel/light/xeno
+ name = "alien bone fragments"
+ icon_state = "shrapnel_xeno"
+
+ shrapnel_chance = 50
+ shrapnel_type = /obj/item/shard/shrapnel/bone_chips/xeno
+
+/datum/ammo/bullet/shrapnel/spall // weak shrapnel
+ name = "spall"
+ icon_state = "shrapnel_light"
+
+ damage = 10
+ penetration = ARMOR_PENETRATION_TIER_1
+ shell_speed = AMMO_SPEED_TIER_1
+ shrapnel_chance = 0
+
+/datum/ammo/bullet/shrapnel/light/glass
+ name = "glass shrapnel"
+ icon_state = "shrapnel_glass"
+
+/datum/ammo/bullet/shrapnel/light/effect/ // no damage, but looks bright and neat
+ name = "sparks"
+
+ damage = 1 // Tickle tickle
+
+/datum/ammo/bullet/shrapnel/light/effect/ver1
+ icon_state = "shrapnel_bright1"
+
+/datum/ammo/bullet/shrapnel/light/effect/ver2
+ icon_state = "shrapnel_bright2"
+
+/datum/ammo/bullet/shrapnel/jagged
+ shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
+ accuracy = HIT_ACCURACY_TIER_MAX
+
+/datum/ammo/bullet/shrapnel/jagged/on_hit_mob(mob/M, obj/projectile/P)
+ if(isxeno(M))
+ M.apply_effect(0.4, SLOW)
+
+/*
+//========
+ CAS 30mm impacters
+//========
+*/
+/datum/ammo/bullet/shrapnel/gau //for the GAU to have a impact bullet instead of firecrackers
+ name = "30mm Multi-Purpose shell"
+
+ damage = 1 // ALL DAMAGE IS IN dropship_ammo SO WE CAN DEAL DAMAGE TO RESTING MOBS, these will still remain however so that we can get cause_data and status effects.
+ damage_type = BRUTE
+ penetration = ARMOR_PENETRATION_TIER_2
+ accuracy = HIT_ACCURACY_TIER_MAX
+ max_range = 0
+ shrapnel_chance = 100 //the least of your problems
+
+/datum/ammo/bullet/shrapnel/gau/at
+ name = "30mm Anti-Tank shell"
+
+ damage = 1 // ALL DAMAGE IS IN dropship_ammo SO WE CAN DEAL DAMAGE TO RESTING MOBS, these will still remain however so that we can get cause_data and status effects.
+ penetration = ARMOR_PENETRATION_TIER_8
+ accuracy = HIT_ACCURACY_TIER_MAX
diff --git a/code/datums/ammo/xeno.dm b/code/datums/ammo/xeno.dm
new file mode 100644
index 000000000000..654ab88c7abc
--- /dev/null
+++ b/code/datums/ammo/xeno.dm
@@ -0,0 +1,396 @@
+/*
+//======
+ Xeno Spits
+//======
+*/
+/datum/ammo/xeno
+ icon_state = "neurotoxin"
+ ping = "ping_x"
+ damage_type = TOX
+ flags_ammo_behavior = AMMO_XENO
+
+ ///used to make cooldown of the different spits vary.
+ var/added_spit_delay = 0
+ var/spit_cost
+
+ /// Should there be a windup for this spit?
+ var/spit_windup = FALSE
+
+ /// Should there be an additional warning while winding up? (do not put to true if there is not a windup)
+ var/pre_spit_warn = FALSE
+ accuracy = HIT_ACCURACY_TIER_8*2
+ max_range = 12
+
+/datum/ammo/xeno/toxin
+ name = "neurotoxic spit"
+ damage_falloff = 0
+ flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST
+ spit_cost = 25
+ var/effect_power = XENO_NEURO_TIER_4
+ var/datum/callback/neuro_callback
+
+ shell_speed = AMMO_SPEED_TIER_3
+ max_range = 7
+
+/datum/ammo/xeno/toxin/New()
+ ..()
+
+ neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_neuro))
+
+/proc/apply_neuro(mob/living/M, power, insta_neuro)
+ if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX) && !insta_neuro)
+ M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!"))
+ return //endurance 5 makes you immune to weak neurotoxin
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || H.species.flags & NO_NEURO)
+ H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!"))
+ return //species like zombies or synths are immune to neurotoxin
+
+ if(!isxeno(M))
+ if(insta_neuro)
+ if(M.GetKnockDownDuration() < 3) // Why are you not using KnockDown(3) ? Do you even know 3 is SIX seconds ? So many questions left unanswered.
+ M.KnockDown(power)
+ M.Stun(power)
+ return
+
+ if(ishuman(M))
+ M.apply_effect(2.5, SUPERSLOW)
+ M.visible_message(SPAN_DANGER("[M]'s movements are slowed."))
+
+ var/no_clothes_neuro = FALSE
+
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(!H.wear_suit || H.wear_suit.slowdown == 0)
+ no_clothes_neuro = TRUE
+
+ if(no_clothes_neuro)
+ if(M.GetKnockDownDuration() < 5) // Nobody actually knows what this means. Supposedly it means less than 10 seconds. Frankly if you get locked into 10s of knockdown to begin with there are bigger issues.
+ M.KnockDown(power)
+ M.Stun(power)
+ M.visible_message(SPAN_DANGER("[M] falls prone."))
+
+/proc/apply_scatter_neuro(mob/living/M)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX))
+ M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!"))
+ return //endurance 5 makes you immune to weak neuro
+ if(H.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || H.species.flags & NO_NEURO)
+ H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!"))
+ return
+
+ M.KnockDown(0.7) // Completely arbitrary values from another time where stun timers incorrectly stacked. Kill as needed.
+ M.Stun(0.7)
+ M.visible_message(SPAN_DANGER("[M] falls prone."))
+
+/datum/ammo/xeno/toxin/on_hit_mob(mob/M,obj/projectile/P)
+ if(ishuman(M))
+ var/mob/living/carbon/human/H = M
+ if(H.status_flags & XENO_HOST)
+ neuro_callback.Invoke(H, effect_power, TRUE)
+ return
+
+ neuro_callback.Invoke(M, effect_power, FALSE)
+
+/datum/ammo/xeno/toxin/medium //Spitter
+ name = "neurotoxic spatter"
+ spit_cost = 50
+ effect_power = 1
+
+ shell_speed = AMMO_SPEED_TIER_3
+
+/datum/ammo/xeno/toxin/queen
+ name = "neurotoxic spit"
+ spit_cost = 50
+ effect_power = 2
+
+ accuracy = HIT_ACCURACY_TIER_5*2
+ max_range = 6 - 1
+
+/datum/ammo/xeno/toxin/queen/on_hit_mob(mob/M,obj/projectile/P)
+ neuro_callback.Invoke(M, effect_power, TRUE)
+
+/datum/ammo/xeno/toxin/shotgun
+ name = "neurotoxic droplet"
+ flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST
+ bonus_projectiles_type = /datum/ammo/xeno/toxin/shotgun/additional
+
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
+ accurate_range = 5
+ max_range = 5
+ scatter = SCATTER_AMOUNT_NEURO
+ bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_4
+
+/datum/ammo/xeno/toxin/shotgun/New()
+ ..()
+
+ neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_scatter_neuro))
+
+/datum/ammo/xeno/toxin/shotgun/additional
+ name = "additional neurotoxic droplets"
+
+ bonus_projectiles_amount = 0
+
+/datum/ammo/xeno/acid
+ name = "acid spit"
+ icon_state = "xeno_acid"
+ sound_hit = "acid_hit"
+ sound_bounce = "acid_bounce"
+ damage_type = BURN
+ spit_cost = 25
+ flags_ammo_behavior = AMMO_ACIDIC|AMMO_XENO
+ accuracy = HIT_ACCURACY_TIER_5
+ damage = 20
+ max_range = 8 // 7 will disappear on diagonals. i love shitcode
+ penetration = ARMOR_PENETRATION_TIER_2
+ shell_speed = AMMO_SPEED_TIER_3
+
+/datum/ammo/xeno/acid/on_shield_block(mob/M, obj/projectile/P)
+ burst(M,P,damage_type)
+
+/datum/ammo/xeno/acid/on_hit_mob(mob/M, obj/projectile/P)
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ if(C.status_flags & XENO_HOST && HAS_TRAIT(C, TRAIT_NESTED) || C.stat == DEAD)
+ return FALSE
+ ..()
+
+/datum/ammo/xeno/acid/spatter
+ name = "acid spatter"
+
+ damage = 30
+ max_range = 6
+
+/datum/ammo/xeno/acid/spatter/on_hit_mob(mob/M, obj/projectile/P)
+ . = ..()
+ if(. == FALSE)
+ return
+
+ new /datum/effects/acid(M, P.firer)
+
+/datum/ammo/xeno/acid/praetorian
+ name = "acid splash"
+
+ accuracy = HIT_ACCURACY_TIER_10 + HIT_ACCURACY_TIER_5
+ max_range = 8
+ damage = 30
+ shell_speed = AMMO_SPEED_TIER_2
+ added_spit_delay = 0
+
+/datum/ammo/xeno/acid/dot
+ name = "acid spit"
+
+/datum/ammo/xeno/acid/prae_nade // Used by base prae's acid nade
+ name = "acid scatter"
+
+ flags_ammo_behavior = AMMO_STOPPED_BY_COVER
+ accuracy = HIT_ACCURACY_TIER_5
+ accurate_range = 32
+ max_range = 4
+ damage = 25
+ shell_speed = AMMO_SPEED_TIER_1
+ scatter = SCATTER_AMOUNT_TIER_6
+
+ apply_delegate = FALSE
+
+/datum/ammo/xeno/acid/prae_nade/on_hit_mob(mob/M, obj/projectile/P)
+ if (!ishuman(M))
+ return
+
+ var/mob/living/carbon/human/H = M
+
+ var/datum/effects/prae_acid_stacks/PAS = null
+ for (var/datum/effects/prae_acid_stacks/prae_acid_stacks in H.effects_list)
+ PAS = prae_acid_stacks
+ break
+
+ if (PAS == null)
+ PAS = new /datum/effects/prae_acid_stacks(H)
+ else
+ PAS.increment_stack_count()
+
+/datum/ammo/xeno/boiler_gas
+ name = "glob of neuro gas"
+ icon_state = "neuro_glob"
+ ping = "ping_x"
+ debilitate = list(2,2,0,1,11,12,1,10) // Stun,knockdown,knockout,irradiate,stutter,eyeblur,drowsy,agony
+ flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE|AMMO_IGNORE_RESIST|AMMO_HITS_TARGET_TURF|AMMO_ACIDIC
+ var/datum/effect_system/smoke_spread/smoke_system
+ spit_cost = 200
+ pre_spit_warn = TRUE
+ spit_windup = 5 SECONDS
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_4
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_4
+ accuracy = HIT_ACCURACY_TIER_2
+ scatter = SCATTER_AMOUNT_TIER_4
+ shell_speed = 0.75
+ max_range = 16
+ /// range on the smoke in tiles from center
+ var/smokerange = 4
+ var/lifetime_mult = 1.0
+
+/datum/ammo/xeno/boiler_gas/New()
+ ..()
+ set_xeno_smoke()
+
+/datum/ammo/xeno/boiler_gas/Destroy()
+ qdel(smoke_system)
+ smoke_system = null
+ . = ..()
+
+/datum/ammo/xeno/boiler_gas/on_hit_mob(mob/moob, obj/projectile/proj)
+ if(iscarbon(moob))
+ var/mob/living/carbon/carbon = moob
+ if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD)
+ return
+ var/datum/effects/neurotoxin/neuro_effect = locate() in moob.effects_list
+ if(!neuro_effect)
+ neuro_effect = new /datum/effects/neurotoxin(moob, proj.firer)
+ neuro_effect.duration += 5
+ moob.apply_effect(3, DAZE)
+ to_chat(moob, SPAN_HIGHDANGER("Neurotoxic liquid spreads all over you and immediately soaks into your pores and orifices! Oh fuck!")) // Fucked up but have a chance to escape rather than being game-ended
+ drop_nade(get_turf(proj), proj,TRUE)
+
+/datum/ammo/xeno/boiler_gas/on_hit_obj(obj/outbacksteakhouse, obj/projectile/proj)
+ drop_nade(get_turf(proj), proj)
+
+/datum/ammo/xeno/boiler_gas/on_hit_turf(turf/Turf, obj/projectile/proj)
+ if(Turf.density && isturf(proj.loc))
+ drop_nade(proj.loc, proj) //we don't want the gas globs to land on dense turfs, they block smoke expansion.
+ else
+ drop_nade(Turf, proj)
+
+/datum/ammo/xeno/boiler_gas/do_at_max_range(obj/projectile/proj)
+ drop_nade(get_turf(proj), proj)
+
+/datum/ammo/xeno/boiler_gas/proc/set_xeno_smoke(obj/projectile/proj)
+ smoke_system = new /datum/effect_system/smoke_spread/xeno_weaken()
+
+/datum/ammo/xeno/boiler_gas/proc/drop_nade(turf/turf, obj/projectile/proj)
+ var/lifetime_mult = 1.0
+ var/datum/cause_data
+ if(isboiler(proj.firer))
+ cause_data = proj.weapon_cause_data
+ smoke_system.set_up(smokerange, 0, turf, new_cause_data = cause_data)
+ smoke_system.lifetime = 12 * lifetime_mult
+ smoke_system.start()
+ turf.visible_message(SPAN_DANGER("A glob of acid lands with a splat and explodes into noxious fumes!"))
+
+
+/datum/ammo/xeno/boiler_gas/acid
+ name = "glob of acid gas"
+ icon_state = "acid_glob"
+ ping = "ping_x"
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_4
+ smokerange = 3
+
+
+/datum/ammo/xeno/boiler_gas/acid/set_xeno_smoke(obj/projectile/proj)
+ smoke_system = new /datum/effect_system/smoke_spread/xeno_acid()
+
+/datum/ammo/xeno/boiler_gas/acid/on_hit_mob(mob/moob, obj/projectile/proj)
+ if(iscarbon(moob))
+ var/mob/living/carbon/carbon = moob
+ if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD)
+ return
+ to_chat(moob,SPAN_HIGHDANGER("Acid covers your body! Oh fuck!"))
+ playsound(moob,"acid_strike",75,1)
+ INVOKE_ASYNC(moob, TYPE_PROC_REF(/mob, emote), "pain") // why do I need this bullshit
+ new /datum/effects/acid(moob, proj.firer)
+ drop_nade(get_turf(proj), proj,TRUE)
+
+/datum/ammo/xeno/bone_chips
+ name = "bone chips"
+ icon_state = "shrapnel_light"
+ ping = null
+ flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_STOPPED_BY_COVER|AMMO_IGNORE_ARMOR
+ damage_type = BRUTE
+ bonus_projectiles_type = /datum/ammo/xeno/bone_chips/spread
+
+ damage = 8
+ max_range = 6
+ accuracy = HIT_ACCURACY_TIER_8
+ accuracy_var_low = PROJECTILE_VARIANCE_TIER_7
+ accuracy_var_high = PROJECTILE_VARIANCE_TIER_7
+ bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_7
+ shrapnel_type = /obj/item/shard/shrapnel/bone_chips
+ shrapnel_chance = 60
+
+/datum/ammo/xeno/bone_chips/on_hit_mob(mob/living/M, obj/projectile/P)
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD)
+ return
+ if(ishuman_strict(M) || isxeno(M))
+ playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1)
+ if(M.slowed < 3)
+ M.apply_effect(3, SLOW)
+
+/datum/ammo/xeno/bone_chips/spread
+ name = "small bone chips"
+
+ scatter = 30 // We want a wild scatter angle
+ max_range = 5
+ bonus_projectiles_amount = 0
+
+/datum/ammo/xeno/bone_chips/spread/short_range
+ name = "small bone chips"
+
+ max_range = 3 // Very short range
+
+/datum/ammo/xeno/bone_chips/spread/runner_skillshot
+ name = "bone chips"
+
+ scatter = 0
+ max_range = 5
+ damage = 10
+ shrapnel_chance = 0
+
+/datum/ammo/xeno/bone_chips/spread/runner/on_hit_mob(mob/living/M, obj/projectile/P)
+ if(iscarbon(M))
+ var/mob/living/carbon/C = M
+ if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD)
+ return
+ if(ishuman_strict(M) || isxeno(M))
+ playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1)
+ if(M.slowed < 6)
+ M.apply_effect(6, SLOW)
+
+/datum/ammo/xeno/oppressor_tail
+ name = "tail hook"
+ icon_state = "none"
+ ping = null
+ flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_STOPPED_BY_COVER|AMMO_IGNORE_ARMOR
+ damage_type = BRUTE
+
+ damage = XENO_DAMAGE_TIER_5
+ max_range = 4
+ accuracy = HIT_ACCURACY_TIER_MAX
+
+/datum/ammo/xeno/oppressor_tail/on_bullet_generation(obj/projectile/generated_projectile, mob/bullet_generator)
+ //The projectile has no icon, so the overlay shows up in FRONT of the projectile, and the beam connects to it in the middle.
+ var/image/hook_overlay = new(icon = 'icons/effects/beam.dmi', icon_state = "oppressor_tail_hook", layer = BELOW_MOB_LAYER)
+ generated_projectile.overlays += hook_overlay
+
+/datum/ammo/xeno/oppressor_tail/on_hit_mob(mob/target, obj/projectile/fired_proj)
+ var/mob/living/carbon/xenomorph/xeno_firer = fired_proj.firer
+ if(xeno_firer.can_not_harm(target))
+ return
+
+ shake_camera(target, 5, 0.1 SECONDS)
+ var/obj/effect/beam/tail_beam = fired_proj.firer.beam(target, "oppressor_tail", 'icons/effects/beam.dmi', 0.5 SECONDS, 5)
+ var/image/tail_image = image('icons/effects/status_effects.dmi', "hooked")
+ target.overlays += tail_image
+
+ new /datum/effects/xeno_slow(target, fired_proj.firer, ttl = 0.5 SECONDS)
+ target.apply_effect(0.5, STUN)
+ INVOKE_ASYNC(target, TYPE_PROC_REF(/atom/movable, throw_atom), fired_proj.firer, get_dist(fired_proj.firer, target)-1, SPEED_VERY_FAST)
+
+ qdel(tail_beam)
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/ammo/xeno/oppressor_tail, remove_tail_overlay), target, tail_image), 0.5 SECONDS) //needed so it can actually be seen as it gets deleted too quickly otherwise.
+
+/datum/ammo/xeno/oppressor_tail/proc/remove_tail_overlay(mob/overlayed_mob, image/tail_image)
+ overlayed_mob.overlays -= tail_image
diff --git a/code/datums/autocells/auto_cell.dm b/code/datums/autocells/auto_cell.dm
index accc5f180119..fb679c56676e 100644
--- a/code/datums/autocells/auto_cell.dm
+++ b/code/datums/autocells/auto_cell.dm
@@ -37,7 +37,7 @@
in_turf = T
LAZYADD(in_turf.autocells, src)
- cellauto_cells += src
+ GLOB.cellauto_cells += src
birth()
@@ -48,7 +48,7 @@
LAZYREMOVE(in_turf.autocells, src)
in_turf = null
- cellauto_cells -= src
+ GLOB.cellauto_cells -= src
death()
@@ -88,7 +88,7 @@
// Get cardinal neighbors
if(neighbor_type & NEIGHBORS_CARDINAL)
- for(var/dir in cardinal)
+ for(var/dir in GLOB.cardinals)
var/turf/T = get_step(in_turf, dir)
if(QDELETED(T))
continue
@@ -100,7 +100,7 @@
// Get ordinal/diagonal neighbors
if(neighbor_type & NEIGHBORS_ORDINAL)
- for(var/dir in diagonals)
+ for(var/dir in GLOB.diagonals)
var/turf/T = get_step(in_turf, dir)
if(QDELETED(T))
continue
diff --git a/code/datums/autocells/explosion.dm b/code/datums/autocells/explosion.dm
index 42e1409d595f..970e5618bae3 100644
--- a/code/datums/autocells/explosion.dm
+++ b/code/datums/autocells/explosion.dm
@@ -109,7 +109,7 @@
survivor.power += dying.power
// Two waves travling towards each other weakens the explosion
- if(survivor.direction == reverse_dir[dying.direction])
+ if(survivor.direction == GLOB.reverse_dir[dying.direction])
survivor.power -= dying.power
return is_stronger
@@ -120,11 +120,11 @@
// If the cell is the epicenter, propagate in all directions
if(isnull(direction))
- return alldirs
+ return GLOB.alldirs
- var/dir = reflected ? reverse_dir[direction] : direction
+ var/dir = reflected ? GLOB.reverse_dir[direction] : direction
- if(dir in cardinal)
+ if(dir in GLOB.cardinals)
propagation_dirs += list(dir, turn(dir, 45), turn(dir, -45))
else
propagation_dirs += dir
@@ -180,7 +180,7 @@
for(var/dir in to_spread)
// Diagonals are longer, that should be reflected in the power falloff
var/dir_falloff = 1
- if(dir in diagonals)
+ if(dir in GLOB.diagonals)
dir_falloff = 1.414
if(isnull(direction))
@@ -210,7 +210,7 @@
// Set the direction the explosion is traveling in
E.direction = dir
//Diagonal cells have a small delay when branching off the center. This helps the explosion look circular
- if(!direction && (dir in diagonals))
+ if(!direction && (dir in GLOB.diagonals))
E.delay = 1
setup_new_cell(E)
diff --git a/code/datums/autocells/vomit_wave.dm b/code/datums/autocells/vomit_wave.dm
index 62ea1d4c6e7e..396bf6d3e528 100644
--- a/code/datums/autocells/vomit_wave.dm
+++ b/code/datums/autocells/vomit_wave.dm
@@ -37,7 +37,7 @@
return
// Propagate to cardinal directions
- var/list/to_spread = cardinal.Copy()
+ var/list/to_spread = GLOB.cardinals.Copy()
for(var/datum/automata_cell/vomit_wave/C in neighbors)
to_spread -= get_dir(in_turf, C.in_turf)
diff --git a/code/datums/components/autofire/autofire.dm b/code/datums/components/autofire/autofire.dm
index 2b9401e8d346..455fb70a9fa1 100644
--- a/code/datums/components/autofire/autofire.dm
+++ b/code/datums/components/autofire/autofire.dm
@@ -82,6 +82,8 @@
/datum/component/automatedfire/autofire/proc/initiate_shot()
SIGNAL_HANDLER
if(shooting)//if we are already shooting, it means the shooter is still on cooldown
+ if(bursting && (world.time > (next_fire + (burstfire_shot_delay * burst_shots_to_fire))))
+ hard_reset()
return
shooting = TRUE
process_shot()
@@ -123,19 +125,19 @@
if(GUN_FIREMODE_BURSTFIRE)
shots_fired++
if(shots_fired == burst_shots_to_fire)
- callback_bursting.Invoke(FALSE)
- callback_display_ammo.Invoke()
+ callback_bursting?.Invoke(FALSE)
+ callback_display_ammo?.Invoke()
bursting = FALSE
stop_firing()
if(have_to_reset_at_burst_end)//We failed to reset because we were bursting, we do it now
- callback_reset_fire.Invoke()
+ callback_reset_fire?.Invoke()
have_to_reset_at_burst_end = FALSE
return
- callback_bursting.Invoke(TRUE)
+ callback_bursting?.Invoke(TRUE)
bursting = TRUE
next_fire = world.time + burstfire_shot_delay
if(GUN_FIREMODE_AUTOMATIC)
- callback_set_firing.Invoke(TRUE)
+ callback_set_firing?.Invoke(TRUE)
next_fire = world.time + (auto_fire_shot_delay * automatic_delay_mult)
if(GUN_FIREMODE_SEMIAUTO)
return
diff --git a/code/datums/components/cell.dm b/code/datums/components/cell.dm
new file mode 100644
index 000000000000..81ef3733e2e2
--- /dev/null
+++ b/code/datums/components/cell.dm
@@ -0,0 +1,202 @@
+#define UNLIMITED_CHARGE -1
+#define UNLIMITED_DISTANCE -1
+
+/datum/component/cell
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+ /// Maximum charge of the power cell, set to -1 for infinite charge
+ var/max_charge = 10000
+ /// Initial max charge of the power cell
+ var/initial_max_charge
+ /// Current charge of power cell
+ var/charge = 10000
+ /// If the component can be recharged by hitting its parent with a cell
+ var/hit_charge = FALSE
+ /// The maximum amount that can be recharged per tick when using a cell to recharge this component
+ var/max_recharge_tick = 400
+ /// If draining charge on process(), how much to drain per process call
+ var/charge_drain = 10
+ /// If the parent should show cell charge on examine
+ var/display_charge = TRUE
+ /// From how many tiles at the highest someone can examine the parent to see the charge
+ var/charge_examine_range = 1
+ /// If the component requires a cell to be inserted to work instead of having an integrated one
+ var/cell_insert = FALSE
+ /// Ref to an inserted cell. Should only be null if cell_insert is false
+ var/obj/item/cell/inserted_cell
+
+
+/datum/component/cell/Initialize(
+ max_charge = 10000,
+ hit_charge = FALSE,
+ max_recharge_tick = 400,
+ charge_drain = 10,
+ display_charge = TRUE,
+ charge_examine_range = 1,
+ cell_insert = FALSE,
+ )
+
+ . = ..()
+ if(!isatom(parent))
+ return COMPONENT_INCOMPATIBLE
+
+ src.max_charge = max_charge
+ charge = max_charge
+ src.hit_charge = hit_charge
+ src.max_recharge_tick = max_recharge_tick
+ src.charge_drain = charge_drain
+ src.display_charge = display_charge
+ src.charge_examine_range = charge_examine_range
+ src.cell_insert = cell_insert
+
+/datum/component/cell/Destroy(force, silent)
+ QDEL_NULL(inserted_cell)
+ return ..()
+
+
+/datum/component/cell/RegisterWithParent()
+ ..()
+ RegisterSignal(parent, list(COMSIG_PARENT_ATTACKBY, COMSIG_ITEM_ATTACKED), PROC_REF(on_object_hit))
+ RegisterSignal(parent, COMSIG_CELL_ADD_CHARGE, PROC_REF(add_charge))
+ RegisterSignal(parent, COMSIG_CELL_USE_CHARGE, PROC_REF(use_charge))
+ RegisterSignal(parent, COMSIG_CELL_CHECK_CHARGE, PROC_REF(has_charge))
+ RegisterSignal(parent, COMSIG_CELL_START_TICK_DRAIN, PROC_REF(start_drain))
+ RegisterSignal(parent, COMSIG_CELL_STOP_TICK_DRAIN, PROC_REF(stop_drain))
+ RegisterSignal(parent, COMSIG_CELL_REMOVE_CELL, PROC_REF(remove_cell))
+ RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(on_examine))
+ RegisterSignal(parent, COMSIG_ATOM_EMP_ACT, PROC_REF(on_emp))
+
+/datum/component/cell/process()
+ use_charge(null, charge_drain)
+
+/datum/component/cell/proc/on_emp(datum/source, severity)
+ SIGNAL_HANDLER
+
+ use_charge(null, round(max_charge / severity))
+
+/datum/component/cell/proc/start_drain(datum/source)
+ SIGNAL_HANDLER
+
+ START_PROCESSING(SSobj, src)
+
+/datum/component/cell/proc/stop_drain(datum/source)
+ SIGNAL_HANDLER
+
+ STOP_PROCESSING(SSobj, src)
+
+/datum/component/cell/proc/on_examine(datum/source, mob/examiner, list/examine_text)
+ SIGNAL_HANDLER
+
+ if(!display_charge)
+ return
+
+ if((charge_examine_range != UNLIMITED_DISTANCE) && get_dist(examiner, parent) > charge_examine_range)
+ return
+
+ examine_text += "A small gauge in the corner reads \"Power: [round(100 * charge / max_charge)]%\"."
+
+/datum/component/cell/proc/on_object_hit(datum/source, obj/item/cell/attack_obj, mob/living/attacker, params)
+ SIGNAL_HANDLER
+
+ if(!hit_charge || !istype(attack_obj))
+ return
+
+ if(!cell_insert)
+ INVOKE_ASYNC(src, PROC_REF(charge_from_cell), attack_obj, attacker)
+
+ else
+ insert_cell(attack_obj, attacker)
+
+ return COMPONENT_NO_AFTERATTACK|COMPONENT_CANCEL_ITEM_ATTACK
+
+/datum/component/cell/proc/insert_cell(obj/item/cell/power_cell, mob/living/user)
+ if(inserted_cell)
+ to_chat(user, SPAN_WARNING("There's already a power cell in [parent]!"))
+ return
+
+ if(SEND_SIGNAL(parent, COMSIG_CELL_TRY_INSERT_CELL) & COMPONENT_CANCEL_CELL_INSERT)
+ return
+
+ power_cell.drop_to_floor(user)
+ power_cell.forceMove(parent)
+ inserted_cell = power_cell
+ charge = power_cell.charge
+ max_charge = power_cell.maxcharge
+
+/datum/component/cell/proc/remove_cell(mob/living/user)
+ SIGNAL_HANDLER
+
+ user.put_in_hands(inserted_cell, TRUE)
+ to_chat(user, SPAN_NOTICE("You remove [inserted_cell] from [parent]."))
+ inserted_cell = null
+ max_charge = initial_max_charge
+ charge = 0
+
+/datum/component/cell/proc/charge_from_cell(obj/item/cell/power_cell, mob/living/user)
+ if(max_charge == UNLIMITED_CHARGE)
+ to_chat(user, SPAN_WARNING("[parent] doesn't need more power."))
+ return
+
+ while(charge < max_charge)
+ if(SEND_SIGNAL(parent, COMSIG_CELL_TRY_RECHARGING, user) & COMPONENT_CELL_NO_RECHARGE)
+ return
+
+ if(power_cell.charge <= 0)
+ to_chat(user, SPAN_WARNING("[power_cell] is completely dry."))
+ return
+
+ if(!do_after(user, 1 SECONDS, (INTERRUPT_ALL & (~INTERRUPT_MOVED)), BUSY_ICON_BUILD, power_cell, INTERRUPT_DIFF_LOC))
+ to_chat(user, SPAN_WARNING("You were interrupted."))
+ return
+
+ if(power_cell.charge <= 0)
+ return
+
+ var/to_transfer = min(max_recharge_tick, power_cell.charge, (max_charge - charge))
+ if(power_cell.use(to_transfer))
+ add_charge(null, to_transfer)
+ to_chat(user, "You transfer some power between [power_cell] and [parent]. The gauge now reads: [round(100 * charge / max_charge)]%.")
+
+/datum/component/cell/proc/add_charge(datum/source, charge_add = 0)
+ SIGNAL_HANDLER
+
+ if(max_charge == UNLIMITED_CHARGE)
+ return
+
+ if(!charge_add)
+ return
+
+ charge = clamp(charge + charge_add, 0, max_charge)
+
+/datum/component/cell/proc/use_charge(datum/source, charge_use = 0)
+ SIGNAL_HANDLER
+
+ if(max_charge == UNLIMITED_CHARGE)
+ return
+
+ if(!charge_use)
+ return
+
+ if(!charge)
+ return COMPONENT_CELL_NO_USE_CHARGE
+
+ charge = clamp(charge - charge_use, 0, max_charge)
+
+ if(!charge)
+ on_charge_empty()
+ return
+
+/datum/component/cell/proc/has_charge(datum/source, charge_amount = 0)
+ SIGNAL_HANDLER
+
+ if(!charge)
+ return COMPONENT_CELL_CHARGE_INSUFFICIENT
+
+ if(charge < charge_amount)
+ return COMPONENT_CELL_CHARGE_INSUFFICIENT
+
+/datum/component/cell/proc/on_charge_empty()
+ stop_drain()
+ SEND_SIGNAL(parent, COMSIG_CELL_OUT_OF_CHARGE)
+
+#undef UNLIMITED_CHARGE
+#undef UNLIMITED_DISTANCE
diff --git a/code/datums/components/crate_tag.dm b/code/datums/components/crate_tag.dm
new file mode 100644
index 000000000000..379df82a2084
--- /dev/null
+++ b/code/datums/components/crate_tag.dm
@@ -0,0 +1,36 @@
+/datum/component/crate_tag
+ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS
+ /// The crate tag used for notifications and as label
+ var/name
+
+/datum/component/crate_tag/Initialize(name, obj/structure/closet/crate/masquarade_type)
+ var/obj/structure/closet/crate/crate = parent
+ if(!istype(crate))
+ return COMPONENT_INCOMPATIBLE
+ setup(name, masquarade_type)
+ RegisterSignal(parent, COMSIG_STRUCTURE_CRATE_SQUAD_LAUNCHED, PROC_REF(notify_squad))
+
+/datum/component/crate_tag/InheritComponent(datum/component/C, i_am_original, name, obj/structure/closet/crate/masquarade_type)
+ . = ..()
+ setup(name, masquarade_type)
+
+/datum/component/crate_tag/proc/setup(name, obj/structure/closet/crate/masquarade_type)
+ var/obj/structure/closet/crate/crate = parent
+ if(masquarade_type)
+ crate.name = initial(masquarade_type.name)
+ crate.desc = initial(masquarade_type.desc)
+ crate.icon_opened = initial(masquarade_type.icon_opened)
+ crate.icon_closed = initial(masquarade_type.icon_closed)
+ if(crate.opened)
+ crate.icon_state = crate.icon_opened
+ else
+ crate.icon_state = crate.icon_closed
+ if(name)
+ parent.AddComponent(/datum/component/label, name)
+ src.name = name // Keep it around additionally for notifications
+
+/// Handler to notify an overwatched squad that this crate has been dropped for them
+/datum/component/crate_tag/proc/notify_squad(datum/source, datum/squad/squad)
+ SIGNAL_HANDLER
+ squad.send_message("'[name]' supply drop incoming. Heads up!")
+ squad.send_maptext(name, "Incoming Supply Drop:")
diff --git a/code/datums/components/footstep.dm b/code/datums/components/footstep.dm
index ef77aaf471dc..6eaaa6e76af5 100644
--- a/code/datums/components/footstep.dm
+++ b/code/datums/components/footstep.dm
@@ -47,7 +47,7 @@
if(!T)
return
var/mob/living/parent_mob = parent
- if(parent_mob.lying && (isfile(drag_sounds) || istext(drag_sounds)))
+ if(parent_mob.body_position == LYING_DOWN && (isfile(drag_sounds) || istext(drag_sounds)))
playsound(T, drag_sounds, volume, rand(20000, 25000), range, falloff = falloff)
else if(isfile(footstep_sounds) || istext(footstep_sounds))
playsound(T, footstep_sounds, volume, rand(20000, 25000), range, falloff = falloff)
diff --git a/code/datums/components/healing_reduction.dm b/code/datums/components/healing_reduction.dm
index b98d52cab251..54ea02dc6b73 100644
--- a/code/datums/components/healing_reduction.dm
+++ b/code/datums/components/healing_reduction.dm
@@ -21,33 +21,36 @@ Humans will take continuous damage instead.
src.healing_reduction_dissipation = healing_reduction_dissipation
src.max_buildup = max_buildup
-/datum/component/healing_reduction/InheritComponent(datum/component/healing_reduction/C, i_am_original, healing_reduction)
+/datum/component/healing_reduction/InheritComponent(datum/component/healing_reduction/inherit_component, i_am_original, healing_reduction)
. = ..()
- if(!C)
+ if(!inherit_component)
src.healing_reduction += healing_reduction
else
- src.healing_reduction += C.healing_reduction
+ src.healing_reduction += inherit_component.healing_reduction
src.healing_reduction = min(src.healing_reduction, max_buildup)
/datum/component/healing_reduction/process(delta_time)
if(!parent)
qdel(src)
- healing_reduction = max(healing_reduction - healing_reduction_dissipation * delta_time, 0)
+ return
- if(ishuman(parent)) //deals brute to humans
- var/mob/living/carbon/human/H = parent
- H.apply_damage(healing_reduction_dissipation * delta_time, BRUTE)
+ healing_reduction = max(healing_reduction - healing_reduction_dissipation * delta_time, 0)
if(healing_reduction <= 0)
qdel(src)
+ return
+
+ if(ishuman(parent)) //deals brute to humans
+ var/mob/living/carbon/human/human_parent = parent
+ human_parent.apply_damage(healing_reduction_dissipation * delta_time, BRUTE)
var/color = GLOW_COLOR
var/intensity = healing_reduction/max_buildup
color += num2text(MAX_ALPHA*intensity, 2, 16)
- var/atom/A = parent
- A.add_filter("healing_reduction", 2, list("type" = "outline", "color" = color, "size" = 1))
+ var/atom/parent_atom = parent
+ parent_atom.add_filter("healing_reduction", 2, list("type" = "outline", "color" = color, "size" = 1))
/datum/component/healing_reduction/RegisterWithParent()
START_PROCESSING(SSdcs, src)
@@ -64,14 +67,14 @@ Humans will take continuous damage instead.
COMSIG_XENO_ON_HEAL_WOUNDS,
COMSIG_XENO_APPEND_TO_STAT
))
- var/atom/A = parent
- A.remove_filter("healing_reduction")
+ var/atom/parent_atom = parent
+ parent_atom.remove_filter("healing_reduction")
-/datum/component/healing_reduction/proc/stat_append(mob/M, list/L)
+/datum/component/healing_reduction/proc/stat_append(mob/target_mob, list/stat_list)
SIGNAL_HANDLER
- L += "Healing Reduction: [healing_reduction]/[max_buildup]"
+ stat_list += "Healing Reduction: [healing_reduction]/[max_buildup]"
-/datum/component/healing_reduction/proc/apply_healing_reduction(mob/living/carbon/xenomorph/X, list/healing)
+/datum/component/healing_reduction/proc/apply_healing_reduction(mob/living/carbon/xenomorph/xeno, list/healing)
SIGNAL_HANDLER
healing["healing"] -= healing_reduction
diff --git a/code/datums/components/tutorial_status.dm b/code/datums/components/tutorial_status.dm
new file mode 100644
index 000000000000..97b8d408bcb5
--- /dev/null
+++ b/code/datums/components/tutorial_status.dm
@@ -0,0 +1,25 @@
+/datum/component/tutorial_status
+ dupe_mode = COMPONENT_DUPE_UNIQUE
+ /// What the mob's current tutorial status is, displayed in the status panel
+ var/tutorial_status = ""
+
+/datum/component/tutorial_status/Initialize()
+ . = ..()
+ if(!ismob(parent))
+ return COMPONENT_INCOMPATIBLE
+
+/datum/component/tutorial_status/RegisterWithParent()
+ ..()
+ RegisterSignal(parent, COMSIG_MOB_TUTORIAL_UPDATE_OBJECTIVE, PROC_REF(update_objective))
+ RegisterSignal(parent, COMSIG_MOB_GET_STATUS_TAB_ITEMS, PROC_REF(get_status_tab_item))
+
+/datum/component/tutorial_status/proc/update_objective(datum/source, objective_text)
+ SIGNAL_HANDLER
+
+ tutorial_status = objective_text
+
+/datum/component/tutorial_status/proc/get_status_tab_item(datum/source, list/status_tab_items)
+ SIGNAL_HANDLER
+
+ if(tutorial_status)
+ status_tab_items += "Tutorial Objective: " + tutorial_status
diff --git a/code/datums/components/weed_food.dm b/code/datums/components/weed_food.dm
index ce6c17e0af95..2335a053412f 100644
--- a/code/datums/components/weed_food.dm
+++ b/code/datums/components/weed_food.dm
@@ -6,15 +6,19 @@
desc = "Weird black weeds in the shape of a body..."
gender = PLURAL
vis_flags = VIS_INHERIT_DIR|VIS_INHERIT_PLANE|VIS_INHERIT_LAYER
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
icon = 'icons/mob/xenos/weeds.dmi'
- var/static/list/icon_states = list("human_1","human_2","human_3","human_4","human_5")
- var/static/list/icon_states_flipped = list("human_1_f","human_2_f","human_3_f","human_4_f","human_5_f")
+ var/list/icon_states
+ var/list/icon_states_flipped
var/icon_state_idx = 0
var/timer_id = null
var/flipped = FALSE
-/atom/movable/vis_obj/weed_food/Initialize(mapload, is_flipped, ...)
+/atom/movable/vis_obj/weed_food/Initialize(mapload, is_flipped, weeds_icon, states, states_flipped, ...)
flipped = is_flipped
+ icon = weeds_icon
+ icon_states = states
+ icon_states_flipped = states_flipped
timer_id = addtimer(CALLBACK(src, PROC_REF(on_animation_timer)), WEED_FOOD_STATE_DELAY, TIMER_STOPPABLE|TIMER_UNIQUE|TIMER_LOOP|TIMER_DELETE_ME)
on_animation_timer()
return ..()
@@ -22,6 +26,7 @@
/// Timer callback for changing the icon_state
/atom/movable/vis_obj/weed_food/proc/on_animation_timer()
icon_state_idx++
+ // Assumption: Length of icon_states is the same as icon_states_flipped
if(icon_state_idx > length(icon_states))
deltimer(timer_id)
timer_id = null
@@ -50,6 +55,8 @@
var/turf/parent_turf
/// The obj that our parent is buckled to and we have registered a signal
var/obj/parent_buckle
+ /// A nest our parent is buckled to and we have registered a signal
+ var/obj/structure/bed/nest/parent_nest
/// The weeds that we are merging/merged with
var/obj/effect/alien/weeds/absorbing_weeds
/// The overlay image when merged
@@ -57,10 +64,9 @@
/datum/component/weed_food/Initialize(...)
parent_mob = parent
- //if(!istype(parent_mob))
- //return COMPONENT_INCOMPATIBLE
- if(!istype(parent_mob, /mob/living/carbon/human))
- return COMPONENT_INCOMPATIBLE // TODO: At the moment we only support humans
+ // At the moment we only support humans and xenos
+ if(!istype(parent_mob, /mob/living/carbon/human) && !istype(parent_mob, /mob/living/carbon/xenomorph))
+ return COMPONENT_INCOMPATIBLE
parent_turf = get_turf(parent_mob)
if(parent_turf != parent_mob.loc)
@@ -78,6 +84,7 @@
QDEL_NULL(weed_appearance)
parent_mob = null
parent_turf = null
+ parent_buckle = null
/datum/component/weed_food/RegisterWithParent()
RegisterSignal(parent_mob, COMSIG_MOVABLE_MOVED, PROC_REF(on_move))
@@ -100,6 +107,8 @@
UnregisterSignal(parent_turf, COMSIG_WEEDNODE_GROWTH)
if(parent_buckle)
UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE)
+ if(parent_nest)
+ UnregisterSignal(parent_nest, COMSIG_PARENT_QDELETING)
/// SIGNAL_HANDLER for COMSIG_MOVABLE_MOVED
/datum/component/weed_food/proc/on_move()
@@ -160,6 +169,15 @@
unmerge_with_weeds()
return
+/// SIGNAL_HANDLER for COMSIG_PARENT_QDELETING of nest
+/datum/component/weed_food/proc/on_nest_deletion()
+ SIGNAL_HANDLER
+
+ if(merged)
+ parent_mob.plane = FLOOR_PLANE
+ UnregisterSignal(parent_nest, COMSIG_PARENT_QDELETING)
+ parent_nest = null
+
/**
* Try to start the process to turn into weeds
* Returns TRUE if started successfully
@@ -243,6 +261,10 @@
parent_buckle = parent_mob.buckled
RegisterSignal(parent_mob.buckled, COSMIG_OBJ_AFTER_BUCKLE, PROC_REF(on_after_buckle))
return FALSE
+ else
+ parent_nest = parent_mob.buckled
+ RegisterSignal(parent_nest, COMSIG_PARENT_QDELETING, PROC_REF(on_nest_deletion))
+
if(parent_buckle)
UnregisterSignal(parent_buckle, COSMIG_OBJ_AFTER_BUCKLE)
parent_buckle = null
@@ -259,19 +281,20 @@
active = FALSE
merged = TRUE
- parent_mob.density = FALSE
+ ADD_TRAIT(parent_mob, TRAIT_UNDENSE, XENO_WEED_TRAIT)
+ ADD_TRAIT(parent_mob, TRAIT_MERGED_WITH_WEEDS, XENO_WEED_TRAIT)
parent_mob.anchored = TRUE
parent_mob.mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- parent_mob.plane = FLOOR_PLANE
+ if(!parent_nest)
+ parent_mob.plane = FLOOR_PLANE
parent_mob.remove_from_all_mob_huds()
if(!weed_appearance) // Make a new sprite if we aren't re-merging
var/is_flipped = parent_mob.transform.b == -1 // Technically we should check if d is 1 too, but corpses can only be rotated 90 or 270 (1/-1 or -1/1)
if(parent_mob.dir & WEST)
is_flipped = !is_flipped // The direction reversed the effect of the flip!
- weed_appearance = new(null, is_flipped)
+ weed_appearance = new(null, is_flipped, parent_mob.weed_food_icon, parent_mob.weed_food_states, parent_mob.weed_food_states_flipped)
weed_appearance.color = absorbing_weeds.color
- // TODO: For non-humans change the icon_state or something here
parent_mob.vis_contents += weed_appearance
return TRUE
@@ -288,6 +311,11 @@
UnregisterSignal(absorbing_weeds, COMSIG_PARENT_QDELETING)
absorbing_weeds = null
+ if(parent_nest)
+ UnregisterSignal(parent_nest, COMSIG_PARENT_QDELETING)
+ parent_nest = null
+
+ REMOVE_TRAIT(parent_mob, TRAIT_MERGED_WITH_WEEDS, XENO_WEED_TRAIT)
parent_mob.anchored = FALSE
parent_mob.mouse_opacity = MOUSE_OPACITY_ICON
parent_mob.plane = GAME_PLANE
diff --git a/code/datums/construction/construction_template.dm b/code/datums/construction/construction_template.dm
index 0b874def4495..37832327c381 100644
--- a/code/datums/construction/construction_template.dm
+++ b/code/datums/construction/construction_template.dm
@@ -14,8 +14,8 @@
var/pixel_y = -16
var/pixel_x = -16
- var/crystals_required = 0
- var/crystals_stored = 0
+ var/plasma_required = 0
+ var/plasma_stored = 0
var/materials_required = list() //Example resource requirements i.e. MATERIAL_METAL = 1
var/extras_required = list() //Example extra requirements i.e. /obj/item = 1
@@ -43,47 +43,23 @@
return
if(!xeno.plasma_max)
return
- if(crystals_stored >= crystals_required)
+ if(plasma_stored >= plasma_required)
to_chat(xeno, SPAN_WARNING("\The [name] does not require plasma."))
return
- to_chat(xeno, SPAN_NOTICE("You begin adding \the plasma to \the [name]."))
+ to_chat(xeno, SPAN_NOTICE("We begin adding \the plasma to \the [name]."))
xeno_attack_delay(xeno)
if(!do_after(xeno, 40, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
return
//double-check amount required
- if(crystals_stored >= crystals_required)
+ if(plasma_stored >= plasma_required)
to_chat(xeno, SPAN_WARNING("\The [name] has enough plasma."))
return
- var/amount_to_use = min(xeno.plasma_stored, (crystals_required - crystals_stored))
- crystals_stored += amount_to_use
+ var/amount_to_use = min(xeno.plasma_stored, (plasma_required - plasma_stored))
+ plasma_stored += amount_to_use
xeno.plasma_stored -= amount_to_use
- to_chat(xeno, SPAN_WARNING("\The [name] requires [crystals_required - crystals_stored] more plasma."))
+ to_chat(xeno, SPAN_WARNING("\The [name] requires [plasma_required - plasma_stored] more plasma."))
check_completion()
-// Xeno ressource collection
-/*
-/datum/construction_template/proc/add_crystal(mob/living/carbon/xenomorph/M)
- if(!istype(M))
- return
- if(!M.crystal_stored)
- to_chat(M, SPAN_WARNING("You have no [MATERIAL_CRYSTAL] stored."))
- return
- if(crystals_stored >= crystals_required)
- to_chat(M, SPAN_WARNING("\The [name] does not require [MATERIAL_CRYSTAL]."))
- return
- to_chat(M, SPAN_NOTICE("You begin adding \the [MATERIAL_CRYSTAL] to \the [name]."))
- if(!do_after(M, 40, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
- return
- //double-check amount required
- if(crystals_stored >= crystals_required)
- to_chat(M, SPAN_WARNING("\The [name] has enough [MATERIAL_CRYSTAL]."))
- return
- var/amount_to_use = min(M.crystal_stored, (crystals_required - crystals_stored))
- crystals_stored += amount_to_use
- M.crystal_stored -= amount_to_use
- to_chat(M, SPAN_WARNING("\The [name] requires [crystals_required - crystals_stored] more [MATERIAL_CRYSTAL]."))
- check_completion() */
-
/datum/construction_template/proc/add_material(mob/user, obj/item/I)
if(isStack(I))
var/obj/item/stack/S = I
@@ -123,7 +99,7 @@
check_completion()
/datum/construction_template/proc/check_completion()
- if(crystals_stored < crystals_required)
+ if(plasma_stored < plasma_required)
return FALSE
for(var/material_req in materials_required)
if(materials_required[material_req] > 0)
diff --git a/code/datums/construction/xenomorph/construction_template_xenomorph.dm b/code/datums/construction/xenomorph/construction_template_xenomorph.dm
index 46b7e797632f..94914eb1e9ce 100644
--- a/code/datums/construction/xenomorph/construction_template_xenomorph.dm
+++ b/code/datums/construction/xenomorph/construction_template_xenomorph.dm
@@ -3,8 +3,10 @@
/datum/construction_template/xenomorph
name = "xenomorph structure"
build_type = /obj/effect/alien/resin/special
- crystals_required = 45 * XENO_STRUCTURE_PLASMA_MULTIPLIER
- var/datum/hive_status/hive_ref //Who gets what we build
+ plasma_required = 45 * XENO_STRUCTURE_PLASMA_MULTIPLIER
+ /// The hive that this structure belongs to.
+ var/datum/hive_status/hive_ref
+ /// The range around this structure which needs to be clear for it to be constructed.
var/block_range = 1
/datum/construction_template/xenomorph/set_structure_image()
@@ -24,18 +26,20 @@
/datum/construction_template/xenomorph/core
name = XENO_STRUCTURE_CORE
+ description = "Heart of the hive, grows hive weeds (which are necessary for other structures), stores larva, spawns lesser drones, and protects the hive from skyfire."
build_type = /obj/effect/alien/resin/special/pylon/core
build_icon_state = "core"
- crystals_required = 100 * XENO_STRUCTURE_PLASMA_MULTIPLIER
+ plasma_required = 100 * XENO_STRUCTURE_PLASMA_MULTIPLIER
block_range = 0
/datum/construction_template/xenomorph/cluster
name = XENO_STRUCTURE_CLUSTER
+ description = "Remote section of the hive, grows hive weeds, and morphs into a hive pylon when placed near a communications tower."
build_type = /obj/effect/alien/resin/special/cluster
build_icon_state = "hive_cluster"
pixel_y = -8
pixel_x = -8
- crystals_required = 50 * XENO_STRUCTURE_PLASMA_MULTIPLIER
+ plasma_required = 50 * XENO_STRUCTURE_PLASMA_MULTIPLIER
block_range = 0
/datum/construction_template/xenomorph/cluster/set_structure_image()
@@ -43,23 +47,27 @@
/datum/construction_template/xenomorph/pylon
name = XENO_STRUCTURE_PYLON
+ description = "Remote section of the hive, grows hive weeds, spawns lesser drones, and protects sisters from air strikes."
build_type = /obj/effect/alien/resin/special/pylon
build_icon_state = "pylon"
- crystals_required = 100 * XENO_STRUCTURE_PLASMA_MULTIPLIER
+ plasma_required = 100 * XENO_STRUCTURE_PLASMA_MULTIPLIER
block_range = 0
/datum/construction_template/xenomorph/eggmorph
name = XENO_STRUCTURE_EGGMORPH
+ description = "Processes hatched hosts into new facehuggers."
build_type = /obj/effect/alien/resin/special/eggmorph
build_icon_state = "eggmorph_preview"
/datum/construction_template/xenomorph/recovery
name = XENO_STRUCTURE_RECOVERY
+ description = "Hastily recovers the strength of sisters resting around it."
build_type = /obj/effect/alien/resin/special/recovery
build_icon_state = "recovery"
/datum/construction_template/xenomorph/nest
name = XENO_STRUCTURE_NEST
+ description = "Strong enough to secure a headhunter for indeterminate durations."
build_type = /obj/effect/alien/resin/special/nest
build_icon_state = "reinforced_nest"
@@ -101,3 +109,5 @@
xeno_message(SPAN_XENOWARNING("This structure needs to be built directly next to an vertical surface."), 7, XENO_HIVE_NORMAL)
qdel(owner)
qdel(src)
+
+#undef XENO_STRUCTURE_PLASMA_MULTIPLIER
diff --git a/code/datums/datacore.dm b/code/datums/datacore.dm
index b60b20bc9026..ae19a3044678 100644
--- a/code/datums/datacore.dm
+++ b/code/datums/datacore.dm
@@ -8,16 +8,16 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
var/locked[] = list()
/datum/datacore/proc/get_manifest(monochrome, OOC, nonHTML)
- var/list/cic = ROLES_CIC.Copy()
- var/list/auxil = ROLES_AUXIL_SUPPORT.Copy()
- var/list/misc = ROLES_MISC.Copy()
- var/list/mp = ROLES_POLICE.Copy()
- var/list/eng = ROLES_ENGINEERING.Copy()
- var/list/req = ROLES_REQUISITION.Copy()
- var/list/med = ROLES_MEDICAL.Copy()
- var/list/marines_by_squad = ROLES_SQUAD_ALL.Copy()
+ var/list/cic = GLOB.ROLES_CIC.Copy()
+ var/list/auxil = GLOB.ROLES_AUXIL_SUPPORT.Copy()
+ var/list/misc = GLOB.ROLES_MISC.Copy()
+ var/list/mp = GLOB.ROLES_POLICE.Copy()
+ var/list/eng = GLOB.ROLES_ENGINEERING.Copy()
+ var/list/req = GLOB.ROLES_REQUISITION.Copy()
+ var/list/med = GLOB.ROLES_MEDICAL.Copy()
+ var/list/marines_by_squad = GLOB.ROLES_SQUAD_ALL.Copy()
for(var/squad_name in marines_by_squad)
- marines_by_squad[squad_name] = ROLES_MARINES.Copy()
+ marines_by_squad[squad_name] = GLOB.ROLES_MARINES.Copy()
var/list/isactive = new()
// If we need not the HTML table, but list
@@ -32,18 +32,18 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
)
departments += marines_by_squad
var/list/manifest_out = list()
- for(var/datum/data/record/t in GLOB.data_core.general)
- if(t.fields["mob_faction"] != FACTION_MARINE) //we process only USCM humans
+ for(var/datum/data/record/record_entry in GLOB.data_core.general)
+ if(record_entry.fields["mob_faction"] != FACTION_MARINE) //we process only USCM humans
continue
- var/name = t.fields["name"]
- var/rank = t.fields["rank"]
- var/squad = t.fields["squad"]
+ var/name = record_entry.fields["name"]
+ var/rank = record_entry.fields["rank"]
+ var/squad = record_entry.fields["squad"]
if(isnull(name) || isnull(rank))
continue
var/has_department = FALSE
for(var/department in departments)
// STOP SIGNING ALL MARINES IN ALPHA!
- if(department in ROLES_SQUAD_ALL)
+ if(department in GLOB.ROLES_SQUAD_ALL)
if(squad != department)
continue
var/list/jobs = departments[department]
@@ -83,16 +83,16 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
// sort mobs
var/dept_flags = NO_FLAGS //Is there anybody in the department?.
- var/list/squad_sublists = ROLES_SQUAD_ALL.Copy() //Are there any marines in the squad?
+ var/list/squad_sublists = GLOB.ROLES_SQUAD_ALL.Copy() //Are there any marines in the squad?
- for(var/datum/data/record/t in GLOB.data_core.general)
- if(t.fields["mob_faction"] != FACTION_MARINE) //we process only USCM humans
+ for(var/datum/data/record/record_entry in GLOB.data_core.general)
+ if(record_entry.fields["mob_faction"] != FACTION_MARINE) //we process only USCM humans
continue
- var/name = t.fields["name"]
- var/rank = t.fields["rank"]
- var/real_rank = t.fields["real_rank"]
- var/squad_name = t.fields["squad"]
+ var/name = record_entry.fields["name"]
+ var/rank = record_entry.fields["rank"]
+ var/real_rank = record_entry.fields["real_rank"]
+ var/squad_name = record_entry.fields["squad"]
if(isnull(name) || isnull(rank) || isnull(real_rank))
continue
@@ -104,35 +104,38 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
break
isactive[name] = active ? "Active" : "Inactive"
else
- isactive[name] = t.fields["p_stat"]
+ isactive[name] = record_entry.fields["p_stat"]
//cael - to prevent multiple appearances of a player/job combination, add a continue after each line
- if(real_rank in ROLES_CIC)
+ if(real_rank in GLOB.ROLES_CIC)
dept_flags |= FLAG_SHOW_CIC
LAZYSET(cic[real_rank], name, rank)
- else if(real_rank in ROLES_AUXIL_SUPPORT)
+ else if(real_rank in GLOB.ROLES_AUXIL_SUPPORT)
dept_flags |= FLAG_SHOW_AUXIL_SUPPORT
LAZYSET(auxil[real_rank], name, rank)
- else if(real_rank in ROLES_MISC)
+ else if(real_rank in GLOB.ROLES_MISC)
dept_flags |= FLAG_SHOW_MISC
LAZYSET(misc[real_rank], name, rank)
- else if(real_rank in ROLES_POLICE)
+ else if(real_rank in GLOB.ROLES_POLICE)
dept_flags |= FLAG_SHOW_POLICE
LAZYSET(mp[real_rank], name, rank)
- else if(real_rank in ROLES_ENGINEERING)
+ else if(real_rank in GLOB.ROLES_ENGINEERING)
dept_flags |= FLAG_SHOW_ENGINEERING
LAZYSET(eng[real_rank], name, rank)
- else if(real_rank in ROLES_REQUISITION)
+ else if(real_rank in GLOB.ROLES_REQUISITION)
dept_flags |= FLAG_SHOW_REQUISITION
LAZYSET(req[real_rank], name, rank)
- else if(real_rank in ROLES_MEDICAL)
+ else if(real_rank in GLOB.ROLES_MEDICAL)
dept_flags |= FLAG_SHOW_MEDICAL
LAZYSET(med[real_rank], name, rank)
- else if(real_rank in ROLES_MARINES)
+ else if(real_rank in GLOB.ROLES_MARINES)
if(isnull(squad_name))
continue
dept_flags |= FLAG_SHOW_MARINES
squad_sublists[squad_name] = TRUE
+ ///If it is a real squad in the USCM squad list to prevent the crew manifest from breaking
+ if(!(squad_name in GLOB.ROLES_SQUAD_ALL))
+ continue
LAZYSET(marines_by_squad[squad_name][real_rank], name, rank)
//here we fill manifest
@@ -152,7 +155,7 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
even = !even
if(dept_flags & FLAG_SHOW_MARINES)
dat += "
Marines
"
- for(var/squad_name in ROLES_SQUAD_ALL)
+ for(var/squad_name in GLOB.ROLES_SQUAD_ALL)
if(!squad_sublists[squad_name])
continue
dat += "
[squad_name]
"
@@ -202,9 +205,9 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
if(!nosleep)
sleep(40)
- var/list/jobs_to_check = ROLES_CIC + ROLES_AUXIL_SUPPORT + ROLES_MISC + ROLES_POLICE + ROLES_ENGINEERING + ROLES_REQUISITION + ROLES_MEDICAL + ROLES_MARINES
- for(var/mob/living/carbon/human/H in GLOB.human_mob_list)
- if(is_admin_level(H.z))
+ var/list/jobs_to_check = GLOB.ROLES_CIC + GLOB.ROLES_AUXIL_SUPPORT + GLOB.ROLES_MISC + GLOB.ROLES_POLICE + GLOB.ROLES_ENGINEERING + GLOB.ROLES_REQUISITION + GLOB.ROLES_MEDICAL + GLOB.ROLES_MARINES
+ for(var/mob/living/carbon/human/H as anything in GLOB.human_mob_list)
+ if(should_block_game_interaction(H))
continue
if(H.job in jobs_to_check)
manifest_inject(H)
@@ -213,14 +216,14 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
var/datum/data/record/foundrecord
var/use_name = isnull(ref)
- for(var/datum/data/record/t in GLOB.data_core.general)
+ for(var/datum/data/record/record_entry in GLOB.data_core.general)
if(use_name)
- if(t.fields["name"] == name)
- foundrecord = t
+ if(record_entry.fields["name"] == name)
+ foundrecord = record_entry
break
else
- if(t.fields["ref"] == ref)
- foundrecord = t
+ if(record_entry.fields["ref"] == ref)
+ foundrecord = record_entry
break
if(foundrecord)
@@ -236,102 +239,106 @@ GLOBAL_DATUM_INIT(data_core, /datum/datacore, new)
return TRUE
return FALSE
-/datum/datacore/proc/manifest_inject(mob/living/carbon/human/H)
+/datum/datacore/proc/manifest_inject(mob/living/carbon/human/target)
var/assignment
- if(H.job)
- assignment = H.job
+ if(target.job)
+ assignment = target.job
else
assignment = "Unassigned"
- var/id = add_zero(num2hex(H.gid), 6) //this was the best they could come up with? A large random number? *sigh*
+ var/id = add_zero(num2hex(target.gid), 6) //this was the best they could come up with? A large random number? *sigh*
//var/icon/front = new(get_id_photo(H), dir = SOUTH)
//var/icon/side = new(get_id_photo(H), dir = WEST)
//General Record
- var/datum/data/record/G = new()
- G.fields["id"] = id
- G.fields["name"] = H.real_name
- G.fields["real_rank"] = H.job
- G.fields["rank"] = assignment
- G.fields["squad"] = H.assigned_squad ? H.assigned_squad.name : null
- G.fields["age"] = H.age
- G.fields["p_stat"] = "Active"
- G.fields["m_stat"] = "Stable"
- G.fields["sex"] = H.gender
- G.fields["species"] = H.get_species()
- G.fields["origin"] = H.origin
- G.fields["faction"] = H.personal_faction
- G.fields["mob_faction"] = H.faction
- G.fields["religion"] = H.religion
- G.fields["ref"] = WEAKREF(H)
- //G.fields["photo_front"] = front
- //G.fields["photo_side"] = side
-
- if(H.gen_record && !jobban_isbanned(H, "Records"))
- G.fields["notes"] = H.gen_record
+ var/datum/data/record/record_general = new()
+ record_general.fields["id"] = id
+ record_general.fields["name"] = target.real_name
+ record_general.name = target.real_name
+ record_general.fields["real_rank"] = target.job
+ record_general.fields["rank"] = assignment
+ record_general.fields["squad"] = target.assigned_squad ? target.assigned_squad.name : null
+ record_general.fields["age"] = target.age
+ record_general.fields["p_stat"] = "Active"
+ record_general.fields["m_stat"] = "Stable"
+ record_general.fields["sex"] = target.gender
+ record_general.fields["species"] = target.get_species()
+ record_general.fields["origin"] = target.origin
+ record_general.fields["faction"] = target.personal_faction
+ record_general.fields["mob_faction"] = target.faction
+ record_general.fields["religion"] = target.religion
+ record_general.fields["ref"] = WEAKREF(target)
+ //record_general.fields["photo_front"] = front
+ //record_general.fields["photo_side"] = side
+
+ if(target.gen_record && !jobban_isbanned(target, "Records"))
+ record_general.fields["notes"] = target.gen_record
else
- G.fields["notes"] = "No notes found."
- general += G
+ record_general.fields["notes"] = "No notes found."
+ general += record_general
//Medical Record
- var/datum/data/record/M = new()
- M.fields["id"] = id
- M.fields["name"] = H.real_name
- 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"
- M.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
- M.fields["alg"] = "None"
- M.fields["alg_d"] = "No allergies have been detected in this patient."
- M.fields["cdi"] = "None"
- M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
- M.fields["last_scan_time"] = null
- M.fields["last_scan_result"] = "No scan data on record" // body scanner results
- M.fields["autodoc_data"] = list()
- M.fields["autodoc_manual"] = list()
- M.fields["ref"] = WEAKREF(H)
-
- if(H.med_record && !jobban_isbanned(H, "Records"))
- M.fields["notes"] = H.med_record
+ var/datum/data/record/record_medical = new()
+ record_medical.fields["id"] = id
+ record_medical.fields["name"] = target.real_name
+ record_medical.name = target.name
+ record_medical.fields["b_type"] = target.blood_type
+ record_medical.fields["mi_dis"] = "None"
+ record_medical.fields["mi_dis_d"] = "No minor disabilities have been declared."
+ record_medical.fields["ma_dis"] = "None"
+ record_medical.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
+ record_medical.fields["alg"] = "None"
+ record_medical.fields["alg_d"] = "No allergies have been detected in this patient."
+ record_medical.fields["cdi"] = "None"
+ record_medical.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
+ record_medical.fields["last_scan_time"] = null
+ record_medical.fields["last_scan_result"] = "No scan data on record" // body scanner results
+ record_medical.fields["autodoc_data"] = list()
+ record_medical.fields["autodoc_manual"] = list()
+ record_medical.fields["ref"] = WEAKREF(target)
+
+ if(target.med_record && !jobban_isbanned(target, "Records"))
+ record_medical.fields["notes"] = target.med_record
else
- M.fields["notes"] = "No notes found."
- medical += M
+ record_medical.fields["notes"] = "No notes found."
+ medical += record_medical
//Security Record
- var/datum/data/record/S = new()
- S.fields["id"] = id
- S.fields["name"] = H.real_name
- S.fields["criminal"] = "None"
- S.fields["incident"] = ""
- S.fields["ref"] = WEAKREF(H)
+ var/datum/data/record/record_security = new()
+ record_security.fields["id"] = id
+ record_security.fields["name"] = target.real_name
+ record_security.name = target.real_name
+ record_security.fields["criminal"] = "None"
+ record_security.fields["incident"] = ""
+ record_security.fields["ref"] = WEAKREF(target)
- if(H.sec_record && !jobban_isbanned(H, "Records"))
- var/new_comment = list("entry" = H.sec_record, "created_by" = list("name" = "\[REDACTED\]", "rank" = "Military Police"), "deleted_by" = null, "deleted_at" = null, "created_at" = "Pre-Deployment")
- S.fields["comments"] = list("1" = new_comment)
- S.fields["notes"] = H.sec_record
- security += S
+ if(target.sec_record && !jobban_isbanned(target, "Records"))
+ var/new_comment = list("entry" = target.sec_record, "created_by" = list("name" = "\[REDACTED\]", "rank" = "Military Police"), "deleted_by" = null, "deleted_at" = null, "created_at" = "Pre-Deployment")
+ record_security.fields["comments"] = list("1" = new_comment)
+ record_security.fields["notes"] = target.sec_record
+ security += record_security
//Locked Record
- var/datum/data/record/L = new()
- L.fields["id"] = md5("[H.real_name][H.job]")
- L.fields["name"] = H.real_name
- L.fields["rank"] = H.job
- L.fields["age"] = H.age
- L.fields["sex"] = H.gender
- L.fields["b_type"] = H.b_type
- L.fields["species"] = H.get_species()
- L.fields["origin"] = H.origin
- L.fields["faction"] = H.personal_faction
- L.fields["religion"] = H.religion
- L.fields["ref"] = WEAKREF(H)
-
- if(H.exploit_record && !jobban_isbanned(H, "Records"))
- L.fields["exploit_record"] = H.exploit_record
+ var/datum/data/record/record_locked = new()
+ record_locked.fields["id"] = md5("[target.real_name][target.job]")
+ record_locked.fields["name"] = target.real_name
+ record_locked.name = target.real_name
+ record_locked.fields["rank"] = target.job
+ record_locked.fields["age"] = target.age
+ record_locked.fields["sex"] = target.gender
+ record_locked.fields["b_type"] = target.b_type
+ record_locked.fields["species"] = target.get_species()
+ record_locked.fields["origin"] = target.origin
+ record_locked.fields["faction"] = target.personal_faction
+ record_locked.fields["religion"] = target.religion
+ record_locked.fields["ref"] = WEAKREF(target)
+
+ if(target.exploit_record && !jobban_isbanned(target, "Records"))
+ record_locked.fields["exploit_record"] = target.exploit_record
else
- L.fields["exploit_record"] = "No additional information acquired."
- locked += L
+ record_locked.fields["exploit_record"] = "No additional information acquired."
+ locked += record_locked
/proc/get_id_photo(mob/living/carbon/human/H)
diff --git a/code/datums/datum.dm b/code/datums/datum.dm
index b26c6afe4d91..7d497785a72a 100644
--- a/code/datums/datum.dm
+++ b/code/datums/datum.dm
@@ -19,8 +19,8 @@
/// Active timers with this datum as the target
var/list/active_timers
- /// Status traits attached.
- var/list/status_traits
+ /// Status traits attached to this datum. associative list of the form: list(trait name (string) = list(source1, source2, source3,...))
+ var/list/_status_traits
/**
* Components attached to this datum
diff --git a/code/datums/disease.dm b/code/datums/disease.dm
index e9c399c7b8bf..024337c8e065 100644
--- a/code/datums/disease.dm
+++ b/code/datums/disease.dm
@@ -7,7 +7,7 @@ to null does not delete the object itself. Thank you.
*/
-var/list/diseases = typesof(/datum/disease) - /datum/disease
+GLOBAL_LIST_INIT(diseases, typesof(/datum/disease) - /datum/disease)
/datum/disease
@@ -121,17 +121,17 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease
check_range = 1 // everything else, like infect-on-contact things, only infect things on top of it
if(isturf(source.loc))
- for(var/mob/living/carbon/M in oview(check_range, source))
- if(isturf(M.loc))
- if(AStar(source.loc, M.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, check_range))
- M.contract_disease(src, 0, 1, force_spread)
+ for(var/mob/living/carbon/victim in oview(check_range, source))
+ if(isturf(victim.loc))
+ if(AStar(source.loc, victim.loc, /turf/proc/AdjacentTurfs, /turf/proc/Distance, check_range))
+ victim.contract_disease(src, 0, 1, force_spread)
return
/datum/disease/process()
if(!holder)
- active_diseases -= src
+ SSdisease.all_diseases -= src
return
if(prob(65))
spread(holder)
@@ -173,12 +173,10 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease
var/mob/living/carbon/human/H = affected_mob
H.med_hud_set_status()
-
-
/datum/disease/New(process=TRUE)//process = 1 - adding the object to global list. List is processed by master controller.
cure_list = list(cure_id) // to add more cures, add more vars to this list in the actual disease's New()
if(process) // Viruses in list are considered active.
- active_diseases += src
+ SSdisease.all_diseases += src
initial_spread = spread
/datum/disease/proc/IsSame(datum/disease/D)
@@ -193,5 +191,5 @@ var/list/diseases = typesof(/datum/disease) - /datum/disease
/datum/disease/Destroy()
affected_mob = null
holder = null
- active_diseases -= src
+ SSdisease.all_diseases -= src
. = ..()
diff --git a/code/datums/diseases/advance/advance.dm b/code/datums/diseases/advance/advance.dm
index 6440c9734374..d933b81eb620 100644
--- a/code/datums/diseases/advance/advance.dm
+++ b/code/datums/diseases/advance/advance.dm
@@ -9,15 +9,15 @@
#define RANDOM_STARTING_LEVEL 2
-var/list/archive_diseases = list()
+GLOBAL_LIST_EMPTY(archive_diseases)
// The order goes from easy to cure to hard to cure.
-var/list/advance_cures = list(
+GLOBAL_LIST_INIT(advance_cures, list(
"nutriment", "sugar", "orangejuice",
"spaceacillin", "kelotane", "ethanol",
"leporazine", "lipozine",
"silver", "gold", "phoron"
- )
+ ))
/*
@@ -50,10 +50,10 @@ var/list/advance_cures = list(
/datum/disease/advance/New(process = 1, datum/disease/advance/D)
// Setup our dictionary if it hasn't already.
- if(!dictionary_symptoms.len)
- for(var/symp in list_symptoms)
+ if(!GLOB.dictionary_symptoms.len)
+ for(var/symp in GLOB.list_symptoms)
var/datum/symptom/S = new symp
- dictionary_symptoms[S.id] = symp
+ GLOB.dictionary_symptoms[S.id] = symp
if(!istype(D))
D = null
@@ -142,7 +142,7 @@ var/list/advance_cures = list(
// Generate symptoms. By default, we only choose non-deadly symptoms.
var/list/possible_symptoms = list()
- for(var/symp in list_symptoms)
+ for(var/symp in GLOB.list_symptoms)
var/datum/symptom/S = new symp
if(S.level <= type_level_limit)
if(!HasSymptom(S))
@@ -170,13 +170,13 @@ var/list/advance_cures = list(
var/list/properties = GenerateProperties()
AssignProperties(properties)
- if(!archive_diseases[GetDiseaseID()])
+ if(!GLOB.archive_diseases[GetDiseaseID()])
if(new_name)
AssignName()
- archive_diseases[GetDiseaseID()] = src // So we don't infinite loop
- archive_diseases[GetDiseaseID()] = new /datum/disease/advance(0, src, 1)
+ GLOB.archive_diseases[GetDiseaseID()] = src // So we don't infinite loop
+ GLOB.archive_diseases[GetDiseaseID()] = new /datum/disease/advance(0, src, 1)
- var/datum/disease/advance/A = archive_diseases[GetDiseaseID()]
+ var/datum/disease/advance/A = GLOB.archive_diseases[GetDiseaseID()]
AssignName(A.name)
//Generate disease properties based on the effects. Returns an associated list.
@@ -254,11 +254,11 @@ var/list/advance_cures = list(
// Will generate a random cure, the less resistance the symptoms have, the harder the cure.
/datum/disease/advance/proc/GenerateCure(list/properties = list())
if(properties && properties.len)
- var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, advance_cures.len)
- cure_id = advance_cures[res]
+ var/res = Clamp(properties["resistance"] - (symptoms.len / 2), 1, GLOB.advance_cures.len)
+ cure_id = GLOB.advance_cures[res]
// Get the cure name from the cure_id
- var/datum/reagent/D = chemical_reagents_list[cure_id]
+ var/datum/reagent/D = GLOB.chemical_reagents_list[cure_id]
cure = D.name
@@ -373,7 +373,7 @@ var/list/advance_cures = list(
var/list/symptoms = list()
symptoms += "Done"
- symptoms += list_symptoms.Copy()
+ symptoms += GLOB.list_symptoms.Copy()
do
var/symptom = tgui_input_list(user, "Choose a symptom to add ([i] remaining)", "Choose a Symptom", symptoms)
if(istext(symptom))
@@ -391,7 +391,7 @@ var/list/advance_cures = list(
D.AssignName(new_name)
D.Refresh()
- for(var/datum/disease/advance/AD in active_diseases)
+ for(var/datum/disease/advance/AD in SSdisease.all_diseases)
AD.Refresh()
for(var/mob/living/carbon/human/H in shuffle(GLOB.alive_mob_list.Copy()))
@@ -409,7 +409,7 @@ var/list/advance_cures = list(
/*
/mob/verb/test()
- for(var/datum/disease/D in active_diseases)
+ for(var/datum/disease/D in SSdisease.all_diseases)
to_chat(src, "[D.name] - [D.holder]")
*/
diff --git a/code/datums/diseases/advance/symptoms/symptoms.dm b/code/datums/diseases/advance/symptoms/symptoms.dm
index 72a132cf517e..7746a03b4f89 100644
--- a/code/datums/diseases/advance/symptoms/symptoms.dm
+++ b/code/datums/diseases/advance/symptoms/symptoms.dm
@@ -1,9 +1,7 @@
// Symptoms are the effects that engineered advanced diseases do.
-var/list/list_symptoms = typesof(/datum/symptom) - /datum/symptom
-var/list/dictionary_symptoms = list()
-
-var/global/const/SYMPTOM_ACTIVATION_PROB = 3
+GLOBAL_LIST_INIT(list_symptoms, typesof(/datum/symptom) - /datum/symptom)
+GLOBAL_LIST_EMPTY(dictionary_symptoms)
/datum/symptom
// Buffs/Debuffs the symptom has to the overall engineered disease.
@@ -18,7 +16,7 @@ var/global/const/SYMPTOM_ACTIVATION_PROB = 3
var/id = ""
/datum/symptom/New()
- var/list/S = list_symptoms
+ var/list/S = GLOB.list_symptoms
for(var/i = 1; i <= S.len; i++)
if(src.type == S[i])
id = "[i]"
diff --git a/code/datums/diseases/advance/symptoms/voice_change.dm b/code/datums/diseases/advance/symptoms/voice_change.dm
index 7547242473db..e5af4a8eaab4 100644
--- a/code/datums/diseases/advance/symptoms/voice_change.dm
+++ b/code/datums/diseases/advance/symptoms/voice_change.dm
@@ -38,10 +38,10 @@ Bonus
var/random_name = ""
switch(H.gender)
if(MALE)
- random_name = pick(first_names_male)
+ random_name = pick(GLOB.first_names_male)
else
- random_name = pick(first_names_female)
- random_name += " [pick(last_names)]"
+ random_name = pick(GLOB.first_names_female)
+ random_name += " [pick(GLOB.last_names)]"
H.SetSpecialVoice(random_name)
return
diff --git a/code/datums/diseases/black_goo.dm b/code/datums/diseases/black_goo.dm
index 38a26f3648c7..183cdadf17aa 100644
--- a/code/datums/diseases/black_goo.dm
+++ b/code/datums/diseases/black_goo.dm
@@ -1,104 +1,140 @@
//Disease Datum
+#define ZOMBIE_INFECTION_STAGE_ONE 1
+#define ZOMBIE_INFECTION_STAGE_TWO 2
+#define ZOMBIE_INFECTION_STAGE_THREE 3
+#define SLOW_INFECTION_RATE 1
+#define FAST_INFECTION_RATE 7
+#define STAGE_LEVEL_THRESHOLD 360
+#define MESSAGE_COOLDOWN_TIME 1 MINUTES
+
/datum/disease/black_goo
name = "Black Goo"
- max_stages = 5
+ max_stages = 3
cure = "Anti-Zed"
cure_id = "antiZed"
spread = "Bites"
spread_type = SPECIAL
affected_species = list("Human")
- curable = 0
- cure_chance = 100
- desc = ""
+ cure_chance = 100 //meaning the cure will kill the virus asap
severity = "Medium"
agent = "Unknown Biological Organism X-65"
hidden = list(1,0) //Hidden from med-huds, but not pandemic scanners. BLOOD TESTS FOR THE WIN
permeability_mod = 2
- stage_prob = 4
- stage_minimum_age = 150
- survive_mob_death = TRUE //FALSE //switch to true to make dead infected humans still transform
- longevity = 500 //should allow the dead to rise
- var/zombie_transforming = 0 //whether we're currently transforming the host into a zombie.
- var/goo_message_cooldown = 0 //to make sure we don't spam messages too often.
- var/stage_counter = 0 // tells a dead infectee their stage, so they can know when-abouts they'll revive
+ survive_mob_death = TRUE //We want the dead to turn into zombie.
+ longevity = 500 //the virus tend to die before the dead is turn into zombie this should fix it.
+ stage_prob = 0//no randomness
+
+ /// boolean value to determine if the mob is currently transforming into a zombie.
+ var/zombie_is_transforming = FALSE
+
+ /// variable to keep track of the stage level, used to prevent the stage message from being displayed more than once for any given stage.
+ var/stage_counter = 0
+
+//new variables to handle infection progression inside a stage.
+
+ /// variable that contains accumulated virus progression for a host. Iterates to a value above 360 and is then reset.
+ var/stage_level = 0
+
+ /// variable that handles passive increase of the virus of a host.
+ var/infection_rate = SLOW_INFECTION_RATE
+
+ /// cooldown for the living mob's symptom messages
+ COOLDOWN_DECLARE(goo_message_cooldown)
/datum/disease/black_goo/stage_act()
..()
- if(!ishuman(affected_mob)) return
- var/mob/living/carbon/human/H = affected_mob
+ if(!ishuman_strict(affected_mob))
+ return
+ var/mob/living/carbon/human/infected_mob = affected_mob
+
+ if(iszombie(infected_mob))
+ return
+
+ // infection rate is faster for dead mobs
+ if(infected_mob.stat == DEAD)
+ infection_rate = FAST_INFECTION_RATE
+
+ // standard infection rate for living mobs
+ if(infected_mob.stat != DEAD)
+ infection_rate = SLOW_INFECTION_RATE
+
+ stage_level += infection_rate
+
+ // resets the stage_level once it passes the threshold.
+ if(stage_level >= STAGE_LEVEL_THRESHOLD)
+ stage++
+ stage_level = stage_level % STAGE_LEVEL_THRESHOLD
- if(age > 1.5*stage_minimum_age) stage_prob = 100 //if it takes too long we force a stage increase
- else stage_prob = initial(stage_prob)
- if(H.stat == DEAD) stage_minimum_age = 75 //the virus progress faster when the host is dead.
switch(stage)
- if(1)
- if(H.stat == DEAD && stage_counter != stage)
- to_chat(H, SPAN_CENTERBOLD("Your zombie infection is now at Stage One! Zombie transformation begins at Stage Four."))
+ if(ZOMBIE_INFECTION_STAGE_ONE)
+ if(infected_mob.stat == DEAD && stage_counter != stage)
+ to_chat(infected_mob, SPAN_CENTERBOLD("Your zombie infection is now at stage one! Zombie transformation begins at stage three."))
stage_counter = stage
- survive_mob_death = TRUE //changed because infection rate was REALLY horrible.
- if(goo_message_cooldown < world.time )
- if(prob(3))
- to_chat(affected_mob, SPAN_DANGER("You feel really warm..."))
- goo_message_cooldown = world.time + 100
- if(2)
- if(H.stat == DEAD && stage_counter != stage)
- to_chat(H, SPAN_CENTERBOLD("Your zombie infection is now at Stage Two! Zombie transformation begins at Stage Four."))
+
+ // dead mobs should not have symptoms, because... they are dead.
+ if(infected_mob.stat != DEAD)
+ if (!COOLDOWN_FINISHED(src, goo_message_cooldown))
+ return
+ COOLDOWN_START(src, goo_message_cooldown, MESSAGE_COOLDOWN_TIME)
+
+ switch(rand(0, 100))
+ if(0 to 25)
+ return
+ if(25 to 75)
+ to_chat(infected_mob, SPAN_DANGER("You feel warm..."))
+ stage_level += 9
+ if(75 to 95)
+ to_chat(infected_mob, SPAN_DANGER("Your throat is really dry..."))
+ stage_level += 18
+ if(95 to 100)
+ to_chat(infected_mob, SPAN_DANGER("You can't trust them..."))
+ stage_level += 36
+
+ if(ZOMBIE_INFECTION_STAGE_TWO)
+ if(infected_mob.stat == DEAD && stage_counter != stage)
+ to_chat(infected_mob, SPAN_CENTERBOLD("Your zombie infection is now at stage two! Zombie transformation begins at stage three."))
stage_counter = stage
- if(goo_message_cooldown < world.time)
- if (prob(3)) to_chat(affected_mob, SPAN_DANGER("Your throat is really dry..."))
- else if (prob(6)) to_chat(affected_mob, SPAN_DANGER("You feel really warm..."))
- else if (prob(2)) H.vomit_on_floor()
- goo_message_cooldown = world.time + 100
- if(3)
- if(H.stat == DEAD && stage_counter != stage)
- to_chat(H, SPAN_CENTERBOLD("Your zombie infection is now at Stage Three! Zombie transformation begins at Stage Four, which will be soon."))
+
+ if(infected_mob.stat != DEAD)
+ if (!COOLDOWN_FINISHED(src, goo_message_cooldown))
+ return
+ COOLDOWN_START(src, goo_message_cooldown, MESSAGE_COOLDOWN_TIME)
+
+ switch(rand(0, 100))
+ if(0 to 25)
+ return
+ if(25 to 50)
+ to_chat(infected_mob, SPAN_DANGER("You can't trust them..."))
+ stage_level += 5
+ if(50 to 75)
+ to_chat(infected_mob, SPAN_DANGER("You feel really warm..."))
+ stage_level += 9
+ if(75 to 85)
+ to_chat(infected_mob, SPAN_DANGER("Your throat is really dry..."))
+ stage_level += 18
+ if(85 to 95)
+ infected_mob.vomit_on_floor()
+ stage_level += 36
+ if(95 to 100)
+ to_chat(infected_mob, SPAN_DANGER("You cough up some black fluid..."))
+ stage_level += 42
+
+ if(ZOMBIE_INFECTION_STAGE_THREE)
+ //check if the mob is already a zombie and just return to avoid weird stuff, edge case if zombie_is_transforming deoesn't work.
+ if(iszombie(infected_mob))
+ return
+
+ if(infected_mob.stat == DEAD && stage_counter != stage)
+ to_chat(infected_mob, SPAN_CENTERBOLD("Your zombie infection is now at stage three! Zombie transformation begin!"))
stage_counter = stage
hidden = list(0,0)
- //survive_mob_death = TRUE //even if host dies now, the transformation will occur.
- H.next_move_slowdown = max(H.next_move_slowdown, 1)
- if(goo_message_cooldown < world.time)
- if (prob(3))
- to_chat(affected_mob, SPAN_DANGER("You cough up some black fluid..."))
- goo_message_cooldown = world.time + 100
- else if (prob(6))
- to_chat(affected_mob, SPAN_DANGER("Your throat is really dry..."))
- goo_message_cooldown = world.time + 100
- else if (prob(9))
- to_chat(affected_mob, SPAN_DANGER("You feel really warm..."))
- goo_message_cooldown = world.time + 100
- else if(prob(5))
- goo_message_cooldown = world.time + 100
- H.vomit_on_floor()
- if(4)
- if(H.stat == DEAD && stage_counter != stage)
- to_chat(H, SPAN_CENTERBOLD("Your zombie infection is now at Stage Four! Your transformation will happen any moment now."))
- stage_counter = stage
- H.next_move_slowdown = max(H.next_move_slowdown, 2)
- if(prob(5) || age >= stage_minimum_age-1)
- if(!zombie_transforming)
- zombie_transform(H)
- else if(prob(5))
- H.vomit_on_floor()
- if(5)
- if(H.stat == DEAD && stage_counter != stage)
- stage_counter = stage
- if(H.species.name != SPECIES_ZOMBIE && !zombie_transforming)
- to_chat(H, SPAN_CENTERBOLD("Your zombie infection is now at Stage Five! Your transformation should have happened already, but will be forced now."))
- zombie_transform(H)
- if(!zombie_transforming && prob(50))
- if(H.stat != DEAD)
- var/healamt = 2
- if(H.health < H.maxHealth)
- H.apply_damage(-healamt, BURN)
- H.apply_damage(-healamt, BRUTE)
- H.apply_damage(-healamt, TOX)
- H.apply_damage(-healamt, OXY)
- H.nutrition = NUTRITION_MAX //never hungry
-
+ if(!zombie_is_transforming)
+ zombie_transform(infected_mob)
+ infected_mob.next_move_slowdown = max(infected_mob.next_move_slowdown, 2)
/datum/disease/black_goo/proc/zombie_transform(mob/living/carbon/human/human)
set waitfor = 0
- zombie_transforming = TRUE
+ zombie_is_transforming = TRUE
human.vomit_on_floor()
human.adjust_effect(5, STUN)
sleep(20)
@@ -113,9 +149,9 @@
playsound(human.loc, 'sound/hallucinations/wail.ogg', 25, 1)
human.jitteriness = 0
human.set_species(SPECIES_ZOMBIE)
- stage = 5
+ stage = 3
human.faction = FACTION_ZOMBIE
- zombie_transforming = FALSE
+ zombie_is_transforming = FALSE
/obj/item/weapon/zombie_claws
@@ -211,6 +247,15 @@
. = ..()
reagents.add_reagent("antiZed", 30)
+/obj/item/reagent_container/glass/bottle/labeled_black_goo_cure
+ name = "\"Pathogen\" cure bottle"
+ desc = "The bottle has a biohazard symbol on the front, and has a label, designating its use against Agent A0-3959X.91–15, colloquially known as the \"Black Goo\"."
+ icon_state = "bottle20"
+
+/obj/item/reagent_container/glass/bottle/labeled_black_goo_cure/Initialize()
+ . = ..()
+ reagents.add_reagent("antiZed", 60)
+
/datum/language/zombie
name = "Zombie"
desc = "A growling, guttural method of communication, only Zombies seem to be capable of producing these sounds."
@@ -261,3 +306,11 @@
for(var/i=1; i <= storage_slots; i++)
new /obj/item/reagent_container/food/drinks/bottle/black_goo(src)
return
+
+#undef ZOMBIE_INFECTION_STAGE_ONE
+#undef ZOMBIE_INFECTION_STAGE_TWO
+#undef ZOMBIE_INFECTION_STAGE_THREE
+#undef STAGE_LEVEL_THRESHOLD
+#undef SLOW_INFECTION_RATE
+#undef FAST_INFECTION_RATE
+#undef MESSAGE_COOLDOWN_TIME
diff --git a/code/datums/diseases/cold.dm b/code/datums/diseases/cold.dm
index 46cd8952dda1..fd3fbc3a7d2d 100644
--- a/code/datums/diseases/cold.dm
+++ b/code/datums/diseases/cold.dm
@@ -20,7 +20,7 @@
cure()
return
*/
- if(affected_mob.lying && prob(40)) //changed FROM prob(10) until sleeping is fixed
+ if(affected_mob.body_position == LYING_DOWN && prob(40)) //changed FROM prob(10) until sleeping is fixed
to_chat(affected_mob, SPAN_NOTICE(" You feel better."))
cure()
return
@@ -43,7 +43,7 @@
cure()
return
*/
- if(affected_mob.lying && prob(25)) //changed FROM prob(5) until sleeping is fixed
+ if(affected_mob.body_position == LYING_DOWN && prob(25)) //changed FROM prob(5) until sleeping is fixed
to_chat(affected_mob, SPAN_NOTICE(" You feel better."))
cure()
return
diff --git a/code/datums/diseases/flu.dm b/code/datums/diseases/flu.dm
index f2c029587616..fad0b15228b1 100644
--- a/code/datums/diseases/flu.dm
+++ b/code/datums/diseases/flu.dm
@@ -21,7 +21,7 @@
stage--
return
*/
- if(affected_mob.lying && prob(20)) //added until sleeping is fixed --Blaank
+ if(affected_mob.body_position == LYING_DOWN && prob(20)) //added until sleeping is fixed --Blaank
to_chat(affected_mob, SPAN_NOTICE(" You feel better."))
stage--
return
@@ -46,7 +46,7 @@
stage--
return
*/
- if(affected_mob.lying && prob(15)) //added until sleeping is fixed
+ if(affected_mob.body_position == LYING_DOWN && prob(15)) //added until sleeping is fixed
to_chat(affected_mob, SPAN_NOTICE(" You feel better."))
stage--
return
diff --git a/code/datums/diseases/mob_procs.dm b/code/datums/diseases/mob_procs.dm
index 7f9704c46f47..c27efecdff84 100644
--- a/code/datums/diseases/mob_procs.dm
+++ b/code/datums/diseases/mob_procs.dm
@@ -80,9 +80,6 @@
passed = check_disease_pass_clothes(target_zone)
- if(!passed && spread_type == AIRBORNE && !internal)
- passed = (prob((50*virus.permeability_mod) - 1))
-
if(passed)
AddDisease(virus)
@@ -111,36 +108,39 @@
/mob/living/carbon/human/check_disease_pass_clothes(target_zone)
var/obj/item/clothing/Cl
+ var/protection = 0
switch(target_zone)
if(1)
if(isobj(head) && !istype(head, /obj/item/paper))
Cl = head
- . = prob((Cl.permeability_coefficient*100) - 1)
- if(. && wear_mask)
- . = prob((Cl.permeability_coefficient*100) - 1)
+ protection += (Cl.permeability_coefficient*100)-100
+ if(isobj(wear_mask))
+ Cl = wear_mask
+ protection += (Cl.permeability_coefficient*100)-100
if(2)//arms and legs included
if(isobj(wear_suit))
Cl = wear_suit
- . = prob((Cl.permeability_coefficient*100) - 1)
- if(. && isobj(WEAR_BODY))
+ protection += (Cl.permeability_coefficient*100)-100
+ if(isobj(WEAR_BODY))
Cl = WEAR_BODY
- . = prob((Cl.permeability_coefficient*100) - 1)
+ protection += (Cl.permeability_coefficient*100)-100
if(3)
if(isobj(wear_suit) && wear_suit.flags_armor_protection & BODY_FLAG_HANDS)
Cl = wear_suit
- . = prob((Cl.permeability_coefficient*100) - 1)
+ protection += (Cl.permeability_coefficient*100)-100
- if(. && isobj(gloves))
+ if(isobj(gloves))
Cl = gloves
- . = prob((Cl.permeability_coefficient*100) - 1)
+ protection += (Cl.permeability_coefficient*100)-100
if(4)
if(isobj(wear_suit) && wear_suit.flags_armor_protection & BODY_FLAG_FEET)
Cl = wear_suit
- . = prob((Cl.permeability_coefficient*100) - 1)
+ protection += (Cl.permeability_coefficient*100)-100
- if(. && isobj(shoes))
+ if(isobj(shoes))
Cl = shoes
- . = prob((Cl.permeability_coefficient*100) - 1)
+ protection += (Cl.permeability_coefficient*100)-100
else
to_chat(src, "Something bad happened with disease target zone code, tell a dev or admin ")
+ return prob(clamp(protection, 5, 90))
diff --git a/code/datums/effects/_effects.dm b/code/datums/effects/_effects.dm
index 932dc44954fc..ea6823574f54 100644
--- a/code/datums/effects/_effects.dm
+++ b/code/datums/effects/_effects.dm
@@ -41,7 +41,7 @@
if(!validate_atom(thing) || QDELETED(thing))
qdel(src)
return
- START_PROCESSING(SSeffects, src)
+ START_PROCESSING(SSoldeffects, src)
affected_atom = thing
LAZYADD(affected_atom.effects_list, src)
@@ -118,7 +118,7 @@
if(affected_atom)
LAZYREMOVE(affected_atom.effects_list, src)
affected_atom = null
- STOP_PROCESSING(SSeffects, src)
+ STOP_PROCESSING(SSoldeffects, src)
. = ..()
diff --git a/code/datums/effects/bleeding.dm b/code/datums/effects/bleeding.dm
index e6cb184850d4..2171580a94db 100644
--- a/code/datums/effects/bleeding.dm
+++ b/code/datums/effects/bleeding.dm
@@ -19,6 +19,13 @@
if(L && istype(L))
limb = L
+/datum/effects/bleeding/Destroy()
+ if(limb)
+ SEND_SIGNAL(limb, COMSIG_LIMB_STOP_BLEEDING, TRUE, FALSE)
+ limb.bleeding_effects_list -= src
+ limb = null
+ return ..()
+
/datum/effects/bleeding/validate_atom(atom/A)
if(isobj(A))
return FALSE
@@ -48,12 +55,6 @@
duration += damage * (blood_duration_multiplier / BLOOD_ADD_PENALTY)
blood_loss += damage / (blood_loss_divider * BLOOD_ADD_PENALTY) //Make the first hit count, adding on bleeding has a penalty
-/datum/effects/bleeding/Destroy()
- if(limb)
- limb.bleeding_effects_list -= src
- return ..()
-
-
/datum/effects/bleeding/external
var/buffer_blood_loss = 0
diff --git a/code/datums/effects/tether.dm b/code/datums/effects/tether.dm
index ddaafff46489..1667d901a08a 100644
--- a/code/datums/effects/tether.dm
+++ b/code/datums/effects/tether.dm
@@ -52,7 +52,7 @@
var/turf/T
var/dir_away = get_dir(affected_atom, A)
- for (var/dir in alldirs)
+ for (var/dir in GLOB.alldirs)
if (dir & dir_away)
continue
T = get_step(A, dir)
diff --git a/code/datums/effects/xeno_strains/boiler_trap.dm b/code/datums/effects/xeno_strains/boiler_trap.dm
index 61451391e816..199505379b27 100644
--- a/code/datums/effects/xeno_strains/boiler_trap.dm
+++ b/code/datums/effects/xeno_strains/boiler_trap.dm
@@ -4,19 +4,17 @@
effect_name = "boiler trap"
duration = null
flags = INF_DURATION
- /// Ghetto flag indicating whether we actually placed the freeze or not, until we have an actual effects system
- var/freezer = FALSE
-/datum/effects/boiler_trap/New(atom/A, mob/from, last_dmg_source, zone)
+/datum/effects/boiler_trap/New(atom/A, mob/living/from, last_dmg_source, zone)
. = ..()
if(!QDELETED(src))
- var/mob/M = affected_atom
- freezer = M.freeze()
+ var/mob/living/affected_living = affected_atom
+ ADD_TRAIT(affected_living, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name))
/datum/effects/boiler_trap/Destroy(force)
- if(ismob(affected_atom) && freezer)
- var/mob/M = affected_atom
- M.unfreeze()
+ if(ismob(affected_atom))
+ var/mob/living/affected_living = affected_atom
+ REMOVE_TRAIT(affected_living, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name))
return ..()
/datum/effects/boiler_trap/validate_atom(atom/A)
@@ -28,8 +26,6 @@
/datum/effects/boiler_trap/process_mob()
. = ..()
if(!.) return FALSE
- var/mob/M = affected_atom
- if(M.frozen) return TRUE
- if(!freezer)
- freezer = M.freeze()
+ var/mob/living/affected_living = affected_atom
+ ADD_TRAIT(affected_living, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY(effect_name))
return TRUE
diff --git a/code/datums/effects/xeno_strains/xeno_buff.dm b/code/datums/effects/xeno_strains/xeno_buff.dm
index ad39a61dd13e..16a4bb82113e 100644
--- a/code/datums/effects/xeno_strains/xeno_buff.dm
+++ b/code/datums/effects/xeno_strains/xeno_buff.dm
@@ -21,7 +21,7 @@
if(!isxeno(A))
qdel(src)
- to_chat(A, SPAN_XENONOTICE("You feel empowered"))
+ to_chat(A, SPAN_XENONOTICE("We feel empowered"))
var/mob/living/carbon/xenomorph/X = A
X.melee_damage_lower += bonus_damage
@@ -47,7 +47,7 @@
/datum/effects/xeno_buff/Destroy()
if(affected_atom)
- to_chat(affected_atom, SPAN_XENONOTICE("You no longer feel empowered"))
+ to_chat(affected_atom, SPAN_XENONOTICE("We no longer feel empowered"))
var/mob/living/carbon/xenomorph/X = affected_atom
X.melee_damage_lower -= bonus_damage
X.melee_damage_upper -= bonus_damage
diff --git a/code/datums/elements/bullet_trait/incendiary.dm b/code/datums/elements/bullet_trait/incendiary.dm
index 2d5d0a15f368..861e67651a53 100644
--- a/code/datums/elements/bullet_trait/incendiary.dm
+++ b/code/datums/elements/bullet_trait/incendiary.dm
@@ -13,7 +13,7 @@
if(ispath(reagent))
var/datum/reagent/R = reagent
- burn_reagent = chemical_reagents_list[initial(R.id)]
+ burn_reagent = GLOB.chemical_reagents_list[initial(R.id)]
else
burn_reagent = reagent
burn_stacks = stacks
diff --git a/code/datums/elements/mouth_drop_item.dm b/code/datums/elements/mouth_drop_item.dm
index 42c61bd275cc..7a546c6b3933 100644
--- a/code/datums/elements/mouth_drop_item.dm
+++ b/code/datums/elements/mouth_drop_item.dm
@@ -19,9 +19,9 @@
SIGNAL_HANDLER
if(slot == WEAR_FACE)
- I.RegisterSignal(user, COMSIG_MOB_KNOCKED_DOWN, TYPE_PROC_REF(/obj/item, drop_to_floor))
+ I.RegisterSignal(user, COMSIG_LIVING_SET_BODY_POSITION, TYPE_PROC_REF(/obj/item, drop_to_floor))
/datum/element/mouth_drop_item/proc/item_dropped(obj/item/I, mob/living/carbon/human/user)
SIGNAL_HANDLER
- I.UnregisterSignal(user, COMSIG_MOB_KNOCKED_DOWN)
+ I.UnregisterSignal(user, COMSIG_LIVING_SET_BODY_POSITION)
diff --git a/code/datums/emergency_calls/cbrn.dm b/code/datums/emergency_calls/cbrn.dm
new file mode 100644
index 000000000000..cee96e10137e
--- /dev/null
+++ b/code/datums/emergency_calls/cbrn.dm
@@ -0,0 +1,80 @@
+/datum/emergency_call/cbrn
+ name = "CBRN (Squad)"
+ arrival_message = "A CBRN squad has been dispatched to your ship. Stand by."
+ objectives = "Handle the chemical, biological, radiological, or nuclear threat. Further orders may be provided."
+ mob_min = 3
+ mob_max = 5
+ max_heavies = 0
+ max_smartgunners = 0
+
+/datum/emergency_call/cbrn/create_member(datum/mind/new_mind, turf/override_spawn_loc)
+ var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/mob = new(spawn_loc)
+ new_mind.transfer_to(mob, TRUE)
+
+ if(!leader && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job))
+ leader = mob
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/leader, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Fireteam Leader!"))
+
+ else if(medics < max_medics && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(mob.client, JOB_SQUAD_MEDIC, time_required_for_job))
+ medics++
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/medic, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Squad Medic!"))
+
+ else if(engineers < max_engineers && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(mob.client, JOB_SQUAD_ENGI, time_required_for_job))
+ engineers++
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/engineer, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Squad Engineer!"))
+
+ else
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/standard, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are a CBRN Squad Rifleman!"))
+
+ to_chat(mob, SPAN_ROLE_BODY("You are a member of the USCM's CBRN. The CBRN is a force that specializes in handling chemical, biological, radiological, and nuclear threats."))
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), mob, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+
+/datum/emergency_call/cbrn/ert
+ name = "CBRN (Distress)"
+ arrival_message = "Your distress signal has been received and we are dispatching the nearest CBRN squad to board with you now. Stand by."
+ probability = 10
+
+/datum/emergency_call/cbrn/ert/New()
+ ..()
+ objectives = "Investigate the distress signal aboard the [MAIN_SHIP_NAME]."
+
+/datum/emergency_call/cbrn/specialists
+ name = "CBRN (Specialists)"
+ mob_min = 2
+ mob_max = 5
+ max_engineers = 0
+ max_medics = 0
+
+/datum/emergency_call/cbrn/specialists/New()
+ var/cbrn_ship_name = "Unit [pick(GLOB.nato_phonetic_alphabet)]-[rand(1, 99)]"
+ arrival_message = "[MAIN_SHIP_NAME], CBRN [cbrn_ship_name] has been dispatched. Follow all orders provided by [cbrn_ship_name]."
+ objectives = "You are a specialist team in [cbrn_ship_name] dispatched to quell a threat to [MAIN_SHIP_NAME]. Further orders may be provided."
+
+/datum/emergency_call/cbrn/specialists/create_member(datum/mind/new_mind, turf/override_spawn_loc)
+ var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/mob = new(spawn_loc)
+ new_mind.transfer_to(mob, TRUE)
+
+ if(!leader && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job))
+ leader = mob
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/specialist/lead, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are the CBRN Specialist Squad Leader!"))
+ else
+ arm_equipment(mob, /datum/equipment_preset/uscm/cbrn/specialist, TRUE, TRUE)
+ to_chat(mob, SPAN_ROLE_HEADER("You are a CBRN Specialist!"))
+
+ to_chat(mob, SPAN_ROLE_BODY("You are a member of the USCM's CBRN. The CBRN is a force that specializes in handling chemical, biological, radiological, and nuclear threats."))
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), mob, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
diff --git a/code/datums/emergency_calls/clf.dm b/code/datums/emergency_calls/clf.dm
index 0a5f09e2a2f2..837ecb340dda 100644
--- a/code/datums/emergency_calls/clf.dm
+++ b/code/datums/emergency_calls/clf.dm
@@ -28,7 +28,7 @@
to_chat(H, SPAN_BOLD("The Dust Raiders responded with deadly force, scattering many of the colonists who attempted to fight their occupation."))
to_chat(H, SPAN_BOLD("The Dust Raiders and their flagship, the USS Alistoun eventually withdrew from the sector by the end of the year."))
to_chat(H, SPAN_BOLD("With the Neroid Sector existing in relative isolation from United America oversight for the last five years, many colonists have considered themselves free from governmental rule."))
- to_chat(H, SPAN_BOLD("The year is now [game_year]."))
+ to_chat(H, SPAN_BOLD("The year is now [GLOB.game_year]."))
to_chat(H, SPAN_BOLD("The arrival of the USCM Battalion, the Falling Falcons, and their flagship, the [MAIN_SHIP_NAME], have reaffirmed that the United Americas considers the Neroid Sector part of their holdings."))
to_chat(H, SPAN_BOLD("It is up to you and your fellow colonists to make them realize their trespasses. This sector is no longer theirs."))
@@ -45,7 +45,7 @@
leader = H
to_chat(H, SPAN_ROLE_HEADER("You are a Cell Leader of the local resistance group, the Colonial Liberation Front!"))
arm_equipment(H, /datum/equipment_preset/clf/leader, TRUE, TRUE)
- else if(synths < max_synths && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SYNTH) && RoleAuthority.roles_whitelist[H.ckey] & WHITELIST_SYNTHETIC)
+ else if(synths < max_synths && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SYNTH) && GLOB.RoleAuthority.roles_whitelist[H.ckey] & WHITELIST_SYNTHETIC)
synths++
to_chat(H, SPAN_ROLE_HEADER("You are a Multi-Purpose Synthetic for the local resistance group, the Colonial Liberation Front!"))
arm_equipment(H, /datum/equipment_preset/clf/synth, TRUE, TRUE)
diff --git a/code/datums/emergency_calls/cmb.dm b/code/datums/emergency_calls/cmb.dm
index 777ad322befc..5dba3ee8fc7d 100644
--- a/code/datums/emergency_calls/cmb.dm
+++ b/code/datums/emergency_calls/cmb.dm
@@ -35,7 +35,7 @@
leader = mob
to_chat(mob, SPAN_ROLE_HEADER("You are the Colonial Marshal!"))
arm_equipment(mob, /datum/equipment_preset/cmb/leader, TRUE, TRUE)
- else if(synths < max_synths && HAS_FLAG(mob?.client.prefs.toggles_ert, PLAY_SYNTH) && RoleAuthority.roles_whitelist[mob.ckey] & WHITELIST_SYNTHETIC)
+ else if(synths < max_synths && HAS_FLAG(mob?.client.prefs.toggles_ert, PLAY_SYNTH) && GLOB.RoleAuthority.roles_whitelist[mob.ckey] & WHITELIST_SYNTHETIC)
synths++
to_chat(mob, SPAN_ROLE_HEADER("You are a CMB Investigative Synthetic!"))
arm_equipment(mob, /datum/equipment_preset/cmb/synth, TRUE, TRUE)
@@ -100,6 +100,19 @@
to_chat(M, SPAN_BOLD("Corporate Officers chase after paychecks and promotions, but you are motivated to do your sworn duty and care for the population, no matter how far or isolated a colony may be."))
to_chat(M, SPAN_BOLD("Despite being stretched thin, the stalwart oath of the Marshals has continued to keep communities safe, with the CMB well respected by many. You are a representation of that oath, serve with distinction."))
+
+// A Nearby Colonial Marshal patrol team responding to Marshals in Distress.
+/datum/emergency_call/cmb/alt
+ name = "CMB - Patrol Team - Marshals in Distress (Friendly)"
+ mob_max = 5
+ mob_min = 1
+ probability = 0
+
+/datum/emergency_call/cmb/alt/New()
+ ..()
+ arrival_message = "CMB Team, this is Anchorpoint Station. We have confirmed you are in distress. Routing nearby units to assist!"
+ objectives = "Patrol Unit 5807, we have nearby Marshals in Distress! Locate and assist them immediately."
+
// Anchorpoint Station Colonial Marines, use this primarily for reinforcing or evacuating the CMB, as the CMB themselves are not equipped to handle heavy engagements.
/datum/emergency_call/cmb/anchorpoint
name = "CMB - Anchorpoint Station Colonial Marine QRF (Friendly)"
diff --git a/code/datums/emergency_calls/contractor.dm b/code/datums/emergency_calls/contractor.dm
index a5d6c2d7e80f..0e0c975f0d13 100644
--- a/code/datums/emergency_calls/contractor.dm
+++ b/code/datums/emergency_calls/contractor.dm
@@ -29,7 +29,7 @@
leader = mob
to_chat(mob, SPAN_ROLE_HEADER("You are a Contractor Team Leader of Vanguard's Arrow Incorporated!"))
arm_equipment(mob, /datum/equipment_preset/contractor/duty/leader, TRUE, TRUE)
- else if(synths < max_synths && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_SYNTH) && RoleAuthority.roles_whitelist[mob.ckey] & WHITELIST_SYNTHETIC)
+ else if(synths < max_synths && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_SYNTH) && GLOB.RoleAuthority.roles_whitelist[mob.ckey] & WHITELIST_SYNTHETIC)
synths++
to_chat(mob, SPAN_ROLE_HEADER("You are a Contractor Support Synthetic of Vanguard's Arrow Incorporated!"))
arm_equipment(mob, /datum/equipment_preset/contractor/duty/synth, TRUE, TRUE)
@@ -117,13 +117,13 @@
var/mob/living/carbon/human/H = new(spawn_loc)
H.key = M.key
if(H.client)
- H.client.change_view(world_view_size)
+ H.client.change_view(GLOB.world_view_size)
if(!leader && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job)) //First one spawned is always the leader.
leader = H
to_chat(H, SPAN_ROLE_HEADER("You are a Covert Contractor Team Leader of Vanguard's Arrow Incorporated!"))
arm_equipment(H, /datum/equipment_preset/contractor/covert/leader, TRUE, TRUE)
- else if(synths < max_synths && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SYNTH) && RoleAuthority.roles_whitelist[H.ckey] & WHITELIST_SYNTHETIC)
+ else if(synths < max_synths && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SYNTH) && GLOB.RoleAuthority.roles_whitelist[H.ckey] & WHITELIST_SYNTHETIC)
synths++
to_chat(H, SPAN_ROLE_HEADER("You are a Contractor Support Synthetic of Vanguard's Arrow Incorporated!"))
arm_equipment(H, /datum/equipment_preset/contractor/covert/synth, TRUE, TRUE)
diff --git a/code/datums/emergency_calls/cryo_marines.dm b/code/datums/emergency_calls/cryo_marines.dm
index 7ed61852e9bf..fb8d4b8a5a69 100644
--- a/code/datums/emergency_calls/cryo_marines.dm
+++ b/code/datums/emergency_calls/cryo_marines.dm
@@ -13,8 +13,8 @@
var/leaders = 0
spawn_max_amount = TRUE
-/datum/emergency_call/cryo_squad/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message)
- var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo]
+/datum/emergency_call/cryo_squad/spawn_candidates(quiet_launch, announce_incoming, override_spawn_loc)
+ var/datum/squad/marine/cryo/cryo_squad = GLOB.RoleAuthority.squads_by_type[/datum/squad/marine/cryo]
leaders = cryo_squad.num_leaders
. = ..()
shipwide_ai_announcement("Successfully deployed [mob_max] Foxtrot marines, of which [length(members)] are ready for duty.")
@@ -43,41 +43,41 @@
break
sleep(5)
- var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo]
+ var/datum/squad/marine/cryo/cryo_squad = GLOB.RoleAuthority.squads_by_type[/datum/squad/marine/cryo]
if(leaders < cryo_squad.max_leaders && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(human.client, JOB_SQUAD_LEADER, time_required_for_job))))
leader = human
leaders++
human.client?.prefs.copy_all_to(human, JOB_SQUAD_LEADER, TRUE, TRUE)
arm_equipment(human, /datum/equipment_preset/uscm/leader/cryo, mind == null, TRUE)
to_chat(human, SPAN_ROLE_HEADER("You are a Squad Leader in the USCM"))
- to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
+ to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced."))
else if (heavies < max_heavies && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_HEAVY) && check_timelock(human.client, JOB_SQUAD_SPECIALIST, time_required_for_job))))
heavies++
human.client?.prefs.copy_all_to(human, JOB_SQUAD_SPECIALIST, TRUE, TRUE)
arm_equipment(human, /datum/equipment_preset/uscm/spec/cryo, mind == null, TRUE)
to_chat(human, SPAN_ROLE_HEADER("You are a Weapons Specialist in the USCM"))
- to_chat(human, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
+ to_chat(human, SPAN_ROLE_BODY("Your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced."))
else if (medics < max_medics && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(human.client, JOB_SQUAD_MEDIC, time_required_for_job))))
medics++
human.client?.prefs.copy_all_to(human, JOB_SQUAD_MEDIC, TRUE, TRUE)
arm_equipment(human, /datum/equipment_preset/uscm/medic/cryo, mind == null, TRUE)
to_chat(human, SPAN_ROLE_HEADER("You are a Hospital Corpsman in the USCM"))
- to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
+ to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced."))
else if (engineers < max_engineers && (!mind || (HAS_FLAG(human.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(human.client, JOB_SQUAD_ENGI, time_required_for_job))))
engineers++
human.client?.prefs.copy_all_to(human, JOB_SQUAD_ENGI, TRUE, TRUE)
arm_equipment(human, /datum/equipment_preset/uscm/engineer/cryo, mind == null, TRUE)
to_chat(human, SPAN_ROLE_HEADER("You are an Engineer in the USCM"))
- to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
+ to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced."))
else
human.client?.prefs.copy_all_to(human, JOB_SQUAD_MARINE, TRUE, TRUE)
arm_equipment(human, /datum/equipment_preset/uscm/pfc/cryo, mind == null, TRUE)
to_chat(human, SPAN_ROLE_HEADER("You are a Rifleman in the USCM"))
- to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
+ to_chat(human, SPAN_ROLE_BODY("You are here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced."))
sleep(10)
diff --git a/code/datums/emergency_calls/cryo_marines_heavy.dm b/code/datums/emergency_calls/cryo_marines_heavy.dm
index 70ce52443573..42f25a461254 100644
--- a/code/datums/emergency_calls/cryo_marines_heavy.dm
+++ b/code/datums/emergency_calls/cryo_marines_heavy.dm
@@ -16,8 +16,8 @@
var/leaders = 0
-/datum/emergency_call/cryo_squad_equipped/spawn_candidates(announce, override_spawn_loc, announce_dispatch_message)
- var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo]
+/datum/emergency_call/cryo_squad_equipped/spawn_candidates(quiet_launch, announce_incoming, override_spawn_loc)
+ var/datum/squad/marine/cryo/cryo_squad = GLOB.RoleAuthority.squads_by_type[/datum/squad/marine/cryo]
leaders = cryo_squad.num_leaders
. = ..()
if(length(members))
@@ -35,37 +35,37 @@
M.transfer_to(H, TRUE)
sleep(5)
- var/datum/squad/marine/cryo/cryo_squad = RoleAuthority.squads_by_type[/datum/squad/marine/cryo]
+ var/datum/squad/marine/cryo/cryo_squad = GLOB.RoleAuthority.squads_by_type[/datum/squad/marine/cryo]
if(leaders < cryo_squad.max_leaders && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job))
leader = H
leaders++
arm_equipment(H, /datum/equipment_preset/uscm/leader_equipped/cryo, TRUE, TRUE)
to_chat(H, SPAN_ROLE_HEADER("You are a Squad Leader in the USCM"))
- to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else if (heavies < max_heavies && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_HEAVY) && check_timelock(H.client, JOB_SQUAD_SPECIALIST, time_required_for_job))
heavies++
arm_equipment(H, /datum/equipment_preset/uscm/specialist_equipped/cryo, TRUE, TRUE)
to_chat(H, SPAN_ROLE_HEADER("You are a Weapons Specialist in the USCM"))
- to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else if(smartgunners < max_smartgunners && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(H.client, JOB_SQUAD_SMARTGUN, time_required_for_job))
smartgunners++
arm_equipment(H, /datum/equipment_preset/uscm/smartgunner_equipped/cryo, TRUE, TRUE)
to_chat(H, SPAN_ROLE_HEADER("You are a Smartgunner in the USCM"))
- to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else if(engineers < max_engineers && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(H.client, JOB_SQUAD_ENGI, time_required_for_job))
engineers++
arm_equipment(H, /datum/equipment_preset/uscm/engineer_equipped/cryo, TRUE, TRUE)
to_chat(H, SPAN_ROLE_HEADER("You are an Engineer in the USCM"))
- to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else if (medics < max_medics && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(H.client, JOB_SQUAD_MEDIC, time_required_for_job))
medics++
arm_equipment(H, /datum/equipment_preset/uscm/medic_equipped/cryo, TRUE, TRUE)
to_chat(H, SPAN_ROLE_HEADER("You are a Hospital Corpsman in the USCM"))
- to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else
arm_equipment(H, /datum/equipment_preset/uscm/private_equipped/cryo, TRUE, TRUE)
to_chat(H, SPAN_ROLE_HEADER("You are a Rifleman in the USCM"))
- to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(H, SPAN_ROLE_BODY("Your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
sleep(10)
to_chat(H, SPAN_BOLD("Objectives: [objectives]"))
diff --git a/code/datums/emergency_calls/cryo_spec.dm b/code/datums/emergency_calls/cryo_spec.dm
index 6cc7c905efbc..8d563b0693f8 100644
--- a/code/datums/emergency_calls/cryo_spec.dm
+++ b/code/datums/emergency_calls/cryo_spec.dm
@@ -34,7 +34,7 @@
human.client?.prefs.copy_all_to(human, JOB_SQUAD_SPECIALIST, TRUE, TRUE)
arm_equipment(human, /datum/equipment_preset/uscm/spec/cryo, mind == null, TRUE)
to_chat(human, SPAN_ROLE_HEADER("You are a Weapons Specialist in the USCM"))
- to_chat(human, SPAN_ROLE_BODY("Your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
+ to_chat(human, SPAN_ROLE_BODY("Your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
to_chat(human, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced."))
sleep(10)
diff --git a/code/datums/emergency_calls/deathsquad.dm b/code/datums/emergency_calls/deathsquad.dm
index 0bfab8fbf2b7..1cd5bdef6713 100644
--- a/code/datums/emergency_calls/deathsquad.dm
+++ b/code/datums/emergency_calls/deathsquad.dm
@@ -3,7 +3,7 @@
//Weyland-Yutani Deathsquad - W-Y Deathsquad. Event only
/datum/emergency_call/death
- name = "Weyland Whiteout Operators"
+ name = "Weyland Whiteout Operators (!DEATHSQUAD!)"
mob_max = 8
mob_min = 5
arrival_message = "'!`2*%slau#*jer t*h$em a!l%. le&*ve n(o^ w&*nes%6es.*v$e %#d ou^'"
@@ -18,41 +18,76 @@
// DEATH SQUAD--------------------------------------------------------------------------------
-/datum/emergency_call/death/create_member(datum/mind/M, turf/override_spawn_loc)
+/datum/emergency_call/death/create_member(datum/mind/player, turf/override_spawn_loc)
var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
if(!istype(spawn_loc))
return //Didn't find a useable spawn point.
- var/mob/living/carbon/human/H = new(spawn_loc)
- M.transfer_to(H, TRUE)
+ var/mob/living/carbon/human/person = new(spawn_loc)
+ player.transfer_to(person, TRUE)
- if(!leader && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job))
- leader = H
- to_chat(H, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!"))
- to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
- arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/leader, TRUE, TRUE)
- else if(medics < max_medics && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(H.client, JOB_SQUAD_MEDIC, time_required_for_job))
+ if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job))
+ leader = person
+ to_chat(person, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/leader, TRUE, TRUE)
+ else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job))
medics++
- to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!"))
- to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
- arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/medic, TRUE, TRUE)
- else if(heavies < max_heavies && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(H.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job))
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/medic, TRUE, TRUE)
+ else if(heavies < max_heavies && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(person.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job))
heavies++
- to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!"))
- to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
- arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout/terminator, TRUE, TRUE)
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/terminator, TRUE, TRUE)
else
- to_chat(H, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!"))
- to_chat(H, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
- arm_equipment(H, /datum/equipment_preset/pmc/w_y_whiteout, TRUE, TRUE)
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout, TRUE, TRUE)
- addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+
+/datum/emergency_call/death/low_threat
+ name = "Weyland Whiteout Operators"
+
+// DEATH SQUAD--------------------------------------------------------------------------------
+/datum/emergency_call/death/low_threat/create_member(datum/mind/player, turf/override_spawn_loc)
+ var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/person = new(spawn_loc)
+ player.transfer_to(person, TRUE)
+
+ if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job))
+ leader = person
+ to_chat(person, SPAN_ROLE_HEADER("You are the Whiteout Team Leader!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/leader, TRUE, TRUE)
+ else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job))
+ medics++
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Medic!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/medic, TRUE, TRUE)
+ else if(heavies < max_heavies && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(person.client, list(JOB_SQUAD_SPECIALIST, JOB_SQUAD_SMARTGUN), time_required_for_job))
+ heavies++
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Terminator!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat/terminator, TRUE, TRUE)
+ else
+ to_chat(person, SPAN_ROLE_HEADER("You are a Whiteout Team Operative!"))
+ to_chat(person, SPAN_ROLE_BODY("Whiteout protocol is in effect for the target, all assets onboard are to be liquidated with expediency unless otherwise instructed by Weyland Yutani personnel holding the position of Director or above."))
+ arm_equipment(person, /datum/equipment_preset/pmc/w_y_whiteout/low_threat, TRUE, TRUE)
+
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
//################################################################################################
// Marine commandos - USCM Deathsquad. Event only
/datum/emergency_call/marsoc
- name = "Marine Raider Strike Team"
+ name = "Marine Raider Strike Team (!DEATHSQUAD!)"
mob_max = 8
mob_min = 5
probability = 0
@@ -81,7 +116,7 @@
return
/datum/emergency_call/marsoc_covert
- name = "Marine Raider Operatives (Covert)"
+ name = "Marine Raider Operatives (!DEATHSQUAD! Covert)"
mob_max = 8
mob_min = 5
probability = 0
@@ -107,3 +142,27 @@
to_chat(H, SPAN_BOLDNOTICE("You are absolutely loyal to High Command and must follow their directives."))
to_chat(H, SPAN_BOLDNOTICE("Execute the mission assigned to you with extreme prejudice!"))
return
+
+
+/datum/emergency_call/marsoc/low_threat
+ name = "Marine Raider Operatives"
+
+/datum/emergency_call/marsoc/low_threat/create_member(datum/mind/MIND)
+
+ var/turf/spawn_loc = get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/player = new(spawn_loc)
+ MIND.transfer_to(player, TRUE)
+ if(!leader && HAS_FLAG(player.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(player.client, JOB_SQUAD_LEADER, time_required_for_job)) //First one spawned is always the leader.
+ leader = player
+ to_chat(player, SPAN_WARNING(FONT_SIZE_BIG("You are a Marine Raider Team Leader, better than all the rest.")))
+ arm_equipment(player, /datum/equipment_preset/uscm/marsoc/low_threat/sl, TRUE, TRUE)
+ else
+ to_chat(player, SPAN_WARNING(FONT_SIZE_BIG("You are an elite Marine Raider, the best of the best.")))
+ arm_equipment(player, /datum/equipment_preset/uscm/marsoc/low_threat, TRUE, TRUE)
+ to_chat(player, SPAN_BOLDNOTICE("You are absolutely loyal to High Command and must follow their directives."))
+ to_chat(player, SPAN_BOLDNOTICE("Execute the mission assigned to you with extreme prejudice!"))
+ return
diff --git a/code/datums/emergency_calls/emergency_call.dm b/code/datums/emergency_calls/emergency_call.dm
index 6533086d98f3..7884d93b18bc 100644
--- a/code/datums/emergency_calls/emergency_call.dm
+++ b/code/datums/emergency_calls/emergency_call.dm
@@ -30,7 +30,7 @@
var/arrival_message = "" //Msg to display about when the shuttle arrives
var/objectives //Txt of objectives to display to joined. Todo: make this into objective notes
var/objective_info //For additional info in the objectives txt
- var/probability = 0 //Chance of it occurring. Total must equal 100%
+ var/probability = 0
var/hostility //For ERTs who are either hostile or friendly by random chance.
var/list/datum/mind/members = list() //Currently-joined members.
var/list/datum/mind/candidates = list() //Potential candidates for enlisting.
@@ -91,12 +91,12 @@
else
return chosen_call
-/datum/game_mode/proc/get_specific_call(call_name, quiet_launch = FALSE, announce = TRUE, is_emergency = TRUE, info = "", announce_dispatch_message = TRUE)
+/datum/game_mode/proc/get_specific_call(call_name, quiet_launch = FALSE, announce_incoming = TRUE, info = "")
for(var/datum/emergency_call/E in all_calls) //Loop through all potential candidates
if(E.name == call_name)
var/datum/emergency_call/em_call = new E.type()
em_call.objective_info = info
- em_call.activate(quiet_launch, announce, is_emergency, announce_dispatch_message)
+ em_call.activate(quiet_launch, announce_incoming)
return
error("get_specific_call could not find emergency call '[call_name]'")
return
@@ -168,7 +168,7 @@
return
var/deathtime = world.time - usr.timeofdeath
- if(deathtime < 1 MINUTES) //Nice try, ghosting right after the announcement
+ if(deathtime < 30 SECONDS) //Nice try, ghosting right after the announcement
if(SSmapping.configs[GROUND_MAP].map_name != MAP_WHISKEY_OUTPOST) // people ghost so often on whiskey outpost.
to_chat(src, SPAN_WARNING("You ghosted too recently."))
return
@@ -192,7 +192,7 @@
else
to_chat(src, SPAN_WARNING("You did not get enlisted in the response team. Better luck next time!"))
-/datum/emergency_call/proc/activate(quiet_launch = FALSE, announce = TRUE, turf/override_spawn_loc, announce_dispatch_message = TRUE)
+/datum/emergency_call/proc/activate(quiet_launch = FALSE, announce_incoming = TRUE, turf/override_spawn_loc)
set waitfor = 0
if(!SSticker.mode) //Something horribly wrong with the gamemode ticker
return
@@ -200,14 +200,14 @@
SSticker.mode.picked_calls += src
show_join_message() //Show our potential candidates the message to let them join.
- message_admins("Distress beacon: '[name]' activated [src.hostility? "[SPAN_WARNING("(THEY ARE HOSTILE)")]":"(they are friendly)"]. Looking for candidates.")
+ message_admins("Distress beacon: '[name]' activated [hostility? "[SPAN_WARNING("(THEY ARE HOSTILE)")]":"(they are friendly)"]. Looking for candidates.")
if(!quiet_launch)
marine_announcement("A distress beacon has been launched from the [MAIN_SHIP_NAME].", "Priority Alert", 'sound/AI/distressbeacon.ogg', logging = ARES_LOG_SECURITY)
- addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/emergency_call, spawn_candidates), quiet_launch, announce, override_spawn_loc, announce_dispatch_message), 30 SECONDS)
+ addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/emergency_call, spawn_candidates), quiet_launch, announce_incoming, override_spawn_loc), 30 SECONDS)
-/datum/emergency_call/proc/spawn_candidates(quiet_launch = FALSE, announce = TRUE, override_spawn_loc, announce_dispatch_message = TRUE)
+/datum/emergency_call/proc/spawn_candidates(quiet_launch = FALSE, announce_incoming = TRUE, override_spawn_loc)
if(SSticker.mode)
SSticker.mode.picked_calls -= src
@@ -248,7 +248,7 @@
if(I.current)
to_chat(I.current, SPAN_WARNING("You didn't get selected to join the distress team. Better luck next time!"))
- if(announce)
+ if(announce_incoming)
marine_announcement(dispatch_message, "Distress Beacon", 'sound/AI/distressreceived.ogg', logging = ARES_LOG_SECURITY) //Announcement that the Distress Beacon has been answered, does not hint towards the chosen ERT
message_admins("Distress beacon: [src.name] finalized, setting up candidates.")
@@ -304,8 +304,8 @@
create_member(null, override_spawn_loc)
candidates = list()
- if(arrival_message && announce)
- marine_announcement(arrival_message, "Intercepted Tranmission:")
+ if(arrival_message && announce_incoming)
+ marine_announcement(arrival_message, "Intercepted Transmission:")
/datum/emergency_call/proc/add_candidate(mob/M)
if(!M.client || (M.mind && (M.mind in candidates)) || istype(M, /mob/living/carbon/xenomorph))
diff --git a/code/datums/emergency_calls/inspection.dm b/code/datums/emergency_calls/inspection.dm
index 4c33d7d9bfa3..2cd121093ea4 100644
--- a/code/datums/emergency_calls/inspection.dm
+++ b/code/datums/emergency_calls/inspection.dm
@@ -183,7 +183,7 @@
/datum/emergency_call/inspection_cmb/New()
..()
- arrival_message = "[MAIN_SHIP_NAME], This is Anchorpoint Station with the Colonial Marshal Bureau. Be advised, a CMB transport vessel is preparing to board you, submitting Federal docking clearances now. Standby."
+ arrival_message = "[MAIN_SHIP_NAME], this is Anchorpoint Station with the Colonial Marshal Bureau. Be advised, a CMB transport vessel is preparing to board you, submitting Federal docking clearances now. Standby."
objectives = "Get your instructions from the CMB Office at Anchorpoint Station, and carry out your orders. Ensure that Colonial assets are safe and in your custody. Do not enforce or override Marine Law on a Marine Ship unless requested, as it's outside of your juristiction."
will_spawn_icc_liaison = prob(90)
@@ -202,7 +202,7 @@
leader = mob
to_chat(mob, SPAN_ROLE_HEADER("You are the Colonial Marshal!"))
arm_equipment(mob, /datum/equipment_preset/cmb/leader, TRUE, TRUE)
- else if(synths < max_synths && HAS_FLAG(mob?.client.prefs.toggles_ert, PLAY_SYNTH) && RoleAuthority.roles_whitelist[mob.ckey] & WHITELIST_SYNTHETIC)
+ else if(synths < max_synths && HAS_FLAG(mob?.client.prefs.toggles_ert, PLAY_SYNTH) && GLOB.RoleAuthority.roles_whitelist[mob.ckey] & WHITELIST_SYNTHETIC)
synths++
to_chat(mob, SPAN_ROLE_HEADER("You are a CMB Investigative Synthetic!"))
arm_equipment(mob, /datum/equipment_preset/cmb/synth, TRUE, TRUE)
@@ -265,7 +265,7 @@
to_chat(M, SPAN_BOLD("Despite being stretched thin, the stalwart oath of the Marshals has continued to keep communities safe, with the CMB well respected by many. You are a representation of that oath, serve with distinction."))
/datum/emergency_call/inspection_cmb/black_market
- name = "Inspection - Colonial Marshal Ledger Investigation Team"
+ name = "Inspection - Colonial Marshals Ledger Investigation Team"
mob_max = 3 //Marshal, Deputy, ICC CL
mob_min = 2
shuttle_id = "Distress_PMC"
diff --git a/code/datums/emergency_calls/mercs.dm b/code/datums/emergency_calls/mercs.dm
index 40210c845c6f..67e09e8992f0 100644
--- a/code/datums/emergency_calls/mercs.dm
+++ b/code/datums/emergency_calls/mercs.dm
@@ -11,7 +11,7 @@
/datum/emergency_call/mercs/New()
. = ..()
hostility = pick(75;FALSE,25;TRUE)
- arrival_message = "[MAIN_SHIP_NAME], this is Freelancer shuttle [pick(alphabet_lowercase)][pick(alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
+ arrival_message = "[MAIN_SHIP_NAME], this is Freelancer shuttle [pick(GLOB.alphabet_lowercase)][pick(GLOB.alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
if(hostility)
objectives = "Ransack the [MAIN_SHIP_NAME] and kill anyone who gets in your way. Do what your Captain says. Ensure your survival at all costs."
else
@@ -25,7 +25,7 @@
/datum/emergency_call/mercs/friendly/New()
. = ..()
hostility = FALSE
- arrival_message = "[MAIN_SHIP_NAME], this is Freelancer shuttle [pick(alphabet_lowercase)][pick(alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
+ arrival_message = "[MAIN_SHIP_NAME], this is Freelancer shuttle [pick(GLOB.alphabet_lowercase)][pick(GLOB.alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
objectives = "Help the crew of the [MAIN_SHIP_NAME] in exchange for payment, and choose your payment well. Do what your Captain says. Ensure your survival at all costs."
/datum/emergency_call/mercs/hostile //ditto
@@ -36,7 +36,7 @@
/datum/emergency_call/mercs/hostile/New()
. = ..()
hostility = TRUE
- arrival_message = "[MAIN_SHIP_NAME], this is Freelancer shuttle [pick(alphabet_lowercase)][pick(alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
+ arrival_message = "[MAIN_SHIP_NAME], this is Freelancer shuttle [pick(GLOB.alphabet_lowercase)][pick(GLOB.alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
objectives = "Ransack the [MAIN_SHIP_NAME] and kill anyone who gets in your way. Do what your Captain says. Ensure your survival at all costs."
/datum/emergency_call/mercs/print_backstory(mob/living/carbon/human/H)
@@ -96,7 +96,7 @@
/datum/emergency_call/heavy_mercs/New()
. = ..()
hostility = pick(75;FALSE,25;TRUE)
- arrival_message = "[MAIN_SHIP_NAME], this is Elite Freelancer shuttle [pick(alphabet_lowercase)][pick(alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
+ arrival_message = "[MAIN_SHIP_NAME], this is Elite Freelancer shuttle [pick(GLOB.alphabet_lowercase)][pick(GLOB.alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
if(hostility)
objectives = "Ransack the [MAIN_SHIP_NAME] and kill anyone who gets in your way. Do what your Captain says. Ensure your survival at all costs."
else
@@ -108,7 +108,7 @@
/datum/emergency_call/heavy_mercs/hostile/New()
. = ..()
hostility = TRUE
- arrival_message = "[MAIN_SHIP_NAME], this is Elite Freelancer shuttle [pick(alphabet_lowercase)][pick(alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
+ arrival_message = "[MAIN_SHIP_NAME], this is Elite Freelancer shuttle [pick(GLOB.alphabet_lowercase)][pick(GLOB.alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
objectives = "Ransack the [MAIN_SHIP_NAME] and kill anyone who gets in your way. Do what your Captain says. Ensure your survival at all costs."
/datum/emergency_call/heavy_mercs/friendly
@@ -117,7 +117,7 @@
/datum/emergency_call/heavy_mercs/friendly/New()
. = ..()
hostility = FALSE
- arrival_message = "[MAIN_SHIP_NAME], this is Elite Freelancer shuttle [pick(alphabet_lowercase)][pick(alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
+ arrival_message = "[MAIN_SHIP_NAME], this is Elite Freelancer shuttle [pick(GLOB.alphabet_lowercase)][pick(GLOB.alphabet_lowercase)]-[rand(1, 99)] responding to your distress call. Prepare for boarding."
objectives = "Help the crew of the [MAIN_SHIP_NAME] in exchange for payment, and choose your payment well. Do what your Captain says. Ensure your survival at all costs."
/datum/emergency_call/heavy_mercs/print_backstory(mob/living/carbon/human/H)
diff --git a/code/datums/emergency_calls/pmc.dm b/code/datums/emergency_calls/pmc.dm
index a06b0cc0c02e..2d21dc768f4a 100644
--- a/code/datums/emergency_calls/pmc.dm
+++ b/code/datums/emergency_calls/pmc.dm
@@ -34,7 +34,7 @@
leader = mob
to_chat(mob, SPAN_ROLE_HEADER("You are a Weyland-Yutani PMC Squad Leader!"))
arm_equipment(mob, /datum/equipment_preset/pmc/pmc_leader, TRUE, TRUE)
- else if(synths < max_synths && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_SYNTH) && RoleAuthority.roles_whitelist[mob.ckey] & WHITELIST_SYNTHETIC)
+ else if(synths < max_synths && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_SYNTH) && GLOB.RoleAuthority.roles_whitelist[mob.ckey] & WHITELIST_SYNTHETIC)
synths++
to_chat(mob, SPAN_ROLE_HEADER("You are a Weyland-Yutani PMC Support Synthetic!"))
arm_equipment(mob, /datum/equipment_preset/pmc/synth, TRUE, TRUE)
@@ -120,7 +120,7 @@
var/mob/living/carbon/human/H = new(spawn_loc)
H.key = M.key
if(H.client)
- H.client.change_view(world_view_size)
+ H.client.change_view(GLOB.world_view_size)
if(!leader && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(H.client, JOB_SQUAD_LEADER, time_required_for_job)) //First one spawned is always the leader.
leader = H
diff --git a/code/datums/emergency_calls/royal_marines.dm b/code/datums/emergency_calls/royal_marines.dm
index b3feaccf87bb..21f79e7c3026 100644
--- a/code/datums/emergency_calls/royal_marines.dm
+++ b/code/datums/emergency_calls/royal_marines.dm
@@ -1,7 +1,7 @@
/datum/emergency_call/royal_marines
name = "Royal Marines Commando (Squad) (Friendly)"
mob_max = 7
- probability = 0
+ probability = 15
name_of_spawn = /obj/effect/landmark/ert_spawns/distress_twe
item_spawn = /obj/effect/landmark/ert_spawns/distress_twe/item
max_engineers = 0
diff --git a/code/datums/emergency_calls/tank_crew.dm b/code/datums/emergency_calls/tank_crew.dm
index fb437c179e48..f8d20051c244 100644
--- a/code/datums/emergency_calls/tank_crew.dm
+++ b/code/datums/emergency_calls/tank_crew.dm
@@ -24,11 +24,10 @@
sleep(5)
arm_equipment(H, /datum/equipment_preset/uscm/tank/full, TRUE, TRUE)
to_chat(H, SPAN_ROLE_HEADER("You are a Vehicle Crewman in the USCM"))
- to_chat(H, SPAN_ROLE_BODY("You are here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
+ to_chat(H, SPAN_ROLE_BODY("You are here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]. Listen to the chain of command."))
to_chat(H, SPAN_BOLDWARNING("If you wish to cryo or ghost upon spawning in, you must ahelp and inform staff so you can be replaced."))
sleep(10)
to_chat(H, SPAN_BOLD("Objectives: [objectives]"))
GLOB.data_core.manifest_inject(H) //Put people in crew manifest
-
diff --git a/code/datums/emergency_calls/upp.dm b/code/datums/emergency_calls/upp.dm
index 04bcfecf9128..80ef111be3e4 100644
--- a/code/datums/emergency_calls/upp.dm
+++ b/code/datums/emergency_calls/upp.dm
@@ -4,7 +4,7 @@
/datum/emergency_call/upp
name = "UPP Naval Infantry (Squad)"
mob_max = 9
- probability = 10
+ probability = 20
shuttle_id = "Distress_UPP"
name_of_spawn = /obj/effect/landmark/ert_spawns/distress_upp
item_spawn = /obj/effect/landmark/ert_spawns/distress_upp/item
@@ -14,15 +14,17 @@
max_heavies = 1
max_smartgunners = 0
var/heavy_pick = TRUE // whether heavy should count as either a minigunner or shotgunner
- hostility = TRUE
var/max_synths = 1
var/synths = 0
/datum/emergency_call/upp/New()
- ..()
- arrival_message = "T*is i* UP* d^sp^*ch`. STr*&e teaM, #*u are cLe*% for a*pr*%^h. Pr*mE a*l wE*p^ns )0r c|*$e @u*r*r$ c0m&*t."
- objectives = "Eliminate the UA Forces to ensure the UPP prescence in this sector is continued. Listen to your superior officers and take over the [MAIN_SHIP_NAME] at all costs."
-
+ . = ..()
+ hostility = pick(50;FALSE,50;TRUE)
+ arrival_message = "[MAIN_SHIP_NAME] t*is i* UP* d^sp^*ch`. STr*&e teaM, #*u are cLe*% for a*pr*%^h. Pr*mE a*l wE*p^ns and pR*epr# t% r@nd$r a(tD."
+ if(hostility)
+ objectives = "Eliminate the UA Forces to ensure the UPP prescence in this sector is continued. Listen to your superior officers and take over the [MAIN_SHIP_NAME] at all costs."
+ else
+ objectives = "Render assistance towards the UA Forces, do not engage UA forces. Listen to your superior officers."
/datum/emergency_call/upp/print_backstory(mob/living/carbon/human/M)
if(ishuman_strict(M))
@@ -59,7 +61,7 @@
leader = H
arm_equipment(H, /datum/equipment_preset/upp/leader, TRUE, TRUE)
to_chat(H, SPAN_ROLE_HEADER("You are an Officer of the Union of Progressive People, a powerful socialist state that rivals the United Americas!"))
- else if(synths < max_synths && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SYNTH) && RoleAuthority.roles_whitelist[H.ckey] & WHITELIST_SYNTHETIC)
+ else if(synths < max_synths && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SYNTH) && GLOB.RoleAuthority.roles_whitelist[H.ckey] & WHITELIST_SYNTHETIC)
synths++
to_chat(H, SPAN_ROLE_HEADER("You are a Combat Synthetic of the Union of Progressive People, a powerful socialist state that rivals the United Americas!"))
arm_equipment(H, /datum/equipment_preset/upp/synth, TRUE, TRUE)
@@ -94,10 +96,26 @@
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+/datum/emergency_call/upp/hostile
+ name = "UPP Naval Infantry (Squad) (Hostile)"
+ hostility = TRUE
+
+/datum/emergency_call/upp/hostile/New()
+ ..()
+ arrival_message = "[MAIN_SHIP_NAME] t*is i* UP* d^sp^*ch`. STr*&e teaM, #*u are cLe*% for a*pr*%^h. Pr*mE a*l wE*p^ns and pR*epr# t% r@nd$r a(tD."
+ objectives = "Eliminate the UA Forces to ensure the UPP presence in this sector is continued. Listen to your superior officers and take over the [MAIN_SHIP_NAME] at all costs."
+
+/datum/emergency_call/upp/friendly
+ name = "UPP Naval Infantry (Squad) (Friendly)"
+ hostility = FALSE
+
+/datum/emergency_call/upp/friendly/New()
+ ..()
+ arrival_message = "This is UPP dispatch. USS Almayer, We are responding to your distress call, we will render aid as able, do not fire."
+ objectives = "Render assistance towards the UA Forces, Listen to your superior officers."
/datum/emergency_call/upp/platoon
- name = "UPP Naval Infantry (Platoon)"
- mob_min = 4
+ name = "UPP Naval Infantry (Platoon) (Hostile)"
mob_max = 30
probability = 0
max_medics = 3
@@ -106,6 +124,21 @@
max_engineers = 2
max_synths = 1
heavy_pick = FALSE
+ hostility = TRUE
+
+/datum/emergency_call/upp/platoon/New()
+ ..()
+ arrival_message = "[MAIN_SHIP_NAME] t*is i* UP* d^sp^*ch`. STr*&e teaM, #*u are cLe*% for a*pr*%^h. Pr*mE a*l wE*p^ns and pR*epr# t% r@nd$r a(tD."
+ objectives = "Eliminate the UA Forces to ensure the UPP presence in this sector is continued. Listen to your superior officers and take over the [MAIN_SHIP_NAME] at all costs."
+
+/datum/emergency_call/upp/platoon/friendly
+ name = "UPP Naval Infantry (Platoon) (Friendly)"
+ hostility = FALSE
+
+/datum/emergency_call/upp/platoon/friendly/New()
+ ..()
+ arrival_message = "This is UPP dispatch. USS Almayer, We are responding to your distress call, we will render aid as able, do not fire."
+ objectives = "Render assistance towards the UA Forces, Listen to your superior officers."
/obj/effect/landmark/ert_spawns/distress_upp
name = "Distress_UPP"
diff --git a/code/datums/emergency_calls/upp_commando.dm b/code/datums/emergency_calls/upp_commando.dm
index 14c4af46c27b..1bc2b59ba08c 100644
--- a/code/datums/emergency_calls/upp_commando.dm
+++ b/code/datums/emergency_calls/upp_commando.dm
@@ -1,7 +1,7 @@
//UPP COMMANDOS
/datum/emergency_call/upp_commando
- name = "UPP Commandos"
+ name = "UPP Commandos (!DEATHSQUAD!)"
mob_max = 6
probability = 0
objectives = "Stealthily assault the ship. Use your silenced weapons, tranquilizers, and night vision to get the advantage on the enemy. Take out the power systems, comms and engine. Stick together and keep a low profile."
@@ -51,3 +51,29 @@
addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), H, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
+/datum/emergency_call/upp_commando/low_threat
+ name = "UPP Commandos"
+
+/datum/emergency_call/upp_commando/create_member(datum/mind/mind, turf/override_spawn_loc)
+ var/turf/spawn_loc = override_spawn_loc ? override_spawn_loc : get_spawn_point()
+
+ if(!istype(spawn_loc))
+ return //Didn't find a useable spawn point.
+
+ var/mob/living/carbon/human/person = new(spawn_loc)
+ mind.transfer_to(person, TRUE)
+
+ if(!leader && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(person.client, JOB_SQUAD_LEADER, time_required_for_job)) //First one spawned is always the leader.
+ leader = person
+ arm_equipment(person, /datum/equipment_preset/upp/commando/leader/low_threat, TRUE, TRUE)
+ to_chat(person, SPAN_ROLE_HEADER("You are a Commando Team Leader of the Union of Progressive People, a powerful socialist state that rivals the United Americas!"))
+ else if(medics < max_medics && HAS_FLAG(person.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(person.client, JOB_SQUAD_MEDIC, time_required_for_job))
+ medics++
+ to_chat(person, SPAN_ROLE_HEADER("You are a Commando Medic of the Union of Progressive People, a powerful socialist state that rivals the United Americas!"))
+ arm_equipment(person, /datum/equipment_preset/upp/commando/medic/low_threat, TRUE, TRUE)
+ else
+ to_chat(person, SPAN_ROLE_HEADER("You are a Commando of the Union of Progressive People, a powerful socialist state that rivals the United Americas!"))
+ arm_equipment(person, /datum/equipment_preset/upp/commando/low_threat, TRUE, TRUE)
+ print_backstory(person)
+
+ addtimer(CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(to_chat), person, SPAN_BOLD("Objectives: [objectives]")), 1 SECONDS)
diff --git a/code/datums/emergency_calls/whiskey_outpost.dm b/code/datums/emergency_calls/whiskey_outpost.dm
index 8a20043da558..c6a7e4947756 100644
--- a/code/datums/emergency_calls/whiskey_outpost.dm
+++ b/code/datums/emergency_calls/whiskey_outpost.dm
@@ -28,30 +28,30 @@
if(!leader && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_LEADER) && check_timelock(mob.client, JOB_SQUAD_LEADER, time_required_for_job))
leader = mob
arm_equipment(mob, /datum/equipment_preset/dust_raider/leader, TRUE, TRUE)
- to_chat(mob, SPAN_BOLDNOTICE("You are a Squad Leader in the USCM, your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(mob, SPAN_BOLDNOTICE("You are a Squad Leader in the USCM, your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else if (heavies < max_heavies && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_HEAVY) && check_timelock(mob.client, JOB_SQUAD_SPECIALIST, time_required_for_job))
heavies++
arm_equipment(mob, /datum/equipment_preset/dust_raider/specialist, TRUE, TRUE)
- to_chat(mob, SPAN_BOLDNOTICE("You are a Specialist in the USCM, your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(mob, SPAN_BOLDNOTICE("You are a Specialist in the USCM, your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else if(smartgunners < max_smartgunners && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_SMARTGUNNER) && check_timelock(mob.client, JOB_SQUAD_SMARTGUN, time_required_for_job))
smartgunners++
arm_equipment(mob, /datum/equipment_preset/dust_raider/smartgunner, TRUE, TRUE)
- to_chat(mob, SPAN_BOLDNOTICE("You are a Smartgunner in the USCM, your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(mob, SPAN_BOLDNOTICE("You are a Smartgunner in the USCM, your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else if(engineers < max_engineers && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_ENGINEER) && check_timelock(mob.client, JOB_SQUAD_ENGI, time_required_for_job))
engineers++
arm_equipment(mob, /datum/equipment_preset/dust_raider/engineer, TRUE, TRUE)
- to_chat(mob, SPAN_BOLDNOTICE("You are an Engineer in the USCM, your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(mob, SPAN_BOLDNOTICE("You are an Engineer in the USCM, your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else if (medics < max_medics && HAS_FLAG(mob.client.prefs.toggles_ert, PLAY_MEDIC) && check_timelock(mob.client, JOB_SQUAD_MEDIC, time_required_for_job))
medics++
arm_equipment(mob, /datum/equipment_preset/dust_raider/medic, TRUE, TRUE)
- to_chat(mob, SPAN_BOLDNOTICE("You are a Hospital Corpsman in the USCM, your squad is here to assist in the defence of the [SSmapping.configs[GROUND_MAP].map_name]."))
+ to_chat(mob, SPAN_BOLDNOTICE("You are a Hospital Corpsman in the USCM, your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
else
arm_equipment(mob, /datum/equipment_preset/dust_raider/private, TRUE, TRUE)
to_chat(mob, SPAN_BOLDNOTICE("You are a Rifleman in the USCM, your squad is here to assist in the defence of [SSmapping.configs[GROUND_MAP].map_name]."))
sleep(10)
to_chat(mob, "Objectives: [objectives]")
- RoleAuthority.randomize_squad(mob)
+ GLOB.RoleAuthority.randomize_squad(mob)
mob.sec_hud_set_ID()
mob.hud_set_squad()
@@ -60,7 +60,7 @@
/datum/game_mode/whiskey_outpost/activate_distress()
var/datum/emergency_call/em_call = /datum/emergency_call/wo
- em_call.activate(FALSE)
+ em_call.activate(TRUE, FALSE)
return
/datum/emergency_call/wo/platoon
diff --git a/code/datums/emergency_calls/xeno_cultists.dm b/code/datums/emergency_calls/xeno_cultists.dm
index e5ebf089a9c2..5da5c9c17e59 100644
--- a/code/datums/emergency_calls/xeno_cultists.dm
+++ b/code/datums/emergency_calls/xeno_cultists.dm
@@ -25,7 +25,7 @@
leader = H
to_chat(H, SPAN_ROLE_HEADER("You are the leader of this xeno cult! Bring glory to Queen Mother!"))
arm_equipment(H, /datum/equipment_preset/other/xeno_cultist/leader, TRUE, TRUE)
- else if(synths < max_synths && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SYNTH) && RoleAuthority.roles_whitelist[H.ckey] & WHITELIST_SYNTHETIC)
+ else if(synths < max_synths && HAS_FLAG(H.client.prefs.toggles_ert, PLAY_SYNTH) && GLOB.RoleAuthority.roles_whitelist[H.ckey] & WHITELIST_SYNTHETIC)
synths++
to_chat(H, SPAN_ROLE_HEADER("You are the xeno cult's synthetic! Tend to the Hive and the captured hosts, make sure the Hive grows!"))
arm_equipment(H, /datum/equipment_preset/synth/survivor/cultist_synth, TRUE, TRUE)
diff --git a/code/datums/entities/clans.dm b/code/datums/entities/clans.dm
index 8caa538e0e31..916afd18c178 100644
--- a/code/datums/entities/clans.dm
+++ b/code/datums/entities/clans.dm
@@ -45,8 +45,8 @@ BSQL_PROTECT_DATUM(/datum/entity/clan)
/datum/entity_meta/clan_player/on_insert(datum/entity/clan_player/player)
player.honor = 0
- player.clan_rank = clan_ranks_ordered[CLAN_RANK_UNBLOODED]
- player.permissions = clan_ranks[CLAN_RANK_UNBLOODED].permissions
+ player.clan_rank = GLOB.clan_ranks_ordered[CLAN_RANK_UNBLOODED]
+ player.permissions = GLOB.clan_ranks[CLAN_RANK_UNBLOODED].permissions
player.save()
diff --git a/code/datums/entities/player.dm b/code/datums/entities/player.dm
index febeb1fc73a9..e5fa811002a2 100644
--- a/code/datums/entities/player.dm
+++ b/code/datums/entities/player.dm
@@ -93,7 +93,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player)
notes_add(ckey, note_text, admin.mob)
else
// notes_add already sends a message
- message_admins("[key_name_admin(admin.mob)] has edited [ckey]'s [note_categories[note_category]] notes: [sanitize(note_text)]")
+ message_admins("[key_name_admin(admin.mob)] has edited [ckey]'s [GLOB.note_categories[note_category]] notes: [sanitize(note_text)]")
if(!is_confidential && note_category == NOTE_ADMIN && owning_client)
to_chat_immediate(owning_client, SPAN_WARNING(FONT_SIZE_LARGE("You have been noted by [key_name_admin(admin.mob, FALSE)].")))
to_chat_immediate(owning_client, SPAN_WARNING(FONT_SIZE_BIG("The note is : [sanitize(note_text)]")))
@@ -235,7 +235,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player)
if(job_bans[safe_rank])
continue
var/old_rank = check_jobban_path(safe_rank)
- jobban_keylist[old_rank][ckey] = ban_text
+ GLOB.jobban_keylist[old_rank][ckey] = ban_text
jobban_savebanfile()
add_note("Banned from [total_rank] - [ban_text]", FALSE, NOTE_ADMIN, TRUE, duration) // it is ban related note
@@ -570,33 +570,33 @@ BSQL_PROTECT_DATUM(/datum/entity/player)
save()
/datum/entity/player/proc/migrate_bans()
- if(!Banlist) // if Banlist cannot be located for some reason
+ if(!GLOB.Banlist) // if GLOB.Banlist cannot be located for some reason
LoadBans() // try to load the bans
- if(!Banlist) // uh oh, can't find bans!
+ if(!GLOB.Banlist) // uh oh, can't find bans!
return
var/reason
var/expiration
var/banned_by
- Banlist.cd = "/base"
+ GLOB.Banlist.cd = "/base"
- for (var/A in Banlist.dir)
- Banlist.cd = "/base/[A]"
+ for (var/A in GLOB.Banlist.dir)
+ GLOB.Banlist.cd = "/base/[A]"
- if(ckey != Banlist["key"])
+ if(ckey != GLOB.Banlist["key"])
continue
- if(Banlist["temp"])
- if (!GetExp(Banlist["minutes"]))
+ if(GLOB.Banlist["temp"])
+ if (!GetExp(GLOB.Banlist["minutes"]))
return
- if(expiration > Banlist["minutes"])
+ if(expiration > GLOB.Banlist["minutes"])
return // found longer ban
- reason = Banlist["reason"]
- banned_by = Banlist["bannedby"]
- expiration = Banlist["minutes"]
+ reason = GLOB.Banlist["reason"]
+ banned_by = GLOB.Banlist["bannedby"]
+ expiration = GLOB.Banlist["minutes"]
migrated_bans = TRUE
save()
@@ -619,13 +619,13 @@ BSQL_PROTECT_DATUM(/datum/entity/player)
/datum/entity/player/proc/migrate_jobbans()
if(!job_bans)
job_bans = list()
- for(var/name in RoleAuthority.roles_for_mode)
+ for(var/name in GLOB.RoleAuthority.roles_for_mode)
var/safe_job_name = ckey(name)
- if(!jobban_keylist[safe_job_name])
+ if(!GLOB.jobban_keylist[safe_job_name])
continue
if(!safe_job_name)
continue
- var/reason = jobban_keylist[safe_job_name][ckey]
+ var/reason = GLOB.jobban_keylist[safe_job_name][ckey]
if(!reason)
continue
diff --git a/code/datums/entities/player_times.dm b/code/datums/entities/player_times.dm
index a6304bd5d874..2bbd4a3bc39e 100644
--- a/code/datums/entities/player_times.dm
+++ b/code/datums/entities/player_times.dm
@@ -84,7 +84,7 @@ BSQL_PROTECT_DATUM(/datum/entity/player_time)
return GLOB.always_state
/datum/entity/player/proc/load_timestat_data()
- if(!playtime_loaded || !RoleAuthority || LAZYACCESS(playtime_data, "loading")) // Need roleauthority to be up to see which job is xeno-related
+ if(!playtime_loaded || !GLOB.RoleAuthority || LAZYACCESS(playtime_data, "loading")) // Need roleauthority to be up to see which job is xeno-related
return
LAZYSET(playtime_data, "loading", TRUE)
@@ -118,13 +118,13 @@ BSQL_PROTECT_DATUM(/datum/entity/player_time)
LAZYADD(marine_playtimes, list(marine_playtime))
for(var/datum/view_record/playtime/PT in PTs)
- var/isxeno = (PT.role_id in RoleAuthority.castes_by_name)
+ var/isxeno = (PT.role_id in GLOB.RoleAuthority.castes_by_name)
var/isOther = (PT.role_id == JOB_OBSERVER) // more maybe eventually
if(PT.role_id == JOB_XENOMORPH)
continue // Snowflake check, will need to be removed in the future
- if(!(PT.role_id in RoleAuthority.roles_by_name) && !isxeno && !isOther)
+ if(!(PT.role_id in GLOB.RoleAuthority.roles_by_name) && !isxeno && !isOther)
continue
if(isxeno)
diff --git a/code/datums/factions/upp.dm b/code/datums/factions/upp.dm
index 5a790c89be67..90b04765cf85 100644
--- a/code/datums/factions/upp.dm
+++ b/code/datums/factions/upp.dm
@@ -41,6 +41,8 @@
hud_icon_state = "co"
if(JOB_UPP_COMBAT_SYNTH)
hud_icon_state = "synth"
+ if(JOB_UPP_SUPPORT_SYNTH)
+ hud_icon_state = "synth"
if(JOB_UPP_COMMANDO)
hud_icon_state = "com"
if(JOB_UPP_COMMANDO_MEDIC)
diff --git a/code/datums/factions/uscm.dm b/code/datums/factions/uscm.dm
index cf77142ce5d6..0a9b0cff40b9 100644
--- a/code/datums/factions/uscm.dm
+++ b/code/datums/factions/uscm.dm
@@ -189,6 +189,19 @@
if(JOB_CMB_OBS)
marine_rk = "obs"
icon_prefix = "cmb_"
+ // Check squad marines here too, for the unique ones
+ if(JOB_SQUAD_ENGI)
+ marine_rk = "engi"
+ if(JOB_SQUAD_MEDIC)
+ marine_rk = "med"
+ if(JOB_SQUAD_SPECIALIST)
+ marine_rk = "spec"
+ if(JOB_SQUAD_SMARTGUN)
+ marine_rk = "gun"
+ if(JOB_SQUAD_TEAM_LEADER)
+ marine_rk = "tl"
+ if(JOB_SQUAD_LEADER)
+ marine_rk = "leader"
if(marine_rk)
var/image/I = image('icons/mob/hud/marine_hud.dmi', current_human, "hudsquad")
diff --git a/code/datums/helper_datums/getrev.dm b/code/datums/helper_datums/getrev.dm
index a2932532e78e..b7d528380a42 100644
--- a/code/datums/helper_datums/getrev.dm
+++ b/code/datums/helper_datums/getrev.dm
@@ -48,6 +48,8 @@ GLOBAL_DATUM_INIT(revdata, /datum/getrev, new)
var/datum/tgs_revision_information/test_merge/tm = line
var/cm = tm.head_commit
var/details = ": '" + html_encode(tm.title) + "' by " + html_encode(tm.author) + " at commit " + html_encode(copytext_char(cm, 1, 11))
+ if(details && findtext(details, "\[s\]") && (!usr || !usr.client.admin_holder))
+ continue
. += "#[tm.number][details] "
/client/verb/showrevinfo()
diff --git a/code/datums/helper_datums/teleport.dm b/code/datums/helper_datums/teleport.dm
index 16825ab8a7ba..6a4276208d13 100644
--- a/code/datums/helper_datums/teleport.dm
+++ b/code/datums/helper_datums/teleport.dm
@@ -166,18 +166,18 @@
/datum/teleport/instant/science/teleportChecks()
if(istype(teleatom, /obj/item/disk/nuclear)) // Don't let nuke disks get teleported --NeoFite
- teleatom.visible_message(SPAN_DANGER("The [teleatom] bounces off of the portal!"))
+ teleatom.visible_message(SPAN_DANGER("[teleatom] bounces off of the portal!"))
return 0
if(length(teleatom.search_contents_for(/obj/item/disk/nuclear)))
if(istype(teleatom, /mob/living))
var/mob/living/MM = teleatom
- MM.visible_message(SPAN_DANGER("The [MM] bounces off of the portal!"),SPAN_DANGER("Something you are carrying seems to be unable to pass through the portal. Better drop it if you want to go through."))
+ MM.visible_message(SPAN_DANGER("[MM] bounces off of the portal!"),SPAN_DANGER("Something you are carrying seems to be unable to pass through the portal. Better drop it if you want to go through."))
else
- teleatom.visible_message(SPAN_DANGER("The [teleatom] bounces off of the portal!"))
+ teleatom.visible_message(SPAN_DANGER("[teleatom] bounces off of the portal!"))
return 0
- if(is_admin_level(destination.z))
+ if(should_block_game_interaction(destination))
if(length(teleatom.search_contents_for(/obj/item/storage/backpack/holding)))
teleatom.visible_message(SPAN_DANGER("The Bag of Holding bounces off of the portal!"))
return 0
diff --git a/code/datums/keybinding/client.dm b/code/datums/keybinding/client.dm
index a5baf09a1360..752287882277 100644
--- a/code/datums/keybinding/client.dm
+++ b/code/datums/keybinding/client.dm
@@ -4,8 +4,8 @@
/datum/keybinding/client/admin_help
- hotkey_keys = list("F1")
- classic_keys = list("F1")
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
name = "admin_help"
full_name = "Admin Help"
description = "Ask an admin for help."
diff --git a/code/datums/keybinding/communication.dm b/code/datums/keybinding/communication.dm
index 4164198d4818..e1ba0ab5a31e 100644
--- a/code/datums/keybinding/communication.dm
+++ b/code/datums/keybinding/communication.dm
@@ -32,7 +32,7 @@
/datum/keybinding/client/communication/whisper
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
- name = "Whisper"
+ name = WHISPER_CHANNEL
full_name = "IC Whisper"
keybind_signal = COMSIG_KB_CLIENT_WHISPER_DOWN
@@ -56,4 +56,4 @@
name = MENTOR_CHANNEL
full_name = "Mentor Say"
description = "Talk with other mentors."
- keybind_signal = COMSIG_KB_ADMIN_ASAY_DOWN
+ keybind_signal = COMSIG_KB_ADMIN_MENTORSAY_DOWN
diff --git a/code/datums/keybinding/human.dm b/code/datums/keybinding/human.dm
index 6580c38083ea..6d7037eac398 100644
--- a/code/datums/keybinding/human.dm
+++ b/code/datums/keybinding/human.dm
@@ -1,8 +1,3 @@
-#define QUICK_EQUIP_PRIMARY 1
-#define QUICK_EQUIP_SECONDARY 2
-#define QUICK_EQUIP_TERTIARY 3
-#define QUICK_EQUIP_QUATERNARY 4
-
/datum/keybinding/human
category = CATEGORY_HUMAN
weight = WEIGHT_MOB
@@ -10,86 +5,6 @@
/datum/keybinding/human/can_use(client/user)
return ishuman(user.mob)
-/datum/keybinding/human/quick_equip
- hotkey_keys = list("E")
- classic_keys = list("E")
- name = "quick_equip"
- full_name = "Unholster"
- description = "Take out an available weapon"
- keybind_signal = COMSIG_KB_HUMAN_QUICKEQUIP_DOWN
-
-/datum/keybinding/human/quick_equip/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- H.holster_verb(QUICK_EQUIP_PRIMARY)
- return TRUE
-
-/datum/keybinding/human/quick_equip_secondary
- hotkey_keys = list("Shift+E")
- classic_keys = list("Shift+E")
- name = "quick_equip_secondary"
- full_name = "Unholster secondary"
- description = "Take out your secondary weapon"
- keybind_signal = COMSIG_KB_HUMAN_SECONDARY_DOWN
-
-/datum/keybinding/human/quick_equip_secondary/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- H.holster_verb(QUICK_EQUIP_SECONDARY)
- return TRUE
-
-/datum/keybinding/human/quick_equip_tertiary
- hotkey_keys = list("Ctrl+E", "Alt+E")
- classic_keys = list("Ctrl+E", "Alt+E")
- name = "quick_equip_tertiary"
- full_name = "Unholster tertiary"
- description = "Take out your tertiary item."
- keybind_signal = COMSIG_KB_HUMAN_TERTIARY_DOWN
-
-/datum/keybinding/human/quick_equip_tertiary/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- H.holster_verb(QUICK_EQUIP_TERTIARY)
- return TRUE
-
-/datum/keybinding/human/quick_equip_quaternary
- hotkey_keys = list("Unbound")
- classic_keys = list("Unbound")
- name = "quick_equip_quaternary"
- full_name = "Unholster quaternary"
- description = "Take out your quaternary item."
- keybind_signal = COMSIG_KB_HUMAN_QUATERNARY_DOWN
-
-/datum/keybinding/human/quick_equip_quaternary/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- H.holster_verb(QUICK_EQUIP_QUATERNARY)
- return TRUE
-
-/datum/keybinding/human/quick_equip_inventory
- hotkey_keys = list("Unbound")
- classic_keys = list("Unbound")
- name = "quick_equip_inventory"
- full_name = "Quick equip inventory"
- description = "Quickly puts an item in the best slot available"
- keybind_signal = COMSIG_KB_HUMAN_QUICK_EQUIP_DOWN
-
-/datum/keybinding/human/quick_equip_inventory/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- H.quick_equip()
- return TRUE
-
/datum/keybinding/human/issue_order
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -103,8 +18,8 @@
. = ..()
if(.)
return
- var/mob/living/carbon/human/H = user.mob
- H.issue_order(order)
+ var/mob/living/carbon/human/human_mob = user.mob
+ human_mob.issue_order(order)
return TRUE
/datum/keybinding/human/issue_order/move
@@ -139,8 +54,8 @@
. = ..()
if(.)
return
- var/mob/living/carbon/human/H = user.mob
- H.spec_activation_one()
+ var/mob/living/carbon/human/human_mob = user.mob
+ human_mob.spec_activation_one()
return TRUE
/datum/keybinding/human/specialist_two
@@ -154,24 +69,8 @@
. = ..()
if(.)
return
- var/mob/living/carbon/human/H = user.mob
- H.spec_activation_two()
- return TRUE
-
-/datum/keybinding/human/pick_up
- hotkey_keys = list("F")
- classic_keys = list("Unbound")
- name = "pick_up"
- full_name = "Pick Up Dropped Items"
- keybind_signal = COMSIG_KB_HUMAN_PICK_UP
-
-/datum/keybinding/human/pick_up/down(client/user)
- . = ..()
- if(.)
- return
-
- var/mob/living/carbon/human/human_user = user.mob
- human_user.pickup_recent()
+ var/mob/living/carbon/human/human_mob = user.mob
+ human_mob.spec_activation_two()
return TRUE
/datum/keybinding/human/rotate_chair
@@ -209,7 +108,23 @@
shown_item.showoff(human_user)
return TRUE
-#undef QUICK_EQUIP_PRIMARY
-#undef QUICK_EQUIP_SECONDARY
-#undef QUICK_EQUIP_TERTIARY
-#undef QUICK_EQUIP_QUATERNARY
+/datum/keybinding/human/cycle_helmet_hud
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
+ name = "cycle_helmet_hud"
+ full_name = "Cycle Helmet HUD"
+ keybind_signal = COMSIG_KB_HUMAN_CYCLE_HELMET_HUD
+
+/datum/keybinding/human/cycle_helmet_hud/down(client/user)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/living/carbon/human/human_user = user.mob
+ var/obj/item/clothing/head/helmet/marine/marine_helmet = human_user?.head
+ var/cycled_hud = marine_helmet?.cycle_huds(human_user)
+
+ var/datum/action/item_action/cycle_helmet_huds/cycle_action = locate() in marine_helmet.actions
+ cycle_action.set_action_overlay(cycled_hud)
+
+ return TRUE
diff --git a/code/datums/keybinding/human_combat.dm b/code/datums/keybinding/human_combat.dm
index 70d78437ae03..5517f42c41ea 100644
--- a/code/datums/keybinding/human_combat.dm
+++ b/code/datums/keybinding/human_combat.dm
@@ -1,6 +1,5 @@
/datum/keybinding/human/combat
category = CATEGORY_HUMAN_COMBAT
- weight = WEIGHT_MOB
/datum/keybinding/human/combat/can_use(client/user)
. = ..()
@@ -191,3 +190,20 @@
var/obj/item/weapon/gun/rifle/m46c/COgun = held_item
COgun.toggle_iff(human)
return TRUE
+
+/datum/keybinding/human/combat/toggle_shotgun_tube
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
+ name = "toggle_shotgun_tube"
+ full_name = "Toggle Shotgun Tube"
+ keybind_signal = COMSIG_KB_HUMAN_WEAPON_SHOTGUN_TUBE
+
+/datum/keybinding/human/combat/toggle_shotgun_tube/down(client/user)
+ . = ..()
+ if(.)
+ return
+ var/mob/living/carbon/human/human = user.mob
+ var/obj/item/weapon/gun/shotgun/pump/dual_tube/held_item = human.get_held_item()
+ if(istype(held_item))
+ held_item.toggle_tube()
+ return TRUE
diff --git a/code/datums/keybinding/human_inventory.dm b/code/datums/keybinding/human_inventory.dm
new file mode 100644
index 000000000000..163cbccdd5c0
--- /dev/null
+++ b/code/datums/keybinding/human_inventory.dm
@@ -0,0 +1,244 @@
+/datum/keybinding/human/inventory
+ category = CATEGORY_HUMAN_INVENTORY
+
+#define QUICK_EQUIP_PRIMARY 1
+#define QUICK_EQUIP_SECONDARY 2
+#define QUICK_EQUIP_TERTIARY 3
+#define QUICK_EQUIP_QUATERNARY 4
+
+/datum/keybinding/human/inventory/quick_equip
+ hotkey_keys = list("E")
+ classic_keys = list("E")
+ name = "quick_equip"
+ full_name = "Unholster"
+ description = "Take out an available weapon"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_QUICKEQUIP_DOWN
+
+/datum/keybinding/human/inventory/quick_equip/down(client/user)
+ . = ..()
+ if(.)
+ return
+ var/mob/living/carbon/human/human_mob = user.mob
+ human_mob.holster_verb(QUICK_EQUIP_PRIMARY)
+ return TRUE
+
+/datum/keybinding/human/inventory/quick_equip_secondary
+ hotkey_keys = list("Shift+E")
+ classic_keys = list("Shift+E")
+ name = "quick_equip_secondary"
+ full_name = "Unholster secondary"
+ description = "Take out your secondary weapon"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SECONDARY_DOWN
+
+/datum/keybinding/human/inventory/quick_equip_secondary/down(client/user)
+ . = ..()
+ if(.)
+ return
+ var/mob/living/carbon/human/human_mob = user.mob
+ human_mob.holster_verb(QUICK_EQUIP_SECONDARY)
+ return TRUE
+
+/datum/keybinding/human/inventory/quick_equip_tertiary
+ hotkey_keys = list("Ctrl+E", "Alt+E")
+ classic_keys = list("Ctrl+E", "Alt+E")
+ name = "quick_equip_tertiary"
+ full_name = "Unholster tertiary"
+ description = "Take out your tertiary item."
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_TERTIARY_DOWN
+
+/datum/keybinding/human/inventory/quick_equip_tertiary/down(client/user)
+ . = ..()
+ if(.)
+ return
+ var/mob/living/carbon/human/human_mob = user.mob
+ human_mob.holster_verb(QUICK_EQUIP_TERTIARY)
+ return TRUE
+
+/datum/keybinding/human/inventory/quick_equip_quaternary
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
+ name = "quick_equip_quaternary"
+ full_name = "Unholster quaternary"
+ description = "Take out your quaternary item."
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_QUATERNARY_DOWN
+
+/datum/keybinding/human/inventory/quick_equip_quaternary/down(client/user)
+ . = ..()
+ if(.)
+ return
+ var/mob/living/carbon/human/human_mob = user.mob
+ human_mob.holster_verb(QUICK_EQUIP_QUATERNARY)
+ return TRUE
+
+#undef QUICK_EQUIP_PRIMARY
+#undef QUICK_EQUIP_SECONDARY
+#undef QUICK_EQUIP_TERTIARY
+#undef QUICK_EQUIP_QUATERNARY
+
+/datum/keybinding/human/inventory/quick_equip_inventory
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
+ name = "quick_equip_inventory"
+ full_name = "Quick equip inventory"
+ description = "Quickly puts an item in the best slot available"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_QUICK_EQUIP_DOWN
+
+/datum/keybinding/human/inventory/quick_equip_inventory/down(client/user)
+ . = ..()
+ if(.)
+ return
+ var/mob/living/carbon/human/human_mob = user.mob
+ human_mob.quick_equip()
+ return TRUE
+
+/datum/keybinding/human/inventory/pick_up
+ hotkey_keys = list("F")
+ classic_keys = list("Unbound")
+ name = "pick_up"
+ full_name = "Pick Up Dropped Items"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_PICK_UP
+
+/datum/keybinding/human/inventory/pick_up/down(client/user)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/living/carbon/human/human_user = user.mob
+ human_user.pickup_recent()
+ return TRUE
+
+/datum/keybinding/human/inventory/interact_other_hand
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
+ name = "interact_other_hand"
+ full_name = "Interact With Other Hand"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_OTHER_HAND
+
+/datum/keybinding/human/inventory/interact_other_hand/down(client/user)
+ . = ..()
+ if(.)
+ return
+
+ var/mob/living/carbon/human/human_user = user.mob
+
+ var/active_hand = human_user.get_active_hand()
+ var/inactive_hand = human_user.get_inactive_hand()
+
+ if(!inactive_hand)
+ return
+ human_user.click_adjacent(inactive_hand, active_hand)
+ return TRUE
+
+#define INTERACT_KEYBIND_COOLDOWN_TIME (0.2 SECONDS)
+#define COOLDOWN_SLOT_INTERACT_KEYBIND "slot_interact_keybind_cooldown"
+
+/datum/keybinding/human/inventory/interact_slot
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
+ var/storage_slot
+
+/datum/keybinding/human/inventory/interact_slot/proc/check_slot(mob/living/carbon/human/user)
+ return
+
+/datum/keybinding/human/inventory/interact_slot/down(client/user)
+ . = ..()
+ if(.)
+ return
+ if(!storage_slot)
+ return
+ if(TIMER_COOLDOWN_CHECK(src, COOLDOWN_SLOT_INTERACT_KEYBIND))
+ return
+
+ TIMER_COOLDOWN_START(src, COOLDOWN_SLOT_INTERACT_KEYBIND, INTERACT_KEYBIND_COOLDOWN_TIME)
+ var/mob/living/carbon/human/human_user = user.mob
+ var/obj/item/current_item = check_slot(human_user)
+ var/obj/item/in_hand_item = human_user.get_active_hand()
+
+ if(in_hand_item)
+ if(!current_item)
+ if(!human_user.equip_to_slot_if_possible(in_hand_item, storage_slot, FALSE, FALSE))
+ return
+ return TRUE
+
+ current_item.attackby(in_hand_item, human_user)
+ return TRUE
+
+ if(!current_item)
+ return
+ current_item.attack_hand(human_user)
+ return TRUE
+
+/datum/keybinding/human/inventory/interact_slot/back
+ name = "interact_storage_back"
+ full_name = "Interact With Back Slot"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_BACK
+ storage_slot = WEAR_BACK
+
+/datum/keybinding/human/inventory/interact_slot/back/check_slot(mob/living/carbon/human/user)
+ return user.back
+
+/datum/keybinding/human/inventory/interact_slot/belt
+ name = "interact_storage_belt"
+ full_name = "Interact With Belt Slot"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_BELT
+ storage_slot = WEAR_WAIST
+
+/datum/keybinding/human/inventory/interact_slot/belt/check_slot(mob/living/carbon/human/user)
+ return user.belt
+
+/datum/keybinding/human/inventory/interact_slot/pouch_left
+ name = "interact_storage_pouch_left"
+ full_name = "Interact With Left Pouch Slot"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_LEFT_POUCH
+ storage_slot = WEAR_L_STORE
+
+/datum/keybinding/human/inventory/interact_slot/pouch_left/check_slot(mob/living/carbon/human/user)
+ return user.l_store
+
+/datum/keybinding/human/inventory/interact_slot/pouch_right
+ name = "interact_storage_pouch_right"
+ full_name = "Interact With Right Pouch Slot"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_RIGHT_POUCH
+ storage_slot = WEAR_R_STORE
+
+/datum/keybinding/human/inventory/interact_slot/pouch_right/check_slot(mob/living/carbon/human/user)
+ return user.r_store
+
+/datum/keybinding/human/inventory/interact_slot/uniform
+ name = "interact_storage_uniform"
+ full_name = "Interact With Uniform Slot"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_UNIFORM
+ storage_slot = WEAR_BODY
+
+/datum/keybinding/human/inventory/interact_slot/uniform/check_slot(mob/living/carbon/human/user)
+ return user.w_uniform
+
+/datum/keybinding/human/inventory/interact_slot/suit
+ name = "interact_storage_suit"
+ full_name = "Interact With Suit Slot"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_SUIT
+ storage_slot = WEAR_JACKET
+
+/datum/keybinding/human/inventory/interact_slot/suit/check_slot(mob/living/carbon/human/user)
+ return user.wear_suit
+
+/datum/keybinding/human/inventory/interact_slot/helmet
+ name = "interact_storage_helmet"
+ full_name = "Interact With Head Slot"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SLOT_HELMET
+ storage_slot = WEAR_HEAD
+
+/datum/keybinding/human/inventory/interact_slot/helmet/check_slot(mob/living/carbon/human/user)
+ return user.head
+
+/datum/keybinding/human/inventory/interact_slot/suit_storage
+ name = "interact_storage_suit_store"
+ full_name = "Interact With Suit Storage Slot"
+ keybind_signal = COMSIG_KB_HUMAN_INTERACT_SUIT_S_STORE
+ storage_slot = WEAR_J_STORE
+
+/datum/keybinding/human/inventory/interact_slot/suit_storage/check_slot(mob/living/carbon/human/user)
+ return user.s_store
+
+#undef INTERACT_KEYBIND_COOLDOWN_TIME
+#undef COOLDOWN_SLOT_INTERACT_KEYBIND
diff --git a/code/datums/keybinding/xenomorph.dm b/code/datums/keybinding/xenomorph.dm
index 431b0a1e987f..cef04d01a75c 100644
--- a/code/datums/keybinding/xenomorph.dm
+++ b/code/datums/keybinding/xenomorph.dm
@@ -196,11 +196,11 @@
return
if((!current_xeno.hive.living_xeno_queen || SSmapping.configs[GROUND_MAP].map_name == MAP_WHISKEY_OUTPOST) && !current_xeno.hive.allow_no_queen_actions) //No Hive status on WO
- to_chat(current_xeno, SPAN_WARNING("There is no Queen. You are alone."))
+ to_chat(current_xeno, SPAN_WARNING("There is no Queen. We are alone."))
return
if(current_xeno.interference)
- to_chat(current_xeno, SPAN_WARNING("A headhunter temporarily cut off your psychic connection!"))
+ to_chat(current_xeno, SPAN_WARNING("A headhunter temporarily cut off our psychic connection!"))
return
current_xeno.hive.hive_ui.open_hive_status(current_xeno)
diff --git a/code/datums/keybinding/yautja.dm b/code/datums/keybinding/yautja.dm
index 4729db004582..c79788df49a3 100644
--- a/code/datums/keybinding/yautja.dm
+++ b/code/datums/keybinding/yautja.dm
@@ -30,16 +30,7 @@
classic_keys = list("Unbound")
name = "pred_buy"
full_name = "Claim equipment"
- keybind_signal = COMSIG_KB_YAUTJA_BUTCHER
-
-/datum/keybinding/yautja/pred_buy/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- if(!isyautja(H))
- return
- H.pred_buy()
+ keybind_signal = COMSIG_KB_YAUTJA_PRED_BUY
/datum/keybinding/yautja/mark_panel
hotkey_keys = list("Unbound")
@@ -48,46 +39,12 @@
full_name = "Mark panel"
keybind_signal = COMSIG_KB_YAUTJA_MARK_PANEL
-/datum/keybinding/yautja/mark_panel/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- if(!isyautja(H))
- return
- H.mark_panel()
-
/datum/keybinding/yautja/mark_for_hunt
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
name = "mark_for_hunt"
- full_name = "Mark for hunt"
- keybind_signal = COMSIG_KB_YAUTJA_MARK_FOR_HUNT
-
-/datum/keybinding/yautja/mark_for_hunt/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- if(!isyautja(H))
- return
- H.mark_for_hunt()
-
-/datum/keybinding/yautja/remove_from_hunt
- hotkey_keys = list("Unbound")
- classic_keys = list("Unbound")
- name = "remove_from_hunt"
- full_name = "Remove from hunt"
- keybind_signal = COMSIG_KB_YAUTJA_REMOVE_FROM_HUNT
-
-/datum/keybinding/yautja/remove_from_hunt/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- if(!isyautja(H))
- return
- H.remove_from_hunt()
+ full_name = "Toggle mark for hunt"
+ keybind_signal = COMSIG_KB_YAUTJA_TOGGLE_MARK_FOR_HUNT
// BRACER SPECIFIC \\
@@ -168,22 +125,6 @@
full_name = "Toggle wristblades"
keybind_signal = COMSIG_KB_YAUTJA_WRISTBLADES
-/datum/keybinding/yautja/bracer_hunter/wristblades/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.wristblades()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.wristblades()
- return TRUE
-
/datum/keybinding/yautja/bracer_hunter/track_gear
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -214,22 +155,6 @@
full_name = "Toggle cloak"
keybind_signal = COMSIG_KB_YAUTJA_CLOAKER
-/datum/keybinding/yautja/bracer_hunter/cloaker/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.cloaker()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.cloaker()
- return TRUE
-
/datum/keybinding/yautja/bracer_hunter/caster
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -237,22 +162,6 @@
full_name = "Toggle plasma caster"
keybind_signal = COMSIG_KB_YAUTJA_CASTER
-/datum/keybinding/yautja/bracer_hunter/caster/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.caster()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.caster()
- return TRUE
-
/datum/keybinding/yautja/bracer_hunter/change_explosion_type
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -283,22 +192,6 @@
full_name = "Self-destruct"
keybind_signal = COMSIG_KB_YAUTJA_ACTIVATE_SUICIDE
-/datum/keybinding/yautja/bracer_hunter/activate_suicide/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.activate_suicide()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.activate_suicide()
- return TRUE
-
/datum/keybinding/yautja/bracer_hunter/injectors
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -306,21 +199,6 @@
full_name = "Create Stabilising Crystal"
keybind_signal = COMSIG_KB_YAUTJA_INJECTORS
-/datum/keybinding/yautja/bracer_hunter/injectors/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.injectors()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.injectors()
- return TRUE
/datum/keybinding/yautja/bracer_hunter/healing_capsule
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -328,22 +206,6 @@
full_name = "Create Healing Capsule"
keybind_signal = COMSIG_KB_YAUTJA_CAPSULE
-/datum/keybinding/yautja/bracer_hunter/healing_capsule/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.healing_capsule()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.healing_capsule()
- return TRUE
-
/datum/keybinding/yautja/bracer_hunter/call_disc
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -351,22 +213,6 @@
full_name = "Call smart-disc"
keybind_signal = COMSIG_KB_YAUTJA_CALL_DISC
-/datum/keybinding/yautja/bracer_hunter/call_disc/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.call_disc()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.call_disc()
- return TRUE
-
/datum/keybinding/yautja/bracer_hunter/remove_tracked_item
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -420,22 +266,6 @@
full_name = "Yank combi-stick"
keybind_signal = COMSIG_KB_YAUTJA_CALL_COMBI
-/datum/keybinding/yautja/bracer_hunter/call_combi/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.call_combi()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.call_combi()
- return TRUE
-
/datum/keybinding/yautja/bracer_hunter/translate
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -443,22 +273,6 @@
full_name = "Translator"
keybind_signal = COMSIG_KB_YAUTJA_TRANSLATE
-/datum/keybinding/yautja/bracer_hunter/translate/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
-
- var/obj/item/clothing/gloves/yautja/hunter/gloves = H.gloves
- if(istype(gloves))
- gloves.translate()
- return TRUE
-
- var/obj/item/clothing/gloves/yautja/hunter/held = H.get_held_item()
- if(istype(held))
- held.translate()
- return TRUE
-
/datum/keybinding/yautja/bracer_hunter/bracername
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
@@ -528,6 +342,13 @@
held.link_bracer()
return TRUE
+/datum/keybinding/yautja/bracer_hunter/control_falcon_drone
+ hotkey_keys = list("Unbound")
+ classic_keys = list("Unbound")
+ name = "control_falcon"
+ full_name = "Control falcon drone"
+ keybind_signal = COMSIG_KB_YAUTJA_CONTROL_FALCON
+
// Misc stuff - mask, teleporter \\
// mask
@@ -545,32 +366,14 @@
classic_keys = list("Unbound")
name = "toggle_zoom"
full_name = "Toggle mask zoom"
- keybind_signal = COMSIG_KB_YAUTJA_LINK_BRACER
-
-/datum/keybinding/yautja/mask/toggle_zoom/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- var/obj/item/clothing/mask/gas/yautja/mask = H.wear_mask
- mask.toggle_zoom()
- return TRUE
+ keybind_signal = COMSIG_KB_YAUTJA_MASK_TOGGLE_ZOOM
/datum/keybinding/yautja/mask/togglesight
hotkey_keys = list("Unbound")
classic_keys = list("Unbound")
name = "togglesight"
full_name = "Toggle mask visors"
- keybind_signal = COMSIG_KB_YAUTJA_LINK_BRACER
-
-/datum/keybinding/yautja/mask/togglesight/down(client/user)
- . = ..()
- if(.)
- return
- var/mob/living/carbon/human/H = user.mob
- var/obj/item/clothing/mask/gas/yautja/mask = H.wear_mask
- mask.togglesight()
- return TRUE
+ keybind_signal = COMSIG_KB_YAUTJA_MASK_TOGGLESIGHT
// teleporter
diff --git a/code/datums/langchat/langchat.dm b/code/datums/langchat/langchat.dm
index d1a6adafa2f3..83b9be0ac053 100644
--- a/code/datums/langchat/langchat.dm
+++ b/code/datums/langchat/langchat.dm
@@ -13,7 +13,6 @@
#define LANGCHAT_LONGEST_TEXT 64
#define LANGCHAT_WIDTH 96
-#define LANGCHAT_X_OFFSET -32
#define LANGCHAT_MAX_ALPHA 196
//pop defines
@@ -48,6 +47,13 @@
M.client.images -= langchat_image
langchat_listeners = null
+/atom/proc/langchat_set_x_offset()
+ langchat_image.maptext_x = world.icon_size / 2 - langchat_image.maptext_width / 2
+/atom/movable/langchat_set_x_offset()
+ langchat_image.maptext_x = bound_width / 2 - langchat_image.maptext_width / 2
+/mob/langchat_set_x_offset()
+ langchat_image.maptext_x = icon_size / 2 - langchat_image.maptext_width / 2
+
///Creates the image if one does not exist, resets settings that are modified by speech procs.
/atom/proc/langchat_make_image(override_color = null)
if(!langchat_image)
@@ -57,8 +63,8 @@
langchat_image.appearance_flags = NO_CLIENT_COLOR|KEEP_APART|RESET_COLOR|RESET_TRANSFORM
langchat_image.maptext_y = langchat_height
langchat_image.maptext_height = 64
- langchat_image.maptext_x = LANGCHAT_X_OFFSET
langchat_image.maptext_y -= LANGCHAT_MESSAGE_POP_Y_SINK
+ langchat_set_x_offset()
langchat_image.pixel_y = 0
langchat_image.alpha = 0
@@ -103,6 +109,7 @@
langchat_image.maptext = text_to_display
langchat_image.maptext_width = LANGCHAT_WIDTH
+ langchat_set_x_offset()
langchat_listeners = listeners
for(var/mob/M in langchat_listeners)
@@ -149,6 +156,7 @@
langchat_image.maptext = text_to_display
langchat_image.maptext_width = LANGCHAT_WIDTH * 2
+ langchat_set_x_offset()
langchat_listeners = listeners
for(var/mob/M in langchat_listeners)
diff --git a/code/datums/looping_sounds/_looping_sound.dm b/code/datums/looping_sounds/_looping_sound.dm
index c6fc23c68eba..11ba15146430 100644
--- a/code/datums/looping_sounds/_looping_sound.dm
+++ b/code/datums/looping_sounds/_looping_sound.dm
@@ -37,6 +37,15 @@
/// Has the looping started yet?
var/loop_started = FALSE
+ /**
+ * Let's you make a "loud" sound that "projects." IE you can hear this sound from a further distance away.
+ * Think of like an air raid siren. They're loud if you're close yeah... but you can hear them from mad far away, bruv
+ * with a longer "falloff distance." Fixes the extra_range stuff
+ */
+ var/is_sound_projecting = FALSE
+ ///only applicable to is_sound_projecting: max range till sound volume starts dropping as distance increases
+ var/falloff_distance = 50
+
/* // as of yet unused varen \\
/// How much the sound will be affected by falloff per tile.
@@ -130,19 +139,18 @@
sound_to_play.channel = get_free_channel()
sound_to_play.volume = volume_override || volume //Use volume as fallback if theres no override
SEND_SOUND(parent, sound_to_play)
- else
- playsound(
- parent,
- sound_to_play,
- volume,
- vary,
- extra_range//,
- // falloff_exponent = falloff_exponent,
- // pressure_affected = pressure_affected,
- // ignore_walls = ignore_walls,
- // falloff_distance = falloff_distance,
- // use_reverb = use_reverb
- )
+ return
+ if (is_sound_projecting)
+ playsound(parent, sound_to_play, volume, vary, extra_range, VOLUME_SFX, 0, 0, falloff_distance)
+ return
+
+ playsound(
+ parent,
+ sound_to_play,
+ volume,
+ vary,
+ extra_range
+ )
/// Returns the sound we should now be playing.
/datum/looping_sound/proc/get_sound(_mid_sounds)
diff --git a/code/datums/looping_sounds/misc_sounds.dm b/code/datums/looping_sounds/misc_sounds.dm
new file mode 100644
index 000000000000..6411b3f51f4a
--- /dev/null
+++ b/code/datums/looping_sounds/misc_sounds.dm
@@ -0,0 +1,3 @@
+/datum/looping_sound/looping_launch_announcement_alarm
+ mid_sounds = list('sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg' = 1)
+ start_sound = list('sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg' = 1)
diff --git a/code/datums/map_config.dm b/code/datums/map_config.dm
index 1f3c265ead76..3bf5c601cec9 100644
--- a/code/datums/map_config.dm
+++ b/code/datums/map_config.dm
@@ -87,12 +87,14 @@
/datum/equipment_preset/synth/survivor/janitor_synth,
/datum/equipment_preset/synth/survivor/chef_synth,
/datum/equipment_preset/synth/survivor/teacher_synth,
+ /datum/equipment_preset/synth/survivor/freelancer_synth,
+ /datum/equipment_preset/synth/survivor/trucker_synth,
/datum/equipment_preset/synth/survivor/bartender_synth,
/datum/equipment_preset/synth/survivor/detective_synth,
/datum/equipment_preset/synth/survivor/cmb_synth,
- /datum/equipment_preset/synth/survivor/security_synth,
- /datum/equipment_preset/synth/survivor/protection_synth,
- /datum/equipment_preset/synth/survivor/corporate_synth,
+ /datum/equipment_preset/synth/survivor/wy/security_synth,
+ /datum/equipment_preset/synth/survivor/wy/protection_synth,
+ /datum/equipment_preset/synth/survivor/wy/corporate_synth,
/datum/equipment_preset/synth/survivor/radiation_synth,
)
diff --git a/code/datums/medal_awards.dm b/code/datums/medal_awards.dm
index 54af48fd3345..ba8847c03661 100644
--- a/code/datums/medal_awards.dm
+++ b/code/datums/medal_awards.dm
@@ -35,6 +35,7 @@ GLOBAL_LIST_EMPTY(jelly_awards)
giver_mob = list()
giver_ckey = list()
+GLOBAL_LIST_INIT(human_medals, list(MARINE_CONDUCT_MEDAL, MARINE_BRONZE_HEART_MEDAL, MARINE_VALOR_MEDAL, MARINE_HEROISM_MEDAL))
/proc/give_medal_award(medal_location, as_admin = FALSE)
if(as_admin && !check_rights(R_ADMIN))
@@ -52,7 +53,7 @@ GLOBAL_LIST_EMPTY(jelly_awards)
return FALSE
// Pick a medal
- var/medal_type = tgui_input_list(usr, "What type of medal do you want to award?", "Medal Type", list(MARINE_CONDUCT_MEDAL, MARINE_BRONZE_HEART_MEDAL, MARINE_VALOR_MEDAL, MARINE_HEROISM_MEDAL))
+ var/medal_type = tgui_input_list(usr, "What type of medal do you want to award?", "Medal Type", GLOB.human_medals)
if(!medal_type)
return FALSE
@@ -173,15 +174,15 @@ GLOBAL_LIST_EMPTY(jelly_awards)
user.visible_message("ERROR: ID card not registered in USCM registry. Potential medal fraud detected.")
return
- var/real_owner_ref = card.registered_ref
-
- if(real_owner_ref != WEAKREF(user))
+ if(!card.check_biometrics(user))
user.visible_message("ERROR: ID card not registered for [user.real_name] in USCM registry. Potential medal fraud detected.")
return
if(give_medal_award(get_turf(printer)))
user.visible_message(SPAN_NOTICE("[printer] prints a medal."))
+GLOBAL_LIST_INIT(xeno_medals, list(XENO_SLAUGHTER_MEDAL, XENO_RESILIENCE_MEDAL, XENO_SABOTAGE_MEDAL, XENO_PROLIFERATION_MEDAL, XENO_REJUVENATION_MEDAL))
+
/proc/give_jelly_award(datum/hive_status/hive, as_admin = FALSE)
if(!hive)
return FALSE
@@ -220,7 +221,7 @@ GLOBAL_LIST_EMPTY(jelly_awards)
return FALSE
// Pick a jelly
- var/medal_type = tgui_input_list(usr, "What type of jelly do you want to award?", "Jelly Type", list(XENO_SLAUGHTER_MEDAL, XENO_RESILIENCE_MEDAL, XENO_SABOTAGE_MEDAL, XENO_PROLIFERATION_MEDAL, XENO_REJUVENATION_MEDAL), theme="hive_status")
+ var/medal_type = tgui_input_list(usr, "What type of jelly do you want to award?", "Jelly Type", GLOB.xeno_medals, theme="hive_status")
if(!medal_type)
return FALSE
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index 2e56b963e88f..74f445f21597 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -29,9 +29,14 @@
research_objective_interface = new()
/datum/mind/Destroy()
+ QDEL_NULL(initial_account)
QDEL_NULL(objective_memory)
QDEL_NULL(objective_interface)
QDEL_NULL(research_objective_interface)
+ current = null
+ original = null
+ ghost_mob = null
+ player_entity = null
return ..()
/datum/mind/proc/transfer_to(mob/living/new_character, force = FALSE)
@@ -39,11 +44,9 @@
msg_admin_niche("[key]/[ckey] has tried to transfer to deleted [new_character].")
return
- SEND_SIGNAL(current.client, COMSIG_CLIENT_MIND_TRANSFER, new_character)
-
if(current)
current.mind = null //remove ourself from our old body's mind variable
- nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user
+ SSnano.nanomanager.user_transferred(current, new_character) // transfer active NanoUI instances to new user
if(key)
if(new_character.key != key)
@@ -63,7 +66,7 @@
SSround_recording.recorder.update_key(new_character)
if(new_character.client)
new_character.client.init_verbs()
- new_character.client.change_view(world_view_size) //reset view range to default.
+ new_character.client.change_view(GLOB.world_view_size) //reset view range to default.
new_character.client.pixel_x = 0
new_character.client.pixel_y = 0
if(usr && usr.open_uis)
diff --git a/code/datums/mob_hud.dm b/code/datums/mob_hud.dm
index 65c5a47896fa..778ec2b75a36 100644
--- a/code/datums/mob_hud.dm
+++ b/code/datums/mob_hud.dm
@@ -1,7 +1,7 @@
/* HUD DATUMS */
//GLOBAL HUD LIST
-var/list/datum/mob_hud/huds = list(
+GLOBAL_LIST_INIT_TYPED(huds, /datum/mob_hud, list(
MOB_HUD_SECURITY_BASIC = new /datum/mob_hud/security/basic(),
MOB_HUD_SECURITY_ADVANCED = new /datum/mob_hud/security/advanced(),
MOB_HUD_MEDICAL_BASIC = new /datum/mob_hud/medical/basic(),
@@ -19,7 +19,7 @@ var/list/datum/mob_hud/huds = list(
MOB_HUD_FACTION_PMC = new /datum/mob_hud/faction/pmc(),
MOB_HUD_HUNTER = new /datum/mob_hud/hunter_hud(),
MOB_HUD_HUNTER_CLAN = new /datum/mob_hud/hunter_clan()
- )
+ ))
/datum/mob_hud
var/list/mob/hudmobs = list() //list of all mobs which display this hud
@@ -33,10 +33,8 @@ var/list/datum/mob_hud/huds = list(
/datum/mob_hud/proc/remove_hud_from(mob/user, source)
if(length(hudusers[user]) && (source in hudusers[user]))
hudusers[user] -= source
-
if(length(hudusers[user]))
return FALSE
-
for(var/mob/target in hudmobs)
remove_from_single_hud(user, target)
@@ -220,17 +218,17 @@ var/list/datum/mob_hud/huds = list(
return
/mob/hologram/queen/add_to_all_mob_huds()
- var/datum/mob_hud/hud = huds[MOB_HUD_XENO_STATUS]
+ var/datum/mob_hud/hud = GLOB.huds[MOB_HUD_XENO_STATUS]
hud.add_to_hud(src)
/mob/living/carbon/human/add_to_all_mob_huds()
- for(var/datum/mob_hud/hud in huds)
+ for(var/datum/mob_hud/hud in GLOB.huds)
if(istype(hud, /datum/mob_hud/xeno)) //this one is xeno only
continue
hud.add_to_hud(src)
/mob/living/carbon/xenomorph/add_to_all_mob_huds()
- for(var/datum/mob_hud/hud in huds)
+ for(var/datum/mob_hud/hud in GLOB.huds)
if(!istype(hud, /datum/mob_hud/xeno))
continue
hud.add_to_hud(src)
@@ -240,17 +238,17 @@ var/list/datum/mob_hud/huds = list(
return
/mob/hologram/queen/remove_from_all_mob_huds()
- var/datum/mob_hud/hud = huds[MOB_HUD_XENO_STATUS]
+ var/datum/mob_hud/hud = GLOB.huds[MOB_HUD_XENO_STATUS]
hud.remove_from_hud(src)
/mob/living/carbon/human/remove_from_all_mob_huds()
- for(var/datum/mob_hud/hud in huds)
+ for(var/datum/mob_hud/hud in GLOB.huds)
if(istype(hud, /datum/mob_hud/xeno))
continue
hud.remove_from_hud(src)
/mob/living/carbon/xenomorph/remove_from_all_mob_huds()
- for(var/datum/mob_hud/hud in huds)
+ for(var/datum/mob_hud/hud in GLOB.huds)
if(istype(hud, /datum/mob_hud/xeno))
hud.remove_from_hud(src)
hud.remove_hud_from(src, src)
@@ -258,14 +256,14 @@ var/list/datum/mob_hud/huds = list(
hud.remove_hud_from(src, src)
if (xeno_hostile_hud)
xeno_hostile_hud = FALSE
- var/datum/mob_hud/hostile_hud = huds[MOB_HUD_XENO_HOSTILE]
+ var/datum/mob_hud/hostile_hud = GLOB.huds[MOB_HUD_XENO_HOSTILE]
hostile_hud.remove_hud_from(src, src)
/mob/proc/refresh_huds(mob/source_mob)
var/mob/M = source_mob ? source_mob : src
- for(var/datum/mob_hud/hud in huds)
+ for(var/datum/mob_hud/hud in GLOB.huds)
if(M in hud.hudusers)
hud.refresh_hud(src, hud.hudusers[M])
@@ -273,7 +271,7 @@ var/list/datum/mob_hud/huds = list(
//called when a human changes suit sensors
/mob/living/carbon/human/proc/update_suit_sensors()
- var/datum/mob_hud/medical/basic/B = huds[MOB_HUD_MEDICAL_BASIC]
+ var/datum/mob_hud/medical/basic/B = GLOB.huds[MOB_HUD_MEDICAL_BASIC]
B.update_suit_sensors(src)
//called when a human changes health
@@ -283,6 +281,12 @@ var/list/datum/mob_hud/huds = list(
return
/mob/living/carbon/xenomorph/med_hud_set_health()
+ if(QDELETED(src))
+ return
+
+ if(!(HEALTH_HUD_XENO in hud_list))
+ CRASH("hud_list lacks HEALTH_HUD_XENO despite not being deleted in med_hud_set_health()")
+
var/image/holder = hud_list[HEALTH_HUD_XENO]
var/health_hud_type = "xenohealth"
@@ -666,11 +670,11 @@ var/list/datum/mob_hud/huds = list(
/mob/proc/hud_set_hunter()
return
-var/global/image/hud_icon_hunter_gear
-var/global/image/hud_icon_hunter_hunted
-var/global/image/hud_icon_hunter_dishonored
-var/global/image/hud_icon_hunter_honored
-var/global/image/hud_icon_hunter_thralled
+GLOBAL_DATUM(hud_icon_hunter_gear, /image)
+GLOBAL_DATUM(hud_icon_hunter_hunted, /image)
+GLOBAL_DATUM(hud_icon_hunter_dishonored, /image)
+GLOBAL_DATUM(hud_icon_hunter_honored, /image)
+GLOBAL_DATUM(hud_icon_hunter_thralled, /image)
/mob/living/carbon/hud_set_hunter()
@@ -678,27 +682,27 @@ var/global/image/hud_icon_hunter_thralled
holder.icon_state = "hudblank"
holder.overlays.Cut()
if(hunter_data.hunted)
- if(!hud_icon_hunter_hunted)
- hud_icon_hunter_hunted = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_hunted")
- holder.overlays += hud_icon_hunter_hunted
+ if(!GLOB.hud_icon_hunter_hunted)
+ GLOB.hud_icon_hunter_hunted = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_hunted")
+ holder.overlays += GLOB.hud_icon_hunter_hunted
if(hunter_data.dishonored)
- if(!hud_icon_hunter_dishonored)
- hud_icon_hunter_dishonored = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_dishonored")
- holder.overlays += hud_icon_hunter_dishonored
+ if(!GLOB.hud_icon_hunter_dishonored)
+ GLOB.hud_icon_hunter_dishonored = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_dishonored")
+ holder.overlays += GLOB.hud_icon_hunter_dishonored
else if(hunter_data.honored)
- if(!hud_icon_hunter_honored)
- hud_icon_hunter_honored = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_honored")
- holder.overlays += hud_icon_hunter_honored
+ if(!GLOB.hud_icon_hunter_honored)
+ GLOB.hud_icon_hunter_honored = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_honored")
+ holder.overlays += GLOB.hud_icon_hunter_honored
if(hunter_data.thralled)
- if(!hud_icon_hunter_thralled)
- hud_icon_hunter_thralled = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_thralled")
- holder.overlays += hud_icon_hunter_thralled
+ if(!GLOB.hud_icon_hunter_thralled)
+ GLOB.hud_icon_hunter_thralled = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_thralled")
+ holder.overlays += GLOB.hud_icon_hunter_thralled
else if(hunter_data.gear)
- if(!hud_icon_hunter_gear)
- hud_icon_hunter_gear = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_gear")
- holder.overlays += hud_icon_hunter_gear
+ if(!GLOB.hud_icon_hunter_gear)
+ GLOB.hud_icon_hunter_gear = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_gear")
+ holder.overlays += GLOB.hud_icon_hunter_gear
hud_list[HUNTER_HUD] = holder
@@ -708,18 +712,18 @@ var/global/image/hud_icon_hunter_thralled
holder.overlays.Cut()
holder.pixel_x = -18
if(hunter_data.hunted)
- if(!hud_icon_hunter_hunted)
- hud_icon_hunter_hunted = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_hunted")
- holder.overlays += hud_icon_hunter_hunted
+ if(!GLOB.hud_icon_hunter_hunted)
+ GLOB.hud_icon_hunter_hunted = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_hunted")
+ holder.overlays += GLOB.hud_icon_hunter_hunted
if(hunter_data.dishonored)
- if(!hud_icon_hunter_dishonored)
- hud_icon_hunter_dishonored = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_dishonored")
- holder.overlays += hud_icon_hunter_dishonored
+ if(!GLOB.hud_icon_hunter_dishonored)
+ GLOB.hud_icon_hunter_dishonored = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_dishonored")
+ holder.overlays += GLOB.hud_icon_hunter_dishonored
else if(hunter_data.honored)
- if(!hud_icon_hunter_honored)
- hud_icon_hunter_honored = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_honored")
- holder.overlays += hud_icon_hunter_honored
+ if(!GLOB.hud_icon_hunter_honored)
+ GLOB.hud_icon_hunter_honored = image('icons/mob/hud/hud_yautja.dmi', src, "hunter_honored")
+ holder.overlays += GLOB.hud_icon_hunter_honored
hud_list[HUNTER_HUD] = holder
@@ -727,26 +731,26 @@ var/global/image/hud_icon_hunter_thralled
/mob/proc/hud_set_order()
return
-var/global/image/hud_icon_hudmove
-var/global/image/hud_icon_hudhold
-var/global/image/hud_icon_hudfocus
+GLOBAL_DATUM(hud_icon_hudmove, /image)
+GLOBAL_DATUM(hud_icon_hudhold, /image)
+GLOBAL_DATUM(hud_icon_hudfocus, /image)
// ORDER HUD
/mob/living/carbon/human/hud_set_order()
var/image/holder = hud_list[ORDER_HUD]
holder.icon_state = "hudblank"
holder.overlays.Cut()
if(mobility_aura)
- if(!hud_icon_hudmove)
- hud_icon_hudmove = image('icons/mob/hud/marine_hud.dmi', src, "hudmove")
- holder.overlays += hud_icon_hudmove
+ if(!GLOB.hud_icon_hudmove)
+ GLOB.hud_icon_hudmove = image('icons/mob/hud/marine_hud.dmi', src, "hudmove")
+ holder.overlays += GLOB.hud_icon_hudmove
if(protection_aura)
- if(!hud_icon_hudhold)
- hud_icon_hudhold = image('icons/mob/hud/marine_hud.dmi', src, "hudhold")
- holder.overlays += hud_icon_hudhold
+ if(!GLOB.hud_icon_hudhold)
+ GLOB.hud_icon_hudhold = image('icons/mob/hud/marine_hud.dmi', src, "hudhold")
+ holder.overlays += GLOB.hud_icon_hudhold
if(marksman_aura)
- if(!hud_icon_hudfocus)
- hud_icon_hudfocus = image('icons/mob/hud/marine_hud.dmi', src, "hudfocus")
- holder.overlays += hud_icon_hudfocus
+ if(!GLOB.hud_icon_hudfocus)
+ GLOB.hud_icon_hudfocus = image('icons/mob/hud/marine_hud.dmi', src, "hudfocus")
+ holder.overlays += GLOB.hud_icon_hudfocus
hud_list[ORDER_HUD] = holder
@@ -797,8 +801,6 @@ var/global/image/hud_icon_hudfocus
if (tag_found)
tag_holder.overlays += image('icons/mob/hud/hud.dmi', src, "prae_tag")
- // Hacky, but works. Currently effects are hard to make with precise timings
- var/freeze_found = frozen
-
+ var/freeze_found = HAS_TRAIT(src, TRAIT_IMMOBILIZED) && body_position == STANDING_UP && !buckled // Eligible targets are unable to move but can stand and aren't buckled (eg nested) - This is to convey that they are temporarily unable to move
if (freeze_found)
freeze_holder.overlays += image('icons/mob/hud/hud.dmi', src, "xeno_freeze")
diff --git a/code/datums/modules.dm b/code/datums/modules.dm
deleted file mode 100644
index 4dd47497ffcc..000000000000
--- a/code/datums/modules.dm
+++ /dev/null
@@ -1,62 +0,0 @@
-// module datum.
-// this is per-object instance, and shows the condition of the modules in the object
-// actual modules needed is referenced through modulestypes and the object type
-
-/datum/module
- var/status // bits set if working, 0 if broken
- var/installed // bits set if installed, 0 if missing
-
-// moduletypes datum
-// this is per-object type, and shows the modules needed for a type of object
-
-/datum/moduletypes
- var/list/modcount = list() // assoc list of the count of modules for a type
-
-
-var/list/modules = list( // global associative list
- /obj/structure/machinery/power/apc = "card_reader,power_control,id_auth,cell_power,cell_charge")
-
-
-/datum/module/New(obj/O)
-
- var/type = O.type // the type of the creating object
-
- var/mneed = mods.inmodlist(type) // find if this type has modules defined
-
- if(!mneed) // not found in module list?
- qdel(src) // delete self, thus ending proc
-
- var/needed = mods.getbitmask(type) // get a bitmask for the number of modules in this object
- status = needed
- installed = needed
-
-/datum/moduletypes/proc/addmod(type, modtextlist)
- modules += type // index by type text
- modules[type] = modtextlist
-
-/datum/moduletypes/proc/inmodlist(type)
- return type in modules
-
-/datum/moduletypes/proc/getbitmask(type)
- var/count = modcount[type]
- if(count)
- return 2**count-1
-
- var/modtext = modules[type]
- var/num = 1
- var/pos = 1
-
- while(1)
- pos = findtext(modtext, ",", pos, 0)
- if(!pos)
- break
- else
- pos++
- num++
-
- modcount += type
- modcount[type] = num
-
- return 2**num-1
-
-
diff --git a/code/datums/origin/origin.dm b/code/datums/origin/origin.dm
index 4bbd8b6505b5..46027a49941a 100644
--- a/code/datums/origin/origin.dm
+++ b/code/datums/origin/origin.dm
@@ -3,7 +3,7 @@
var/desc = "You were born somewhere, someplace. The area is known for doing things, you think."
/datum/origin/proc/generate_human_name(gender = MALE)
- return pick(gender == MALE ? first_names_male : first_names_female) + " " + pick(last_names)
+ return pick(gender == MALE ? GLOB.first_names_male : GLOB.first_names_female) + " " + pick(GLOB.last_names)
/// Return null if the name is correct, otherwise return a string containing the error message
/datum/origin/proc/validate_name(name_to_check)
diff --git a/code/datums/origin/upp.dm b/code/datums/origin/upp.dm
index f684410d59bf..8346657c5020 100644
--- a/code/datums/origin/upp.dm
+++ b/code/datums/origin/upp.dm
@@ -10,16 +10,16 @@
if(prob(40))
first_name = "[capitalize(randomly_generate_chinese_word(1))]"
else
- first_name = "[pick(first_names_male_upp)]"
+ first_name = "[pick(GLOB.first_names_male_upp)]"
else
if(prob(40))
first_name = "[capitalize(randomly_generate_chinese_word(1))]"
else
- first_name = "[pick(first_names_female_upp)]"
+ first_name = "[pick(GLOB.first_names_female_upp)]"
if(prob(35))
last_name = "[capitalize(randomly_generate_chinese_word(pick(20;1, 80;2)))]"
else
- last_name = "[pick(last_names_upp)]"
+ last_name = "[pick(GLOB.last_names_upp)]"
return first_name + " " + last_name
diff --git a/code/datums/origin/uscm.dm b/code/datums/origin/uscm.dm
index 8021ed3fd3a8..9608537bdf3f 100644
--- a/code/datums/origin/uscm.dm
+++ b/code/datums/origin/uscm.dm
@@ -28,7 +28,7 @@
desc = "You were a product of an experimental military programme that sought to breed the perfect supersoldier. In some aspects, they've succeeded."
/datum/origin/uscm/aw/generate_human_name(gender = MALE)
- return pick(gender == MALE ? first_names_male : first_names_female) + " A.W. " + pick(weapon_surnames)
+ return pick(gender == MALE ? GLOB.first_names_male : GLOB.first_names_female) + " A.W. " + pick(GLOB.weapon_surnames)
/datum/origin/uscm/aw/validate_name(name_to_check)
if(!findtext(name_to_check, "A.W. "))
diff --git a/code/datums/paygrades/factions/civillian/civilian.dm b/code/datums/paygrades/factions/civillian/civilian.dm
deleted file mode 100644
index 2c2aa5feac1c..000000000000
--- a/code/datums/paygrades/factions/civillian/civilian.dm
+++ /dev/null
@@ -1,30 +0,0 @@
-/datum/paygrade/civilian
- name = "Civilian Paygrade"
- pay_multiplier = 0.5 // civvies are poor
-
-/datum/paygrade/civilian/civilian
- paygrade = "C"
- name = "Civilian"
-
-/datum/paygrade/civilian/nurse
- paygrade = "CN"
- name = "Nurse"
- prefix = "Nrs."
-
-/datum/paygrade/civilian/doctor
- paygrade = "CD"
- name = "Doctor"
- prefix = "Dr."
- pay_multiplier = 0.75
-
-/datum/paygrade/civilian/professor
- paygrade = "CCMO"
- name = "Professor"
- prefix = "Prof."
- pay_multiplier = 1
-
-/datum/paygrade/civillian/representative
- paygrade = "CR"
- name = "Representative"
- prefix = "Rep."
- pay_multiplier = 1
diff --git a/code/datums/paygrades/factions/other/civilian.dm b/code/datums/paygrades/factions/other/civilian.dm
new file mode 100644
index 000000000000..6587a82a54d6
--- /dev/null
+++ b/code/datums/paygrades/factions/other/civilian.dm
@@ -0,0 +1,52 @@
+/datum/paygrade/civilian
+ name = "Civilian Paygrade"
+ pay_multiplier = 0.5 // civvies are poor
+
+/datum/paygrade/civilian/civilian
+ paygrade = PAY_SHORT_CIV
+ name = "Civilian"
+ prefix = "C"
+
+/datum/paygrade/civilian/nurse
+ paygrade = PAY_SHORT_CNUR
+ name = "Nurse"
+ prefix = "Nrs."
+
+/datum/paygrade/civilian/doctor
+ paygrade = PAY_SHORT_CDOC
+ name = "Doctor"
+ prefix = "Dr."
+ pay_multiplier = 0.75
+
+/datum/paygrade/civilian/professor
+ paygrade = PAY_SHORT_CCMO
+ name = "Professor"
+ prefix = "Prof."
+ pay_multiplier = 1
+
+/datum/paygrade/civillian/representative
+ paygrade = PAY_SHORT_CREP
+ name = "Representative"
+ prefix = "Rep."
+ pay_multiplier = 1
+
+/datum/paygrade/civillian/officer
+ paygrade = PAY_SHORT_CPO
+ name = "Officer"
+ prefix = "Off."
+ pay_multiplier = 0.66
+
+/datum/paygrade/civillian/officer/senior
+ paygrade = PAY_SHORT_CSPO
+ name = "Senior Officer"
+ prefix = "Sr. Off."
+ pay_multiplier = 0.8
+
+/datum/paygrade/civilian/rebel
+ paygrade = PAY_SHORT_REB
+ name = "Rebel"
+
+/datum/paygrade/civilian/rebel/leader
+ paygrade = PAY_SHORT_REBC
+ name = "Rebel Commander"
+ prefix = "CMDR."
diff --git a/code/datums/paygrades/factions/other/cmb.dm b/code/datums/paygrades/factions/other/cmb.dm
index a4b656d8692d..eeeb061ea335 100644
--- a/code/datums/paygrades/factions/other/cmb.dm
+++ b/code/datums/paygrades/factions/other/cmb.dm
@@ -3,78 +3,29 @@
pay_multiplier = 1.4 // Government work. Nice benefits.
/datum/paygrade/cmb/standard
- paygrade = "GS-9"
+ paygrade = PAY_SHORT_CMBD
name = "CMB Deputy"
prefix = "Dep."
/datum/paygrade/cmb/leader
- paygrade = "GS-13"
+ paygrade = PAY_SHORT_CMBM
name = "CMB Marshal"
prefix = "Marshal"
/datum/paygrade/cmb/syn
- paygrade = "GS-C.9"
+ paygrade = PAY_SHORT_CMBS
name = "CMB Investigative Synthetic"
-/datum/paygrade/cmb/liaison
- paygrade = "GS-6"
+/datum/paygrade/cmb/icc
+ paygrade = PAY_SHORT_ICCA
+ name = "Interstellar Commerce Commission Agent"
+ prefix = "Agent"
+
+/datum/paygrade/cmb/icc/liaison
+ paygrade = PAY_SHORT_ICCL
name = "Interstellar Commerce Commission Corporate Liaison"
prefix = "Exec."
/datum/paygrade/cmb/observer
- paygrade = "GS-3"
+ paygrade = PAY_SHORT_IHRO
name = "Interstellar Human Rights Observer"
-/datum/paygrade/marine
- name = "Marine Paygrade"
- rank_pin = /obj/item/clothing/accessory/ranks/marine
- pay_multiplier = 1
-
-// ENLISTED PAYGRADES
-
-/datum/paygrade/marine/e1
- paygrade = "ME1"
- name = "Private"
- prefix = "PVT"
- rank_pin = /obj/item/clothing/accessory/ranks/marine/e1
- ranking = 0
- pay_multiplier = 0.8
-
-/datum/paygrade/marine/e2
- paygrade = "ME2"
- name = "Private First Class"
- prefix = "PFC"
- rank_pin = /obj/item/clothing/accessory/ranks/marine/e2
- ranking = 1
- pay_multiplier = 1 // the default.
-
-/datum/paygrade/marine/e3
- paygrade = "ME3"
- name = "Lance Corporal"
- prefix = "LCpl"
- rank_pin = /obj/item/clothing/accessory/ranks/marine/e3
- ranking = 2
- pay_multiplier = 1.4
-
-/datum/paygrade/marine/e4
- paygrade = "ME4"
- name = "Corporal"
- prefix = "Cpl"
- rank_pin = /obj/item/clothing/accessory/ranks/marine/e4
- ranking = 3
- pay_multiplier = 1.6
-
-/datum/paygrade/marine/e5
- paygrade = "ME5"
- name = "Sergeant"
- prefix = "Sgt"
- rank_pin = /obj/item/clothing/accessory/ranks/marine/e5
- ranking = 4
- pay_multiplier = 1.8
-
-/datum/paygrade/marine/e6
- paygrade = "ME6"
- name = "Staff Sergeant"
- prefix = "SSgt"
- rank_pin = /obj/item/clothing/accessory/ranks/marine/e6
- ranking = 5
- pay_multiplier = 2
diff --git a/code/datums/paygrades/factions/other/dutch_dozen.dm b/code/datums/paygrades/factions/other/dutch_dozen.dm
index 9b8bd7e4f8c4..8877bd11afbb 100644
--- a/code/datums/paygrades/factions/other/dutch_dozen.dm
+++ b/code/datums/paygrades/factions/other/dutch_dozen.dm
@@ -1,33 +1,33 @@
/datum/paygrade/dutch
name = "Dutch Paygrade"
pay_multiplier = 5
+ fprefix = "DTC."
/datum/paygrade/dutch/standard
- paygrade = "DTC"
+ paygrade = PAY_SHORT_DTC
name = "Dutch's Dozen Standard Mercenary"
- prefix = "DTC."
/datum/paygrade/dutch/medic
- paygrade = "DTCM"
+ paygrade = PAY_SHORT_DTCM
name = "Dutch's Dozen Medic"
- prefix = "DTC MED."
+ prefix = "MED."
pay_multiplier = 6
/datum/paygrade/dutch/specialist_flamer
- paygrade = "DTCF"
+ paygrade = PAY_SHORT_DTCF
name = "Dutch's Dozen Flamethrower Specialist"
- prefix = "DTC SPC."
+ prefix = "SPC."
pay_multiplier = 6
/datum/paygrade/dutch/specialist_minigunner
- paygrade = "DTCMG"
- name = "Dutch's Dozen Medic"
- prefix = "DTC SPC."
+ paygrade = PAY_SHORT_DTCMG
+ name = "Dutch's Dozen Machinegunner"
+ prefix = "SPC."
pay_multiplier = 6
/datum/paygrade/dutch/arnold
- paygrade = "ARN"
- name = "Arnold"
- prefix = "DTC LDR."
+ paygrade = PAY_SHORT_DTCA
+ name = "Major"
+ prefix = "LDR."
pay_multiplier = 9
diff --git a/code/datums/paygrades/factions/other/misc.dm b/code/datums/paygrades/factions/other/misc.dm
index 30865228d3af..04e522580b50 100644
--- a/code/datums/paygrades/factions/other/misc.dm
+++ b/code/datums/paygrades/factions/other/misc.dm
@@ -1,9 +1,9 @@
-/datum/paygrade/misc/operator
+/datum/paygrade/misc/operative
name = "Operative"
- paygrade = "O"
+ paygrade = PAY_SHORT_OPR
pay_multiplier = 1 //????
/datum/paygrade/misc/synth
name = "Synthetic"
- paygrade = "SYN"
+ paygrade = PAY_SHORT_SYN
pay_multiplier = 1
diff --git a/code/datums/paygrades/factions/upp/upp.dm b/code/datums/paygrades/factions/upp/upp.dm
index a1363383ad55..8670f99269dc 100644
--- a/code/datums/paygrades/factions/upp/upp.dm
+++ b/code/datums/paygrades/factions/upp/upp.dm
@@ -5,115 +5,115 @@
//UPP Enlisted
/datum/paygrade/upp/ue0
- paygrade = "UE0"
+ paygrade = PAY_SHORT_UEC
name = "Conscript"
pay_multiplier = 0.05
/datum/paygrade/upp/ue1
- paygrade = "UE1"
+ paygrade = PAY_SHORT_UE1
name = "Private"
prefix = "PVT."
/datum/paygrade/upp/ue2
- paygrade = "UE2"
+ paygrade = PAY_SHORT_UE2
name = "Private First Class"
prefix = "PFC."
pay_multiplier = 0.2
/datum/paygrade/upp/ue3
- paygrade = "UE3"
+ paygrade = PAY_SHORT_UE3
name = "Korporal"
prefix = "Kpl."
pay_multiplier = 0.3
/datum/paygrade/upp/ue4
- paygrade = "UE4"
+ paygrade = PAY_SHORT_UE4
name = "Junior Serzhant"
prefix = "JrSzh."
pay_multiplier = 0.5
/datum/paygrade/upp/ue5
- paygrade = "UE5"
+ paygrade = PAY_SHORT_UE5
name = "Serzhant"
prefix = "Szh."
pay_multiplier = 0.7
/datum/paygrade/upp/ue6
- paygrade = "UE6"
+ paygrade = PAY_SHORT_UE6
name = "Master Serzhant"
prefix = "MSzh."
pay_multiplier = 0.9
//UPP Commandos
/datum/paygrade/upp/uc1
- paygrade = "UC1"
+ paygrade = PAY_SHORT_UC1
name = "Junior Kommando"
prefix = "JKdo."
pay_multiplier = 1.5
/datum/paygrade/upp/uc2
- paygrade = "UC2"
+ paygrade = PAY_SHORT_UC2
name = "2nd Kommando"
prefix = "2ndKdo."
pay_multiplier = 2
/datum/paygrade/upp/uc3
- paygrade = "UC3"
+ paygrade = PAY_SHORT_UC3
name = "1st Kommando"
prefix = "1stKdo."
pay_multiplier = 2.5
//UPP Officers
/datum/paygrade/upp/uo1
- paygrade = "UO1"
+ paygrade = PAY_SHORT_UO1
name = "Leytenant"
prefix = "Lt."
pay_multiplier = 1.25
/datum/paygrade/upp/uo2
- paygrade = "UO2"
+ paygrade = PAY_SHORT_UO2
name = "Senior Leytenant"
prefix = "Sr. LT."
pay_multiplier = 1.5
/datum/paygrade/upp/uo3
- paygrade = "UO3"
+ paygrade = PAY_SHORT_UO3
name = "Kapitan"
prefix = "Kpt."
pay_multiplier = 2
/datum/paygrade/upp/uo4
- paygrade = "UO4"
- name = "Mayjor."
+ paygrade = PAY_SHORT_UO4
+ name = "Mayjor"
prefix = "May."
pay_multiplier = 2.5
/datum/paygrade/upp/uo5
- paygrade = "UO5"
+ paygrade = PAY_SHORT_UO5
name = "Leytenant Kolonel"
prefix = "Lt. Kol."
pay_multiplier = 3
/datum/paygrade/upp/uo6
- paygrade = "UO6"
+ paygrade = PAY_SHORT_UO6
name = "Kolonel"
prefix = "Kol."
pay_multiplier = 4
/datum/paygrade/upp/uo7
- paygrade = "UO7"
+ paygrade = PAY_SHORT_UO7
name = "Mayjor General"
prefix = "May. Gen."
pay_multiplier = 5
/datum/paygrade/upp/uo8
- paygrade = "UO8"
+ paygrade = PAY_SHORT_UO8
name = "Leytenant General"
prefix = "Lt. Gen."
pay_multiplier = 6
/datum/paygrade/upp/uo9
- paygrade = "UO9"
+ paygrade = PAY_SHORT_UO9
name = "Army General"
prefix = "Gen."
pay_multiplier = 7
diff --git a/code/datums/paygrades/factions/uscm/marine.dm b/code/datums/paygrades/factions/uscm/marine.dm
index e351311e65ee..7d315f364025 100644
--- a/code/datums/paygrades/factions/uscm/marine.dm
+++ b/code/datums/paygrades/factions/uscm/marine.dm
@@ -6,7 +6,7 @@
// ENLISTED PAYGRADES
/datum/paygrade/marine/e1
- paygrade = "ME1"
+ paygrade = PAY_SHORT_ME1
name = "Private"
prefix = "PVT"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e1
@@ -14,7 +14,7 @@
pay_multiplier = 1.6
/datum/paygrade/marine/e2
- paygrade = "ME2"
+ paygrade = PAY_SHORT_ME2
name = "Private First Class"
prefix = "PFC"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e2
@@ -22,7 +22,7 @@
pay_multiplier = 1.7
/datum/paygrade/marine/e3
- paygrade = "ME3"
+ paygrade = PAY_SHORT_ME3
name = "Lance Corporal"
prefix = "LCpl"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e3
@@ -30,7 +30,7 @@
pay_multiplier = 1.9
/datum/paygrade/marine/e4
- paygrade = "ME4"
+ paygrade = PAY_SHORT_ME4
name = "Corporal"
prefix = "Cpl"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e4
@@ -38,7 +38,7 @@
pay_multiplier = 2.1
/datum/paygrade/marine/e5
- paygrade = "ME5"
+ paygrade = PAY_SHORT_ME5
name = "Sergeant"
prefix = "Sgt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e5
@@ -46,7 +46,7 @@
pay_multiplier = 2.2
/datum/paygrade/marine/e6
- paygrade = "ME6"
+ paygrade = PAY_SHORT_ME6
name = "Staff Sergeant"
prefix = "SSgt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e6
@@ -54,7 +54,7 @@
pay_multiplier = 2.4
/datum/paygrade/marine/e7
- paygrade = "ME7"
+ paygrade = PAY_SHORT_ME7
name = "Gunnery Sergeant"
prefix = "GySgt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e7
@@ -62,7 +62,7 @@
pay_multiplier = 2.75
/datum/paygrade/marine/e8
- paygrade = "ME8"
+ paygrade = PAY_SHORT_ME8
name = "Master Sergeant"
prefix = "MSgt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e8
@@ -70,7 +70,7 @@
pay_multiplier = 2.75
/datum/paygrade/marine/e8e
- paygrade = "ME8E"
+ paygrade = PAY_SHORT_ME8E
name = "First Sergeant"
prefix = "1Sgt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e8e
@@ -78,7 +78,7 @@
pay_multiplier = 2.75
/datum/paygrade/marine/e9
- paygrade = "ME9"
+ paygrade = PAY_SHORT_ME9
name = "Master Gunnery Sergeant"
prefix = "MGySgt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e9
@@ -86,7 +86,7 @@
pay_multiplier = 3
/datum/paygrade/marine/e9e
- paygrade = "ME9E"
+ paygrade = PAY_SHORT_ME9E
name = "Sergeant Major"
prefix = "SgtMaj"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e9e
@@ -94,7 +94,7 @@
pay_multiplier = 3
/datum/paygrade/marine/e9c
- paygrade = "ME9C"
+ paygrade = PAY_SHORT_ME9C
name = "Sergeant Major of the Colonial Marine Corps"
prefix = "SMCMC"
rank_pin = /obj/item/clothing/accessory/ranks/marine/e9c
@@ -104,7 +104,7 @@
// COMMISSIONED PAYGRADES
/datum/paygrade/marine/o1
- paygrade = "MO1"
+ paygrade = PAY_SHORT_MO1
name = "Second Lieutenant"
prefix = "2ndLt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o1
@@ -112,7 +112,7 @@
pay_multiplier = 3
/datum/paygrade/marine/o2
- paygrade = "MO2"
+ paygrade = PAY_SHORT_MO2
name = "First Lieutenant"
prefix = "1stLt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o2
@@ -120,7 +120,7 @@
pay_multiplier = 3.2
/datum/paygrade/marine/o3
- paygrade = "MO3"
+ paygrade = PAY_SHORT_MO3
name = "Captain"
prefix = "Capt"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o3
@@ -128,7 +128,7 @@
pay_multiplier = 4
/datum/paygrade/marine/o4
- paygrade = "MO4"
+ paygrade = PAY_SHORT_MO4
name = "Major"
prefix = "Maj"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o4
@@ -136,7 +136,7 @@
pay_multiplier = 4
/datum/paygrade/marine/o5
- paygrade = "MO5"
+ paygrade = PAY_SHORT_MO5
name = "Lieutenant Colonel"
prefix = "LtCol"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o5
@@ -145,7 +145,7 @@
//Platoon Commander
/datum/paygrade/marine/o6
- paygrade = "MO6"
+ paygrade = PAY_SHORT_MO6
name = "Colonel"
prefix = "Col"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o6
@@ -153,7 +153,7 @@
pay_multiplier = 4.4
/datum/paygrade/marine/o6e
- paygrade = "MO6E"
+ paygrade = PAY_SHORT_MO6E
name = "Senior Colonel"
prefix = "Snr Col."
rank_pin = /obj/item/clothing/accessory/ranks/marine/o6e
@@ -161,7 +161,7 @@
pay_multiplier = 4.6
/datum/paygrade/marine/o6c
- paygrade = "MO6C"
+ paygrade = PAY_SHORT_MO6C
name = "Division Colonel"
prefix = "Div Col."
rank_pin = /obj/item/clothing/accessory/ranks/marine/o6c
@@ -170,7 +170,7 @@
//High Command
/datum/paygrade/marine/o7
- paygrade = "MO7"
+ paygrade = PAY_SHORT_MO7
name = "Brigadier General"
prefix = "BGen"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o7
@@ -178,7 +178,7 @@
pay_multiplier = 6
/datum/paygrade/marine/o8
- paygrade = "MO8"
+ paygrade = PAY_SHORT_MO8
name = "Major General"
prefix = "MajGen"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o8
@@ -186,7 +186,7 @@
pay_multiplier = 6.2
/datum/paygrade/marine/o9
- paygrade = "MO9"
+ paygrade = PAY_SHORT_MO9
name = "Lieutenant General"
prefix = "LtGen"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o9
@@ -194,7 +194,7 @@
pay_multiplier = 6.4
/datum/paygrade/marine/o10
- paygrade = "MO10"
+ paygrade = PAY_SHORT_MO10
name = "General"
prefix = "Gen"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o10
@@ -202,7 +202,7 @@
pay_multiplier = 6.6
/datum/paygrade/marine/o10c
- paygrade = "MO10C"
+ paygrade = PAY_SHORT_MO10C
name = "Assistant Commandant of the Marine Corps"
prefix = "ACMC"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o10c
@@ -210,7 +210,7 @@
pay_multiplier = 6.8
/datum/paygrade/marine/o10s
- paygrade = "MO10S"
+ paygrade = PAY_SHORT_MO10S
name = "Commandant of the Marine Corps"
prefix = "CMC"
rank_pin = /obj/item/clothing/accessory/ranks/marine/o10c
diff --git a/code/datums/paygrades/factions/uscm/navy.dm b/code/datums/paygrades/factions/uscm/navy.dm
index 7e648a75bac2..9e22c72fe566 100644
--- a/code/datums/paygrades/factions/uscm/navy.dm
+++ b/code/datums/paygrades/factions/uscm/navy.dm
@@ -6,77 +6,77 @@
// ENLISTED PAYGRADES
/datum/paygrade/navy/e1
- paygrade = "NE1"
+ paygrade = PAY_SHORT_NE1
name = "Seaman Recruit"
prefix = "SR."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e1
ranking = 0
/datum/paygrade/navy/e2
- paygrade = "NE2"
+ paygrade = PAY_SHORT_NE2
name = "Seaman Apprentice"
prefix = "SA."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e2
ranking = 1
/datum/paygrade/navy/e3
- paygrade = "NE3"
+ paygrade = PAY_SHORT_NE3
name = "Seaman"
prefix = "SN."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e3
ranking = 2
/datum/paygrade/navy/e4
- paygrade = "NE4"
+ paygrade = PAY_SHORT_NE4
name = "Petty Officer 3rd Class"
prefix = "PO1."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e4
ranking = 3
/datum/paygrade/navy/e5
- paygrade = "NE5"
+ paygrade = PAY_SHORT_NE5
name = "Petty Officer 2nd Class"
prefix = "PO2."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e5
ranking = 4
/datum/paygrade/navy/e6
- paygrade = "NE6"
+ paygrade = PAY_SHORT_NE6
name = "Petty Officer 1st Class"
prefix = "PO1."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e6
ranking = 5
/datum/paygrade/navy/e7
- paygrade = "NE7"
+ paygrade = PAY_SHORT_NE7
name = "Chief Petty Officer"
prefix = "CPO."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e7
ranking = 6
/datum/paygrade/navy/e8
- paygrade = "NE8"
+ paygrade = PAY_SHORT_NE8
name = "Senior Chief Petty Officer"
prefix = "SCPO."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e8
ranking = 7
/datum/paygrade/navy/e8c
- paygrade = "NE8C"
+ paygrade = PAY_SHORT_NE8C
name = "Command Senior Chief Petty Officer"
prefix = "CSCPO."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e8c
ranking = 8
/datum/paygrade/navy/e9
- paygrade = "NE9"
+ paygrade = PAY_SHORT_NE9
name = "Master Chief Petty Officer"
prefix = "MCPO."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e9
ranking = 9
/datum/paygrade/navy/e9c
- paygrade = "NE9C"
+ paygrade = PAY_SHORT_NE9C
name = "Command Master Chief Petty Officer"
prefix = "CMCPO."
rank_pin = /obj/item/clothing/accessory/ranks/navy/e9c
@@ -85,91 +85,91 @@
// COMMISSIONED PAYGRADES
/datum/paygrade/navy/o1
- paygrade = "NO1"
+ paygrade = PAY_SHORT_NO1
name = "Ensign"
prefix = "ENS."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o1
ranking = 11
/datum/paygrade/navy/o2
- paygrade = "NO2"
+ paygrade = PAY_SHORT_NO2
name = "Lieutenant Junior Grade"
prefix = "LTJG."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o2
ranking = 12
/datum/paygrade/navy/o3
- paygrade = "NO3"
+ paygrade = PAY_SHORT_NO3
name = "Lieutenant"
prefix = "LT."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o3
ranking = 13
/datum/paygrade/navy/o4
- paygrade = "NO4"
+ paygrade = PAY_SHORT_NO4
name = "Lieutenant Commander"
prefix = "LCDR."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o4
ranking = 14
/datum/paygrade/navy/o5
- paygrade = "NO5"
+ paygrade = PAY_SHORT_NO5
name = "Commander"
prefix = "CDR."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o5
ranking = 15
/datum/paygrade/navy/o6
- paygrade = "NO6"
+ paygrade = PAY_SHORT_NO6
name = "Captain"
prefix = "CAPT."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o6
ranking = 16
/datum/paygrade/navy/o6e
- paygrade = "NO6E"
+ paygrade = PAY_SHORT_NO6E
name = "Commodore"
prefix = "CDRE."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o6e
ranking = 17
/datum/paygrade/navy/o6c
- paygrade = "NO6C"
+ paygrade = PAY_SHORT_NO6C
name = "Senior Commodore"
prefix = "Snr CDRE."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o6e
ranking = 18
/datum/paygrade/navy/o7
- paygrade = "NO7"
+ paygrade = PAY_SHORT_NO7
name = "Rear Admiral (Lower Half)"
prefix = "RDML."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o7
ranking = 19
/datum/paygrade/navy/o8
- paygrade = "NO8"
+ paygrade = PAY_SHORT_NO8
name = "Rear Admiral (Upper Half)"
prefix = "RADM."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o8
ranking = 20
/datum/paygrade/navy/o9
- paygrade = "NO9"
+ paygrade = PAY_SHORT_NO9
name = "Vice Admiral"
prefix = "VADM."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o9
ranking = 21
/datum/paygrade/navy/o10
- paygrade = "NO10"
+ paygrade = PAY_SHORT_NO10
name = "Admiral"
prefix = "ADM."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o10
ranking = 22
/datum/paygrade/navy/o10c
- paygrade = "NO10C"
+ paygrade = PAY_SHORT_NO10C
name = "Chief of Naval Operations"
prefix = "CNO."
rank_pin = /obj/item/clothing/accessory/ranks/navy/o10c
diff --git a/code/datums/paygrades/factions/uscm/provost.dm b/code/datums/paygrades/factions/uscm/provost.dm
index b27c8f7f721f..e378bd7beb61 100644
--- a/code/datums/paygrades/factions/uscm/provost.dm
+++ b/code/datums/paygrades/factions/uscm/provost.dm
@@ -2,44 +2,23 @@
name = "Provost Paygrade"
pay_multiplier = 2
-/datum/paygrade/provost/officer
- paygrade = "PvE7"
- name = "Chief Petty Officer"
- prefix = "CPO."
- rank_pin = /obj/item/clothing/accessory/ranks/navy/e7/pvst
-
-/datum/paygrade/provost/enforcer
- paygrade = "PvE8"
- name = "Senior Chief Petty Officer"
- prefix = "SCPO."
- rank_pin = /obj/item/clothing/accessory/ranks/navy/e8/pvst
-
-/datum/paygrade/provost/tml
- paygrade = "PvE9"
- name = "Master Chief Petty Officer"
- prefix = "MCPO."
- rank_pin = /obj/item/clothing/accessory/ranks/navy/e9/pvst
-
/datum/paygrade/provost/inspector
- paygrade = "PvI"
- name = "Inspector"
+ paygrade = PAY_SHORT_PVI
+ name = "Provost Inspector"
prefix = "Insp."
rank_pin = /obj/item/clothing/accessory/ranks/special/insp
/datum/paygrade/provost/marshal
- paygrade = "PvO8"
- name = "Rear Admiral"
- prefix = "RADM."
- rank_pin = /obj/item/clothing/accessory/ranks/navy/o8/pvst
+ paygrade = PAY_SHORT_PVM
+ name = "Provost Marshal"
+ prefix = "Marshal"
/datum/paygrade/provost/sectormarshal
- paygrade = "PvO9"
- name = "Vice Admiral"
- prefix = "VADM."
- rank_pin = /obj/item/clothing/accessory/ranks/navy/o9/pvst
+ paygrade = PAY_SHORT_PVSM
+ name = "Provost Sector Marshal"
+ prefix = "S. Marshal"
/datum/paygrade/provost/chiefmarshal
- paygrade = "PvCM"
+ paygrade = PAY_SHORT_PVCM
name = "Provost Chief Marshal"
- prefix = "PCM."
- rank_pin = /obj/item/clothing/accessory/ranks/navy/o10c/pvst
+ prefix = "Chief Marshal"
diff --git a/code/datums/paygrades/factions/wy/goons.dm b/code/datums/paygrades/factions/wy/goons.dm
deleted file mode 100644
index 679bb42e7f76..000000000000
--- a/code/datums/paygrades/factions/wy/goons.dm
+++ /dev/null
@@ -1,15 +0,0 @@
-/datum/paygrade/goon
- name = "WY Goon Paygrade"
- pay_multiplier = 0.66 // better than colonists. barely.
-
-//Standard PMCs
-/datum/paygrade/goon/standard
- paygrade = "WEY-GOON"
- name = "Officer"
- prefix = "Off."
-
-/datum/paygrade/goon/lead
- paygrade = "WEY-GOON-L"
- name = "Senior Officer"
- prefix = "Sr. Off."
- pay_multiplier = 0.8
diff --git a/code/datums/paygrades/factions/wy/wy.dm b/code/datums/paygrades/factions/wy/wy.dm
index 03d54cbd3cda..58ec9eb3f197 100644
--- a/code/datums/paygrades/factions/wy/wy.dm
+++ b/code/datums/paygrades/factions/wy/wy.dm
@@ -3,69 +3,69 @@
pay_multiplier = 1
/datum/paygrade/wy_ranks/wyc1
- paygrade = "WYC1"
+ paygrade = PAY_SHORT_WYC1
name = "Trainee"
prefix = "Trn."
ranking = 0
/datum/paygrade/wy_ranks/wyc2
- paygrade = "WYC2"
+ paygrade = PAY_SHORT_WYC2
name = "Junior Executive"
prefix = "Jr. Exec."
ranking = 1
pay_multiplier = 2
/datum/paygrade/wy_ranks/wyc3
- paygrade = "WYC3"
+ paygrade = PAY_SHORT_WYC3
name = "Executive"
prefix = "Exec."
ranking = 2
pay_multiplier = 3
/datum/paygrade/wy_ranks/wyc4
- paygrade = "WYC4"
+ paygrade = PAY_SHORT_WYC4
name = "Senior Executive"
prefix = "Sr. Exec."
ranking = 3
pay_multiplier = 4
/datum/paygrade/wy_ranks/wyc5
- paygrade = "WYC5"
+ paygrade = PAY_SHORT_WYC5
name = "Executive Specialist"
prefix = "Exec. Spc."
ranking = 4
pay_multiplier = 5
/datum/paygrade/wy_ranks/wyc6
- paygrade = "WYC6"
+ paygrade = PAY_SHORT_WYC6
name = "Executive Supervisor"
prefix = "Exec. Suvp."
ranking = 5
pay_multiplier = 6
/datum/paygrade/wy_ranks/wyc7
- paygrade = "WYC7"
+ paygrade = PAY_SHORT_WYC7
name = "Assistant Manager"
prefix = "Assis. Mng."
ranking = 6
pay_multiplier = 7
/datum/paygrade/wy_ranks/wyc8
- paygrade = "WYC8"
+ paygrade = PAY_SHORT_WYC8
name = "Division Manager"
prefix = "Div. Mng."
ranking = 7
pay_multiplier = 8
/datum/paygrade/wy_ranks/wyc9
- paygrade = "WYC9"
+ paygrade = PAY_SHORT_WYC9
name = "Chief Executive"
prefix = "Chief. Exec."
ranking = 8
pay_multiplier = 9
/datum/paygrade/wy_ranks/wyc10
- paygrade = "WYC10"
+ paygrade = PAY_SHORT_WYC10
name = "Director"
prefix = "Director"
ranking = 9
diff --git a/code/datums/paygrades/paygrade.dm b/code/datums/paygrades/paygrade.dm
index bb0a3aa84bfa..cc336319278a 100644
--- a/code/datums/paygrades/paygrade.dm
+++ b/code/datums/paygrades/paygrade.dm
@@ -26,36 +26,36 @@ GLOBAL_LIST_INIT_TYPED(paygrades, /datum/paygrade, setup_paygrades())
GLOBAL_LIST_INIT(highcom_paygrades, list(
"PvI",
- "NO7",
- "MO7",
- "NO8",
- "MO8",
- "NO9",
- "MO9",
- "NO10",
- "MO10",
- "NO10C",
- "MO10C",
+ PAY_SHORT_NO7,
+ PAY_SHORT_MO7,
+ PAY_SHORT_NO8,
+ PAY_SHORT_MO8,
+ PAY_SHORT_NO9,
+ PAY_SHORT_MO9,
+ PAY_SHORT_NO10,
+ PAY_SHORT_MO10,
+ PAY_SHORT_NO10C,
+ PAY_SHORT_MO10C,
"PvO8",
"PvO9",
"PvCM"
))
GLOBAL_LIST_INIT(co_paygrades, list(
- "NO6",
- "NO6E",
- "NO6C",
- "NO5",
- "NO4",
- "MO6",
- "MO6E",
- "MO6C",
- "MO5",
- "MO4"
+ PAY_SHORT_NO6,
+ PAY_SHORT_NO6E,
+ PAY_SHORT_NO6C,
+ PAY_SHORT_NO5,
+ PAY_SHORT_NO4,
+ PAY_SHORT_MO6,
+ PAY_SHORT_MO6E,
+ PAY_SHORT_MO6C,
+ PAY_SHORT_MO5,
+ PAY_SHORT_MO4
))
GLOBAL_LIST_INIT(wy_paygrades, list(
- "WYC8",
- "WYC9",
- "WYC10"
+ PAY_SHORT_WYC8,
+ PAY_SHORT_WYC9,
+ PAY_SHORT_WYC10
))
diff --git a/code/datums/quadtree.dm b/code/datums/quadtree.dm
index d00f202cc15c..2b0360152997 100644
--- a/code/datums/quadtree.dm
+++ b/code/datums/quadtree.dm
@@ -10,14 +10,14 @@
var/z_level
/// Don't divide further when truthy
- var/final
+ var/final_divide = FALSE
/datum/quadtree/New(datum/shape/rectangle/rect, z)
. = ..()
boundary = rect
z_level = z
if(boundary.width <= QUADTREE_BOUNDARY_MINIMUM_WIDTH || boundary.height <= QUADTREE_BOUNDARY_MINIMUM_HEIGHT)
- final = TRUE
+ final_divide = TRUE
// By design i guess, discarding branch discards rest with BYOND soft-GCing
// There should never be anything else but SSquadtree referencing quadtrees,
@@ -103,7 +103,7 @@
player_coords = list(p_coords)
return TRUE
- else if(!final && player_coords.len >= QUADTREE_CAPACITY)
+ else if(!final_divide && player_coords.len >= QUADTREE_CAPACITY)
if(!is_divided)
subdivide()
if(nw_branch.insert_player(p_coords))
diff --git a/code/datums/shuttles.dm b/code/datums/shuttles.dm
index eb1fd2341920..98bcf296755b 100644
--- a/code/datums/shuttles.dm
+++ b/code/datums/shuttles.dm
@@ -100,6 +100,18 @@
if(movement_force)
M.movement_force = movement_force.Copy()
+
/datum/map_template/shuttle/vehicle
shuttle_id = MOBILE_SHUTTLE_VEHICLE_ELEVATOR
name = "Vehicle Elevator"
+
+/datum/map_template/shuttle/trijent_elevator
+ name = "Trijent Elevator"
+ shuttle_id = MOBILE_TRIJENT_ELEVATOR
+ var/elevator_network
+
+/datum/map_template/shuttle/trijent_elevator/A
+ elevator_network = "A"
+
+/datum/map_template/shuttle/trijent_elevator/B
+ elevator_network = "B"
diff --git a/code/datums/skills.dm b/code/datums/skills.dm
deleted file mode 100644
index 9178e6f7a1b1..000000000000
--- a/code/datums/skills.dm
+++ /dev/null
@@ -1,2199 +0,0 @@
-// Individual skill
-/datum/skill
- /// Name of the skill
- var/skill_name = null
- /// used for the view UI
- var/readable_skill_name = null
- /// Level of skill in this... skill
- var/skill_level = 0
- /// the max level this skill can be, used for tgui
- var/max_skill_level = 0
-
-/datum/skill/proc/get_skill_level()
- return skill_level
-
-/datum/skill/proc/set_skill(new_level, mob/owner)
- skill_level = new_level
-
-/datum/skill/proc/is_skilled(req_level, is_explicit = FALSE)
- if(is_explicit)
- return (skill_level == req_level)
- return (skill_level >= req_level)
-
-// Lots of defines here. See #define/skills.dm
-
-/datum/skill/cqc
- skill_name = SKILL_CQC
- readable_skill_name = "CQC"
- skill_level = SKILL_CQC_DEFAULT
- max_skill_level = SKILL_CQC_MAX
-
-/datum/skill/melee_weapons
- skill_name = SKILL_MELEE_WEAPONS
- readable_skill_name = "melee weapons"
- skill_level = SKILL_MELEE_DEFAULT
- max_skill_level = SKILL_MELEE_MAX
-
-/datum/skill/firearms
- skill_name = SKILL_FIREARMS
- skill_level = SKILL_FIREARMS_TRAINED
- max_skill_level = SKILL_FIREARMS_MAX
-
-/datum/skill/spec_weapons
- skill_name = SKILL_SPEC_WEAPONS
- readable_skill_name = "specialist weapons"
- skill_level = SKILL_SPEC_DEFAULT
- max_skill_level = SKILL_SPEC_ALL
-
-/datum/skill/endurance
- skill_name = SKILL_ENDURANCE
- skill_level = SKILL_ENDURANCE_WEAK
- max_skill_level = SKILL_ENDURANCE_MAX
-
-/datum/skill/engineer
- skill_name = SKILL_ENGINEER
- skill_level = SKILL_ENGINEER_DEFAULT
- max_skill_level = SKILL_ENGINEER_MAX
-
-/datum/skill/construction
- skill_name = SKILL_CONSTRUCTION
- skill_level = SKILL_CONSTRUCTION_DEFAULT
- max_skill_level = SKILL_CONSTRUCTION_MAX
-
-/datum/skill/leadership
- skill_name = SKILL_LEADERSHIP
- skill_level = SKILL_LEAD_NOVICE
- max_skill_level = SKILL_LEAD_MAX
-
-/datum/skill/leadership/set_skill(new_level, mob/living/owner)
- ..()
- if(!owner)
- return
-
- if(!ishuman(owner))
- return
-
- // Give/remove issue order actions
- if(is_skilled(SKILL_LEAD_TRAINED))
- ADD_TRAIT(owner, TRAIT_LEADERSHIP, TRAIT_SOURCE_SKILL(skill_name))
- else
- REMOVE_TRAIT(owner, TRAIT_LEADERSHIP, TRAIT_SOURCE_SKILL(skill_name))
-
-/datum/skill/overwatch
- skill_name = SKILL_OVERWATCH
- skill_level = SKILL_OVERWATCH_DEFAULT
- max_skill_level = SKILL_OVERWATCH_MAX
-
-/datum/skill/medical
- skill_name = SKILL_MEDICAL
- skill_level = SKILL_MEDICAL_DEFAULT
- max_skill_level = SKILL_MEDICAL_MAX
-
-/datum/skill/surgery
- skill_name = SKILL_SURGERY
- skill_level = SKILL_SURGERY_DEFAULT
- max_skill_level = SKILL_SURGERY_MAX
-
-/datum/skill/surgery/set_skill(new_level, mob/living/owner)
- ..()
- if(!owner)
- return
-
- if(!ishuman(owner))
- return
-
- // Give/remove surgery toggle action
- var/datum/action/surgery_toggle/surgery_action = locate() in owner.actions
- if(is_skilled(SKILL_SURGERY_NOVICE))
- if(!surgery_action)
- give_action(owner, /datum/action/surgery_toggle)
- else
- surgery_action.update_surgery_skill()
- else
- if(surgery_action)
- surgery_action.remove_from(owner)
-
-/datum/skill/research
- skill_name = SKILL_RESEARCH
- skill_level = SKILL_RESEARCH_DEFAULT
- max_skill_level = SKILL_RESEARCH_MAX
-
-/datum/skill/antag
- skill_name = SKILL_ANTAG
- readable_skill_name = "illegal technology"
- skill_level = SKILL_ANTAG_DEFAULT
- max_skill_level = SKILL_ANTAG_MAX
-
-/datum/skill/pilot
- skill_name = SKILL_PILOT
- skill_level = SKILL_PILOT_DEFAULT
- max_skill_level = SKILL_PILOT_MAX
-
-/datum/skill/navigations
- skill_name = SKILL_NAVIGATIONS
- skill_level = SKILL_NAVIGATIONS_DEFAULT
- max_skill_level = SKILL_NAVIGATIONS_MAX
-
-/datum/skill/police
- skill_name = SKILL_POLICE
- skill_level = SKILL_POLICE_DEFAULT
- max_skill_level = SKILL_POLICE_MAX
-
-/datum/skill/powerloader
- skill_name = SKILL_POWERLOADER
- skill_level = SKILL_POWERLOADER_DEFAULT
- max_skill_level = SKILL_POWERLOADER_MAX
-
-/datum/skill/vehicles
- skill_name = SKILL_VEHICLE
- skill_level = SKILL_VEHICLE_DEFAULT
- max_skill_level = SKILL_VEHICLE_MAX
-
-/datum/skill/jtac
- skill_name = SKILL_JTAC
- readable_skill_name = "JTAC"
- skill_level = SKILL_JTAC_NOVICE
- max_skill_level = SKILL_JTAC_MAX
-
-/datum/skill/execution
- skill_name = SKILL_EXECUTION
- skill_level = SKILL_EXECUTION_DEFAULT
- max_skill_level = SKILL_EXECUTION_MAX
-
-/datum/skill/intel
- skill_name = SKILL_INTEL
- skill_level = SKILL_INTEL_NOVICE
- max_skill_level = SKILL_INTEL_MAX
-
-/datum/skill/domestic
- skill_name = SKILL_DOMESTIC
- skill_level = SKILL_DOMESTIC_NONE
- max_skill_level = SKILL_DOMESTIC_MAX
-
-/datum/skill/fireman
- skill_name = SKILL_FIREMAN
- readable_skill_name = "fireman carrying"
- skill_level = SKILL_FIREMAN_DEFAULT
- max_skill_level = SKILL_FIREMAN_MAX
-
-/// Skill with an extra S at the end is a collection of multiple skills. Basically a skillSET
-/// This is to organize and provide a common interface to the huge heap of skills there are
-/datum/skills
- /// The name of the skillset
- var/name
- // The mob that has this skillset
- var/mob/owner
-
- // List of skill datums.
- // Also, if this is populated when the datum is created, it will set the skill levels automagically
- var/list/skills = list()
- // Same as above, but for children of parents that just add a lil something else
- var/list/additional_skills = list()
-
-/datum/skills/New(mob/skillset_owner)
- owner = skillset_owner
-
- // Setup every single skill
- for(var/skill_type in subtypesof(/datum/skill))
- var/datum/skill/S = new skill_type()
-
- // Fancy hack to convert a list of desired skill levels in each named skill into a skill level in the actual skill datum
- // Lets the skills list be used multipurposely for both storing skill datums and choosing skill levels for different skillsets
- var/predetermined_skill_level = additional_skills[S.skill_name] ? additional_skills[S.skill_name] : skills[S.skill_name]
- skills[S.skill_name] = S
-
- if(!isnull(predetermined_skill_level))
- S.set_skill(predetermined_skill_level, owner)
-
-/datum/skills/Destroy()
- owner = null
- skills = null // Don't need to delete, /datum/skill should softdel
- SStgui.close_uis(src)
- return ..()
-
-// Checks if the given skill is contained in this skillset at all
-/datum/skills/proc/has_skill(skill)
- return isnull(skills[skill])
-
-// Returns the skill DATUM for the given skill
-/datum/skills/proc/get_skill(skill)
- if(!skills)
- return null
- return skills[skill]
-
-// Returns the skill level for the given skill
-/datum/skills/proc/get_skill_level(skill)
- var/datum/skill/S = get_skill(skill)
- if(!S)
- return -1
- if(QDELETED(S))
- return -1
- return S.get_skill_level()
-
-// Sets the skill LEVEL for a given skill
-/datum/skills/proc/set_skill(skill, new_level)
- var/datum/skill/S = skills[skill]
- if(!S)
- return
- return S.set_skill(new_level, owner)
-
-/datum/skills/proc/increment_skill(skill, increment, cap)
- var/datum/skill/S = skills[skill]
- if(!S || skillcheck(owner, skill, cap))
- return
- return S.set_skill(min(cap,S.skill_level+increment), owner)
-
-/datum/skills/proc/decrement_skill(skill, increment)
- var/datum/skill/S = skills[skill]
- if(!S)
- return
- return S.set_skill(max(0,S.skill_level-increment), owner)
-
-// Checks if the skillset is AT LEAST skilled enough to pass a skillcheck for the given skill level
-/datum/skills/proc/is_skilled(skill, req_level, is_explicit = FALSE)
- var/datum/skill/S = get_skill(skill)
- if(QDELETED(S))
- return FALSE
- return S.is_skilled(req_level, is_explicit)
-
-// Adjusts the full skillset to a new type of skillset. Pass the datum type path for the desired skillset
-/datum/skills/proc/set_skillset(skillset_type)
- var/datum/skills/skillset = new skillset_type()
- var/list/skill_levels = initial(skillset.skills)
-
- name = skillset.name
- for(var/skill in skill_levels)
- set_skill(skill, skill_levels[skill])
- qdel(skillset)
-
-/*
----------------------
-CIVILIAN
----------------------
-*/
-
-/datum/skills/civilian
- name = "Civilian"
- skills = list(
- SKILL_CQC = SKILL_CQC_DEFAULT,
- SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
- SKILL_ENDURANCE = SKILL_ENDURANCE_NONE,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- )
-
-/datum/skills/civilian/manager
- name = "Weyland-Yutani Manager" // Semi-competent leader with basic knowledge in most things.
- skills = list(
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- )
-
-/datum/skills/civilian/icc_investigation
- name = "ICC CL - Black Market ERT"
- skills = list(
- SKILL_CQC = SKILL_CQC_DEFAULT,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI, //The ASRS consoles
- SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
- SKILL_POLICE = SKILL_POLICE_SKILLED, //The CMB Tradeband Compliance Device
- )
-
-/datum/skills/civilian/manager/director
- name = "Weyland-Yutani Director"
- skills = list(
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_EXECUTION = SKILL_EXECUTION_TRAINED,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- )
-
-/datum/skills/civilian/survivor
- name = "Survivor"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- )
-
-/datum/skills/civilian/survivor/manager
- name = "Weyland-Yutani Manager"
- skills = list(
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- )
-
-/datum/skills/civilian/survivor/goon
- name = "Survivor Goon"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- )
-
-/datum/skills/civilian/survivor/pmc
- name = "Survivor PMC"
- additional_skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- )
-
-/datum/skills/civilian/survivor/pmc/medic
- name = "Survivor PMC Medic"
- additional_skills = list(
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- )
-
-/datum/skills/civilian/survivor/pmc/engineer
- name = "Survivor PMC Engineer"
- additional_skills = list(
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- )
-
-/datum/skills/civilian/survivor/doctor
- name = "Survivor Doctor"
- additional_skills = list(
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- )
-
-/datum/skills/civilian/survivor/clf
- name = "Survivor CLF"
- additional_skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- )
-
-/datum/skills/civilian/survivor/scientist
- name = "Survivor Scientist"
- additional_skills = list(
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- )
-
-/datum/skills/civilian/survivor/chef
- name = "Survivor Chef"
- additional_skills = list(
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_DOMESTIC = SKILL_DOMESTIC_TRAINED,
- )
-
-/datum/skills/civilian/survivor/miner
- name = "Survivor Miner"
- additional_skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- )
-
-/datum/skills/civilian/survivor/trucker
- name = "Survivor Trucker"
- additional_skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN,
- )
-
-/datum/skills/civilian/survivor/engineer
- name = "Survivor Engineer"
- additional_skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- )
-
-/datum/skills/civilian/survivor/chaplain
- name = "Survivor Chaplain"
- additional_skills = list(
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- )
-
-/datum/skills/civilian/survivor/marshal
- name = "Survivor Marshal"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- )
-
-/datum/skills/civilian/survivor/prisoner
- name = "Survivor Prisoner"
- additional_skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- )
-
-/datum/skills/civilian/survivor/gangleader
- name = "Survivor Gang Leader"
- additional_skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- )
-
-/*
----------------------
-MILITARY SURVIVORS
----------------------
-*/
-//Hardcore survivors with poor equipment and skills, prove you're the best of the best.
-
-/datum/skills/military/survivor/forecon_standard
- name = "Reconnaissance Rifleman"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/military/survivor/forecon_techician
- name = "Reconnaissance Support Technician"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/military/survivor/forecon_marksman
- name = "Reconnaissance Designated Marksman"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SCOUT,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/military/survivor/forecon_smartgunner
- name = "Reconnaissance Smartgunner"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/military/survivor/forecon_sniper
- name = "Reconnaissance Sniper"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SNIPER,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/military/survivor/forecon_squad_leader
- name = "Reconnaissance Squad Leader"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/*
----------------------
-COMMAND STAFF
----------------------
-*/
-
-/datum/skills/general
- name = "General"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, //can BE people
- SKILL_INTEL = SKILL_INTEL_EXPERT
- )
-
-/datum/skills/commander
- name = "Commanding Officer"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, //can BE people
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED //can change ship alt
- )
-
-/datum/skills/XO
- name = "Executive Officer"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI, //to fix CIC apc.
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_POLICE = SKILL_POLICE_FLASH,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED,
- )
-
-/datum/skills/SO
- name = "Staff Officer"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_POLICE = SKILL_POLICE_FLASH,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- )
-
-/datum/skills/SEA
- name = "Senior Enlisted Advisor"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_PILOT = SKILL_PILOT_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- )
-
-/datum/skills/SEA/New(mob/skillset_owner)
- ..()
- give_action(skillset_owner, /datum/action/looc_toggle)
-
-/datum/skills/SEA/Destroy()
- remove_action(owner, /datum/action/looc_toggle)
- return ..()
-
-/datum/skills/CMO
- name = "CMO"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_POLICE = SKILL_POLICE_FLASH,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- )
-
-/datum/skills/CMP
- name = "Chief MP"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- )
-
-/datum/skills/auxiliary_officer
- name = "Auxiliary Support Officer"
- skills = list(
- SKILL_PILOT = SKILL_PILOT_EXPERT,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_POLICE = SKILL_POLICE_FLASH,
- SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- )
-
-/datum/skills/CE
- name = "Chief Engineer"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_POLICE = SKILL_POLICE_FLASH,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED,
- )
-
-/datum/skills/RO
- name = "Requisition Officer"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_POLICE = SKILL_POLICE_FLASH,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- )
-
-/*
----------------------
-MILITARY NONCOMBATANT
----------------------
-*/
-
-/datum/skills/doctor
- name = "Doctor"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- )
-
-/datum/skills/nurse
- name = "Nurse"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- )
-
-/datum/skills/researcher
- name = "Researcher"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- )
-
-/datum/skills/pilot
- name = "Pilot Officer"
- skills = list(
- SKILL_PILOT = SKILL_PILOT_EXPERT,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- )
-
-/datum/skills/crew_chief
- name = "Dropship Crew Chief"
- skills = list(
- SKILL_PILOT = SKILL_PILOT_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- )
-
-/datum/skills/MP
- name = "Military Police"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- )
-
-/datum/skills/MW
- name = "Military Warden"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- )
-
-/datum/skills/provost
- name = "Provost"
- skills = list(
- SKILL_CQC = SKILL_CQC_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- )
-
-/datum/skills/OT
- name = "Ordnance Technician"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- )
-
-/datum/skills/MT
- name = "Maintenance Technician"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_DOMESTIC = SKILL_DOMESTIC_TRAINED,
- )
-
-/datum/skills/mess_technician
- name = "Mess Technician"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, // need to hunt food somehow
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER
- )
-
-/datum/skills/CT
- name = "Cargo Technician"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- )
-
-/*
----------------------
-SYNTHETIC
----------------------
-*/
-
-/datum/skills/synthetic
- name = "Synthetic"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MASTER,
- SKILL_SURGERY = SKILL_SURGERY_EXPERT,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_PILOT = SKILL_PILOT_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_MAX,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER,
- SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED,
- )
-
-/datum/skills/colonial_synthetic
- name = SYNTH_COLONY
- skills = list(
- SKILL_CQC = SKILL_CQC_EXPERT,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_PILOT = SKILL_PILOT_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER,
- )
-
-/datum/skills/working_joe
- name = SYNTH_WORKING_JOE
- skills = list(
- SKILL_CQC = SKILL_CQC_EXPERT,
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER, //So they can fully use the Maintenance Jack
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER,
- )
-
-/datum/skills/infiltrator_synthetic
- name = SYNTH_INFILTRATOR
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MASTER,
- SKILL_SURGERY = SKILL_SURGERY_EXPERT,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_PILOT = SKILL_PILOT_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_MAX,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER,
- SKILL_ANTAG = SKILL_ANTAG_AGENT,
- )
-
-/*
-------------------------------
-United States Colonial Marines
-------------------------------
-*/
-
-/datum/skills/pfc
- name = "Private"
- //same as default
-
-/datum/skills/pfc/crafty
- name = "Crafty Private"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- )
-
-/datum/skills/combat_medic
- name = "Combat Medic"
- skills = list(
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/combat_medic/crafty
- name = "Crafty Combat Medic"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- )
-
-/datum/skills/combat_engineer
- name = "Combat Engineer"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/smartgunner
- name = "Squad Smartgunner"
- skills = list(
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/specialist
- name = "Squad Weapons Specialist"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set.
- SKILL_SPEC_WEAPONS = SKILL_SPEC_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER
- )
-
-/datum/skills/tl
- name = "Fireteam Leader"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- )
-
-/datum/skills/SL
- name = "Squad Leader"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_INTEL = SKILL_INTEL_TRAINED,
- )
-
-/datum/skills/intel
- name = "Intelligence Officer"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- )
-
-/*
--------------------------
-COLONIAL LIBERATION FRONT
--------------------------
-*/
-
-/datum/skills/clf
- name = "CLF Soldier"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/clf/combat_engineer
- name = "CLF Engineer"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/clf/combat_medic
- name = "CLF Medic"
- skills = list(
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/clf/specialist
- name = "CLF Specialist"
- skills = list(
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set.
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_TRAINED
- )
-
-/datum/skills/clf/leader
- name = "CLF Leader"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI, // to use their C4
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI
- )
-
-/datum/skills/clf/commander
- name = "CLF Cell Commander"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
- SKILL_EXECUTION = SKILL_EXECUTION_TRAINED,
- )
-
-/*
------------
-FREELANCERS
------------
-*/
-
-//NOTE: Freelancer training is similar to the USCM's, but with additional construction skills
-
-/datum/skills/freelancer
- name = "Freelancer Private"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- )
-
-/datum/skills/freelancer/combat_medic
- name = "Freelancer Medic"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- )
-
-/datum/skills/freelancer/SL
- name = "Freelancer Leader"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- )
-
-/*
---------------------------
-UNITED PROGRESSIVE PEOPLES
---------------------------
-*/
-
-//NOTE: UPP make up for their subpar gear with extreme training.
-
-/datum/skills/upp
- name = "UPP Private"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_CQC = SKILL_CQC_DEFAULT,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- )
-
-/datum/skills/upp/combat_engineer
- name = "UPP Sapper"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_CQC = SKILL_CQC_DEFAULT,
- SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- )
-
-/datum/skills/upp/combat_medic
- name = "UPP Medic"
- skills = list(
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_CQC = SKILL_CQC_DEFAULT,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- )
-
-/datum/skills/upp/specialist
- name = "UPP Specialist"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- )
-
-/datum/skills/upp/SL
- name = "UPP Squad Leader"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- )
-
-/datum/skills/upp/military_police
- name = "UPP Military Police"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- )
-
-/datum/skills/upp/officer
- name = "UPP Officer"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_POLICE = SKILL_POLICE_FLASH,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- )
-
-/datum/skills/upp/kapitan
- name = "UPP Kapitan"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- )
-
-/datum/skills/upp/commander
- name = "UPP Command Officer"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_EXECUTION = SKILL_EXECUTION_TRAINED,
- )
-/datum/skills/upp/conscript
- name = "UPP Conscript"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- )
-
-/*
-----------------------------
-Private Military Contractors
-----------------------------
-*/
-
-//NOTE: Compared to the USCM, PMCs have additional firearms training, construction skills and policing skills
-
-/datum/skills/pmc
- name = "PMC Private"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- )
-
-/datum/skills/pmc/medic
- name = "PMC Medic"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- )
-
-/datum/skills/pmc/medic/chem
- name = "PMC Medical Investigator"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- )
-
-/datum/skills/pmc/smartgunner
- name = "PMC Smartgunner"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/pmc/specialist
- name = "PMC Specialist"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/pmc/SL
- name = "PMC Leader"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/pmc/SL/chem
- name = "PMC Lead Investigator"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/pmc/tank_crew
- name = "Vehicle Crewman"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- )
-
-/datum/skills/pmc/doctor
- name = "PMC Triage Doctor"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_EXPERT,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, //trained in medicine more than combat
- SKILL_CQC = SKILL_CQC_TRAINED
- )
-
-/datum/skills/pmc/engineer
- name = "PMC Corporate Technician"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- )
-
-/datum/skills/pmc/director
- name = "PMC Site Director"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- SKILL_EXECUTION = SKILL_EXECUTION_TRAINED,
- )
-
-/*
----------------------
-CONTRACTORS
----------------------
-*/
-/datum/skills/contractor
- name = "Contractor Standard"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- )
-
-/datum/skills/contractor/leader
- name = "Contractor Leader"
- skills = list(
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- )
-
-/datum/skills/contractor/medic
- name = "Contractor Medic"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/contractor/engi
- name = "Contractor Engi"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_MAX,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
- )
-
-/datum/skills/contractor/heavy
- name = "Contractor Machinegunner"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- )
-
-/*
----------------------
-COLONIAL MARSHALS
----------------------
-*/
-/datum/skills/cmb
- name = "CMB Deputy"
- skills = list(
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_CQC = SKILL_CQC_EXPERT,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- )
-
-/datum/skills/cmb/leader
- name = "CMB Marshal"
- skills = list(
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_CQC = SKILL_CQC_EXPERT,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_FIREMAN = SKILL_FIREMAN_MASTER,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- )
-
-/datum/skills/synthetic/cmb
- name = "CMB Investigative Synthetic"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, // incase the synth needs to use consoles for investigations or tracking
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED, // Not a medical Synthetic, but operate if absolutely needed.
- SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_PILOT = SKILL_PILOT_TRAINED,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_MAX,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_INTEL = SKILL_INTEL_EXPERT,
- SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER
- )
-
-/datum/skills/military/survivor/upp_private
- name = "UPP Private"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/military/survivor/upp_sapper
- name = "UPP Sapper"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/military/survivor/upp_medic
- name = "UPP Medic"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/military/survivor/upp_spec
- name = "UPP Specialist"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- )
-
-/datum/skills/military/survivor/upp_sl
- name = "UPP Squad Leader"
- skills = list(
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP,
- SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- )
-
-/*
----------------------
-SPEC-OPS
----------------------
-*/
-
-/datum/skills/commando
- name = "Commando"
- skills = list(
- SKILL_CQC = SKILL_CQC_EXPERT,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/commando/medic
- name = "Commando Medic"
- skills = list(
- SKILL_CQC = SKILL_CQC_EXPERT,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/commando/leader
- name = "Commando Leader"
- skills = list(
- SKILL_CQC = SKILL_CQC_EXPERT,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/commando/deathsquad
- name = "Deathsquad"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/commando/deathsquad/leader
- name = "Deathsquad Leader"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/commando/deathsquad/officer
- name = "Deathsquad Officer"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/spy
- name = "Spy"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/ninja
- name = "Ninja"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/*
----------------------
-MISCELLANEOUS
----------------------
-*/
-
-/datum/skills/mercenary
- name = "Mercenary"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/mercenary/elite
- name = "Elite Mercenary"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- )
-
-/datum/skills/mercenary/elite/medic
- name = "Elite Mercenary Medic"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_MEDICAL = SKILL_MEDICAL_MASTER,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_SURGERY = SKILL_SURGERY_TRAINED,
- )
-
-/datum/skills/mercenary/elite/engineer
- name = "Elite Mercenary Engineer"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_PILOT = SKILL_PILOT_EXPERT,
- )
-
-/datum/skills/mercenary/elite/heavy
- name = "Elite Mercenary Heavy"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- )
-
-/datum/skills/mercenary/elite/leader
- name = "Elite Mercenary Leader"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_PILOT = SKILL_PILOT_EXPERT,
- )
-
-/datum/skills/dutchmerc
- name = "Dutch's Dozen Mercenary"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
- )
-
-/datum/skills/dutchmedic
- name = "Dutch's Dozen Medic"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
- )
-
-/datum/skills/tank_crew
- name = "Vehicle Crewman"
- skills = list(
- SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN,
- SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- )
-
-/datum/skills/gladiator
- name = "Gladiator"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
- SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- )
-
-/datum/skills/gladiator/champion
- name = "Gladiator Champion"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- )
-
-/datum/skills/gladiator/champion/leader
- name = "Gladiator Leader"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER, //Spartacus!
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- )
-
-/datum/skills/yautja/warrior
- name = "Yautja Warrior"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_MAX,
- SKILL_ANTAG = SKILL_ANTAG_HUNTER,
- )
-
-/datum/skills/dutch
- name = "Dutch"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_MAX,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_JTAC = SKILL_JTAC_EXPERT,
- SKILL_ANTAG = SKILL_ANTAG_HUNTER,
- )
-
-/datum/skills/cultist_leader
- name = "Cultist Leader"
- skills = list(
- SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
- SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_JTAC = SKILL_JTAC_MASTER,
- )
-
-/datum/skills/souto
- name = "Souto Man"
- skills = list(
- SKILL_CQC = SKILL_CQC_MASTER,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- )
-
-/datum/skills/everything //max it out
- name = "Ultra"
- skills = list(
- SKILL_CQC = SKILL_CQC_MAX,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_MAX,
- SKILL_FIREARMS = SKILL_FIREARMS_MAX,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
- SKILL_ENGINEER = SKILL_ENGINEER_MAX,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX,
- SKILL_LEADERSHIP = SKILL_LEAD_MAX,
- SKILL_OVERWATCH = SKILL_OVERWATCH_MAX,
- SKILL_MEDICAL = SKILL_MEDICAL_MAX,
- SKILL_SURGERY = SKILL_SURGERY_MAX,
- SKILL_RESEARCH = SKILL_RESEARCH_MAX,
- SKILL_ANTAG = SKILL_ANTAG_MAX,
- SKILL_PILOT = SKILL_PILOT_MAX,
- SKILL_POLICE = SKILL_POLICE_MAX,
- SKILL_FIREMAN = SKILL_FIREMAN_MAX,
- SKILL_POWERLOADER = SKILL_POWERLOADER_MAX,
- SKILL_VEHICLE = SKILL_VEHICLE_MAX,
- SKILL_JTAC = SKILL_JTAC_MAX,
- SKILL_EXECUTION = SKILL_EXECUTION_MAX,
- SKILL_INTEL = SKILL_INTEL_MAX,
- )
-
-/*
-----------------------------
-Royal Marines Commando
-----------------------------
-*/
-
-//NOTE: Skills take heavy from PMCs
-
-/datum/skills/rmc
- name = "Royal Marines Commando"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- )
-
-/datum/skills/rmc/specialist
- name = "Royal Marines Commando Specialist"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- )
-
-/datum/skills/rmc/smartgun
- name = "Royal Marines Commando Smartgunner"
- skills = list(
- SKILL_CQC = SKILL_CQC_TRAINED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_BEGINNER,
- SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
- )
-
-/datum/skills/rmc/leader
- name = "Royal Marines Commando Leader"
- skills = list(
- SKILL_CQC = SKILL_CQC_SKILLED,
- SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
- SKILL_POLICE = SKILL_POLICE_SKILLED,
- SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
- SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
- SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
- SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
- SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
- SKILL_SURGERY = SKILL_SURGERY_NOVICE,
- SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
- SKILL_JTAC = SKILL_JTAC_TRAINED,
- SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
- )
diff --git a/code/datums/skills/civilian.dm b/code/datums/skills/civilian.dm
new file mode 100644
index 000000000000..9dc4afd78826
--- /dev/null
+++ b/code/datums/skills/civilian.dm
@@ -0,0 +1,214 @@
+/*
+---------------------
+CIVILIAN
+---------------------
+*/
+
+/datum/skills/civilian
+ name = "Civilian"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_DEFAULT,
+ SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_NONE,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ )
+
+/datum/skills/civilian/manager
+ name = "Weyland-Yutani Manager" // Semi-competent leader with basic knowledge in most things.
+ skills = list(
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ )
+
+/datum/skills/civilian/icc_investigation
+ name = "ICC CL - Black Market ERT"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_DEFAULT,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI, //The ASRS consoles
+ SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
+ SKILL_POLICE = SKILL_POLICE_SKILLED, //The CMB Tradeband Compliance Device
+ )
+
+/datum/skills/civilian/manager/director
+ name = "Weyland-Yutani Director"
+ skills = list(
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_EXECUTION = SKILL_EXECUTION_TRAINED,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ )
+
+//civilian that are survivor could be in is own file maybe
+
+/datum/skills/civilian/survivor
+ name = "Survivor"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ )
+
+/datum/skills/civilian/survivor/manager
+ name = "Weyland-Yutani Manager"
+ skills = list(
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ )
+
+/datum/skills/civilian/survivor/goon
+ name = "Survivor Goon"
+ additional_skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ )
+
+/datum/skills/civilian/survivor/pmc
+ name = "Survivor PMC"
+ additional_skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ )
+
+/datum/skills/civilian/survivor/pmc/medic
+ name = "Survivor PMC Medic"
+ additional_skills = list(
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ )
+
+/datum/skills/civilian/survivor/pmc/engineer
+ name = "Survivor PMC Engineer"
+ additional_skills = list(
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ )
+
+/datum/skills/civilian/survivor/doctor
+ name = "Survivor Doctor"
+ additional_skills = list(
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ )
+
+/datum/skills/civilian/survivor/clf
+ name = "Survivor CLF"
+ additional_skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ )
+
+/datum/skills/civilian/survivor/scientist
+ name = "Survivor Scientist"
+ additional_skills = list(
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ )
+
+/datum/skills/civilian/survivor/chef
+ name = "Survivor Chef"
+ additional_skills = list(
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_DOMESTIC = SKILL_DOMESTIC_TRAINED,
+ )
+
+/datum/skills/civilian/survivor/miner
+ name = "Survivor Miner"
+ additional_skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ )
+
+/datum/skills/civilian/survivor/trucker
+ name = "Survivor Trucker"
+ additional_skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN,
+ )
+
+/datum/skills/civilian/survivor/engineer
+ name = "Survivor Engineer"
+ additional_skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ )
+
+/datum/skills/civilian/survivor/chaplain
+ name = "Survivor Chaplain"
+ additional_skills = list(
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ )
+
+/datum/skills/civilian/survivor/marshal
+ name = "Survivor Marshal"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ )
+
+/datum/skills/civilian/survivor/prisoner
+ name = "Survivor Prisoner"
+ additional_skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ )
+
+/datum/skills/civilian/survivor/gangleader
+ name = "Survivor Gang Leader"
+ additional_skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ )
diff --git a/code/datums/skills/clf.dm b/code/datums/skills/clf.dm
new file mode 100644
index 000000000000..6042febb6b48
--- /dev/null
+++ b/code/datums/skills/clf.dm
@@ -0,0 +1,92 @@
+/*
+-------------------------
+COLONIAL LIBERATION FRONT
+-------------------------
+*/
+
+/datum/skills/clf
+ name = "CLF Soldier"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/clf/combat_engineer
+ name = "CLF Engineer"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/clf/combat_medic
+ name = "CLF Medic"
+ skills = list(
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_WEAK,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/clf/specialist
+ name = "CLF Specialist"
+ skills = list(
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set.
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_TRAINED
+ )
+
+/datum/skills/clf/leader
+ name = "CLF Leader"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI, // to use their C4
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI
+ )
+
+/datum/skills/clf/commander
+ name = "CLF Cell Commander"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
+ SKILL_EXECUTION = SKILL_EXECUTION_TRAINED,
+ )
diff --git a/code/datums/skills/cmb.dm b/code/datums/skills/cmb.dm
new file mode 100644
index 000000000000..b29a4c314567
--- /dev/null
+++ b/code/datums/skills/cmb.dm
@@ -0,0 +1,60 @@
+/*
+---------------------
+COLONIAL MARSHALS
+---------------------
+*/
+/datum/skills/cmb
+ name = "CMB Deputy"
+ skills = list(
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_CQC = SKILL_CQC_EXPERT,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ )
+
+/datum/skills/cmb/leader
+ name = "CMB Marshal"
+ skills = list(
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_CQC = SKILL_CQC_EXPERT,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_FIREMAN = SKILL_FIREMAN_MASTER,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ )
+
+/datum/skills/synthetic/cmb
+ name = "CMB Investigative Synthetic"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT, // incase the synth needs to use consoles for investigations or tracking
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED, // Not a medical Synthetic, but operate if absolutely needed.
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_PILOT = SKILL_PILOT_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_MAX,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER
+ )
diff --git a/code/datums/skills/commando.dm b/code/datums/skills/commando.dm
new file mode 100644
index 000000000000..dabae682bd0b
--- /dev/null
+++ b/code/datums/skills/commando.dm
@@ -0,0 +1,116 @@
+/*
+---------------------
+SPEC-OPS
+---------------------
+*/
+
+/datum/skills/commando
+ name = "Commando"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_EXPERT,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/commando/medic
+ name = "Commando Medic"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_EXPERT,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/commando/leader
+ name = "Commando Leader"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_EXPERT,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/commando/deathsquad
+ name = "Deathsquad"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/commando/deathsquad/leader
+ name = "Deathsquad Leader"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/commando/deathsquad/officer
+ name = "Deathsquad Officer"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/spy
+ name = "Spy"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/ninja
+ name = "Ninja"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
diff --git a/code/datums/skills/contractor.dm b/code/datums/skills/contractor.dm
new file mode 100644
index 000000000000..183e95c941f5
--- /dev/null
+++ b/code/datums/skills/contractor.dm
@@ -0,0 +1,90 @@
+/*
+---------------------
+CONTRACTORS
+---------------------
+*/
+/datum/skills/contractor
+ name = "Contractor Standard"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ )
+
+/datum/skills/contractor/leader
+ name = "Contractor Leader"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ )
+
+/datum/skills/contractor/medic
+ name = "Contractor Medic"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/contractor/engi
+ name = "Contractor Engi"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_MAX,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
+ )
+
+/datum/skills/contractor/heavy
+ name = "Contractor Machinegunner"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ )
diff --git a/code/datums/skills/dutch.dm b/code/datums/skills/dutch.dm
new file mode 100644
index 000000000000..5c2c63a8c463
--- /dev/null
+++ b/code/datums/skills/dutch.dm
@@ -0,0 +1,46 @@
+/datum/skills/dutch
+ name = "Dutch"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_MAX,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_ANTAG = SKILL_ANTAG_HUNTER,
+ )
+
+/datum/skills/dutchmerc
+ name = "Dutch's Dozen Mercenary"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
+ )
+
+/datum/skills/dutchmedic
+ name = "Dutch's Dozen Medic"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_EXPERT,
+ )
diff --git a/code/datums/skills/forecon.dm b/code/datums/skills/forecon.dm
new file mode 100644
index 000000000000..4799dd68d617
--- /dev/null
+++ b/code/datums/skills/forecon.dm
@@ -0,0 +1,102 @@
+/*
+---------------------
+MILITARY SURVIVORS
+---------------------
+*/
+//Hardcore survivors with poor equipment and skills, prove you're the best of the best.
+
+/datum/skills/military/survivor/forecon_standard
+ name = "Reconnaissance Rifleman"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/military/survivor/forecon_techician
+ name = "Reconnaissance Support Technician"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/military/survivor/forecon_marksman
+ name = "Reconnaissance Designated Marksman"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SCOUT,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/military/survivor/forecon_smartgunner
+ name = "Reconnaissance Smartgunner"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/military/survivor/forecon_sniper
+ name = "Reconnaissance Sniper"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SNIPER,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/military/survivor/forecon_squad_leader
+ name = "Reconnaissance Squad Leader"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_DEFAULT,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_SURVIVOR,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
diff --git a/code/datums/skills/freelancer.dm b/code/datums/skills/freelancer.dm
new file mode 100644
index 000000000000..7f7256318edb
--- /dev/null
+++ b/code/datums/skills/freelancer.dm
@@ -0,0 +1,40 @@
+/*
+-----------
+FREELANCERS
+-----------
+*/
+
+//NOTE: Freelancer training is similar to the USCM's, but with additional construction skills
+
+/datum/skills/freelancer
+ name = "Freelancer Private"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ )
+
+/datum/skills/freelancer/combat_medic
+ name = "Freelancer Medic"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ )
+
+/datum/skills/freelancer/SL
+ name = "Freelancer Leader"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ )
+
+
diff --git a/code/datums/skills/gladiator.dm b/code/datums/skills/gladiator.dm
new file mode 100644
index 000000000000..7ba2c9eff455
--- /dev/null
+++ b/code/datums/skills/gladiator.dm
@@ -0,0 +1,33 @@
+/datum/skills/gladiator
+ name = "Gladiator"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
+ SKILL_LEADERSHIP = SKILL_LEAD_NOVICE,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ )
+
+/datum/skills/gladiator/champion
+ name = "Gladiator Champion"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/gladiator/champion/leader
+ name = "Gladiator Leader"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER, //Spartacus!
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ )
diff --git a/code/datums/skills/mercenary.dm b/code/datums/skills/mercenary.dm
new file mode 100644
index 000000000000..8d842ea30dd2
--- /dev/null
+++ b/code/datums/skills/mercenary.dm
@@ -0,0 +1,85 @@
+/datum/skills/mercenary
+ name = "Mercenary"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/mercenary/elite
+ name = "Elite Mercenary"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ )
+
+/datum/skills/mercenary/elite/medic
+ name = "Elite Mercenary Medic"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_MEDICAL = SKILL_MEDICAL_MASTER,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ )
+
+/datum/skills/mercenary/elite/engineer
+ name = "Elite Mercenary Engineer"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_PILOT = SKILL_PILOT_EXPERT,
+ )
+
+/datum/skills/mercenary/elite/heavy
+ name = "Elite Mercenary Heavy"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ )
+
+/datum/skills/mercenary/elite/leader
+ name = "Elite Mercenary Leader"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_PILOT = SKILL_PILOT_EXPERT,
+ )
diff --git a/code/datums/skills/misc.dm b/code/datums/skills/misc.dm
new file mode 100644
index 000000000000..e4f78219b5c6
--- /dev/null
+++ b/code/datums/skills/misc.dm
@@ -0,0 +1,86 @@
+/*
+---------------------
+MISCELLANEOUS
+---------------------
+*/
+
+/datum/skills/tank_crew
+ name = "Vehicle Crewman"
+ skills = list(
+ SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ )
+
+/datum/skills/yautja/warrior
+ name = "Yautja Warrior"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_MAX,
+ SKILL_ANTAG = SKILL_ANTAG_HUNTER,
+ )
+
+/datum/skills/cultist_leader
+ name = "Cultist Leader"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ )
+
+/datum/skills/souto
+ name = "Souto Man"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ )
+
+/datum/skills/everything //max it out
+ name = "Ultra"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MAX,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_MAX,
+ SKILL_FIREARMS = SKILL_FIREARMS_MAX,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_ENGINEER = SKILL_ENGINEER_MAX,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MAX,
+ SKILL_LEADERSHIP = SKILL_LEAD_MAX,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_MAX,
+ SKILL_MEDICAL = SKILL_MEDICAL_MAX,
+ SKILL_SURGERY = SKILL_SURGERY_MAX,
+ SKILL_RESEARCH = SKILL_RESEARCH_MAX,
+ SKILL_ANTAG = SKILL_ANTAG_MAX,
+ SKILL_PILOT = SKILL_PILOT_MAX,
+ SKILL_POLICE = SKILL_POLICE_MAX,
+ SKILL_FIREMAN = SKILL_FIREMAN_MAX,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MAX,
+ SKILL_VEHICLE = SKILL_VEHICLE_MAX,
+ SKILL_JTAC = SKILL_JTAC_MAX,
+ SKILL_EXECUTION = SKILL_EXECUTION_MAX,
+ SKILL_INTEL = SKILL_INTEL_MAX,
+ )
diff --git a/code/datums/skills/pmc.dm b/code/datums/skills/pmc.dm
new file mode 100644
index 000000000000..df7027e2a7ab
--- /dev/null
+++ b/code/datums/skills/pmc.dm
@@ -0,0 +1,171 @@
+/*
+----------------------------
+Private Military Contractors
+----------------------------
+*/
+
+//NOTE: Compared to the USCM, PMCs have additional firearms training, construction skills and policing skills
+
+/datum/skills/pmc
+ name = "PMC Private"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ )
+
+/datum/skills/pmc/medic
+ name = "PMC Medic"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ )
+
+/datum/skills/pmc/medic/chem
+ name = "PMC Medical Investigator"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ )
+
+/datum/skills/pmc/smartgunner
+ name = "PMC Smartgunner"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/pmc/specialist
+ name = "PMC Specialist"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/pmc/SL
+ name = "PMC Leader"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/pmc/SL/chem
+ name = "PMC Lead Investigator"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/pmc/tank_crew
+ name = "Vehicle Crewman"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ )
+
+/datum/skills/pmc/doctor
+ name = "PMC Triage Doctor"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_EXPERT,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER, //trained in medicine more than combat
+ SKILL_CQC = SKILL_CQC_TRAINED
+ )
+
+/datum/skills/pmc/engineer
+ name = "PMC Corporate Technician"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ )
+
+/datum/skills/pmc/director
+ name = "PMC Site Director"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ SKILL_EXECUTION = SKILL_EXECUTION_TRAINED,
+ )
diff --git a/code/datums/skills/rmc.dm b/code/datums/skills/rmc.dm
new file mode 100644
index 000000000000..89aa39b154ad
--- /dev/null
+++ b/code/datums/skills/rmc.dm
@@ -0,0 +1,71 @@
+/*
+----------------------------
+Royal Marines Commando
+----------------------------
+*/
+
+//NOTE: Skills take heavy from PMCs
+
+/datum/skills/rmc
+ name = "Royal Marines Commando"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ )
+
+/datum/skills/rmc/specialist
+ name = "Royal Marines Commando Specialist"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/rmc/smartgun
+ name = "Royal Marines Commando Smartgunner"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
+ )
+
+/datum/skills/rmc/leader
+ name = "Royal Marines Commando Leader"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ )
diff --git a/code/datums/skills/skills.dm b/code/datums/skills/skills.dm
new file mode 100644
index 000000000000..5d1a69e174ed
--- /dev/null
+++ b/code/datums/skills/skills.dm
@@ -0,0 +1,267 @@
+// Individual skill
+/datum/skill
+ /// Name of the skill
+ var/skill_name = null
+ /// used for the view UI
+ var/readable_skill_name = null
+ /// Level of skill in this... skill
+ var/skill_level = 0
+ /// the max level this skill can be, used for tgui
+ var/max_skill_level = 0
+
+/datum/skill/proc/get_skill_level()
+ return skill_level
+
+/datum/skill/proc/set_skill(new_level, mob/owner)
+ skill_level = new_level
+
+/datum/skill/proc/is_skilled(req_level, is_explicit = FALSE)
+ if(is_explicit)
+ return (skill_level == req_level)
+ return (skill_level >= req_level)
+
+// Lots of defines here. See #define/skills.dm
+
+/datum/skill/cqc
+ skill_name = SKILL_CQC
+ readable_skill_name = "CQC"
+ skill_level = SKILL_CQC_DEFAULT
+ max_skill_level = SKILL_CQC_MAX
+
+/datum/skill/melee_weapons
+ skill_name = SKILL_MELEE_WEAPONS
+ readable_skill_name = "melee weapons"
+ skill_level = SKILL_MELEE_DEFAULT
+ max_skill_level = SKILL_MELEE_MAX
+
+/datum/skill/firearms
+ skill_name = SKILL_FIREARMS
+ skill_level = SKILL_FIREARMS_TRAINED
+ max_skill_level = SKILL_FIREARMS_MAX
+
+/datum/skill/spec_weapons
+ skill_name = SKILL_SPEC_WEAPONS
+ readable_skill_name = "specialist weapons"
+ skill_level = SKILL_SPEC_DEFAULT
+ max_skill_level = SKILL_SPEC_ALL
+
+/datum/skill/endurance
+ skill_name = SKILL_ENDURANCE
+ skill_level = SKILL_ENDURANCE_WEAK
+ max_skill_level = SKILL_ENDURANCE_MAX
+
+/datum/skill/engineer
+ skill_name = SKILL_ENGINEER
+ skill_level = SKILL_ENGINEER_DEFAULT
+ max_skill_level = SKILL_ENGINEER_MAX
+
+/datum/skill/construction
+ skill_name = SKILL_CONSTRUCTION
+ skill_level = SKILL_CONSTRUCTION_DEFAULT
+ max_skill_level = SKILL_CONSTRUCTION_MAX
+
+/datum/skill/leadership
+ skill_name = SKILL_LEADERSHIP
+ skill_level = SKILL_LEAD_NOVICE
+ max_skill_level = SKILL_LEAD_MAX
+
+/datum/skill/leadership/set_skill(new_level, mob/living/owner)
+ ..()
+ if(!owner)
+ return
+
+ if(!ishuman(owner))
+ return
+
+ // Give/remove issue order actions
+ if(is_skilled(SKILL_LEAD_TRAINED))
+ ADD_TRAIT(owner, TRAIT_LEADERSHIP, TRAIT_SOURCE_SKILL(skill_name))
+ else
+ REMOVE_TRAIT(owner, TRAIT_LEADERSHIP, TRAIT_SOURCE_SKILL(skill_name))
+
+/datum/skill/overwatch
+ skill_name = SKILL_OVERWATCH
+ skill_level = SKILL_OVERWATCH_DEFAULT
+ max_skill_level = SKILL_OVERWATCH_MAX
+
+/datum/skill/medical
+ skill_name = SKILL_MEDICAL
+ skill_level = SKILL_MEDICAL_DEFAULT
+ max_skill_level = SKILL_MEDICAL_MAX
+
+/datum/skill/surgery
+ skill_name = SKILL_SURGERY
+ skill_level = SKILL_SURGERY_DEFAULT
+ max_skill_level = SKILL_SURGERY_MAX
+
+/datum/skill/surgery/set_skill(new_level, mob/living/owner)
+ ..()
+ if(!owner)
+ return
+
+ if(!ishuman(owner))
+ return
+
+ // Give/remove surgery toggle action
+ var/datum/action/surgery_toggle/surgery_action = locate() in owner.actions
+ if(is_skilled(SKILL_SURGERY_NOVICE))
+ if(!surgery_action)
+ give_action(owner, /datum/action/surgery_toggle)
+ else
+ surgery_action.update_surgery_skill()
+ else
+ if(surgery_action)
+ surgery_action.remove_from(owner)
+
+/datum/skill/research
+ skill_name = SKILL_RESEARCH
+ skill_level = SKILL_RESEARCH_DEFAULT
+ max_skill_level = SKILL_RESEARCH_MAX
+
+/datum/skill/antag
+ skill_name = SKILL_ANTAG
+ readable_skill_name = "illegal technology"
+ skill_level = SKILL_ANTAG_DEFAULT
+ max_skill_level = SKILL_ANTAG_MAX
+
+/datum/skill/pilot
+ skill_name = SKILL_PILOT
+ skill_level = SKILL_PILOT_DEFAULT
+ max_skill_level = SKILL_PILOT_MAX
+
+/datum/skill/navigations
+ skill_name = SKILL_NAVIGATIONS
+ skill_level = SKILL_NAVIGATIONS_DEFAULT
+ max_skill_level = SKILL_NAVIGATIONS_MAX
+
+/datum/skill/police
+ skill_name = SKILL_POLICE
+ skill_level = SKILL_POLICE_DEFAULT
+ max_skill_level = SKILL_POLICE_MAX
+
+/datum/skill/powerloader
+ skill_name = SKILL_POWERLOADER
+ skill_level = SKILL_POWERLOADER_DEFAULT
+ max_skill_level = SKILL_POWERLOADER_MAX
+
+/datum/skill/vehicles
+ skill_name = SKILL_VEHICLE
+ skill_level = SKILL_VEHICLE_DEFAULT
+ max_skill_level = SKILL_VEHICLE_MAX
+
+/datum/skill/jtac
+ skill_name = SKILL_JTAC
+ readable_skill_name = "JTAC"
+ skill_level = SKILL_JTAC_NOVICE
+ max_skill_level = SKILL_JTAC_MAX
+
+/datum/skill/execution
+ skill_name = SKILL_EXECUTION
+ skill_level = SKILL_EXECUTION_DEFAULT
+ max_skill_level = SKILL_EXECUTION_MAX
+
+/datum/skill/intel
+ skill_name = SKILL_INTEL
+ skill_level = SKILL_INTEL_NOVICE
+ max_skill_level = SKILL_INTEL_MAX
+
+/datum/skill/domestic
+ skill_name = SKILL_DOMESTIC
+ skill_level = SKILL_DOMESTIC_NONE
+ max_skill_level = SKILL_DOMESTIC_MAX
+
+/datum/skill/fireman
+ skill_name = SKILL_FIREMAN
+ readable_skill_name = "fireman carrying"
+ skill_level = SKILL_FIREMAN_DEFAULT
+ max_skill_level = SKILL_FIREMAN_MAX
+
+/// Skill with an extra S at the end is a collection of multiple skills. Basically a skillSET
+/// This is to organize and provide a common interface to the huge heap of skills there are
+/datum/skills
+ /// The name of the skillset
+ var/name
+ // The mob that has this skillset
+ var/mob/owner
+
+ // List of skill datums.
+ // Also, if this is populated when the datum is created, it will set the skill levels automagically
+ var/list/skills = list()
+ // Same as above, but for children of parents that just add a lil something else
+ var/list/additional_skills = list()
+
+/datum/skills/New(mob/skillset_owner)
+ owner = skillset_owner
+
+ // Setup every single skill
+ for(var/skill_type in subtypesof(/datum/skill))
+ var/datum/skill/S = new skill_type()
+
+ // Fancy hack to convert a list of desired skill levels in each named skill into a skill level in the actual skill datum
+ // Lets the skills list be used multipurposely for both storing skill datums and choosing skill levels for different skillsets
+ var/predetermined_skill_level = additional_skills[S.skill_name] ? additional_skills[S.skill_name] : skills[S.skill_name]
+ skills[S.skill_name] = S
+
+ if(!isnull(predetermined_skill_level))
+ S.set_skill(predetermined_skill_level, owner)
+
+/datum/skills/Destroy()
+ owner = null
+ skills = null // Don't need to delete, /datum/skill should softdel
+ SStgui.close_uis(src)
+ return ..()
+
+// Checks if the given skill is contained in this skillset at all
+/datum/skills/proc/has_skill(skill)
+ return isnull(skills[skill])
+
+// Returns the skill DATUM for the given skill
+/datum/skills/proc/get_skill(skill)
+ if(!skills)
+ return null
+ return skills[skill]
+
+// Returns the skill level for the given skill
+/datum/skills/proc/get_skill_level(skill)
+ var/datum/skill/S = get_skill(skill)
+ if(!S)
+ return -1
+ if(QDELETED(S))
+ return -1
+ return S.get_skill_level()
+
+// Sets the skill LEVEL for a given skill
+/datum/skills/proc/set_skill(skill, new_level)
+ var/datum/skill/S = skills[skill]
+ if(!S)
+ return
+ return S.set_skill(new_level, owner)
+
+/datum/skills/proc/increment_skill(skill, increment, cap)
+ var/datum/skill/S = skills[skill]
+ if(!S || skillcheck(owner, skill, cap))
+ return
+ return S.set_skill(min(cap,S.skill_level+increment), owner)
+
+/datum/skills/proc/decrement_skill(skill, increment)
+ var/datum/skill/S = skills[skill]
+ if(!S)
+ return
+ return S.set_skill(max(0,S.skill_level-increment), owner)
+
+// Checks if the skillset is AT LEAST skilled enough to pass a skillcheck for the given skill level
+/datum/skills/proc/is_skilled(skill, req_level, is_explicit = FALSE)
+ var/datum/skill/S = get_skill(skill)
+ if(QDELETED(S))
+ return FALSE
+ return S.is_skilled(req_level, is_explicit)
+
+// Adjusts the full skillset to a new type of skillset. Pass the datum type path for the desired skillset
+/datum/skills/proc/set_skillset(skillset_type)
+ var/datum/skills/skillset = new skillset_type()
+ var/list/skill_levels = initial(skillset.skills)
+
+ name = skillset.name
+ for(var/skill in skill_levels)
+ set_skill(skill, skill_levels[skill])
+ qdel(skillset)
diff --git a/code/datums/skills/synthetic.dm b/code/datums/skills/synthetic.dm
new file mode 100644
index 000000000000..3925dd9605b3
--- /dev/null
+++ b/code/datums/skills/synthetic.dm
@@ -0,0 +1,90 @@
+/*
+---------------------
+SYNTHETIC
+---------------------
+*/
+
+/datum/skills/synthetic
+ name = "Synthetic"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MASTER,
+ SKILL_SURGERY = SKILL_SURGERY_EXPERT,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_PILOT = SKILL_PILOT_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_MAX,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER,
+ SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED,
+ )
+
+/datum/skills/colonial_synthetic
+ name = SYNTH_COLONY
+ skills = list(
+ SKILL_CQC = SKILL_CQC_EXPERT,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_PILOT = SKILL_PILOT_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER,
+ )
+
+/datum/skills/working_joe
+ name = SYNTH_WORKING_JOE
+ skills = list(
+ SKILL_CQC = SKILL_CQC_EXPERT,
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER, //So they can fully use the Maintenance Jack
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER,
+ )
+
+/datum/skills/infiltrator_synthetic
+ name = SYNTH_INFILTRATOR
+ skills = list(
+ SKILL_CQC = SKILL_CQC_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MASTER,
+ SKILL_SURGERY = SKILL_SURGERY_EXPERT,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_SUPER,
+ SKILL_PILOT = SKILL_PILOT_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_MAX,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_VEHICLE = SKILL_VEHICLE_CREWMAN,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER,
+ SKILL_ANTAG = SKILL_ANTAG_AGENT,
+ )
diff --git a/code/datums/skills/upp.dm b/code/datums/skills/upp.dm
new file mode 100644
index 000000000000..77401ab62878
--- /dev/null
+++ b/code/datums/skills/upp.dm
@@ -0,0 +1,218 @@
+/*
+--------------------------
+UNITED PROGRESSIVE PEOPLES
+--------------------------
+*/
+
+//NOTE: UPP make up for their subpar gear with extreme training.
+
+/datum/skills/upp
+ name = "UPP Private"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_CQC = SKILL_CQC_DEFAULT,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ )
+
+/datum/skills/upp/combat_engineer
+ name = "UPP Sapper"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_CQC = SKILL_CQC_DEFAULT,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ )
+
+/datum/skills/upp/combat_medic
+ name = "UPP Medic"
+ skills = list(
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_CQC = SKILL_CQC_DEFAULT,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ )
+
+/datum/skills/upp/specialist
+ name = "UPP Specialist"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ )
+
+/datum/skills/upp/SL
+ name = "UPP Squad Leader"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ )
+
+/datum/skills/upp/military_police
+ name = "UPP Military Police"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ )
+
+/datum/skills/upp/officer
+ name = "UPP Officer"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_FLASH,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ )
+
+/datum/skills/upp/kapitan
+ name = "UPP Kapitan"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ )
+
+/datum/skills/upp/commander
+ name = "UPP Command Officer"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_EXPERT,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_EXECUTION = SKILL_EXECUTION_TRAINED,
+ )
+/datum/skills/upp/conscript
+ name = "UPP Conscript"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ )
+
+
+//Survivor
+
+/datum/skills/military/survivor/upp_private
+ name = "UPP Private"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/military/survivor/upp_sapper
+ name = "UPP Sapper"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/military/survivor/upp_medic
+ name = "UPP Medic"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_DEFAULT,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ )
+
+/datum/skills/military/survivor/upp_spec
+ name = "UPP Specialist"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ )
+
+/datum/skills/military/survivor/upp_sl
+ name = "UPP Squad Leader"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_UPP,
+ SKILL_FIREARMS = SKILL_FIREARMS_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ )
diff --git a/code/datums/skills/uscm.dm b/code/datums/skills/uscm.dm
new file mode 100644
index 000000000000..8a6d2fd2c8c2
--- /dev/null
+++ b/code/datums/skills/uscm.dm
@@ -0,0 +1,410 @@
+/*
+------------------------------
+United States Colonial Marines
+------------------------------
+*/
+
+/datum/skills/pfc
+ name = "Private"
+ //same as default
+
+/datum/skills/pfc/crafty
+ name = "Crafty Private"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ )
+
+/datum/skills/combat_medic
+ name = "Combat Medic"
+ skills = list(
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/combat_medic/crafty
+ name = "Crafty Combat Medic"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ )
+
+/datum/skills/combat_engineer
+ name = "Combat Engineer"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/smartgunner
+ name = "Squad Smartgunner"
+ skills = list(
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER,
+ )
+
+/datum/skills/specialist
+ name = "Squad Weapons Specialist"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED, //to use c4 in demo set.
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_BEGINNER
+ )
+
+/datum/skills/tl
+ name = "Fireteam Leader"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ )
+
+/datum/skills/SL
+ name = "Squad Leader"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ )
+
+/datum/skills/intel
+ name = "Intelligence Officer"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ )
+
+/*
+---------------------
+MILITARY NONCOMBATANT
+---------------------
+*/
+
+/datum/skills/doctor
+ name = "Doctor"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ )
+
+/datum/skills/nurse
+ name = "Nurse"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ )
+
+/datum/skills/researcher
+ name = "Researcher"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ )
+
+/datum/skills/pilot
+ name = "Pilot Officer"
+ skills = list(
+ SKILL_PILOT = SKILL_PILOT_EXPERT,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ )
+
+/datum/skills/crew_chief
+ name = "Dropship Crew Chief"
+ skills = list(
+ SKILL_PILOT = SKILL_PILOT_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_JTAC = SKILL_JTAC_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ )
+
+/datum/skills/MP
+ name = "Military Police"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ )
+
+/datum/skills/MW
+ name = "Military Warden"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_LEADERSHIP = SKILL_LEAD_TRAINED,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ )
+
+/datum/skills/provost
+ name = "Provost"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MASTER,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ )
+
+/datum/skills/OT
+ name = "Ordnance Technician"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ )
+
+/datum/skills/MT
+ name = "Maintenance Technician"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_DOMESTIC = SKILL_DOMESTIC_TRAINED,
+ )
+
+/datum/skills/mess_technician
+ name = "Mess Technician"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT, // need to hunt food somehow
+ SKILL_ENGINEER = SKILL_ENGINEER_TRAINED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_DOMESTIC = SKILL_DOMESTIC_MASTER
+ )
+
+/datum/skills/CT
+ name = "Cargo Technician"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ )
+
+/*
+---------------------
+COMMAND STAFF
+---------------------
+*/
+
+/datum/skills/general
+ name = "General"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_TRAINED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_MAX,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_ALL,
+ SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, //can BE people
+ SKILL_INTEL = SKILL_INTEL_EXPERT
+ )
+
+/datum/skills/commander
+ name = "Commanding Officer"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_SPEC_WEAPONS = SKILL_SPEC_SMARTGUN,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ SKILL_EXECUTION = SKILL_EXECUTION_TRAINED, //can BE people
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED //can change ship alt
+ )
+
+/datum/skills/XO
+ name = "Executive Officer"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI, //to fix CIC apc.
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_POLICE = SKILL_POLICE_FLASH,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED,
+ )
+
+/datum/skills/SO
+ name = "Staff Officer"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_POLICE = SKILL_POLICE_FLASH,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ )
+
+/datum/skills/SEA
+ name = "Senior Enlisted Advisor"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_FIREARMS = SKILL_FIREARMS_EXPERT,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_PILOT = SKILL_PILOT_EXPERT,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_VEHICLE = SKILL_VEHICLE_LARGE,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ )
+
+/datum/skills/SEA/New(mob/skillset_owner)
+ ..()
+ give_action(skillset_owner, /datum/action/looc_toggle)
+
+/datum/skills/SEA/Destroy()
+ remove_action(owner, /datum/action/looc_toggle)
+ return ..()
+
+/datum/skills/CMO
+ name = "CMO"
+ skills = list(
+ SKILL_FIREARMS = SKILL_FIREARMS_CIVILIAN,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_DOCTOR,
+ SKILL_SURGERY = SKILL_SURGERY_TRAINED,
+ SKILL_RESEARCH = SKILL_RESEARCH_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_FLASH,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ )
+
+/datum/skills/CMP
+ name = "Chief MP"
+ skills = list(
+ SKILL_CQC = SKILL_CQC_SKILLED,
+ SKILL_POLICE = SKILL_POLICE_SKILLED,
+ SKILL_FIREMAN = SKILL_FIREMAN_SKILLED,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_ENDURANCE = SKILL_ENDURANCE_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_MEDICAL = SKILL_MEDICAL_TRAINED,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_MELEE_WEAPONS = SKILL_MELEE_TRAINED,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ )
+
+/datum/skills/auxiliary_officer
+ name = "Auxiliary Support Officer"
+ skills = list(
+ SKILL_PILOT = SKILL_PILOT_EXPERT,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_MEDICAL = SKILL_MEDICAL_MEDIC,
+ SKILL_SURGERY = SKILL_SURGERY_NOVICE,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_INTEL = SKILL_INTEL_EXPERT,
+ SKILL_VEHICLE = SKILL_VEHICLE_SMALL,
+ SKILL_ENGINEER = SKILL_ENGINEER_ENGI,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_POLICE = SKILL_POLICE_FLASH,
+ SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ )
+
+/datum/skills/CE
+ name = "Chief Engineer"
+ skills = list(
+ SKILL_ENGINEER = SKILL_ENGINEER_MASTER,
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_MASTER,
+ SKILL_LEADERSHIP = SKILL_LEAD_MASTER,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_POLICE = SKILL_POLICE_FLASH,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_JTAC = SKILL_JTAC_MASTER,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ SKILL_NAVIGATIONS = SKILL_NAVIGATIONS_TRAINED,
+ )
+
+/datum/skills/RO
+ name = "Requisition Officer"
+ skills = list(
+ SKILL_CONSTRUCTION = SKILL_CONSTRUCTION_ENGI,
+ SKILL_LEADERSHIP = SKILL_LEAD_EXPERT,
+ SKILL_OVERWATCH = SKILL_OVERWATCH_TRAINED,
+ SKILL_POWERLOADER = SKILL_POWERLOADER_MASTER,
+ SKILL_POLICE = SKILL_POLICE_FLASH,
+ SKILL_FIREMAN = SKILL_FIREMAN_TRAINED,
+ SKILL_JTAC = SKILL_JTAC_EXPERT,
+ SKILL_INTEL = SKILL_INTEL_TRAINED,
+ )
diff --git a/code/datums/soundOutput.dm b/code/datums/soundOutput.dm
index bc5ffd8efcfb..1f4512b28d59 100644
--- a/code/datums/soundOutput.dm
+++ b/code/datums/soundOutput.dm
@@ -152,11 +152,6 @@
adjust_volume_prefs(VOLUME_AMB, "Set the volume for ambience and soundscapes", 0)
soundOutput.update_ambience(null, null, TRUE)
-/client/verb/adjust_volume_admin_music()
- set name = "Adjust Volume Admin MIDIs"
- set category = "Preferences.Sound"
- adjust_volume_prefs(VOLUME_ADM, "Set the volume for admin MIDIs", SOUND_CHANNEL_ADMIN_MIDI)
-
/client/verb/adjust_volume_lobby_music()
set name = "Adjust Volume LobbyMusic"
set category = "Preferences.Sound"
diff --git a/code/datums/stamina/_stamina.dm b/code/datums/stamina/_stamina.dm
index 36705e3be300..e233aaa81676 100644
--- a/code/datums/stamina/_stamina.dm
+++ b/code/datums/stamina/_stamina.dm
@@ -37,13 +37,11 @@
current_stamina = Clamp(current_stamina - amount, 0, max_stamina)
if(current_stamina < max_stamina)
- if(!(src in active_staminas))
- active_staminas.Add(src)
-
+ START_PROCESSING(SSobj, src)
if(amount > 0)
apply_rest_period(STAMINA_REST_PERIOD)
else
- active_staminas.Remove(src)
+ STOP_PROCESSING(SSobj, src)
update_stamina_level()
diff --git a/code/datums/statistics/entities/caste_stats.dm b/code/datums/statistics/entities/caste_stats.dm
index 639e1b4a05f5..6bfc18d124b7 100644
--- a/code/datums/statistics/entities/caste_stats.dm
+++ b/code/datums/statistics/entities/caste_stats.dm
@@ -3,6 +3,10 @@
var/total_hits = 0
var/list/abilities_used = list() // types of /datum/entity/statistic, "tail sweep" = 10, "screech" = 2
+/datum/entity/player_stats/caste/Destroy(force)
+ . = ..()
+ QDEL_LIST_ASSOC_VAL(abilities_used)
+
/datum/entity/player_stats/caste/proc/setup_ability(ability)
if(!ability)
return
diff --git a/code/datums/statistics/entities/death_stats.dm b/code/datums/statistics/entities/death_stats.dm
index 4a01e4e9d72b..76e3605c157f 100644
--- a/code/datums/statistics/entities/death_stats.dm
+++ b/code/datums/statistics/entities/death_stats.dm
@@ -84,6 +84,10 @@
if(!mind || statistic_exempt)
return
+ var/area/area = get_area(death_loc)
+ handle_observer_message(cause_data, cause_mob, death_loc, area)
+
+ // Perform logging above before get_player_from_key to avoid delays
var/datum/entity/statistic/death/new_death = DB_ENTITY(/datum/entity/statistic/death)
var/datum/entity/player/player_entity = get_player_from_key(mind.ckey)
if(player_entity)
@@ -95,11 +99,8 @@
new_death.role_name = get_role_name()
new_death.mob_name = real_name
new_death.faction_name = faction
-
new_death.is_xeno = FALSE
-
- var/area/A = get_area(death_loc)
- new_death.area_name = A.name
+ new_death.area_name = area.name
new_death.cause_name = cause_data?.cause_name
var/datum/entity/player/cause_player = get_player_from_key(cause_data?.ckey)
@@ -132,25 +133,23 @@
new_death.total_damage_taken = life_damage_taken_total
new_death.total_revives_done = life_revives_total
- handle_observer_message(cause_data, cause_mob, death_loc, A)
-
- if(round_statistics)
- round_statistics.track_death(new_death)
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.track_death(new_death)
new_death.save()
new_death.detach()
return new_death
-/mob/living/carbon/human/track_mob_death(cause, cause_mob)
- . = ..(cause, cause_mob, job)
+/mob/living/carbon/human/track_mob_death(datum/cause_data/cause_data, turf/death_loc)
+ . = ..()
if(statistic_exempt || !mind)
return
var/datum/entity/player_stats/human/human_stats = mind.setup_human_stats()
if(human_stats && human_stats.death_list)
human_stats.death_list.Insert(1, .)
-/mob/living/carbon/xenomorph/track_mob_death(cause, cause_mob)
- var/datum/entity/statistic/death/new_death = ..(cause, cause_mob, caste_type)
+/mob/living/carbon/xenomorph/track_mob_death(datum/cause_data/cause_data, turf/death_loc)
+ var/datum/entity/statistic/death/new_death = ..()
if(!new_death)
return
new_death.is_xeno = TRUE // this was placed beneath the if below, which meant gibbing as a xeno wouldn't track properly in stats
diff --git a/code/datums/statistics/entities/human_stats.dm b/code/datums/statistics/entities/human_stats.dm
index 51b07867dfd3..20d5a284becd 100644
--- a/code/datums/statistics/entities/human_stats.dm
+++ b/code/datums/statistics/entities/human_stats.dm
@@ -5,17 +5,24 @@
var/total_shots = 0
var/total_shots_hit = 0
var/total_screams = 0
- var/datum/entity/weapon_stats/top_weapon = null // reference to /datum/entity/weapon_stats (like tac-shotty)
- var/list/weapon_stats_list = list() // list of types /datum/entity/weapon_stats
- var/list/job_stats_list = list() // list of types /datum/entity/job_stats
- var/list/datum/entity/statistic/medal/medal_list = list() // list of all medals earned
+ var/list/weapon_stats_list = list() //! indexed list of types /datum/entity/weapon_stats
+ var/list/job_stats_list = list() //! indexed list of types /datum/entity/job_stats
+ var/datum/entity/weapon_stats/top_weapon //! reference to /datum/entity/weapon_stats (like tac-shotty)
+ var/list/datum/entity/statistic/medal/medal_list = list() //! list of all medals earned
+
+/datum/entity/player_stats/human/Destroy(force)
+ . = ..()
+ QDEL_LIST_ASSOC_VAL(weapon_stats_list)
+ QDEL_LIST_ASSOC_VAL(job_stats_list)
+ QDEL_NULL(top_weapon)
+ QDEL_LIST(medal_list)
/datum/entity/player_stats/human/get_playtime(type)
if(!type)
return ..()
if(type == "Squad Roles")
var/total_squad_time = 0
- for(var/squad_type in job_squad_roles)
+ for(var/squad_type in GLOB.job_squad_roles)
var/datum/entity/player_stats/job/squad_stat = job_stats_list["[squad_type]"]
if(!squad_stat) // Have not played the squad role yet
continue
@@ -23,7 +30,7 @@
return total_squad_time
else if(type == "CIC Roles")
var/total_command_time = 0
- for(var/command_type in job_command_roles)
+ for(var/command_type in GLOB.job_command_roles)
var/datum/entity/player_stats/job/command_stat = job_stats_list["[command_type]"]
if(!command_stat) // Have not played the command role yet
continue
@@ -115,15 +122,15 @@
S.total_rounds_played++
S.round_played = TRUE
S.total_playtime += time
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.total_playtime += time
/datum/entity/player_stats/human/count_personal_death(job)
var/datum/entity/player_stats/job/S = setup_job_stats(job)
S.total_deaths++
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.total_deaths++
//******************
@@ -133,27 +140,27 @@
/datum/entity/player_stats/human/count_personal_human_kill(job_name, cause, job)
var/datum/entity/player_stats/job/S = setup_job_stats(job)
S.count_human_kill(job_name, cause)
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.count_human_kill(job_name, cause)
if(cause)
var/datum/entity/weapon_stats/W = setup_weapon_stats(cause)
W.count_human_kill(job_name)
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(cause)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(cause)
R.count_human_kill(job_name)
/datum/entity/player_stats/human/count_personal_xeno_kill(caste_type, cause, job)
var/datum/entity/player_stats/job/S = setup_job_stats(job)
S.count_xeno_kill(caste_type, cause)
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.count_xeno_kill(caste_type, cause)
if(cause)
var/datum/entity/weapon_stats/W = setup_weapon_stats(cause)
W.count_xeno_kill(caste_type)
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(cause)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(cause)
R.count_xeno_kill(caste_type)
/datum/entity/player_stats/human/count_human_kill(job_name, cause, job)
@@ -162,8 +169,8 @@
if(cause)
var/datum/entity/weapon_stats/W = setup_weapon_stats(cause)
W.total_kills++
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(cause)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(cause)
R.total_kills++
recalculate_top_weapon()
..()
@@ -174,8 +181,8 @@
if(cause)
var/datum/entity/weapon_stats/W = setup_weapon_stats(cause)
W.total_kills++
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(cause)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(cause)
R.total_kills++
recalculate_top_weapon()
..()
@@ -187,8 +194,8 @@
/datum/entity/player_stats/human/count_personal_niche_stat(niche_name, amount = 1, job)
var/datum/entity/player_stats/job/S = setup_job_stats(job)
S.count_niche_stat(niche_name, amount)
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.count_niche_stat(niche_name, amount)
/datum/entity/player_stats/human/count_niche_stat(niche_name, amount = 1, job, weapon)
@@ -197,8 +204,8 @@
if(weapon)
var/datum/entity/weapon_stats/W = setup_weapon_stats(weapon)
W.count_niche_stat(niche_name, amount)
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(weapon)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(weapon)
R.count_niche_stat(niche_name, amount)
recalculate_top_weapon()
..()
@@ -208,8 +215,8 @@
return
var/datum/entity/player_stats/job/S = setup_job_stats(job, FALSE)
S.steps_walked += amount
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job, FALSE)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job, FALSE)
R.steps_walked += amount
/mob/living/carbon/human/track_steps_walked(amount = 1)
@@ -230,8 +237,8 @@
if(isnull(S.total_hits))
S.total_hits = 0
S.total_hits += amount
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(weapon)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(weapon)
R.total_hits +=amount
/mob/proc/track_hit(weapon, amount = 1)
@@ -249,8 +256,8 @@
if(isnull(S.total_shots))
S.total_shots = 0
S.total_shots += amount
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(weapon)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(weapon)
R.total_shots +=amount
/datum/entity/player_stats/human/proc/count_personal_shot(job, amount = 1)
@@ -260,8 +267,8 @@
if(isnull(S.total_shots))
S.total_shots = 0
S.total_shots += amount
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.total_shots += amount
/mob/proc/track_shot(weapon, amount = 1)
@@ -281,8 +288,8 @@
if(isnull(S.total_shots_hit))
S.total_shots_hit = 0
S.total_shots_hit += amount
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(weapon)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(weapon)
R.total_shots_hit += amount
/datum/entity/player_stats/human/proc/count_personal_shot_hit(job, amount = 1)
@@ -292,8 +299,8 @@
if(isnull(S.total_shots_hit))
S.total_shots_hit = 0
S.total_shots_hit += amount
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.total_shots_hit += amount
/mob/proc/track_shot_hit(weapon, shot_mob, amount = 1)
@@ -305,13 +312,13 @@
human_stats.total_shots_hit += amount
human_stats.count_weapon_shot_hit(weapon, amount)
human_stats.count_personal_shot_hit(job, amount)
- if(round_statistics)
- round_statistics.total_projectiles_hit += amount
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.total_projectiles_hit += amount
if(shot_mob)
if(ishuman(shot_mob))
- round_statistics.total_projectiles_hit_human += amount
+ GLOB.round_statistics.total_projectiles_hit_human += amount
else if(isxeno(shot_mob))
- round_statistics.total_projectiles_hit_xeno += amount
+ GLOB.round_statistics.total_projectiles_hit_xeno += amount
/datum/entity/player_stats/human/proc/count_weapon_friendly_fire(weapon, amount = 1)
if(!weapon)
@@ -320,8 +327,8 @@
if(isnull(S.total_friendly_fire))
S.total_friendly_fire = 0
S.total_friendly_fire += amount
- if(round_statistics)
- var/datum/entity/weapon_stats/R = round_statistics.setup_weapon_stats(weapon)
+ if(GLOB.round_statistics)
+ var/datum/entity/weapon_stats/R = GLOB.round_statistics.setup_weapon_stats(weapon)
R.total_friendly_fire += amount
/datum/entity/player_stats/human/proc/count_personal_friendly_fire(job, amount = 1)
@@ -331,8 +338,8 @@
if(isnull(S.total_friendly_fire))
S.total_friendly_fire = 0
S.total_friendly_fire += amount
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.total_friendly_fire += amount
/mob/proc/track_friendly_fire(weapon, amount = 1)
@@ -352,8 +359,8 @@
if(isnull(S.total_revives))
S.total_revives = 0
S.total_revives += amount
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.total_revives += amount
/mob/proc/track_revive(job, amount = 1)
@@ -372,8 +379,8 @@
if(isnull(S.total_lives_saved))
S.total_lives_saved = 0
S.total_lives_saved += amount
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.total_lives_saved += amount
/mob/proc/track_life_saved(job, amount = 1)
@@ -392,8 +399,8 @@
if(isnull(S.total_screams))
S.total_screams = 0
S.total_screams += amount
- if(round_statistics)
- var/datum/entity/player_stats/job/R = round_statistics.setup_job_stats(job)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/job/R = GLOB.round_statistics.setup_job_stats(job)
R.total_screams += amount
/mob/proc/track_scream(job, amount = 1)
diff --git a/code/datums/statistics/entities/job_stats.dm b/code/datums/statistics/entities/job_stats.dm
index ecde1c942082..199c2adb3160 100644
--- a/code/datums/statistics/entities/job_stats.dm
+++ b/code/datums/statistics/entities/job_stats.dm
@@ -1,8 +1,8 @@
/datum/entity/player_stats/job
- var/name = null
- var/total_friendly_fire = null
- var/total_revives = null
- var/total_lives_saved = null
- var/total_shots = null
- var/total_shots_hit = null
- var/total_screams = null
+ var/name
+ var/total_friendly_fire
+ var/total_revives
+ var/total_lives_saved
+ var/total_shots
+ var/total_shots_hit
+ var/total_screams
diff --git a/code/datums/statistics/entities/panel_stats.dm b/code/datums/statistics/entities/panel_stats.dm
index d6e391e1731f..5cfb888b8ea1 100644
--- a/code/datums/statistics/entities/panel_stats.dm
+++ b/code/datums/statistics/entities/panel_stats.dm
@@ -3,17 +3,17 @@
//*******************************************************
-/datum/entity/player_entity/proc/show_statistics(mob/user, datum/entity/statistic/round/viewing_round = round_statistics, update_data = FALSE)
+/datum/entity/player_entity/proc/show_statistics(mob/user, datum/entity/statistic/round/viewing_round = GLOB.round_statistics, update_data = FALSE)
if(update_data)
- update_panel_data(round_statistics)
+ update_panel_data(GLOB.round_statistics)
ui_interact(user)
-/datum/entity/player_entity/proc/ui_interact(mob/user, ui_key = "statistics", datum/nanoui/ui = null, force_open = 1)
+/datum/entity/player_entity/proc/ui_interact(mob/user, ui_key = "statistics", datum/nanoui/ui, force_open = 1)
data["menu"] = menu
data["subMenu"] = subMenu
data["dataMenu"] = dataMenu
- ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ ui = SSnano.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "cm_stat_panel.tmpl", "Statistics", 450, 700, null, -1)
@@ -31,7 +31,7 @@
if(href_list["dataMenu"])
dataMenu = href_list["dataMenu"]
- nanomanager.update_uis(src)
+ SSnano.nanomanager.update_uis(src)
/datum/entity/player_entity/proc/check_eye()
return
@@ -68,7 +68,7 @@
//*******************PLAYER DATA*************************
//*******************************************************
-/datum/entity/player_entity/proc/update_panel_data(datum/entity/statistic/round/viewing_round = round_statistics)
+/datum/entity/player_entity/proc/update_panel_data(datum/entity/statistic/round/viewing_round = GLOB.round_statistics)
data["current_time"] = worldtime2text()
if(viewing_round)
diff --git a/code/datums/statistics/entities/player_entity.dm b/code/datums/statistics/entities/player_entity.dm
index 72f4d95d7aa3..f0b3d37ede7e 100644
--- a/code/datums/statistics/entities/player_entity.dm
+++ b/code/datums/statistics/entities/player_entity.dm
@@ -8,8 +8,8 @@
/datum/entity/player_entity
var/name
var/ckey // "cakey"
- var/list/datum/entity/player_stats = list()
- var/list/datum/entity/statistic/death/death_stats = list()
+ var/list/player_stats = list() //! Indeed list of /datum/entity/player_stats
+ var/list/death_stats = list() //! Indexed list of /datum/entity/statistic/death
var/menu = 0
var/subMenu = 0
var/dataMenu = 0
@@ -18,6 +18,11 @@
var/savefile_version
var/save_loaded = FALSE
+/datum/entity/player_entity/Destroy(force)
+ QDEL_LIST_ASSOC_VAL(player_stats)
+ QDEL_LIST_ASSOC_VAL(death_stats)
+ return ..()
+
/datum/entity/player_entity/proc/get_playtime(branch, type)
var/playtime = 0
if(player_stats["[branch]"])
diff --git a/code/datums/statistics/entities/player_stats.dm b/code/datums/statistics/entities/player_stats.dm
index b378d7c2ea24..a8444c1a5894 100644
--- a/code/datums/statistics/entities/player_stats.dm
+++ b/code/datums/statistics/entities/player_stats.dm
@@ -6,13 +6,21 @@
var/total_rounds_played = 0
var/steps_walked = 0
var/round_played = FALSE
- var/datum/entity/statistic/nemesis = null // "runner" = 3
+ var/datum/entity/statistic/nemesis // "runner" = 3
var/list/niche_stats = list() // list of type /datum/entity/statistic, "Total Executions" = number
var/list/humans_killed = list() // list of type /datum/entity/statistic, "jobname2" = number
var/list/xenos_killed = list() // list of type /datum/entity/statistic, "caste" = number
var/list/death_list = list() // list of type /datum/entity/death_stats
var/display_stat = TRUE
+/datum/entity/player_stats/Destroy(force)
+ QDEL_NULL(nemesis)
+ QDEL_LIST_ASSOC_VAL(niche_stats)
+ QDEL_LIST_ASSOC_VAL(humans_killed)
+ QDEL_LIST_ASSOC_VAL(xenos_killed)
+ QDEL_LIST_ASSOC_VAL(death_list)
+ return ..()
+
/datum/entity/player_stats/proc/get_playtime()
return total_playtime
@@ -73,10 +81,10 @@
/mob/proc/track_death_calculations()
if(statistic_exempt || statistic_tracked)
return
- if(round_statistics)
- round_statistics.recalculate_nemesis()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.recalculate_nemesis()
if(mind && mind.player_entity)
- mind.player_entity.update_panel_data(round_statistics)
+ mind.player_entity.update_panel_data(GLOB.round_statistics)
statistic_tracked = TRUE
//*****************
diff --git a/code/datums/statistics/entities/round_stats.dm b/code/datums/statistics/entities/round_stats.dm
index 0e1fb6e387db..25543dff22b1 100644
--- a/code/datums/statistics/entities/round_stats.dm
+++ b/code/datums/statistics/entities/round_stats.dm
@@ -23,7 +23,7 @@
var/total_slashes = 0
// untracked data
- var/datum/entity/statistic/map/current_map = null // reference to current map
+ var/datum/entity/statistic/map/current_map // reference to current map
var/list/datum/entity/statistic/death/death_stats_list = list()
var/list/abilities_used = list() // types of /datum/entity/statistic, "tail sweep" = 10, "screech" = 2
@@ -37,8 +37,20 @@
var/list/job_stats_list = list() // list of types /datum/entity/job_stats
// nanoui data
- var/round_data[0]
- var/death_data[0]
+ var/list/round_data = list()
+ var/list/death_data = list()
+
+/datum/entity/statistic/round/Destroy(force)
+ . = ..()
+ QDEL_NULL(current_map)
+ QDEL_LIST(death_stats_list)
+ QDEL_LIST_ASSOC_VAL(abilities_used)
+ QDEL_LIST_ASSOC_VAL(final_participants)
+ QDEL_LIST_ASSOC_VAL(hijack_participants)
+ QDEL_LIST_ASSOC_VAL(total_deaths)
+ QDEL_LIST_ASSOC_VAL(caste_stats_list)
+ QDEL_LIST_ASSOC_VAL(weapon_stats_list)
+ QDEL_LIST_ASSOC_VAL(job_stats_list)
/datum/entity_meta/statistic_round
entity_type = /datum/entity/statistic/round
@@ -72,9 +84,9 @@
if(!round_stats)
var/datum/entity/mc_round/mc_round = SSentity_manager.select(/datum/entity/mc_round)
var/operation_name
- operation_name = "[pick(operation_titles)]"
- operation_name += " [pick(operation_prefixes)]"
- operation_name += "-[pick(operation_postfixes)]"
+ operation_name = "[pick(GLOB.operation_titles)]"
+ operation_name += " [pick(GLOB.operation_prefixes)]"
+ operation_name += "-[pick(GLOB.operation_postfixes)]"
// Round stats
round_stats = DB_ENTITY(/datum/entity/statistic/round)
@@ -86,7 +98,7 @@
round_stats.save()
// Setup the global reference
- round_statistics = round_stats
+ GLOB.round_statistics = round_stats
// Map stats
var/datum/entity/statistic/map/new_map = DB_EKEY(/datum/entity/statistic/map, SSmapping.configs[GROUND_MAP].map_name)
@@ -364,7 +376,7 @@
stats += "Xenos remaining: [end_of_round_xenos]\n"
stats += "Hijack time: [duration2text(round_hijack_time)]\n"
- stats += "[log_end]"
+ stats += "[GLOB.log_end]"
WRITE_LOG(GLOB.round_stats, stats)
@@ -384,4 +396,4 @@
if(!can_use_action())
return
- owner.client.player_entity.show_statistics(owner, round_statistics, TRUE)
+ owner.client.player_entity.show_statistics(owner, GLOB.round_statistics, TRUE)
diff --git a/code/datums/statistics/entities/weapon_stats.dm b/code/datums/statistics/entities/weapon_stats.dm
index 0d8458c20de2..9fff5c514458 100644
--- a/code/datums/statistics/entities/weapon_stats.dm
+++ b/code/datums/statistics/entities/weapon_stats.dm
@@ -1,16 +1,23 @@
/datum/entity/weapon_stats
- var/datum/entity/player = null // "deanthelis"
- var/list/niche_stats = list() // list of type /datum/entity/statistic, "Total Reloads" = number
- var/list/humans_killed = list() // list of type /datum/entity/statistic, "jobname2" = number
- var/list/xenos_killed = list() // list of type /datum/entity/statistic, "caste" = number
- var/name = null
+ var/datum/entity/player
+ var/list/niche_stats = list() //! Indexed list of /datum/entity/statistic, "Total Reloads" = number
+ var/list/humans_killed = list() //! Indexed list of /datum/entity/statistic, "jobname2" = number
+ var/list/xenos_killed = list() //! Indexed list of /datum/entity/statistic, "caste" = number
+ var/name
var/total_kills = 0
- var/total_hits = null
- var/total_shots = null
- var/total_shots_hit = null
- var/total_friendly_fire = null
+ var/total_hits
+ var/total_shots
+ var/total_shots_hit
+ var/total_friendly_fire
var/display_stat = TRUE
+/datum/entity/weapon_stats/Destroy(force)
+ player = null
+ QDEL_LIST_ASSOC_VAL(niche_stats)
+ QDEL_LIST_ASSOC_VAL(humans_killed)
+ QDEL_LIST_ASSOC_VAL(xenos_killed)
+ return ..()
+
/datum/entity/weapon_stats/proc/count_human_kill(job_name)
if(!job_name)
return
diff --git a/code/datums/statistics/entities/xeno_stats.dm b/code/datums/statistics/entities/xeno_stats.dm
index 9ed327258258..9703c8c5e397 100644
--- a/code/datums/statistics/entities/xeno_stats.dm
+++ b/code/datums/statistics/entities/xeno_stats.dm
@@ -4,6 +4,12 @@
var/list/caste_stats_list = list() // list of types /datum/entity/player_stats/caste
var/list/datum/entity/statistic/medal/medal_list = list() // list of all royal jelly earned
+/datum/entity/player_stats/xeno/Destroy(force)
+ . = ..()
+ QDEL_NULL(top_caste)
+ QDEL_LIST_ASSOC_VAL(caste_stats_list)
+ QDEL_LIST(medal_list)
+
/datum/entity/player_stats/xeno/get_playtime(type)
if(!type || type == FACTION_XENOMORPH)
return ..()
@@ -72,15 +78,15 @@
S.total_rounds_played++
S.round_played = TRUE
S.total_playtime += time
- if(round_statistics)
- var/datum/entity/player_stats/caste/R = round_statistics.setup_caste_stats(caste)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/caste/R = GLOB.round_statistics.setup_caste_stats(caste)
R.total_playtime += time
/datum/entity/player_stats/xeno/count_personal_death(caste)
var/datum/entity/player_stats/caste/S = setup_caste_stats(caste)
S.total_deaths++
- if(round_statistics)
- var/datum/entity/player_stats/caste/R = round_statistics.setup_caste_stats(caste)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/caste/R = GLOB.round_statistics.setup_caste_stats(caste)
R.total_deaths++
//******************
@@ -90,16 +96,16 @@
/datum/entity/player_stats/xeno/count_personal_human_kill(job_name, cause, caste)
var/datum/entity/player_stats/caste/S = setup_caste_stats(caste)
S.count_human_kill(job_name, cause)
- if(round_statistics)
- var/datum/entity/player_stats/caste/R = round_statistics.setup_caste_stats(caste)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/caste/R = GLOB.round_statistics.setup_caste_stats(caste)
R.count_human_kill(job_name, cause)
recalculate_top_caste()
/datum/entity/player_stats/xeno/count_personal_xeno_kill(caste_type, cause, caste)
var/datum/entity/player_stats/caste/S = setup_caste_stats(caste)
S.count_xeno_kill(caste_type, cause)
- if(round_statistics)
- var/datum/entity/player_stats/caste/R = round_statistics.setup_caste_stats(caste)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/caste/R = GLOB.round_statistics.setup_caste_stats(caste)
R.count_xeno_kill(caste_type, cause)
recalculate_top_caste()
@@ -110,15 +116,15 @@
/datum/entity/player_stats/xeno/count_personal_niche_stat(niche_name, amount = 1, caste)
var/datum/entity/player_stats/caste/S = setup_caste_stats(caste)
S.count_niche_stat(niche_name, amount)
- if(round_statistics)
- var/datum/entity/player_stats/caste/R = round_statistics.setup_caste_stats(caste)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/caste/R = GLOB.round_statistics.setup_caste_stats(caste)
R.count_niche_stat(niche_name, amount)
/datum/entity/player_stats/xeno/proc/track_personal_abilities_used(caste, ability, amount = 1)
var/datum/entity/player_stats/caste/S = setup_caste_stats(caste)
S.track_personal_abilities_used(ability, amount)
- if(round_statistics)
- var/datum/entity/player_stats/caste/R = round_statistics.setup_caste_stats(caste)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/caste/R = GLOB.round_statistics.setup_caste_stats(caste)
R.track_personal_abilities_used(ability, amount)
/mob/living/carbon/xenomorph/proc/track_ability_usage(ability, caste, amount = 1)
@@ -131,8 +137,8 @@
/datum/entity/player_stats/xeno/count_personal_steps_walked(caste, amount = 1)
var/datum/entity/player_stats/caste/S = setup_caste_stats(caste)
S.steps_walked += amount
- if(round_statistics)
- var/datum/entity/player_stats/caste/R = round_statistics.setup_caste_stats(caste)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/caste/R = GLOB.round_statistics.setup_caste_stats(caste)
R.steps_walked += amount
/mob/living/carbon/xenomorph/track_steps_walked(amount = 1)
@@ -148,8 +154,8 @@
/datum/entity/player_stats/xeno/proc/count_personal_slashes(caste, amount = 1)
var/datum/entity/player_stats/caste/S = setup_caste_stats(caste)
S.total_hits += amount
- if(round_statistics)
- var/datum/entity/player_stats/caste/R = round_statistics.setup_caste_stats(caste)
+ if(GLOB.round_statistics)
+ var/datum/entity/player_stats/caste/R = GLOB.round_statistics.setup_caste_stats(caste)
R.total_hits += amount
/mob/living/carbon/xenomorph/proc/track_slashes(caste, amount = 1)
@@ -161,5 +167,5 @@
xeno_stats.total_hits += amount
if(caste_type)
xeno_stats.count_personal_slashes(caste_type, amount)
- if(round_statistics)
- round_statistics.total_slashes += amount
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.total_slashes += amount
diff --git a/code/datums/statistics/random_facts/random_fact.dm b/code/datums/statistics/random_facts/random_fact.dm
index 76c6e82f776d..d327bd36f4f6 100644
--- a/code/datums/statistics/random_facts/random_fact.dm
+++ b/code/datums/statistics/random_facts/random_fact.dm
@@ -24,8 +24,8 @@
var/datum/entity/statistic/death/death_to_report = null
var/mob/mob_to_report = null
- if(round_statistics && length(round_statistics.death_stats_list))
- for(var/datum/entity/statistic/death/death in round_statistics.death_stats_list)
+ if(GLOB.round_statistics && length(GLOB.round_statistics.death_stats_list))
+ for(var/datum/entity/statistic/death/death in GLOB.round_statistics.death_stats_list)
if(!check_human && !death.is_xeno)
continue
if(!check_xeno && death.is_xeno)
diff --git a/code/datums/status_effects/_status_effect.dm b/code/datums/status_effects/_status_effect.dm
new file mode 100644
index 000000000000..ddbd6366d98c
--- /dev/null
+++ b/code/datums/status_effects/_status_effect.dm
@@ -0,0 +1,277 @@
+/// Status effects are used to apply temporary or permanent effects to mobs.
+/// This file contains their code, plus code for applying and removing them.
+/datum/status_effect
+ /// The ID of the effect. ID is used in adding and removing effects to check for duplicates, among other things.
+ var/id = "effect"
+ /// When set initially / in on_creation, this is how long the status effect lasts in deciseconds.
+ /// While processing, this becomes the world.time when the status effect will expire.
+ /// -1 = infinite duration.
+ VAR_PROTECTED/duration = -1
+ /// Truthy once duration is initialized
+ VAR_PRIVATE/duration_set = FALSE
+ /// When set initially / in on_creation, this is how long between [proc/tick] calls in deciseconds.
+ /// Note that this cannot be faster than the processing subsystem you choose to fire the effect on. (See: [var/processing_speed])
+ /// While processing, this becomes the world.time when the next tick will occur.
+ /// -1 = will prevent ticks, and if duration is also unlimited (-1), stop processing wholesale.
+ var/tick_interval = 1 SECONDS
+ /// The mob affected by the status effect.
+ var/mob/living/owner
+ /// How many of the effect can be on one mob, and/or what happens when you try to add a duplicate.
+ var/status_type = STATUS_EFFECT_UNIQUE
+ /// If TRUE, we call [proc/on_remove] when owner is deleted. Otherwise, we call [proc/be_replaced].
+ var/on_remove_on_mob_delete = FALSE
+ /// The typepath to the alert thrown by the status effect when created.
+ /// Status effect "name"s and "description"s are shown to the owner here.
+ var/alert_type = /atom/movable/screen/alert/status_effect
+ /// The alert itself, created in [proc/on_creation] (if alert_type is specified).
+ var/atom/movable/screen/alert/status_effect/linked_alert
+ /// Used to define if the status effect should be using SSfasteffects or SSeffects
+ var/processing_speed = STATUS_EFFECT_FAST_PROCESS
+ /// Do we self-terminate when a fullheal is called? // CM note: this is rejuvenate
+ var/remove_on_fullheal = FALSE
+
+ /* Unimplemented feature: Our Rejuv needs refactoring to work with this
+ /// If remove_on_fullheal is TRUE, what flag do we need to be removed?
+ var/heal_flag_necessary = HEAL_STATUS
+ */
+
+ /* Particle effects feature was cut due to lacking backend, feel free to add when we have backend */
+
+ /// Timer ID for triggering the effect end precisely
+ var/timerid
+
+/datum/status_effect/New(list/arguments)
+ on_creation(arglist(arguments))
+
+/// Called from New() with any supplied status effect arguments.
+/// Not guaranteed to exist by the end.
+/// Returning FALSE from on_apply will stop on_creation and self-delete the effect.
+/datum/status_effect/proc/on_creation(mob/living/new_owner, ...)
+ SHOULD_NOT_SLEEP(TRUE) // Don't sleep between duration_set and update_timer
+ if(new_owner)
+ owner = new_owner
+ if(QDELETED(owner) || !on_apply())
+ qdel(src)
+ return
+ if(owner)
+ LAZYADD(owner.status_effects, src)
+ RegisterSignal(owner, COMSIG_LIVING_REJUVENATED, PROC_REF(remove_effect_on_heal))
+
+ if(duration != -1)
+ duration = world.time + duration
+ duration_set = TRUE
+ if(tick_interval != -1)
+ tick_interval = world.time + tick_interval
+
+ if(alert_type)
+ var/atom/movable/screen/alert/status_effect/new_alert = owner.throw_alert(id, alert_type)
+ new_alert.attached_effect = src //so the alert can reference us, if it needs to
+ linked_alert = new_alert //so we can reference the alert, if we need to
+
+ if(duration > world.time || tick_interval > world.time) //don't process if we don't care
+ switch(processing_speed)
+ if(STATUS_EFFECT_FAST_PROCESS)
+ START_PROCESSING(SSfasteffects, src)
+ if(STATUS_EFFECT_NORMAL_PROCESS)
+ START_PROCESSING(SSeffects, src)
+ update_timer()
+
+ update_particles()
+
+ return TRUE
+
+/datum/status_effect/Destroy()
+ if(timerid)
+ deltimer(timerid)
+ switch(processing_speed)
+ if(STATUS_EFFECT_FAST_PROCESS)
+ STOP_PROCESSING(SSfasteffects, src)
+ if(STATUS_EFFECT_NORMAL_PROCESS)
+ STOP_PROCESSING(SSeffects, src)
+ if(owner)
+ linked_alert = null
+ owner.clear_alert(id)
+ LAZYREMOVE(owner.status_effects, src)
+ on_remove()
+ UnregisterSignal(owner, COMSIG_LIVING_REJUVENATED)
+ owner = null
+ return ..()
+
+// Status effect process. Handles adjusting its duration and ticks.
+// If you're adding processed effects, put them in [proc/tick]
+// instead of extending / overriding the process() proc.
+/datum/status_effect/process(seconds_per_tick)
+ SHOULD_NOT_OVERRIDE(TRUE)
+ if(QDELETED(owner))
+ qdel(src)
+ return
+ if(tick_interval != -1 && tick_interval < world.time)
+ var/tick_length = initial(tick_interval)
+ tick(tick_length / (1 SECONDS))
+ tick_interval = world.time + tick_length
+ if(QDELING(src))
+ // tick deleted us, no need to continue
+ return
+
+ // Timer and update procs should basically always handle this, it's a safety net
+ if(!timerid && duration != -1 && duration < world.time)
+ qdel(src)
+ else
+ update_timer() // Attempt to start up end timer
+
+/// Updates the timer used for precisely ending the effect
+/// We force_refresh if the duration changed otherwise than ticking down
+/datum/status_effect/proc/update_timer(force_refresh = FALSE)
+ if(duration == -1 || duration <= world.time) // infinite or expired
+ return
+ else if(duration - world.time <= STATUS_EFFECT_TIME_THRESHOLD)
+ if(!timerid || force_refresh)
+ timerid = addtimer(CALLBACK(src, PROC_REF(timer_callback)), duration - world.time, TIMER_OVERRIDE|TIMER_UNIQUE|TIMER_STOPPABLE|TIMER_NO_HASH_WAIT)
+ else if(timerid)
+ deltimer(timerid)
+ timerid = null
+
+/// Timer invocation callback to end the effect
+/datum/status_effect/proc/timer_callback()
+ if(timerid)
+ timerid = null
+ qdel(src) // shrimple as that
+
+/// Called when the effect is applied in on_created
+/// Returning FALSE will cause it to delete itself during creation instead.
+/datum/status_effect/proc/on_apply()
+ return TRUE
+
+/// Gets and formats examine text associated with our status effect.
+/// Return 'null' to have no examine text appear (default behavior).
+/datum/status_effect/proc/get_examine_text()
+ return null
+
+/**
+ * Called every tick from process().
+ * This is only called of tick_interval is not -1.
+ *
+ * Note that every tick =/= every processing cycle.
+ *
+ * * seconds_between_ticks = This is how many SECONDS that elapse between ticks.
+ * This is a constant value based upon the initial tick interval set on the status effect.
+ * It is similar to seconds_per_tick, from processing itself, but adjusted to the status effect's tick interval.
+ */
+/datum/status_effect/proc/tick(seconds_between_ticks)
+ return
+
+/// Called whenever the buff expires or is removed (qdeleted)
+/// Note that at the point this is called, it is out of the
+/// owner's status_effects list, but owner is not yet null
+/datum/status_effect/proc/on_remove()
+ return
+
+/// Called instead of on_remove when a status effect
+/// of status_type STATUS_EFFECT_REPLACE is replaced by itself,
+/// or when a status effect with on_remove_on_mob_delete
+/// set to FALSE has its mob deleted
+/datum/status_effect/proc/be_replaced()
+ linked_alert = null
+ owner.clear_alert(id)
+ LAZYREMOVE(owner.status_effects, src)
+ owner = null
+ qdel(src)
+
+/// Called before being fully removed (before on_remove)
+/// Returning FALSE will cancel removal
+/datum/status_effect/proc/before_remove()
+ return TRUE
+
+/// Called when a status effect of status_type STATUS_EFFECT_REFRESH
+/// has its duration refreshed in apply_status_effect - is passed New() args
+/datum/status_effect/proc/refresh(effect, ...)
+ var/original_duration = initial(duration)
+ if(original_duration == -1)
+ return
+ duration = world.time + original_duration
+ update_timer(force_refresh = TRUE)
+
+/// Adds nextmove modifier multiplicatively to the owner while applied
+/datum/status_effect/proc/nextmove_modifier()
+ return 1
+
+/// Adds nextmove adjustment additiviely to the owner while applied
+/datum/status_effect/proc/nextmove_adjust()
+ return 0
+
+/// Signal proc for [COMSIG_LIVING_REJUVENATED] to remove us on fullheal
+/datum/status_effect/proc/remove_effect_on_heal(datum/source, heal_flags)
+ SIGNAL_HANDLER
+
+ if(!remove_on_fullheal)
+ return
+
+// if(!heal_flag_necessary || (heal_flags & heal_flag_necessary))
+// qdel(src)
+ qdel(src)
+
+/// Updates the duration of the status effect to the given [amount] of deciseconds from now, qdeling / ending if we eclipse the current world time.
+/// If increment is truthy, we only update if the resulting amount is higher.
+/datum/status_effect/proc/update_duration(amount, increment = FALSE)
+ if(!duration_set) // Barebones setter for before we start everything up
+ if(increment)
+ duration = max(duration, amount)
+ else
+ duration = amount
+ return FALSE
+ if(duration == -1) // Infinite duration
+ return FALSE
+ var/new_duration = world.time + amount
+ if(increment && duration >= new_duration)
+ return FALSE
+ duration = new_duration
+ if(duration <= world.time)
+ qdel(src)
+ return TRUE
+ update_timer(force_refresh = TRUE)
+ return FALSE
+
+/// Updates the duration of the status effect to the given [amount] of deciseconds from its current set ending
+/datum/status_effect/proc/adjust_duration(amount)
+ if(!duration_set)
+ duration += amount
+ return FALSE
+ if(duration == -1)
+ return FALSE
+ var/remaining = duration - world.time
+ remaining += amount
+ return update_duration(remaining)
+
+/// Remove [amount] of duration (in deciseconds) from the status effect. Compatibility handler with /tg/.
+/datum/status_effect/proc/remove_duration(amount)
+ adjust_duration(-amount)
+
+/// Get duration left on the effect
+/datum/status_effect/proc/get_duration_left()
+ if(!duration_set)
+ return -1
+ var/remaining = duration - world.time
+ if(remaining < 0)
+ return -1
+ return remaining
+
+
+/**
+ * Updates the particles for the status effects
+ * Should be handled by subtypes!
+ */
+
+/datum/status_effect/proc/update_particles()
+ SHOULD_CALL_PARENT(FALSE)
+
+/// Alert base type for status effect alerts
+/atom/movable/screen/alert/status_effect
+ name = "Curse of Mundanity"
+ desc = "You don't feel any different..."
+ /// The status effect we're linked to
+ var/datum/status_effect/attached_effect
+
+/atom/movable/screen/alert/status_effect/Destroy()
+ attached_effect = null //Don't keep a ref now
+ return ..()
+
diff --git a/code/datums/status_effects/_status_effect_helpers.dm b/code/datums/status_effects/_status_effect_helpers.dm
new file mode 100644
index 000000000000..02a4f9a5ccea
--- /dev/null
+++ b/code/datums/status_effects/_status_effect_helpers.dm
@@ -0,0 +1,137 @@
+
+// Status effect helpers for living mobs
+
+/**
+ * Applies a given status effect to this mob.
+ *
+ * new_effect - TYPEPATH of a status effect to apply.
+ * Additional status effect arguments can be passed.
+ *
+ * Returns the instance of the created effected, if successful.
+ * Returns 'null' if unsuccessful.
+ */
+/mob/living/proc/apply_status_effect(datum/status_effect/new_effect, ...)
+ RETURN_TYPE(/datum/status_effect)
+
+ // The arguments we pass to the start effect. The 1st argument is this mob.
+ var/list/arguments = args.Copy()
+ arguments[1] = src
+
+ // If the status effect we're applying doesn't allow multiple effects, we need to handle it
+ if(initial(new_effect.status_type) != STATUS_EFFECT_MULTIPLE)
+ for(var/datum/status_effect/existing_effect as anything in status_effects)
+ if(existing_effect.id != initial(new_effect.id))
+ continue
+
+ switch(existing_effect.status_type)
+ // Multiple are allowed, continue as normal. (Not normally reachable)
+ if(STATUS_EFFECT_MULTIPLE)
+ break
+ // Only one is allowed of this type - early return
+ if(STATUS_EFFECT_UNIQUE)
+ return
+ // Replace the existing instance (deletes it).
+ if(STATUS_EFFECT_REPLACE)
+ existing_effect.be_replaced()
+ // Refresh the existing type, then early return
+ if(STATUS_EFFECT_REFRESH)
+ existing_effect.refresh(arglist(arguments))
+ return
+
+ // Create the status effect with our mob + our arguments
+ var/datum/status_effect/new_instance = new new_effect(arguments)
+ SEND_SIGNAL(src, COMSIG_LIVING_APPLY_EFFECT, new_instance)
+ if(!QDELETED(new_instance))
+ return new_instance
+
+/**
+ * Removes all instances of a given status effect from this mob
+ *
+ * removed_effect - TYPEPATH of a status effect to remove.
+ * Additional status effect arguments can be passed - these are passed into before_remove.
+ *
+ * Returns TRUE if at least one was removed.
+ */
+/mob/living/proc/remove_status_effect(datum/status_effect/removed_effect, ...)
+ var/list/arguments = args.Copy(2)
+
+ . = FALSE
+ for(var/datum/status_effect/existing_effect as anything in status_effects)
+ if(existing_effect.id == initial(removed_effect.id) && existing_effect.before_remove(arguments))
+ qdel(existing_effect)
+ . = TRUE
+
+ return .
+
+/**
+ * Checks if this mob has a status effect that shares the passed effect's ID
+ *
+ * checked_effect - TYPEPATH of a status effect to check for. Checks for its ID, not it's typepath
+ *
+ * Returns an instance of a status effect, or NULL if none were found.
+ */
+/mob/proc/has_status_effect(datum/status_effect/checked_effect)
+ // Yes I'm being cringe and putting this on the mob level even though status effects only apply to the living level
+ // There's quite a few places (namely examine and, bleh, cult code) where it's easier to not need to cast to living before checking
+ // for an effect such as blindness
+ return null
+
+/mob/living/has_status_effect(datum/status_effect/checked_effect)
+ RETURN_TYPE(/datum/status_effect)
+
+ for(var/datum/status_effect/present_effect as anything in status_effects)
+ if(present_effect.id == initial(checked_effect.id))
+ return present_effect
+
+ return null
+
+/**
+ * Checks if this mob has a status effect that shares the passed effect's ID
+ * and has the passed sources are in its list of sources (ONLY works for grouped efects!)
+ *
+ * checked_effect - TYPEPATH of a status effect to check for. Checks for its ID, not it's typepath
+ *
+ * Returns an instance of a status effect, or NULL if none were found.
+ */
+/mob/proc/has_status_effect_from_source(datum/status_effect/grouped/checked_effect, sources)
+ // See [/mob/proc/has_status_effect] for reason behind having this on the mob level
+ return null
+
+/mob/living/has_status_effect_from_source(datum/status_effect/grouped/checked_effect, sources)
+ RETURN_TYPE(/datum/status_effect)
+
+ if(!ispath(checked_effect))
+ CRASH("has_status_effect_from_source passed with an improper status effect path.")
+
+ if(!islist(sources))
+ sources = list(sources)
+
+ for(var/datum/status_effect/grouped/present_effect in status_effects)
+ if(present_effect.id != initial(checked_effect.id))
+ continue
+ var/list/matching_sources = present_effect.sources & sources
+ if(length(matching_sources))
+ return present_effect
+
+ return null
+
+/**
+ * Returns a list of all status effects that share the passed effect type's ID
+ *
+ * checked_effect - TYPEPATH of a status effect to check for. Checks for its ID, not it's typepath
+ *
+ * Returns a list
+ */
+/mob/proc/has_status_effect_list(datum/status_effect/checked_effect)
+ // See [/mob/proc/has_status_effect] for reason behind having this on the mob level
+ return null
+
+/mob/living/has_status_effect_list(datum/status_effect/checked_effect)
+ RETURN_TYPE(/list)
+
+ var/list/effects_found = list()
+ for(var/datum/status_effect/present_effect as anything in status_effects)
+ if(present_effect.id == initial(checked_effect.id))
+ effects_found += present_effect
+
+ return effects_found
diff --git a/code/datums/status_effects/debuffs/debuffs.dm b/code/datums/status_effects/debuffs/debuffs.dm
new file mode 100644
index 000000000000..0ecfead05615
--- /dev/null
+++ b/code/datums/status_effects/debuffs/debuffs.dm
@@ -0,0 +1,120 @@
+//Largely negative status effects go here, even if they have small benificial effects
+//STUN EFFECTS
+/datum/status_effect/incapacitating
+ tick_interval = -1
+ status_type = STATUS_EFFECT_REPLACE
+ alert_type = null
+ remove_on_fullheal = TRUE
+// heal_flag_necessary = HEAL_CC_STATUS
+ var/needs_update_stat = FALSE
+
+/datum/status_effect/incapacitating/on_creation(mob/living/new_owner, set_duration)
+ if(isnum(set_duration))
+ update_duration(set_duration)
+ . = ..()
+ if(. && needs_update_stat)
+ owner.update_stat()
+
+
+/datum/status_effect/incapacitating/on_remove()
+ if(needs_update_stat ) //silicons need stat updates in addition to normal canmove updates
+ owner.update_stat()
+ return ..()
+
+//STUN
+/datum/status_effect/incapacitating/stun
+ id = "stun"
+// alert_type = /atom/movable/screen/alert/status_effect/stun
+
+/datum/status_effect/incapacitating/stun/on_apply()
+ . = ..()
+ if(!.)
+ return
+ owner.add_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED /*, TRAIT_HANDS_BLOCKED*/), TRAIT_STATUS_EFFECT(id))
+
+/datum/status_effect/incapacitating/stun/on_remove()
+ owner.remove_traits(list(TRAIT_INCAPACITATED, TRAIT_IMMOBILIZED /*, TRAIT_HANDS_BLOCKED*/), TRAIT_STATUS_EFFECT(id))
+ return ..()
+
+/atom/movable/screen/alert/status_effect/stun
+ name = "Stunned"
+ desc = "You are incapacitated. You may not move or act."
+ icon_state = ALERT_INCAPACITATED
+
+
+//KNOCKDOWN
+/datum/status_effect/incapacitating/knockdown
+ id = "knockdown"
+// alert_type = /atom/movable/screen/alert/status_effect/knockdown
+
+/datum/status_effect/incapacitating/knockdown/on_apply()
+ . = ..()
+ if(!.)
+ return
+ owner.add_traits(list(TRAIT_FLOORED, TRAIT_IMMOBILIZED), TRAIT_STATUS_EFFECT(id))
+
+/datum/status_effect/incapacitating/knockdown/on_remove()
+ owner.remove_traits(list(TRAIT_FLOORED, TRAIT_IMMOBILIZED), TRAIT_STATUS_EFFECT(id))
+ return ..()
+
+/atom/movable/screen/alert/status_effect/knockdown
+ name = "Floored"
+ desc = "You can't stand up!"
+ icon_state = ALERT_FLOORED
+
+//IMMOBILIZED
+/datum/status_effect/incapacitating/immobilized
+ id = "immobilized"
+// alert_type = /atom/movable/screen/alert/status_effect/immobilized
+
+/datum/status_effect/incapacitating/immobilized/on_apply()
+ . = ..()
+ if(!.)
+ return
+ ADD_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
+
+/datum/status_effect/incapacitating/immobilized/on_remove()
+ REMOVE_TRAIT(owner, TRAIT_IMMOBILIZED, TRAIT_STATUS_EFFECT(id))
+ return ..()
+
+/atom/movable/screen/alert/status_effect/immobilized
+ name = "Immobilized"
+ desc = "You can't move."
+ icon_state = ALERT_IMMOBILIZED
+
+//UNCONSCIOUS
+/datum/status_effect/incapacitating/unconscious
+ id = "unconscious"
+ needs_update_stat = TRUE
+// alert_type = /atom/movable/screen/alert/status_effect/unconscious
+
+/datum/status_effect/incapacitating/unconscious/on_apply()
+ . = ..()
+ if(!.)
+ return
+ ADD_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id))
+
+/datum/status_effect/incapacitating/unconscious/on_remove()
+ REMOVE_TRAIT(owner, TRAIT_KNOCKEDOUT, TRAIT_STATUS_EFFECT(id))
+ return ..()
+
+/atom/movable/screen/alert/status_effect/unconscious
+ name = "Unconscious"
+ desc = "You've been knocked out."
+ icon_state = ALERT_KNOCKEDOUT
+
+/// DAZED:
+/// This prevents talking as human or using abilities as Xenos, mainly
+/datum/status_effect/incapacitating/dazed
+ id = "dazed"
+ needs_update_stat = TRUE
+
+/datum/status_effect/incapacitating/dazed/on_apply()
+ . = ..()
+ if(!.)
+ return
+ ADD_TRAIT(owner, TRAIT_DAZED, TRAIT_STATUS_EFFECT(id))
+
+/datum/status_effect/incapacitating/dazed/on_remove()
+ REMOVE_TRAIT(owner, TRAIT_DAZED, TRAIT_STATUS_EFFECT(id))
+ return ..()
diff --git a/code/datums/status_effects/grouped_effect.dm b/code/datums/status_effects/grouped_effect.dm
new file mode 100644
index 000000000000..ade0a187e0db
--- /dev/null
+++ b/code/datums/status_effects/grouped_effect.dm
@@ -0,0 +1,20 @@
+/// Status effect from multiple sources, when all sources are removed, so is the effect
+/datum/status_effect/grouped
+ // Grouped effects adds itself to [var/sources] and destroys itself if one exists already, there are never actually multiple
+ status_type = STATUS_EFFECT_MULTIPLE
+ /// A list of all sources applying this status effect. Sources are a list of keys
+ var/list/sources = list()
+
+/datum/status_effect/grouped/on_creation(mob/living/new_owner, source)
+ var/datum/status_effect/grouped/existing = new_owner.has_status_effect(type)
+ if(existing)
+ existing.sources |= source
+ qdel(src)
+ return FALSE
+
+ sources |= source
+ return ..()
+
+/datum/status_effect/grouped/before_remove(source)
+ sources -= source
+ return !length(sources)
diff --git a/code/datums/status_effects/limited_effect.dm b/code/datums/status_effects/limited_effect.dm
new file mode 100644
index 000000000000..0f56e72da52f
--- /dev/null
+++ b/code/datums/status_effects/limited_effect.dm
@@ -0,0 +1,20 @@
+/// These effects reapply their on_apply() effect when refreshed while stacks < max_stacks.
+/datum/status_effect/limited_buff
+ id = "limited_buff"
+ duration = -1
+ status_type = STATUS_EFFECT_REFRESH
+ ///How many stacks we currently have
+ var/stacks = 1
+ ///How many stacks we can have maximum
+ var/max_stacks = 3
+
+/datum/status_effect/limited_buff/refresh(effect)
+ if(stacks < max_stacks)
+ on_apply()
+ stacks++
+ else
+ maxed_out()
+
+/// Called whenever the buff is refreshed when there are more stacks than max_stacks.
+/datum/status_effect/limited_buff/proc/maxed_out()
+ return
diff --git a/code/datums/status_effects/stacking_effect.dm b/code/datums/status_effects/stacking_effect.dm
new file mode 100644
index 000000000000..3ef5855938f7
--- /dev/null
+++ b/code/datums/status_effects/stacking_effect.dm
@@ -0,0 +1,101 @@
+/// Status effects that can stack.
+/datum/status_effect/stacking
+ id = "stacking_base"
+ duration = -1 // Only removed under specific conditions.
+ tick_interval = 1 SECONDS // Deciseconds between decays, once decay starts
+ alert_type = null
+ /// How many stacks are currently accumulated.
+ /// Also, the default stacks number given on application.
+ var/stacks = 0
+ // Deciseconds until ticks start occuring, which removes stacks
+ /// (first stack will be removed at this time plus tick_interval)
+ var/delay_before_decay
+ /// How many stacks are lost per tick (decay trigger)
+ var/stack_decay = 1
+ /// The threshold for having special effects occur when a certain stack number is reached
+ var/stack_threshold
+ /// The maximum number of stacks that can be applied
+ var/max_stacks
+ /// If TRUE, the status effect is consumed / removed when stack_threshold is met
+ var/consumed_on_threshold = TRUE
+ /// Set to true once the stack_threshold is crossed, and false once it falls back below
+ var/threshold_crossed = FALSE
+
+/* This implementation is missing effects overlays because we did not have
+ /tg/ overlays backend available at the time. Feel free to add them when we do! */
+
+/// Effects that occur when the stack count crosses stack_threshold
+/datum/status_effect/stacking/proc/threshold_cross_effect()
+ return
+
+/// Effects that occur if the status effect is removed due to the stack_threshold being crossed
+/datum/status_effect/stacking/proc/stacks_consumed_effect()
+ return
+
+/// Effects that occur if the status is removed due to being under 1 remaining stack
+/datum/status_effect/stacking/proc/fadeout_effect()
+ return
+
+/// Runs every time tick(), causes stacks to decay over time
+/datum/status_effect/stacking/proc/stack_decay_effect()
+ return
+
+/// Called when the stack_threshold is crossed (stacks go over the threshold)
+/datum/status_effect/stacking/proc/on_threshold_cross()
+ threshold_cross_effect()
+ if(consumed_on_threshold)
+ stacks_consumed_effect()
+ qdel(src)
+
+/// Called when the stack_threshold is uncrossed / dropped (stacks go under the threshold after being over it)
+/datum/status_effect/stacking/proc/on_threshold_drop()
+ return
+
+/// Whether the owner can have the status effect.
+/// Return FALSE if the owner is not in a valid state (self-deletes the effect), or TRUE otherwise
+/datum/status_effect/stacking/proc/can_have_status()
+ return owner.stat != DEAD
+
+/// Whether the owner can currently gain stacks or not
+/// Return FALSE if the owner is not in a valid state, or TRUE otherwise
+/datum/status_effect/stacking/proc/can_gain_stacks()
+ return owner.stat != DEAD
+
+/datum/status_effect/stacking/tick(seconds_between_ticks)
+ if(!can_have_status())
+ qdel(src)
+ else
+ add_stacks(-stack_decay)
+ stack_decay_effect()
+
+/// Add (or remove) [stacks_added] stacks to our current stack count.
+/datum/status_effect/stacking/proc/add_stacks(stacks_added)
+ if(stacks_added > 0 && !can_gain_stacks())
+ return FALSE
+ stacks += stacks_added
+ if(stacks > 0)
+ if(stacks >= stack_threshold && !threshold_crossed) //threshold_crossed check prevents threshold effect from occuring if changing from above threshold to still above threshold
+ threshold_crossed = TRUE
+ on_threshold_cross()
+ if(consumed_on_threshold)
+ return
+ else if(stacks < stack_threshold && threshold_crossed)
+ threshold_crossed = FALSE //resets threshold effect if we fall below threshold so threshold effect can trigger again
+ on_threshold_drop()
+ if(stacks_added > 0)
+ tick_interval += delay_before_decay //refreshes time until decay
+ stacks = min(stacks, max_stacks)
+ else
+ fadeout_effect()
+ qdel(src) //deletes status if stacks fall under one
+
+/datum/status_effect/stacking/on_creation(mob/living/new_owner, stacks_to_apply)
+ . = ..()
+ if(.)
+ add_stacks(stacks_to_apply)
+
+/datum/status_effect/stacking/on_apply()
+ if(!can_have_status())
+ return FALSE
+ return ..()
+
diff --git a/code/datums/supply_packs/_supply_packs.dm b/code/datums/supply_packs/_supply_packs.dm
index 061779d9e5ce..5bcd6937f623 100644
--- a/code/datums/supply_packs/_supply_packs.dm
+++ b/code/datums/supply_packs/_supply_packs.dm
@@ -20,7 +20,6 @@
var/group = null
var/buyable = 1 ///Can this pack be bought? These packs don't show up at all - they have to be spawned externally (fe: DEFCON ASRS)
var/randomised_num_contained = 0 //Randomly picks X of items out of the contains list instead of using all.
- var/iteration_needed = 0
/// How many W-Y dollars are deducted from the supply controller. Only use for contraband.
var/dollar_cost = 0
/// How much "heat" this crate adds, too much heat will send an investigation. Only use for contraband.
diff --git a/code/datums/supply_packs/black_market.dm b/code/datums/supply_packs/black_market.dm
index 5f8fae824312..43e0358a96f9 100644
--- a/code/datums/supply_packs/black_market.dm
+++ b/code/datums/supply_packs/black_market.dm
@@ -101,7 +101,7 @@ Non-USCM items, from CLF, UPP, colonies, etc. Mostly combat-related.
new /obj/item/clothing/head/helmet/marine/veteran/UPP(src)
new /obj/item/clothing/under/marine/veteran/UPP(src)
new /obj/item/clothing/suit/storage/marine/faction/UPP(src)
- new /obj/item/clothing/shoes/marine/upp(src)
+ new /obj/item/clothing/shoes/marine/upp/knife(src)
new /obj/item/clothing/gloves/marine/veteran(src)
new /obj/item/storage/backpack/lightpack/five_slot(src)
if(5) //freelancer
@@ -127,70 +127,42 @@ Non-USCM items, from CLF, UPP, colonies, etc. Mostly combat-related.
spawn_guns() //the crate gives 2 guns
/obj/structure/largecrate/black_market/confiscated_weaponry/proc/spawn_guns()
- switch(rand(1,6))
+ switch(rand(1, 5))
if(1) //pmc
- if(prob(50))
- new /obj/item/weapon/gun/rifle/nsg23/no_lock(src)
- new /obj/item/ammo_magazine/rifle/nsg23(src)
- new /obj/item/ammo_magazine/rifle/nsg23(src)
- new /obj/item/ammo_magazine/rifle/nsg23/ap(src)
- new /obj/item/ammo_magazine/rifle/nsg23/extended(src)
- else
- new /obj/item/weapon/gun/smg/fp9000(src)
- new /obj/item/ammo_magazine/smg/fp9000(src)
- new /obj/item/ammo_magazine/smg/fp9000(src)
- new /obj/item/ammo_magazine/smg/fp9000(src)
- new /obj/item/ammo_magazine/smg/fp9000(src)
+ new /obj/item/weapon/gun/smg/fp9000(src)
+ new /obj/item/ammo_magazine/smg/fp9000(src)
+ new /obj/item/ammo_magazine/smg/fp9000(src)
+ new /obj/item/ammo_magazine/smg/fp9000(src)
+ new /obj/item/ammo_magazine/smg/fp9000(src)
if(2) //pizza
new /obj/item/weapon/gun/pistol/holdout(src)
new /obj/item/ammo_magazine/pistol/holdout(src)
if(3) //clf
- switch(rand(1, 3))
+ switch(rand(1, 2))
if(1)
- new /obj/item/weapon/twohanded/lungemine/damaged(src)
- if(2)
new /obj/item/weapon/gun/smg/uzi(src)
new /obj/item/ammo_magazine/smg/uzi/extended(src)
new /obj/item/ammo_magazine/smg/uzi(src)
new /obj/item/ammo_magazine/smg/uzi(src)
- if(3)
+ if(2)
new /obj/item/weapon/gun/smg/mac15(src)
new /obj/item/ammo_magazine/smg/mac15/extended(src)
new /obj/item/ammo_magazine/smg/mac15(src)
new /obj/item/ammo_magazine/smg/mac15(src)
if(4) //upp
- if(prob(50))
- new /obj/item/weapon/gun/rifle/type71(src)
- new /obj/item/ammo_magazine/rifle/type71/ap(src)
- new /obj/item/ammo_magazine/rifle/type71(src)
- new /obj/item/ammo_magazine/rifle/type71(src)
- else
- new /obj/item/weapon/gun/shotgun/type23/riot_control(src)
- new /obj/item/ammo_magazine/handful/shotgun/heavy/beanbag(src)
- new /obj/item/ammo_magazine/handful/shotgun/heavy/beanbag(src)
- new /obj/item/ammo_magazine/handful/shotgun/heavy/flechette(src)
- new /obj/item/ammo_magazine/handful/shotgun/heavy/flechette(src)
- new /obj/item/ammo_magazine/handful/shotgun/heavy/slug(src)
- new /obj/item/ammo_magazine/handful/shotgun/heavy/slug(src) //NO buckshot!
+ new /obj/item/weapon/gun/shotgun/type23/riot_control(src)
+ new /obj/item/ammo_magazine/handful/shotgun/heavy/beanbag(src)
+ new /obj/item/ammo_magazine/handful/shotgun/heavy/beanbag(src)
+ new /obj/item/ammo_magazine/handful/shotgun/heavy/flechette(src)
+ new /obj/item/ammo_magazine/handful/shotgun/heavy/flechette(src)
+ new /obj/item/ammo_magazine/handful/shotgun/heavy/slug(src)
+ new /obj/item/ammo_magazine/handful/shotgun/heavy/slug(src) //NO buckshot!
if(5) //freelancer
- if(prob(80))
- new /obj/item/weapon/gun/rifle/mar40(src)
- new /obj/item/ammo_magazine/rifle/mar40/extended(src)
- new /obj/item/ammo_magazine/rifle/mar40(src)
- new /obj/item/ammo_magazine/rifle/mar40(src)
- else
- new /obj/item/weapon/gun/rifle/mar40/lmg(src)
- new /obj/item/ammo_magazine/rifle/mar40/lmg(src)
- if(6) //VAIPO
- if(prob(50))
- new /obj/item/weapon/gun/rifle/mar40/tactical(src)
- new /obj/item/ammo_magazine/rifle/mar40/extended(src)
- new /obj/item/ammo_magazine/rifle/mar40/extended(src)
- new /obj/item/ammo_magazine/rifle/mar40(src)
- else
- new /obj/item/weapon/gun/rifle/mar40/lmg(src)
- new /obj/item/ammo_magazine/rifle/mar40/lmg(src)
- new /obj/item/ammo_magazine/rifle/mar40/lmg(src)
+ new /obj/item/weapon/gun/rifle/mar40(src)
+ new /obj/item/ammo_magazine/rifle/mar40/extended(src)
+ new /obj/item/ammo_magazine/rifle/mar40(src)
+ new /obj/item/ammo_magazine/rifle/mar40(src)
+
/* Misc. Individual Guns */
@@ -561,10 +533,6 @@ Primarily made up of things that would be best utilized, well, shipside. Recreat
/obj/item/reagent_container/food/snacks/egg/random,
/obj/item/reagent_container/food/snacks/egg/random, //not a dupe
/obj/item/reagent_container/food/snacks/xemeatpie,
- /obj/item/reagent_container/food/snacks/monkeycube,
- /obj/item/reagent_container/food/snacks/monkeycube/farwacube,
- /obj/item/reagent_container/food/snacks/monkeycube/stokcube,
- /obj/item/reagent_container/food/snacks/monkeycube/yirencube,
/obj/item/reagent_container/food/snacks/upp,
/obj/item/reagent_container/food/snacks/mre_pack/xmas1,
/obj/item/reagent_container/food/snacks/mre_pack/xmas2,
@@ -617,7 +585,7 @@ Primarily made up of things that would be best utilized, well, shipside. Recreat
/obj/item/storage/box/packet/hefa/toy,
/obj/item/toy/inflatable_duck,
/obj/item/toy/beach_ball,
- /obj/item/toy/farwadoll,
+ /obj/item/toy/plush/farwa,
/obj/item/toy/waterflower,
/obj/item/toy/spinningtoy,
/obj/item/storage/box/snappops,
@@ -722,13 +690,6 @@ USCM spare items, miscellaneous gear that's too niche and distant (or restricted
dollar_cost = 50
containertype = /obj/structure/largecrate/black_market
-/datum/supply_packs/contraband/surplus/surplus_m4ra_extended
- name = "surplus magazine box (Ext M4RA x 12)"
- contains = list(/obj/item/ammo_box/magazine/m4ra/ext)
- dollar_cost = 45
- crate_heat = 3
- containertype = /obj/structure/largecrate/black_market
-
/* - Misc. USCM weaponry - */
/datum/supply_packs/contraband/surplus/mk45_automag
@@ -788,8 +749,8 @@ This is where the RO can reclaim their lost honor and purchase the M44 custom, t
dollar_cost = 10
containertype = /obj/structure/largecrate/black_market
-/datum/supply_packs/contraband/deep_storage/xm42b_pipe
- name = "10x99mm XM42B casing"
+/datum/supply_packs/contraband/deep_storage/xm43e1_pipe
+ name = "10x99mm XM43E1 casing"
contains = list(/obj/item/prop/helmetgarb/bullet_pipe)
dollar_cost = 10
containertype = /obj/structure/largecrate/black_market
@@ -1108,7 +1069,7 @@ Things that don't fit anywhere else. If they're meant for shipside use, they pro
new /obj/item/ammo_magazine/smg/mac15/extended(loc)
new /obj/item/ammo_magazine/smg/mac15/extended(loc)
loot_message = SPAN_NOTICE("It's some CLF SMG armaments.")
- if(21 to 25)
+ if(21 to 29)
// Discovered Yautja ruins.. (None of these will trigger any alarms. They are far too old, degraded, and useless for any Yautja to care.)
new /obj/item/clothing/mask/yautja_flavor(loc)
new /obj/item/clothing/suit/armor/yautja_flavor(loc)
@@ -1116,13 +1077,7 @@ Things that don't fit anywhere else. If they're meant for shipside use, they pro
new /obj/item/weapon/twohanded/yautja/glaive/damaged(loc)
new /obj/item/stack/yautja_rope(loc)
loot_message = SPAN_NOTICE("It's some strange ancient gear...?")
- if(26 to 30)
- // Damaged lunge mines, don't let the marines near these. Not even *close* to effective against even a runner.
- new /obj/item/weapon/twohanded/lungemine/damaged(loc)
- new /obj/item/weapon/twohanded/lungemine/damaged(loc)
- new /obj/item/weapon/twohanded/lungemine/damaged(loc)
- loot_message = SPAN_NOTICE("It's a bunch of lunge mines..?")
- if(31 to 35)
+ if(30 to 35)
// CLF nades!
loot_message = SPAN_NOTICE("It's a package of assorted CLF grenades!")
var/list/nades_to_pick = list(
diff --git a/code/datums/supply_packs/food.dm b/code/datums/supply_packs/food.dm
index 9e0527aed6cf..f74567c78a89 100644
--- a/code/datums/supply_packs/food.dm
+++ b/code/datums/supply_packs/food.dm
@@ -1,144 +1,47 @@
//Food.Regrouping all the ASRS crate related to food here.
-
-//All the ingredients that you can grown.
-
-/datum/supply_packs/potato
- name = "Potatoes(x20)"
- contains = list(
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- )
- cost = 10
- containertype = /obj/structure/closet/crate/freezer
- containername = "\improper Potato crate"
- group = "Food"
-
-/datum/supply_packs/tomato
- name = "tomato (x20)"
- contains = list(
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- )
- cost = 10
- containertype = /obj/structure/closet/crate/freezer
- containername = "\improper Tomato crate"
- group = "Food"
-
-/datum/supply_packs/wheat
- name = "wheat (x20)"
- contains = list(
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- /obj/item/reagent_container/food/snacks/grown/wheat,
- )
- cost = 10
- containertype = /obj/structure/closet/crate/freezer
- containername = "\improper Wheat crate"
- group = "Food"
-
-//All the meats
-
-/datum/supply_packs/meat
- name = "meat(x5)"
- contains = list(
- /obj/item/reagent_container/food/snacks/meat,
- /obj/item/reagent_container/food/snacks/meat,
- /obj/item/reagent_container/food/snacks/meat,
- /obj/item/reagent_container/food/snacks/meat,
- /obj/item/reagent_container/food/snacks/meat,
- )
- cost = 10
- containertype = /obj/structure/closet/crate/freezer
- containername = "\improper meat crate"
- group = "Food"
-
-/datum/supply_packs/carp_fillet
- name = "carp fillet (x5)"
- contains = list(
- /obj/item/reagent_container/food/snacks/carpmeat,
- /obj/item/reagent_container/food/snacks/carpmeat,
- /obj/item/reagent_container/food/snacks/carpmeat,
- /obj/item/reagent_container/food/snacks/carpmeat,
- /obj/item/reagent_container/food/snacks/carpmeat,
- )
- cost = 10
- containertype = /obj/structure/closet/crate/freezer
- containername = "\improper carp filet crate"
- group = "Food"
-
-//all the condiment type items
-
-/datum/supply_packs/condiment
- name = "crate of condiments"
+// crate of random ingredient that you can buy in vendor in kitchen
+/datum/supply_packs/ingredient
+ name = "surplus boxes of ingredients(x6 boxes)"
+ randomised_num_contained = 6
contains = list(
- /obj/item/reagent_container/food/condiment/enzyme,
- /obj/item/reagent_container/food/condiment/sugar,
- /obj/item/reagent_container/food/condiment/saltshaker,
- /obj/item/reagent_container/food/condiment/peppermill,
+ /obj/item/storage/fancy/egg_box,
+ /obj/item/storage/box/fish,
+ /obj/item/storage/box/meat,
+ /obj/item/storage/box/milk,
+ /obj/item/storage/box/soymilk,
+ /obj/item/storage/box/enzyme,
+ /obj/item/storage/box/flour,
+ /obj/item/storage/box/sugar,
+ /obj/item/storage/box/apple,
+ /obj/item/storage/box/banana,
+ /obj/item/storage/box/chanterelle,
+ /obj/item/storage/box/cherries,
+ /obj/item/storage/box/chili,
+ /obj/item/storage/box/cabbage,
+ /obj/item/storage/box/carrot,
+ /obj/item/storage/box/corn,
+ /obj/item/storage/box/eggplant,
+ /obj/item/storage/box/lemon,
+ /obj/item/storage/box/lime,
+ /obj/item/storage/box/orange,
+ /obj/item/storage/box/potato,
+ /obj/item/storage/box/tomato,
+ /obj/item/storage/box/whitebeet,
/obj/item/reagent_container/food/condiment/hotsauce/cholula,
/obj/item/reagent_container/food/condiment/hotsauce/franks,
/obj/item/reagent_container/food/condiment/hotsauce/sriracha,
/obj/item/reagent_container/food/condiment/hotsauce/tabasco,
+ /obj/item/reagent_container/food/drinks/bottle/whiskey,
+ /obj/item/reagent_container/food/drinks/bottle/tequila,
+ /obj/item/reagent_container/food/drinks/bottle/rum,
+ /obj/item/reagent_container/food/drinks/bottle/wine,
)
cost = 10
containertype = /obj/structure/closet/crate/freezer
- containername = "\improper crate of condiment"
+ containername = "\improper surplus of ingredients crate"
group = "Food"
- //all the finish snacks.
+//all the finish snacks.
/datum/supply_packs/donuts
name = "box of donuts (x5)"
@@ -165,47 +68,6 @@
containername = "\improper USCM MRE crate(x2)"
group = "Food"
-/datum/supply_packs/funfood
- name = "special ingredients crate (x6)"
- randomised_num_contained = 6
- contains = list(
- /obj/item/reagent_container/food/condiment/enzyme,
- /obj/item/reagent_container/food/condiment/saltshaker,
- /obj/item/reagent_container/food/condiment/saltshaker,
- /obj/item/reagent_container/food/condiment/saltshaker,
- /obj/item/reagent_container/food/condiment/peppermill,
- /obj/item/reagent_container/food/condiment/peppermill,
- /obj/item/reagent_container/food/condiment/peppermill,
- /obj/item/reagent_container/food/condiment/sugar,
- /obj/item/reagent_container/food/condiment/sugar,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/grown/potato,
- /obj/item/reagent_container/food/snacks/mint,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/tomato,
- /obj/item/reagent_container/food/snacks/grown/carrot,
- /obj/item/reagent_container/food/snacks/grown/carrot,
- /obj/item/reagent_container/food/snacks/grown/lemon,
- /obj/item/reagent_container/food/snacks/grown/lemon,
- /obj/item/reagent_container/food/snacks/grown/orange,
- /obj/item/reagent_container/food/snacks/grown/orange,
- /obj/item/reagent_container/food/snacks/grown/lime,
- /obj/item/reagent_container/food/snacks/grown/lime,
- /obj/item/reagent_container/food/drinks/bottle/whiskey,
- /obj/item/reagent_container/food/drinks/bottle/tequila,
- /obj/item/reagent_container/food/drinks/bottle/rum,
- /obj/item/reagent_container/food/drinks/bottle/wine,
- /obj/item/reagent_container/food/drinks/bottle/wine,
- /obj/item/reagent_container/food/drinks/bottle/wine,
- )
- cost = 10
- containertype = /obj/structure/closet/crate/freezer
- containername = "\improper Special ingredients crate"
- group = "Food"
-
/datum/supply_packs/pizzas
name = "pizza ready-to-eat (x3)"
contains = list(
diff --git a/code/datums/supply_packs/gear.dm b/code/datums/supply_packs/gear.dm
index b67f8f134c25..54a2ae221c9d 100644
--- a/code/datums/supply_packs/gear.dm
+++ b/code/datums/supply_packs/gear.dm
@@ -63,15 +63,3 @@
containertype = /obj/structure/closet/crate/ammo
containername = "fulton recovery device crate"
group = "Gear"
-
-/datum/supply_packs/nvg
- name = "M2 Night Vision Goggles Crate (x3)"
- contains = list(
- /obj/item/prop/helmetgarb/helmet_nvg,
- /obj/item/prop/helmetgarb/helmet_nvg,
- /obj/item/prop/helmetgarb/helmet_nvg,
- )
- cost = 60
- containertype = /obj/structure/closet/crate/supply
- containername = "M2 Night Vission Goggles Crate"
- group = "Gear"
diff --git a/code/datums/supply_packs/operations.dm b/code/datums/supply_packs/operations.dm
index 6d5e5d14756c..e5525504716a 100644
--- a/code/datums/supply_packs/operations.dm
+++ b/code/datums/supply_packs/operations.dm
@@ -24,7 +24,6 @@
containername = "OB Ammo Crate (Incendiary x2)"
buyable = 0
group = "Operations"
- iteration_needed = null
/datum/supply_packs/ob_explosive
contains = list(
@@ -48,7 +47,6 @@
containername = "OB Ammo Crate (HE x2)"
buyable = 0
group = "Operations"
- iteration_needed = null
/datum/supply_packs/ob_cluster
contains = list(
@@ -72,7 +70,6 @@
containername = "OB Ammo Crate (Cluster x2)"
buyable = 0
group = "Operations"
- iteration_needed = null
/datum/supply_packs/telecommsparts
name = "Replacement Telecommunications Parts"
@@ -99,7 +96,6 @@
containertype = /obj/structure/machinery/nuclearbomb
buyable = 0
group = "Operations"
- iteration_needed = null
/datum/supply_packs/technuclearbomb
name = "Encrypted Operational Nuke"
@@ -107,19 +103,17 @@
containertype = /obj/structure/machinery/nuclearbomb/tech
buyable = 0
group = "Operations"
- iteration_needed = null
/datum/supply_packs/spec_kits
name = "Weapons Specialist Kits"
contains = list(
- /obj/item/spec_kit/asrs,
- /obj/item/spec_kit/asrs,
- /obj/item/spec_kit/asrs,
- /obj/item/spec_kit/asrs,
+ /obj/item/spec_kit/rifleman,
+ /obj/item/spec_kit/rifleman,
+ /obj/item/spec_kit/rifleman,
+ /obj/item/spec_kit/rifleman,
)
cost = 0
containertype = /obj/structure/closet/crate/supply
containername = "weapons specialist kits crate"
buyable = 0
group = "Operations"
- iteration_needed = null
diff --git a/code/datums/supply_packs/restricted_equipment.dm b/code/datums/supply_packs/restricted_equipment.dm
index 452ef313908a..7979d21f9743 100644
--- a/code/datums/supply_packs/restricted_equipment.dm
+++ b/code/datums/supply_packs/restricted_equipment.dm
@@ -4,7 +4,7 @@
name = "B12 pattern marine armor crate (x1 helmet, x1 armor)"
contains = list(
/obj/item/clothing/head/helmet/marine/leader,
- /obj/item/clothing/suit/storage/marine/leader,
+ /obj/item/clothing/suit/storage/marine/medium/leader,
)
cost = 20
containertype = /obj/structure/closet/crate
@@ -15,7 +15,7 @@
name = "M4 pattern marine armor crate (x1 helmet, x1 armor)"
contains = list(
/obj/item/clothing/head/helmet/marine/rto,
- /obj/item/clothing/suit/storage/marine/rto,
+ /obj/item/clothing/suit/storage/marine/medium/rto,
)
cost = 20
containertype = /obj/structure/closet/crate
diff --git a/code/datums/supply_packs/spec_ammo.dm b/code/datums/supply_packs/spec_ammo.dm
index 7931a4d40204..e20a5de865a3 100644
--- a/code/datums/supply_packs/spec_ammo.dm
+++ b/code/datums/supply_packs/spec_ammo.dm
@@ -109,10 +109,10 @@
containername = "M42A Incendiary Magazine Crate"
group = "Weapons Specialist Ammo"
-//XM42B - Disabled during testing per request.
+//XM43E1 - Disabled during testing per request.
/*
/datum/supply_packs/ammo_amr_marksman
- name = "XM42B anti-materiel rifle marksman magazines crate (x5)"
+ name = "XM43E1 anti-materiel rifle marksman magazines crate (x5)"
contains = list(
/obj/item/ammo_magazine/sniper/anti_materiel,
/obj/item/ammo_magazine/sniper/anti_materiel,
@@ -122,7 +122,7 @@
)
cost = 30
containertype = /obj/structure/closet/crate/ammo
- containername = "XM42B Anti-Materiel Magazine Crate"
+ containername = "XM43E1 Anti-Materiel Magazine Crate"
group = "Specialist Ammo"
*/
//M4RA
diff --git a/code/datums/tgs_event_handler.dm b/code/datums/tgs_event_handler.dm
index a47d1e95af00..072a0f4d605c 100644
--- a/code/datums/tgs_event_handler.dm
+++ b/code/datums/tgs_event_handler.dm
@@ -14,21 +14,13 @@
message_admins("TGS: Instance renamed to from [world.TgsInstanceName()] to [args[2]]")
if(TGS_EVENT_COMPILE_START)
message_admins("TGS: Deployment started, new game version incoming...")
- if(world.system_type == UNIX && SSredis.connected)
- SSredis.disconnect(TGS_COMPILE)
if(TGS_EVENT_COMPILE_CANCELLED)
message_admins("TGS: Deployment cancelled!")
- if(world.system_type == UNIX && CONFIG_GET(flag/redis_enabled) && !SSredis.connected)
- SSredis.reconnect()
if(TGS_EVENT_COMPILE_FAILURE)
message_admins("TGS: Deployment failed!")
- if(world.system_type == UNIX && CONFIG_GET(flag/redis_enabled) && !SSredis.connected)
- SSredis.reconnect()
if(TGS_EVENT_DEPLOYMENT_COMPLETE)
message_admins("TGS: Deployment complete!")
to_chat(world, SPAN_BOLDANNOUNCE("Server updated, changes will be applied on the next round..."))
- if(world.system_type == UNIX && CONFIG_GET(flag/redis_enabled) && !SSredis.connected)
- SSredis.reconnect()
if(TGS_EVENT_WATCHDOG_DETACH)
message_admins("TGS restarting...")
reattach_timer = addtimer(CALLBACK(src, PROC_REF(LateOnReattach)), 1 MINUTES, TIMER_STOPPABLE)
diff --git a/code/datums/tutorial/_tutorial.dm b/code/datums/tutorial/_tutorial.dm
new file mode 100644
index 000000000000..5423453bbdb9
--- /dev/null
+++ b/code/datums/tutorial/_tutorial.dm
@@ -0,0 +1,259 @@
+GLOBAL_LIST_EMPTY_TYPED(ongoing_tutorials, /datum/tutorial)
+
+/// A tutorial datum contains a set of instructions for a player tutorial, such as what to spawn, what's scripted to occur, and so on.
+/datum/tutorial
+ /// What the tutorial is called, is player facing
+ var/name = "Base"
+ /// Internal ID of the tutorial, kept for save files
+ var/tutorial_id = "base"
+ /// A short 1-2 sentence description of the tutorial itself
+ var/desc = ""
+ /// What the tutorial's icon in the UI should look like
+ var/icon_state = ""
+ /// What category the tutorial should be under
+ var/category = TUTORIAL_CATEGORY_BASE
+ /// Ref to the bottom-left corner tile of the tutorial room
+ var/turf/bottom_left_corner
+ /// Ref to the turf reservation for this tutorial
+ var/datum/turf_reservation/reservation
+ /// Ref to the player who is doing the tutorial
+ var/mob/tutorial_mob
+ /// If the tutorial will be ending soon
+ var/tutorial_ending = FALSE
+ /// A dict of type:atom ref for some important junk that should be trackable
+ var/list/tracking_atoms = list()
+ /// What map template should be used for the tutorial
+ var/datum/map_template/tutorial/tutorial_template = /datum/map_template/tutorial/s12x12
+ /// What is the parent path of this, to exclude from the tutorial menu
+ var/parent_path = /datum/tutorial
+ /// A dictionary of "bind_name" : "keybind_button". The inverse of `key_bindings` on a client's prefs
+ var/list/player_bind_dict = list()
+
+/datum/tutorial/Destroy(force, ...)
+ GLOB.ongoing_tutorials -= src
+ QDEL_NULL(reservation) // Its Destroy() handles releasing reserved turfs
+
+ tutorial_mob = null // We don't delete it because the turf reservation will typically clean it up
+
+ QDEL_LIST_ASSOC_VAL(tracking_atoms)
+
+ return ..()
+
+/// The proc to begin doing everything related to the tutorial
+/datum/tutorial/proc/start_tutorial(mob/starting_mob)
+ SHOULD_CALL_PARENT(TRUE)
+
+ if(!starting_mob?.client)
+ return FALSE
+
+ ADD_TRAIT(starting_mob, TRAIT_IN_TUTORIAL, TRAIT_SOURCE_TUTORIAL)
+
+ tutorial_mob = starting_mob
+
+ reservation = SSmapping.RequestBlockReservation(initial(tutorial_template.width), initial(tutorial_template.height))
+ if(!reservation)
+ return FALSE
+
+ var/turf/bottom_left_corner_reservation = locate(reservation.bottom_left_coords[1], reservation.bottom_left_coords[2], reservation.bottom_left_coords[3])
+ var/datum/map_template/tutorial/template = new tutorial_template
+ template.load(bottom_left_corner_reservation, FALSE, TRUE)
+ var/obj/landmark = locate(/obj/effect/landmark/tutorial_bottom_left) in GLOB.landmarks_list
+ bottom_left_corner = get_turf(landmark)
+ qdel(landmark)
+
+ if(!verify_template_loaded())
+ abort_tutorial()
+ return FALSE
+
+ generate_binds()
+
+ GLOB.ongoing_tutorials |= src
+ var/area/tutorial_area = get_area(bottom_left_corner)
+ tutorial_area.update_base_lighting() // this will be entirely dark otherwise
+ init_map()
+ if(!tutorial_mob)
+ end_tutorial()
+
+ return TRUE
+
+/// The proc used to end and clean up the tutorial
+/datum/tutorial/proc/end_tutorial(completed = FALSE)
+ SHOULD_CALL_PARENT(TRUE)
+
+ if(tutorial_mob)
+ remove_action(tutorial_mob, /datum/action/tutorial_end) // Just in case to make sure the client can't try and leave the tutorial while it's mid-cleanup
+ if(tutorial_mob.client?.prefs && completed)
+ tutorial_mob.client.prefs.completed_tutorials |= tutorial_id
+ tutorial_mob.client.prefs.save_character()
+ var/mob/new_player/new_player = new
+ if(!tutorial_mob.mind)
+ tutorial_mob.mind_initialize()
+
+ tutorial_mob.mind.transfer_to(new_player)
+
+ if(!QDELETED(src))
+ qdel(src)
+
+/// Verify the template loaded fully and without error.
+/datum/tutorial/proc/verify_template_loaded()
+ // We subtract 1 from x and y because the bottom left corner doesn't start at the walls.
+ var/turf/true_bottom_left_corner = locate(
+ reservation.bottom_left_coords[1],
+ reservation.bottom_left_coords[2],
+ reservation.bottom_left_coords[3],
+ )
+ // We subtract 1 from x and y here because the bottom left corner counts as the first tile
+ var/turf/top_right_corner = locate(
+ true_bottom_left_corner.x + initial(tutorial_template.width) - 1,
+ true_bottom_left_corner.y + initial(tutorial_template.height) - 1,
+ true_bottom_left_corner.z
+ )
+ for(var/turf/tile as anything in block(true_bottom_left_corner, top_right_corner))
+ // For some reason I'm unsure of, the template will not always fully load, leaving some tiles to be space tiles. So, we check all tiles in the (small) tutorial area
+ // and tell start_tutorial to abort if there's any space tiles.
+ if(istype(tile, /turf/open/space))
+ return FALSE
+
+ return TRUE
+
+/// Something went very, very wrong during load so let's abort
+/datum/tutorial/proc/abort_tutorial()
+ to_chat(tutorial_mob, SPAN_BOLDWARNING("Something went wrong during tutorial load, please try again!"))
+ end_tutorial(FALSE)
+
+/datum/tutorial/proc/add_highlight(atom/target, color = "#d19a02")
+ target.add_filter("tutorial_highlight", 2, list("type" = "outline", "color" = color, "size" = 1))
+
+/datum/tutorial/proc/remove_highlight(atom/target)
+ target.remove_filter("tutorial_highlight")
+
+/datum/tutorial/proc/add_to_tracking_atoms(atom/reference)
+ tracking_atoms[reference.type] = reference
+
+/datum/tutorial/proc/remove_from_tracking_atoms(atom/reference)
+ tracking_atoms -= reference.type
+
+/// Broadcast a message to the player's screen
+/datum/tutorial/proc/message_to_player(message)
+ playsound_client(tutorial_mob.client, 'sound/effects/radiostatic.ogg', tutorial_mob.loc, 25, FALSE)
+ tutorial_mob.play_screen_text(message, /atom/movable/screen/text/screen_text/command_order/tutorial, rgb(103, 214, 146))
+ to_chat(tutorial_mob, SPAN_NOTICE(message))
+
+/// Updates a player's objective in their status tab
+/datum/tutorial/proc/update_objective(message)
+ SEND_SIGNAL(tutorial_mob, COMSIG_MOB_TUTORIAL_UPDATE_OBJECTIVE, message)
+
+/// Initialize the tutorial mob.
+/datum/tutorial/proc/init_mob()
+ tutorial_mob.AddComponent(/datum/component/tutorial_status)
+ give_action(tutorial_mob, /datum/action/tutorial_end, null, null, src)
+ ADD_TRAIT(tutorial_mob, TRAIT_IN_TUTORIAL, TRAIT_SOURCE_TUTORIAL)
+
+/// Ends the tutorial after a certain amount of time.
+/datum/tutorial/proc/tutorial_end_in(time = 5 SECONDS, completed = TRUE)
+ tutorial_ending = TRUE
+ addtimer(CALLBACK(src, PROC_REF(end_tutorial), completed), time)
+
+/// Initialize any objects that need to be in the tutorial area from the beginning.
+/datum/tutorial/proc/init_map()
+ return
+
+/// Returns a turf offset by offset_x (left-to-right) and offset_y (up-to-down)
+/datum/tutorial/proc/loc_from_corner(offset_x = 0, offset_y = 0)
+ RETURN_TYPE(/turf)
+ return locate(bottom_left_corner.x + offset_x, bottom_left_corner.y + offset_y, bottom_left_corner.z)
+
+/// Handle the player ghosting out
+/datum/tutorial/proc/on_ghost(datum/source, mob/dead/observer/ghost)
+ SIGNAL_HANDLER
+
+ var/mob/new_player/new_player = new
+ if(!ghost.mind)
+ ghost.mind_initialize()
+
+ ghost.mind.transfer_to(new_player)
+
+ end_tutorial(FALSE)
+
+/// A wrapper for signals to call end_tutorial()
+/datum/tutorial/proc/signal_end_tutorial(datum/source)
+ SIGNAL_HANDLER
+
+ end_tutorial(FALSE)
+
+/// Called whenever the tutorial_mob logs out
+/datum/tutorial/proc/on_logout(datum/source)
+ SIGNAL_HANDLER
+
+ if(tutorial_mob.aghosted)
+ return
+
+ end_tutorial(FALSE)
+
+/// Generate a dictionary of button : action for use of referencing what keys to press
+/datum/tutorial/proc/generate_binds()
+ if(!tutorial_mob.client?.prefs)
+ return
+
+ for(var/bind in tutorial_mob.client.prefs.key_bindings)
+ var/action = tutorial_mob.client.prefs.key_bindings[bind]
+ // We presume the first action under a certain binding is the one we want.
+ if(action[1] in player_bind_dict)
+ player_bind_dict[action[1]] += bind
+ else
+ player_bind_dict[action[1]] = list(bind)
+
+/// Getter for player_bind_dict. Provide an action name like "North" or "quick_equip"
+/datum/tutorial/proc/retrieve_bind(action_name)
+ if(!action_name)
+ return
+
+ if(!(action_name in player_bind_dict))
+ return "Undefined"
+
+ return player_bind_dict[action_name][1]
+
+/datum/action/tutorial_end
+ name = "Stop Tutorial"
+ action_icon_state = "hologram_exit"
+ /// Weakref to the tutorial this is related to
+ var/datum/weakref/tutorial
+
+/datum/action/tutorial_end/New(Target, override_icon_state, datum/tutorial/selected_tutorial)
+ . = ..()
+ tutorial = WEAKREF(selected_tutorial)
+
+/datum/action/tutorial_end/action_activate()
+ if(!tutorial)
+ return
+
+ var/datum/tutorial/selected_tutorial = tutorial.resolve()
+ if(selected_tutorial.tutorial_ending)
+ return
+
+ selected_tutorial.end_tutorial()
+
+
+/datum/map_template/tutorial
+ name = "Tutorial Zone (12x12)"
+ mappath = "maps/tutorial/tutorial_12x12.dmm"
+ width = 12
+ height = 12
+
+/datum/map_template/tutorial/s12x12
+
+/datum/map_template/tutorial/s8x9
+ name = "Tutorial Zone (8x9)"
+ mappath = "maps/tutorial/tutorial_8x9.dmm"
+ width = 8
+ height = 9
+
+/datum/map_template/tutorial/s8x9/no_baselight
+ name = "Tutorial Zone (8x9) (No Baselight)"
+ mappath = "maps/tutorial/tutorial_8x9_nb.dmm"
+
+/datum/map_template/tutorial/s7x7
+ name = "Tutorial Zone (7x7)"
+ mappath = "maps/tutorial/tutorial_7x7.dmm"
+ width = 7
+ height = 7
diff --git a/code/datums/tutorial/_tutorial_menu.dm b/code/datums/tutorial/_tutorial_menu.dm
new file mode 100644
index 000000000000..42eb3f6aabfa
--- /dev/null
+++ b/code/datums/tutorial/_tutorial_menu.dm
@@ -0,0 +1,83 @@
+/datum/tutorial_menu
+ /// List of ["name" = name, "tutorials" = ["name" = name, "path" = "path", "id" = tutorial_id]]
+ var/static/list/categories = list()
+
+
+/datum/tutorial_menu/New()
+ if(!length(categories))
+ var/list/categories_2 = list()
+ for(var/datum/tutorial/tutorial as anything in subtypesof(/datum/tutorial))
+ if(initial(tutorial.parent_path) == tutorial)
+ continue
+
+ if(!(initial(tutorial.category) in categories_2))
+ categories_2[initial(tutorial.category)] = list()
+
+ categories_2[initial(tutorial.category)] += list(list(
+ "name" = initial(tutorial.name),
+ "path" = "[tutorial]",
+ "id" = initial(tutorial.tutorial_id),
+ "description" = initial(tutorial.desc),
+ "image" = initial(tutorial.icon_state),
+ ))
+
+ for(var/category in categories_2)
+ categories += list(list(
+ "name" = category,
+ "tutorials" = categories_2[category],
+ ))
+
+
+/datum/tutorial_menu/proc/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "TutorialMenu")
+ ui.open()
+
+/datum/tutorial_menu/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/tutorial),
+ )
+
+/datum/tutorial_menu/ui_state(mob/user)
+ if(istype(get_area(user), /area/misc/tutorial))
+ return GLOB.never_state
+
+ return GLOB.new_player_state
+
+
+/datum/tutorial_menu/ui_static_data(mob/user)
+ var/list/data = list()
+
+ data["tutorial_categories"] = categories
+ if(user.client?.prefs)
+ data["completed_tutorials"] = user.client.prefs.completed_tutorials
+ else
+ data["completed_tutorials"] = list()
+
+ return data
+
+
+/datum/tutorial_menu/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ switch(action)
+ if("select_tutorial")
+ var/datum/tutorial/path
+ if(!params["tutorial_path"])
+ return
+
+ path = text2path(params["tutorial_path"])
+
+ if(!path || !isnewplayer(usr))
+ return
+
+ if(HAS_TRAIT(usr, TRAIT_IN_TUTORIAL) || istype(get_area(usr), /area/misc/tutorial))
+ to_chat(usr, SPAN_NOTICE("You are currently in a tutorial, or one is loading. Please be patient."))
+ return
+
+ path = new path
+ path.start_tutorial(usr)
+ return TRUE
diff --git a/code/datums/tutorial/creating_a_tutorial.md b/code/datums/tutorial/creating_a_tutorial.md
new file mode 100644
index 000000000000..96a7cb886820
--- /dev/null
+++ b/code/datums/tutorial/creating_a_tutorial.md
@@ -0,0 +1,96 @@
+# Tutorial Creation
+
+[ToC]
+
+## Step 1: Identifying the Goal
+
+Your first objective when making a tutorial should be to have a clear and concise vision of what you want the tutorial to convey to the user. People absorb information better in smaller chunks, so you should ideally keep a tutorial to one section of information at a time.
+
+For example, if you are making a tutorial for new CM players, it should be split into multiple parts like:
+
+- Basics
+- Medical
+- Weaponry
+- Requisitions/Communication
+
+## Step 2: Coding
+
+For an example of the current code standards for tutorials, see [this](https://github.com/cmss13-devs/cmss13/pull/4442/files#diff-843b2f84360b9b932dfc960027992f2b5117667962bfa8da14f9a35f0179a926) file.
+
+The API for tutorials is designed to be very simple, so I'll go over all the base `/datum/tutorial` procs and some vars here:
+
+### Variables
+- `name`
+ - This is the player-facing name of the tutorial.
+- `tutorial_id`
+ - This is the back-end ID of the tutorial, used for save files. Try not to change a tutorial's ID after it's on the live server.
+- `category`
+ - This is what category the tutorial should be under. Use the `TUTORIAL_CATEGORY_XXXX` macros.
+- `tutorial_template`
+ - This is what type the map template of the tutorial should be. The default space is 12x12; ideally make it so it fits the given scale of the tutorial with some wiggle room for the player to move around.
+- `parent_path`
+ - This is the top-most parent `/datum/tutorial` path, used to exclude abstract parents from the tutorial menu. For example, `/datum/tutorial/marine/basic` would have a `parent_path` of `/datum/tutorial/marine`, since that path is the top-most abstract path.
+
+### Procs
+- `start_tutorial(mob/starting_mob)`
+ - This proc starts the tutorial, setting up the map template and player. This should be overridden with a parent call before any overridden code.
+- `end_tutorial(completed = FALSE)`
+ - This proc ends the tutorial, sending the player back to the lobby and deleting the tutorial itself. A parent call on any subtypes should be at the end of the overridden segment. If `completed` is `TRUE`, then the tutorial will save as a completed one for the user.
+- `add_highlight(atom/target, color = "#d19a02")`
+ - This proc adds a highlight filter around an atom, by default this color. Successive calls of highlight on the same atom will override the last.
+- `remove_highlight(atom/target)`
+ - This proc removes the tutorial highlight from a target.
+- `add_to_tracking_atoms(atom/reference)`
+ - This proc will add a reference to the tutorial's tracked atom dictionary. For what a tracked atom is, see Step 2.1.
+- `remove_from_tracking_atoms(atom/reference)`
+ - This proc will remove a reference from the tutorial's tracked atom dictionary. For what a tracked atom is, see Step 2.1.
+- `message_to_player(message)`
+ - This proc is the ideal way to communicate to a player. It is visually similar to overwatch messages or weather alerts, but appears and disappears much faster. The messages sent should be consise, but can have a degree of dialogue to them.
+- `update_objective(message)`
+ - This proc is used to update the player's objective in their status panel. This should be only what is required and how to do it without any dialogue or extra text.
+- `init_mob()`
+ - This proc is used to initialize the mob and set them up correctly.
+- `init_map()`
+ - This proc does nothing by default, but can be overriden to spawn any atoms necessary for the tutorial from the very start.
+- `tutorial_end_in(time = 5 SECONDS, completed = TRUE)`
+ - This proc will end the tutorial in the given time, defaulting to 5 seconds. Once the proc is called, the player will be booted back to the menu screen after the time is up. Will mark the tutorial as completed if `completed` is `TRUE`
+- `loc_from_corner(offset_x = 0, offset_y = 0)`
+ - This proc will return a turf offset from the bottom left corner of the tutorial zone. Keep in mind, the bottom left corner is NOT on a wall, it is on the first floor on the bottom left corner. `offset_x` and `offset_y` are used to offset what turf you want to get, and should never be negative.
+
+## Step 2.1: Tracking Atoms
+Naturally, you will need to keep track of certain objects or mobs for signal purposes, so the tracking system exists to fill that purpose. When you add a reference to the tracking atom list with `add_to_tracking_atoms()`, it gets put into a dictionary of `{path : reference}`. Because of this limitation, you should not track more than 1 object of the same type. To get a tracked atom, use of the `TUTORIAL_ATOM_FROM_TRACKING(path, varname)` macro is recommended. `path` should be replaced with the precise typepath of the tracked atom, and `varname` should be replaced with the variable name you wish to use. If an object is going to be deleted, remove it with `remove_from_tracking_atoms()` first.
+
+## Step 2.2: Scripting Format
+Any proc whose main purpose is to advance the tutorial will be hereon referred to as a "script proc", as part of the entire "script". In the vast majority of cases, a script proc should hand off to the next using signals. Here is an example from `basic_marine.dm`:
+
+```javascript
+/datum/tutorial/marine/basic/proc/on_cryopod_exit()
+ SIGNAL_HANDLER
+
+ UnregisterSignal(tracking_atoms[/obj/structure/machinery/cryopod/tutorial], COMSIG_CRYOPOD_GO_OUT)
+ message_to_player("Good. You may notice the yellow \"food\" icon on the right side of your screen. Proceed to the outlined Food Vendor and vend the USCM Protein Bar.")
+ update_objective("Vend a USCM Protein Bar from the outlined ColMarTech Food Vendor.")
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial, food_vendor)
+ add_highlight(food_vendor)
+ food_vendor.req_access = list()
+ RegisterSignal(food_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, PROC_REF(on_food_vend))
+
+```
+
+Line-by-line:
+ - `SIGNAL_HANDLER` is necessary as this proc was called via signal.
+ - Here we are unregistering the signal we registered in the previous proc to call this one, which in this case was waiting for the player to leave the tracked cryopod.
+ - Now, we tell the user the next step in the script, which is sent to their screen.
+ - Here we update the player's status panel with similar info to the above line, but far more condensed.
+ - Since we need to access the food vendor, we use the `TUTORIAL_ATOM_FROM_TRACKING()` macro to get a ref to it.
+ - We add a yellow outline to the food vendor to make it more clear what is wanted of the player
+ - The tutorial food vendors are locked to `ACCESS_TUTORIAL_LOCKED` by default, so here we remove that access requirement
+ - And finally, we register a signal for the next script proc, waiting for the user to vend something from the food vendor.
+
+
+## Step 2.3: Quirks & Tips
+- Generally speaking, you will want to create `/tutorial` subtypes of anything you add in the tutorial, should it need any special functions or similar.
+- Restrict access from players as much as possible. As seen in the example above, restricting access to vendors and similar machines is recommended to prevent sequence breaking. Additionally, avoid adding anything that detracts from the tutorial itself.
+- Attempt to avoid softlocks when possible. If someone could reasonably do something (e.g. firing every bullet they have at a ranged target and missing, now unable to kill them and progress) that could softlock them, then there should be a fallback of some sort. However, accomodations don't need to be made for people who purposefully cause a softlock; there's a "stop tutorial" button for a reason.
+- When calling `message_to_player()` or `update_objective()`, **bold** the names of objects, items, and keybinds.
+- Attempt to bind as many scripting signals to the `tutorial_mob` as possible. The nature of SS13 means something as sequence-heavy as this will always be fragile, so keeping the fragility we can affect to a minimum is imperative.
diff --git a/code/datums/tutorial/marine/_marine.dm b/code/datums/tutorial/marine/_marine.dm
new file mode 100644
index 000000000000..ceb0ba8ab550
--- /dev/null
+++ b/code/datums/tutorial/marine/_marine.dm
@@ -0,0 +1,21 @@
+/datum/tutorial/marine
+ category = TUTORIAL_CATEGORY_MARINE
+ parent_path = /datum/tutorial/marine
+ icon_state = "marine"
+
+/datum/tutorial/marine/init_mob()
+ var/mob/living/carbon/human/new_character = new(bottom_left_corner)
+ new_character.lastarea = get_area(bottom_left_corner)
+
+ setup_human(new_character, tutorial_mob)
+
+ //SSround_recording.recorder.track_player(new_character) //zonenote: check if necessary
+
+ new_character.marine_snowflake_points = MARINE_TOTAL_SNOWFLAKE_POINTS
+ new_character.marine_buyable_categories = MARINE_CAN_BUY_ALL
+
+ tutorial_mob = new_character
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_GHOSTED, PROC_REF(on_ghost))
+ RegisterSignal(tutorial_mob, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_DEATH, COMSIG_MOB_END_TUTORIAL), PROC_REF(signal_end_tutorial))
+ RegisterSignal(tutorial_mob, COMSIG_MOB_LOGOUT, PROC_REF(on_logout))
+ return ..()
diff --git a/code/datums/tutorial/marine/basic_marine.dm b/code/datums/tutorial/marine/basic_marine.dm
new file mode 100644
index 000000000000..af9d2eaf18dd
--- /dev/null
+++ b/code/datums/tutorial/marine/basic_marine.dm
@@ -0,0 +1,208 @@
+/datum/tutorial/marine/basic
+ name = "Marine - Basic"
+ desc = "A tutorial to get you acquainted with the very basics of how to play a groundside marine role."
+ tutorial_id = "marine_basic_1"
+ tutorial_template = /datum/map_template/tutorial/s8x9/no_baselight
+ /// How many items need to be vended from the clothing vendor for the script to continue, if something vends 2 items (for example), increase this number by 2.
+ var/clothing_items_to_vend = 8
+ /// How many items need to be vended from the gun vendor to continue
+ var/gun_items_to_vend = 2
+
+// START OF SCRIPTING
+
+/datum/tutorial/marine/basic/start_tutorial(mob/starting_mob)
+ . = ..()
+ if(!.)
+ return
+
+ var/obj/item/device/flashlight/flashlight = new(loc_from_corner(2, 3))
+ flashlight.anchored = TRUE
+ flashlight.set_light_power(4)
+ flashlight.set_light_range(12)
+ flashlight.icon = null
+ flashlight.set_light_on(TRUE)
+ add_to_tracking_atoms(flashlight)
+
+ init_mob()
+ message_to_player("This is the tutorial for marine rifleman. Leave the cryopod by pressing [retrieve_bind("North")] or [retrieve_bind("East")] to continue.")
+ update_objective("Exit the cryopod by pressing [retrieve_bind("North")] or [retrieve_bind("East")].")
+ RegisterSignal(tracking_atoms[/obj/structure/machinery/cryopod/tutorial], COMSIG_CRYOPOD_GO_OUT, PROC_REF(on_cryopod_exit))
+
+/datum/tutorial/marine/basic/proc/on_cryopod_exit()
+ SIGNAL_HANDLER
+
+ UnregisterSignal(tracking_atoms[/obj/structure/machinery/cryopod/tutorial], COMSIG_CRYOPOD_GO_OUT)
+ message_to_player("Good. You may notice the yellow \"food\" icon on the right side of your screen. Proceed to the outlined Food Vendor and vend the USCM Protein Bar.")
+ update_objective("Vend a USCM Protein Bar from the outlined ColMarTech Food Vendor.")
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial, food_vendor)
+ add_highlight(food_vendor)
+ food_vendor.req_access = list()
+ RegisterSignal(food_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, PROC_REF(on_food_vend))
+
+/datum/tutorial/marine/basic/proc/on_food_vend(datum/source, obj/structure/machinery/cm_vending/vendor, list/itemspec, mob/living/carbon/human/user)
+ SIGNAL_HANDLER
+
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial, food_vendor)
+ UnregisterSignal(food_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND)
+ remove_highlight(food_vendor)
+ food_vendor.req_access = list(ACCESS_TUTORIAL_LOCKED)
+ message_to_player("Now click on your character with the USCM Protein Bar in-hand until it is fully eaten. If you accidentally switched hands, switch back with [retrieve_bind("swap_hands")].")
+ update_objective("Eat the USCM Protein Bar by clicking on yourself while holding it, until it is gone.")
+ RegisterSignal(tutorial_mob, COMSIG_MOB_EATEN_SNACK, PROC_REF(on_foodbar_eaten))
+
+/datum/tutorial/marine/basic/proc/on_foodbar_eaten(datum/source, obj/item/reagent_container/food/snacks/eaten_food)
+ SIGNAL_HANDLER
+
+ if(!istype(eaten_food, /obj/item/reagent_container/food/snacks/protein_pack) || eaten_food.reagents.total_volume)
+ return
+
+ UnregisterSignal(source, COMSIG_MOB_EATEN_SNACK)
+ message_to_player("Good. Now move to the outlined vendor and vend everything inside.")
+ update_objective("Vend everything inside the ColMarTech Automated Closet.")
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/clothing/tutorial, clothing_vendor)
+ add_highlight(clothing_vendor)
+ clothing_vendor.req_access = list()
+ RegisterSignal(clothing_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, PROC_REF(on_clothing_vend))
+
+/datum/tutorial/marine/basic/proc/on_clothing_vend(datum/source)
+ SIGNAL_HANDLER
+
+ clothing_items_to_vend--
+ if(clothing_items_to_vend <= 0)
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/clothing/tutorial, clothing_vendor)
+ UnregisterSignal(clothing_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND)
+ clothing_vendor.req_access = list(ACCESS_TUTORIAL_LOCKED)
+ remove_highlight(clothing_vendor)
+ message_to_player("Now, the room will darken. Take a flare out of your flare pouch by clicking on it with an empty hand, and then light it by using it in-hand with [retrieve_bind("activate_inhand")].")
+ update_objective("Click on your flare pouch to remove a flare before using it in-hand.")
+ var/obj/item/storage/pouch/flare/flare_pouch = locate(/obj/item/storage/pouch/flare) in tutorial_mob.contents
+ if(flare_pouch)
+ add_highlight(flare_pouch)
+ RegisterSignal(tutorial_mob, COMSIG_MOB_ITEM_ATTACK_SELF, PROC_REF(on_flare_light))
+ addtimer(CALLBACK(src, PROC_REF(dim_room)), 2.5 SECONDS)
+
+/datum/tutorial/marine/basic/proc/on_flare_light(datum/source, obj/item/used)
+ SIGNAL_HANDLER
+
+ if(!istype(used, /obj/item/device/flashlight/flare))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_ITEM_ATTACK_SELF)
+ var/obj/item/storage/pouch/flare/flare_pouch = locate(/obj/item/storage/pouch/flare) in tutorial_mob.contents
+ if(flare_pouch)
+ remove_highlight(flare_pouch)
+
+ message_to_player("Now throw the flare by clicking on a nearby tile, or dropping it with [retrieve_bind("drop_item")].")
+ update_objective("Throw the flare by clicking on a nearby tile, or dropping it with [retrieve_bind("drop_item")].")
+ RegisterSignal(tutorial_mob, COMSIG_MOB_ITEM_DROPPED, PROC_REF(on_flare_throw))
+
+/datum/tutorial/marine/basic/proc/on_flare_throw(datum/source, obj/item/thrown)
+ SIGNAL_HANDLER
+
+ if(!istype(thrown, /obj/item/device/flashlight/flare))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_ITEM_DROPPED)
+ message_to_player("Good. Now, the room will brighten again. Proceed to the highlighted vendor and vend a M41A Pulse Rifle MK2, along with a magazine.")
+ update_objective("Vend everything from the ColMarTech Automated Weapons Rack.")
+ addtimer(CALLBACK(src, PROC_REF(brighten_room)), 1.5 SECONDS)
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial, gun_vendor)
+ gun_vendor.req_access = list()
+ add_highlight(gun_vendor)
+ RegisterSignal(gun_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND, PROC_REF(on_gun_vend))
+
+/datum/tutorial/marine/basic/proc/on_gun_vend(datum/source)
+ SIGNAL_HANDLER
+
+ gun_items_to_vend--
+ if(gun_items_to_vend <= 0)
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial, gun_vendor)
+ gun_vendor.req_access = list(ACCESS_TUTORIAL_LOCKED)
+ remove_highlight(gun_vendor)
+ UnregisterSignal(gun_vendor, COMSIG_VENDOR_SUCCESSFUL_VEND)
+ message_to_player("Now insert the magazine into the M41A Pulse Rifle by having the magazine in your active hand and hitting the Pulse Rifle with it. If it is in the off-hand, switch with [retrieve_bind("swap_hands")].")
+ update_objective("Insert the M41A magazine by hitting the M41A Pulse Rifle with it.")
+ RegisterSignal(tutorial_mob, COMSIG_MOB_RELOADED_GUN, PROC_REF(on_magazine_insert))
+
+/datum/tutorial/marine/basic/proc/on_magazine_insert(datum/source, atom/attacked, obj/item/attacked_with)
+ SIGNAL_HANDLER
+
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_RELOADED_GUN)
+ message_to_player("Good. Now wield your gun by using it in-hand with [retrieve_bind("activate_inhand")].")
+ update_objective("Wield your gun with two hands by pressing [retrieve_bind("activate_inhand")] with the gun in your main hand.")
+ RegisterSignal(tutorial_mob, COMSIG_MOB_ITEM_ATTACK_SELF, PROC_REF(on_gun_wield))
+
+/datum/tutorial/marine/basic/proc/on_gun_wield(datum/source, obj/item/used)
+ SIGNAL_HANDLER
+
+ if(!istype(used, /obj/item/weapon/gun/rifle/m41a))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_ITEM_ATTACK_SELF)
+ message_to_player("Now, shoot at the highlighted Xenomorph until it dies.")
+ update_objective("Shoot at the Xenomorph until it dies.")
+ var/mob/living/carbon/xenomorph/drone/tutorial/xeno_dummy = new(loc_from_corner(4, 5))
+ add_to_tracking_atoms(xeno_dummy)
+ add_highlight(xeno_dummy, COLOR_VIVID_RED)
+ RegisterSignal(xeno_dummy, COMSIG_MOB_DEATH, PROC_REF(on_xeno_death))
+ RegisterSignal(tutorial_mob, COMSIG_MOB_GUN_EMPTY, PROC_REF(on_magazine_empty)) // I'd like to prevent unwilling softlocks as much as I can
+
+/// Non-contiguous part of the script, called if the user manages to run out of ammo in the gun without the xeno dying
+/datum/tutorial/marine/basic/proc/on_magazine_empty(obj/item/weapon/gun/empty_gun)
+ SIGNAL_HANDLER
+
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_GUN_EMPTY)
+ message_to_player("Your gun's out of ammo. Go grab some more from the Weaponry Vendor and kill the Xenomorph.")
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial, gun_vendor)
+ gun_vendor.req_access = list()
+ gun_vendor.load_ammo() // 99 magazines, to make sure that the xeno dies
+
+/datum/tutorial/marine/basic/proc/on_xeno_death(datum/source)
+ SIGNAL_HANDLER
+
+ TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/xenomorph/drone/tutorial, xeno_dummy)
+ UnregisterSignal(xeno_dummy, COMSIG_MOB_DEATH)
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_GUN_EMPTY)
+ remove_highlight(xeno_dummy)
+ addtimer(CALLBACK(src, PROC_REF(disappear_xeno)), 2.5 SECONDS)
+ message_to_player("Very good. This is the end of the tutorial, proceed to the next one to learn the basics of Medical. You will be sent back to the lobby screen momentarily.")
+ update_objective("")
+ tutorial_end_in(7.5 SECONDS, TRUE)
+
+
+// END OF SCRIPTING
+// START OF SCRIPT HELPERS
+
+/datum/tutorial/marine/basic/proc/dim_room()
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/device/flashlight, flashlight)
+ flashlight.set_light_on(FALSE)
+
+/datum/tutorial/marine/basic/proc/brighten_room()
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/device/flashlight, flashlight)
+ flashlight.set_light_on(TRUE)
+
+/datum/tutorial/marine/basic/proc/disappear_xeno()
+ TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/xenomorph/drone/tutorial, xeno_dummy)
+ animate(xeno_dummy, time = 5 SECONDS, alpha = 0)
+ remove_from_tracking_atoms(xeno_dummy)
+ QDEL_IN(xeno_dummy, 5.5 SECONDS)
+
+// END OF SCRIPT HELPERS
+
+/datum/tutorial/marine/basic/init_mob()
+ . = ..()
+ arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial)
+
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/structure/machinery/cryopod/tutorial, tutorial_pod)
+ tutorial_pod.go_in_cryopod(tutorial_mob, TRUE, FALSE)
+
+
+/datum/tutorial/marine/basic/init_map()
+ var/obj/structure/machinery/cryopod/tutorial/tutorial_pod = new(bottom_left_corner)
+ add_to_tracking_atoms(tutorial_pod)
+ var/obj/structure/machinery/cm_vending/sorted/marine_food/tutorial/food_vendor = new(loc_from_corner(0, 2))
+ add_to_tracking_atoms(food_vendor)
+ var/obj/structure/machinery/cm_vending/clothing/tutorial/clothing_vendor = new(loc_from_corner(0, 4))
+ add_to_tracking_atoms(clothing_vendor)
+ var/obj/structure/machinery/cm_vending/sorted/cargo_guns/squad_prep/tutorial/gun_vendor = new(loc_from_corner(0, 5))
+ add_to_tracking_atoms(gun_vendor)
diff --git a/code/datums/tutorial/marine/medical_basic.dm b/code/datums/tutorial/marine/medical_basic.dm
new file mode 100644
index 000000000000..3a42a6d2ecc2
--- /dev/null
+++ b/code/datums/tutorial/marine/medical_basic.dm
@@ -0,0 +1,174 @@
+/datum/tutorial/marine/medical_basic
+ name = "Marine - Medical (Basic)"
+ desc = "Learn how to treat common injuries you may face as a marine."
+ tutorial_id = "marine_medical_1"
+ tutorial_template = /datum/map_template/tutorial/s7x7
+
+// START OF SCRIPTING
+
+/datum/tutorial/marine/medical_basic/start_tutorial(mob/starting_mob)
+ . = ..()
+ if(!.)
+ return
+
+ init_mob()
+ message_to_player("This is the tutorial for the basics of medical that you will need to know for playing a marine role.")
+ addtimer(CALLBACK(src, PROC_REF(brute_tutorial)), 4 SECONDS)
+
+/datum/tutorial/marine/medical_basic/proc/brute_tutorial()
+ message_to_player("The first kind of damage is Brute, the most common kind. It represents physical trauma from things like punches, weapons, or guns.")
+ var/mob/living/living_mob = tutorial_mob
+ living_mob.adjustBruteLoss(10)
+ addtimer(CALLBACK(src, PROC_REF(brute_tutorial_2)), 4 SECONDS)
+
+/datum/tutorial/marine/medical_basic/proc/brute_tutorial_2()
+ message_to_player("You can observe if you have Brute or Burn damage by clicking on yourself with an empty hand on help intent.")
+ update_objective("Click on yourself with an empty hand.")
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN, PROC_REF(on_health_examine))
+
+/datum/tutorial/marine/medical_basic/proc/on_health_examine(datum/source, mob/living/carbon/human/attacked_mob)
+ SIGNAL_HANDLER
+
+ if(attacked_mob != tutorial_mob)
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN)
+ message_to_player("Good. Now, you have taken some brute damage. Bicaridine is used to fix brute over time. Pick up the bicaridine EZ autoinjector and use it in-hand.")
+ update_objective("Inject yourself with the bicaridine injector.")
+ var/obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless/one_use/brute_injector = new(loc_from_corner(0, 4))
+ add_to_tracking_atoms(brute_injector)
+ add_highlight(brute_injector)
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED, PROC_REF(on_brute_inject))
+
+/datum/tutorial/marine/medical_basic/proc/on_brute_inject(datum/source, obj/item/reagent_container/hypospray/injector)
+ SIGNAL_HANDLER
+
+ if(!istype(injector, /obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless/one_use))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED)
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless/one_use, brute_injector)
+ remove_highlight(brute_injector)
+ message_to_player("All medicines take time to work after injection. Next is Burn damage. It is obtained from things like acid or being set on fire.")
+ update_objective("")
+ var/mob/living/living_mob = tutorial_mob
+ living_mob.adjustFireLoss(10)
+ addtimer(CALLBACK(src, PROC_REF(burn_tutorial)), 4 SECONDS)
+
+/datum/tutorial/marine/medical_basic/proc/burn_tutorial()
+ message_to_player("Kelotane is used to fix burn over time. Inject yourself with the kelotane EZ autoinjector.")
+ update_objective("Inject yourself with the kelotane injector.")
+ var/obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless/one_use/burn_injector = new(loc_from_corner(0, 4))
+ add_to_tracking_atoms(burn_injector)
+ add_highlight(burn_injector)
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED, PROC_REF(on_burn_inject))
+
+
+/datum/tutorial/marine/medical_basic/proc/on_burn_inject(datum/source, obj/item/reagent_container/hypospray/injector)
+ SIGNAL_HANDLER
+
+ if(!istype(injector, /obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless/one_use))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED)
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless/one_use, burn_injector)
+ remove_highlight(burn_injector)
+ message_to_player("Good. Now, when you normally take damage, you will also feel pain. Pain slows you down and can knock you out if left unchecked.")
+ update_objective("")
+ var/mob/living/living_mob = tutorial_mob
+ living_mob.pain.apply_pain(PAIN_CHESTBURST_STRONG)
+ addtimer(CALLBACK(src, PROC_REF(pain_tutorial)), 4 SECONDS)
+
+/datum/tutorial/marine/medical_basic/proc/pain_tutorial()
+ message_to_player("Tramadol is used to reduce your pain. Inject yourself with the tramadol EZ autoinjector.")
+ update_objective("Inject yourself with the tramadol injector.")
+ var/obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless/one_use/pain_injector = new(loc_from_corner(0, 4))
+ add_to_tracking_atoms(pain_injector)
+ add_highlight(pain_injector)
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED, PROC_REF(on_pain_inject))
+
+/datum/tutorial/marine/medical_basic/proc/on_pain_inject(datum/source, obj/item/reagent_container/hypospray/injector)
+ SIGNAL_HANDLER
+
+ if(!istype(injector, /obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless/one_use))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_LIVING_HYPOSPRAY_INJECTED)
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless/one_use, pain_injector)
+ remove_highlight(pain_injector)
+ message_to_player("Good. Keep in mind that you can overdose on chemicals, so don't inject yourself with the same chemical too much too often. In the field, injectors have 3 uses.")
+ update_objective("Don't overdose! Generally, 3 injections of a chemical will overdose you.")
+ var/mob/living/living_mob = tutorial_mob
+ living_mob.pain.apply_pain(-PAIN_CHESTBURST_STRONG) // just to make sure
+ addtimer(CALLBACK(src, PROC_REF(bleed_tutorial)), 4 SECONDS)
+
+/datum/tutorial/marine/medical_basic/proc/bleed_tutorial()
+ message_to_player("You can sometimes start bleeding from things like bullets or slashes. Losing blood will accumulate oxygen damage, eventually causing death.")
+ update_objective("")
+ var/mob/living/carbon/human/human_mob = tutorial_mob
+ var/obj/limb/chest/mob_chest = locate(/obj/limb/chest) in human_mob.limbs
+ mob_chest.add_bleeding(damage_amount = 15)
+ addtimer(CALLBACK(src, PROC_REF(bleed_tutorial_2)), 4 SECONDS)
+
+/datum/tutorial/marine/medical_basic/proc/bleed_tutorial_2()
+ message_to_player("Bleeding wounds can clot themselves over time, or you can fix it quickly with gauze. Pick up the gauze and click on yourself while targeting your chest.")
+ update_objective("Gauze your chest, or let it clot on its own.")
+ var/obj/item/stack/medical/bruise_pack/two/bandage = new(loc_from_corner(0, 4))
+ add_to_tracking_atoms(bandage)
+ add_highlight(bandage)
+ var/mob/living/carbon/human/human_mob = tutorial_mob
+ var/obj/limb/chest/mob_chest = locate(/obj/limb/chest) in human_mob.limbs
+ RegisterSignal(mob_chest, COMSIG_LIMB_STOP_BLEEDING, PROC_REF(on_chest_bleed_stop))
+
+/datum/tutorial/marine/medical_basic/proc/on_chest_bleed_stop(datum/source, external, internal)
+ SIGNAL_HANDLER
+
+ // If you exit on this step, your limbs get deleted, which stops the bleeding, which progresses the tutorial despite it ending
+ if(!tutorial_mob || QDELETED(src))
+ return
+
+ var/mob/living/carbon/human/human_mob = tutorial_mob
+ var/obj/limb/chest/mob_chest = locate(/obj/limb/chest) in human_mob.limbs
+ UnregisterSignal(mob_chest, COMSIG_LIMB_STOP_BLEEDING)
+
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/stack/medical/bruise_pack/two, bandage)
+ remove_from_tracking_atoms(bandage)
+ remove_highlight(bandage)
+ qdel(bandage)
+
+ message_to_player("Good. Sometimes, a bullet or bone shard can result in you getting shrapnel, dealing damage over time. Pick up the knife and use it in-hand to remove the shrapnel.")
+ update_objective("Remove your shrapnel by using the knife in-hand.")
+ var/mob/living/living_mob = tutorial_mob
+ living_mob.pain.feels_pain = FALSE
+
+ var/obj/item/attachable/bayonet/knife = new(loc_from_corner(0, 4))
+ add_to_tracking_atoms(knife)
+ add_highlight(knife)
+
+ var/obj/item/shard/shrapnel/tutorial/shrapnel = new
+ shrapnel.on_embed(tutorial_mob, mob_chest, TRUE)
+
+ RegisterSignal(tutorial_mob, COMSIG_HUMAN_SHRAPNEL_REMOVED, PROC_REF(on_shrapnel_removed))
+
+/datum/tutorial/marine/medical_basic/proc/on_shrapnel_removed()
+ SIGNAL_HANDLER
+
+ UnregisterSignal(tutorial_mob, COMSIG_HUMAN_SHRAPNEL_REMOVED)
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/attachable/bayonet, knife)
+ remove_highlight(knife)
+ message_to_player("Good. This is the end of the basic marine medical tutorial. The tutorial will end shortly.")
+ update_objective("Tutorial completed.")
+ tutorial_end_in(5 SECONDS)
+
+// END OF SCRIPTING
+// START OF SCRIPT HELPERS
+
+// END OF SCRIPT HELPERS
+
+/datum/tutorial/marine/medical_basic/init_mob()
+ . = ..()
+ arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial/fed)
+
+
+/datum/tutorial/marine/medical_basic/init_map()
+ new /obj/structure/surface/table/almayer(loc_from_corner(0, 4))
diff --git a/code/datums/tutorial/ss13/_ss13.dm b/code/datums/tutorial/ss13/_ss13.dm
new file mode 100644
index 000000000000..53cf5c918ee9
--- /dev/null
+++ b/code/datums/tutorial/ss13/_ss13.dm
@@ -0,0 +1,41 @@
+/datum/tutorial/ss13
+ category = TUTORIAL_CATEGORY_SS13
+ parent_path = /datum/tutorial/ss13
+ icon_state = "ss13"
+
+/datum/tutorial/ss13/init_mob()
+ tutorial_mob.close_spawn_windows()
+
+ var/mob/living/carbon/human/new_character = new(bottom_left_corner)
+ new_character.lastarea = get_area(bottom_left_corner)
+
+ tutorial_mob.client.prefs.copy_all_to(new_character)
+
+ if(tutorial_mob.client.prefs.be_random_body)
+ var/datum/preferences/rand_prefs = new()
+ rand_prefs.randomize_appearance(new_character)
+
+ new_character.job = tutorial_mob.job
+ new_character.name = tutorial_mob.real_name
+ new_character.voice = tutorial_mob.real_name
+
+ new_character.sec_hud_set_ID()
+ new_character.hud_set_squad()
+
+ SSround_recording.recorder.track_player(new_character)
+
+ if(tutorial_mob.mind)
+ tutorial_mob.mind_initialize()
+ tutorial_mob.mind.transfer_to(new_character, TRUE)
+ tutorial_mob.mind.setup_human_stats()
+
+ INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, regenerate_icons))
+ INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_body), 1, 0)
+ INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_hair))
+
+ tutorial_mob = new_character
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_GHOSTED, PROC_REF(on_ghost))
+ RegisterSignal(tutorial_mob, list(COMSIG_PARENT_QDELETING, COMSIG_MOB_DEATH, COMSIG_MOB_END_TUTORIAL), PROC_REF(signal_end_tutorial))
+ RegisterSignal(tutorial_mob, COMSIG_MOB_LOGOUT, PROC_REF(on_logout))
+ arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial/fed)
+ return ..()
diff --git a/code/datums/tutorial/ss13/basic_ss13.dm b/code/datums/tutorial/ss13/basic_ss13.dm
new file mode 100644
index 000000000000..65bb0cac94f4
--- /dev/null
+++ b/code/datums/tutorial/ss13/basic_ss13.dm
@@ -0,0 +1,84 @@
+/datum/tutorial/ss13/basic
+ name = "Space Station 13 - Basic"
+ desc = "Learn the very basics of Space Station 13. Recommended if you haven't played before."
+ tutorial_id = "ss13_basic_1"
+ tutorial_template = /datum/map_template/tutorial/s7x7
+
+// START OF SCRIPTING
+
+/datum/tutorial/ss13/basic/start_tutorial(mob/starting_mob)
+ . = ..()
+ if(!.)
+ return
+
+ init_mob()
+ message_to_player("This is the tutorial for the basics of Space Station 13. Any current instructions can be found in the top-right corner, in the status panel.")
+ update_objective("Here's where it'll be!")
+
+ addtimer(CALLBACK(src, PROC_REF(require_move)), 4 SECONDS) // check if this is a good amount of time
+
+/datum/tutorial/ss13/basic/proc/require_move()
+ message_to_player("Now, move in any direction using [retrieve_bind("North")], [retrieve_bind("West")], [retrieve_bind("South")], or [retrieve_bind("East")].")
+ update_objective("Move in any direction using the [retrieve_bind("North")][retrieve_bind("West")][retrieve_bind("South")][retrieve_bind("East")] keys.")
+
+ RegisterSignal(tutorial_mob, COMSIG_MOB_MOVE_OR_LOOK, PROC_REF(on_move))
+
+/datum/tutorial/ss13/basic/proc/on_move(datum/source, actually_moving, direction, specific_direction)
+ SIGNAL_HANDLER
+
+ if(!actually_moving) // The mob just looked in a different dir instead of moving
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_MOVE_OR_LOOK)
+
+ message_to_player("Good. Now, switch hands with [retrieve_bind("swap_hands")].")
+ update_objective("Switch hands with [retrieve_bind("swap_hands")].")
+
+ RegisterSignal(tutorial_mob, COMSIG_MOB_SWAPPED_HAND, PROC_REF(on_hand_swap))
+
+/datum/tutorial/ss13/basic/proc/on_hand_swap(datum/source)
+ SIGNAL_HANDLER
+
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_SWAPPED_HAND)
+
+ message_to_player("Good. Now, pick up the satchel that just spawned and equip it with [retrieve_bind("quick_equip")].")
+ update_objective("Pick up the satchel and equip it with [retrieve_bind("quick_equip")].")
+
+ var/obj/item/storage/backpack/marine/satchel/satchel = new(loc_from_corner(2, 2))
+ add_to_tracking_atoms(satchel)
+ add_highlight(satchel)
+
+ RegisterSignal(tutorial_mob, COMSIG_HUMAN_EQUIPPED_ITEM, PROC_REF(on_satchel_equip))
+
+/datum/tutorial/ss13/basic/proc/on_satchel_equip(datum/source, obj/item/equipped, slot)
+ SIGNAL_HANDLER
+
+ if(!istype(equipped, /obj/item/storage/backpack/marine/satchel) || (slot != WEAR_BACK))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_HUMAN_EQUIPPED_ITEM)
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/storage/backpack/marine/satchel, satchel)
+ remove_highlight(satchel)
+ message_to_player("Now, say anything by pressing [retrieve_bind("Say")].")
+ update_objective("Speak using [retrieve_bind("Say")].")
+
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_SPEAK, PROC_REF(on_speak))
+
+/datum/tutorial/ss13/basic/proc/on_speak(datum/source)
+ SIGNAL_HANDLER
+
+ UnregisterSignal(tutorial_mob, COMSIG_LIVING_SPEAK)
+ message_to_player("Excellent. The next tutorial will cover intents. The tutorial will end shortly.")
+ update_objective("")
+ tutorial_end_in(5 SECONDS, TRUE)
+
+// END OF SCRIPTING
+// START OF SCRIPT HELPERS
+
+
+
+// END OF SCRIPT HELPERS
+
+/datum/tutorial/ss13/basic/init_mob()
+ . = ..()
+ tutorial_mob.forceMove(loc_from_corner(2, 1))
diff --git a/code/datums/tutorial/ss13/intents.dm b/code/datums/tutorial/ss13/intents.dm
new file mode 100644
index 000000000000..d67b2ac1b4a1
--- /dev/null
+++ b/code/datums/tutorial/ss13/intents.dm
@@ -0,0 +1,113 @@
+/datum/tutorial/ss13/intents
+ name = "Space Station 13 - Intents"
+ desc = "Learn how the intent interaction system works."
+ icon_state = "intents"
+ tutorial_id = "ss13_intents_1"
+ tutorial_template = /datum/map_template/tutorial/s7x7
+
+// START OF SCRIPTING
+
+/datum/tutorial/ss13/intents/start_tutorial(mob/starting_mob)
+ . = ..()
+ if(!.)
+ return
+
+ init_mob()
+ message_to_player("This is the tutorial for the intents system of Space Station 13. The highlighted UI element in the bottom-right corner is your current intent.")
+ var/datum/hud/human/human_hud = tutorial_mob.hud_used
+ add_highlight(human_hud.action_intent)
+
+ addtimer(CALLBACK(src, PROC_REF(require_help)), 4.5 SECONDS)
+
+/datum/tutorial/ss13/intents/proc/require_help()
+ tutorial_mob.a_intent_change(INTENT_DISARM)
+ message_to_player("Your intent has been changed off of help. Change back to it by pressing [retrieve_bind("select_help_intent")].")
+ update_objective("Change to help intent by pressing [retrieve_bind("select_help_intent")].")
+
+ RegisterSignal(tutorial_mob, COMSIG_MOB_INTENT_CHANGE, PROC_REF(on_help_intent))
+
+/datum/tutorial/ss13/intents/proc/on_help_intent(datum/source, new_intent)
+ SIGNAL_HANDLER
+
+ if(new_intent != INTENT_HELP)
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_INTENT_CHANGE)
+
+ var/mob/living/carbon/human/dummy/tutorial/tutorial_dummy = new(loc_from_corner(2, 3))
+ add_to_tracking_atoms(tutorial_dummy)
+
+ message_to_player("The first of the intents is help intent. It is used to harmlessly touch others, put out fire, give CPR, and similar. Click on the Test Dummy to give them a pat on the back.")
+ update_objective("Click on the dummy on help intent.")
+
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN, PROC_REF(on_help_attack))
+
+/datum/tutorial/ss13/intents/proc/on_help_attack(datum/source, mob/living/carbon/human/attacked_mob)
+ SIGNAL_HANDLER
+
+ if((attacked_mob == src) || (tutorial_mob.a_intent != INTENT_HELP))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN)
+ TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human/dummy/tutorial, tutorial_dummy)
+ tutorial_dummy.status_flags = DEFAULT_MOB_STATUS_FLAGS
+ REMOVE_TRAIT(tutorial_dummy, TRAIT_IMMOBILIZED, TRAIT_SOURCE_TUTORIAL)
+ tutorial_dummy.anchored = FALSE
+
+ message_to_player("The second intent is disarm, selectable with [retrieve_bind("select_disarm_intent")]. Disarm is used to shove people, which can make them drop items or fall to the ground. Shove the Test Dummy until it falls over.")
+ update_objective("Switch to disarm intent by pressing [retrieve_bind("select_disarm_intent")] and shove the dummy to the ground.")
+
+ RegisterSignal(tutorial_dummy, COMSIG_LIVING_APPLY_EFFECT, PROC_REF(on_shove_down))
+
+/datum/tutorial/ss13/intents/proc/on_shove_down(datum/source, datum/status_effect/new_effect)
+ SIGNAL_HANDLER
+
+ if(!istype(new_effect, /datum/status_effect/incapacitating/knockdown))
+ return
+
+ TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human/dummy/tutorial, tutorial_dummy)
+ UnregisterSignal(tutorial_dummy, COMSIG_LIVING_APPLY_EFFECT)
+ tutorial_dummy.rejuvenate()
+
+ message_to_player("The third intent is grab. Grab is used to grab people in either a passive, aggressive, or chokehold grab. Grab successively to \"upgrade\" your grab. Aggressively grab the Test Dummy.")
+ update_objective("Aggressively grab the dummy by grabbing them twice.")
+
+
+ RegisterSignal(tutorial_dummy, COMSIG_MOB_AGGRESSIVELY_GRABBED, PROC_REF(on_aggrograb))
+
+/datum/tutorial/ss13/intents/proc/on_aggrograb(datum/source, mob/living/carbon/human/choker)
+ SIGNAL_HANDLER
+
+ TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human/dummy/tutorial, tutorial_dummy)
+ UnregisterSignal(tutorial_dummy, COMSIG_MOB_AGGRESSIVELY_GRABBED)
+
+ message_to_player("The final intent is harm. Harm is used to injure people with your fists or a melee weapon. Punch the Test Dummy with an empty hand.")
+ update_objective("Attack the dummy with an empty hand.")
+
+ RegisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN, PROC_REF(on_harm_attack))
+
+/datum/tutorial/ss13/intents/proc/on_harm_attack(datum/source, mob/living/carbon/human/attacked_mob)
+ SIGNAL_HANDLER
+
+ if((attacked_mob == src) || (tutorial_mob.a_intent != INTENT_HARM))
+ return
+
+ UnregisterSignal(tutorial_mob, COMSIG_LIVING_ATTACKHAND_HUMAN)
+ TUTORIAL_ATOM_FROM_TRACKING(/mob/living/carbon/human/dummy/tutorial, tutorial_dummy)
+ tutorial_dummy.status_flags = GODMODE
+
+ message_to_player("Excellent. Those are the basics of the intent system. The tutorial will end shortly.")
+ update_objective("")
+
+ tutorial_end_in(5 SECONDS, TRUE)
+
+// END OF SCRIPTING
+// START OF SCRIPT HELPERS
+
+
+
+// END OF SCRIPT HELPERS
+
+/datum/tutorial/ss13/intents/init_mob()
+ . = ..()
+ tutorial_mob.forceMove(loc_from_corner(2, 0))
diff --git a/code/datums/tutorial/tutorial_example.dm b/code/datums/tutorial/tutorial_example.dm
new file mode 100644
index 000000000000..9042346f8d39
--- /dev/null
+++ b/code/datums/tutorial/tutorial_example.dm
@@ -0,0 +1,74 @@
+/datum/tutorial/marine/example
+ name = "Example Tutorial"
+ tutorial_id = "example" // This won't show up in the list, so this'll be irrelevant anyway.
+ category = TUTORIAL_CATEGORY_BASE
+ parent_path = /datum/tutorial/marine/example
+
+// START OF SCRIPTING
+
+/datum/tutorial/marine/example/start_tutorial(mob/starting_mob)
+ // Here, we're calling parent and checking its return value. If it has a falsey one (as done by !.), then something went wrong and we should abort
+ // There isn't really a reason that you _shouldn't_ have this
+ . = ..()
+ if(!.)
+ return
+
+ // Init_mob() isn't called by default, so we call it here
+ init_mob()
+ // As is standard, we give a message to the player and update their status panel with what we want done.
+ message_to_player("This is an example tutorial. Perform any emote to continue.")
+ update_objective("Do any emote.")
+ // This makes the player (tutorial_mob) listen for the COMSIG_MOB_EMOTE event, which will then call on_emote() when it hears it.
+ RegisterSignal(tutorial_mob, COMSIG_MOB_EMOTE, PROC_REF(on_emote))
+
+/datum/tutorial/marine/example/proc/on_emote(datum/source)
+ // With any proc called via signal (see the RegisterSignal line above for details), we add SIGNAL_HANDLER to it.
+ SIGNAL_HANDLER
+
+ // Now that we've gotten the signal and started the script, we want to immediately stop listening for it.
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_EMOTE)
+ message_to_player("Good. Now, pick up that can of Weyland-Yutani Aspen Beer.")
+ update_objective("Pick up that can.")
+ // This macro takes a specific type path (the same used in init_map()) and a variable name to retrieve an object from the tracked object list
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/food/drinks/cans/aspen, beer_can)
+ // Now we're adding a yellow highlight around the can to make sure people know what we're talking about
+ add_highlight(beer_can)
+ // Now, we always prefer to register signals on the tutorial_mob (as opposed to the beer_can) whenever possible
+ RegisterSignal(tutorial_mob, COMSIG_MOB_PICKUP_ITEM, PROC_REF(on_can_pickup))
+
+/// We get these arguments from the signal's definition. If you have VSC, ctrl+click on COMSIG_MOB_PICKUP_ITEM above. When dealing with a signal proc, `datum/source` is always the first argument, then any added ones
+/datum/tutorial/marine/example/proc/on_can_pickup(datum/source, obj/item/picked_up)
+ SIGNAL_HANDLER
+
+ // Since we're just listening for the mob picking anything up, we want to confirm that the picked up item is the can before continuing. If it's not, then we return and keep listening.
+ if(!istype(picked_up, /obj/item/reagent_container/food/drinks/cans/aspen))
+ // If we hit this return here, then the picked up item wasn't the can, so we abort and keep listening.
+ return
+
+ // Since we passed the above if statement, stop listening for item pickups.
+ UnregisterSignal(tutorial_mob, COMSIG_MOB_PICKUP_ITEM)
+ // Let's get the tracked beer can again.
+ TUTORIAL_ATOM_FROM_TRACKING(/obj/item/reagent_container/food/drinks/cans/aspen, beer_can)
+ // And remove the highlight now that it's picked up
+ remove_highlight(beer_can)
+ message_to_player("Very good. This is the end of the example tutorial. You will be sent back to the lobby screen momentarily.")
+ // 7.5 seconds after the above message is sent, kick the player out and end the tutorial.
+ tutorial_end_in(7.5 SECONDS, TRUE)
+
+
+// END OF SCRIPTING
+// START OF SCRIPT HELPERS
+
+// END OF SCRIPT HELPERS
+
+/datum/tutorial/marine/example/init_mob()
+ . = ..()
+ // We give the tutorial mob a basic ID so they can use general vendors and etc. This is here because not all marine tutorials may want to use a naked equipment preset.
+ arm_equipment(tutorial_mob, /datum/equipment_preset/tutorial)
+
+
+/datum/tutorial/marine/example/init_map()
+ // Here we're initializing a new can that we want to track, so we spawn it 2 tiles to the left and up from the bottom left corner of the tutorial zone
+ var/obj/item/reagent_container/food/drinks/cans/aspen/the_can = new(loc_from_corner(2, 2))
+ // Now we start tracking it
+ add_to_tracking_atoms(the_can)
diff --git a/code/datums/weather/weather_map_holders/new_varadero.dm b/code/datums/weather/weather_map_holders/new_varadero.dm
index 8222001f4739..6dae09711e47 100644
--- a/code/datums/weather/weather_map_holders/new_varadero.dm
+++ b/code/datums/weather/weather_map_holders/new_varadero.dm
@@ -16,5 +16,5 @@
return prob(PROB_WEATHER_NEW_VARADERO)
/datum/weather_ss_map_holder/new_varadero/weather_warning()
- for (var/obj/structure/machinery/storm_siren/WS in weather_notify_objects)
+ for (var/obj/structure/machinery/storm_siren/WS in GLOB.weather_notify_objects)
WS.weather_warning()
diff --git a/code/datums/weather/weather_map_holders/sorokyne.dm b/code/datums/weather/weather_map_holders/sorokyne.dm
index db55d12cdfbe..3c27a43ce1b3 100644
--- a/code/datums/weather/weather_map_holders/sorokyne.dm
+++ b/code/datums/weather/weather_map_holders/sorokyne.dm
@@ -21,5 +21,5 @@
return FALSE
/datum/weather_ss_map_holder/sorokyne/weather_warning()
- for (var/obj/structure/machinery/weather_siren/WS in weather_notify_objects)
+ for (var/obj/structure/machinery/weather_siren/WS in GLOB.weather_notify_objects)
WS.weather_warning()
diff --git a/code/defines/procs/announcement.dm b/code/defines/procs/announcement.dm
index 5223d63b8e59..3dd918abbc6b 100644
--- a/code/defines/procs/announcement.dm
+++ b/code/defines/procs/announcement.dm
@@ -45,13 +45,11 @@
if((H.faction != faction_to_display && !add_PMCs) || (H.faction != faction_to_display && add_PMCs && !(H.faction in FACTION_LIST_WY)) && !(faction_to_display in H.faction_group)) //faction checks
targets.Remove(H)
- var/datum/ares_link/link = GLOB.ares_link
- if(ares_can_log())
- switch(logging)
- if(ARES_LOG_MAIN)
- link.log_ares_announcement(title, message)
- if(ARES_LOG_SECURITY)
- link.log_ares_security(title, message)
+ switch(logging)
+ if(ARES_LOG_MAIN)
+ log_ares_announcement(title, message)
+ if(ARES_LOG_SECURITY)
+ log_ares_security(title, message)
else if(faction_to_display == "Everyone (-Yautja)")
for(var/mob/M in targets)
@@ -95,22 +93,20 @@
if(isobserver(M) || ishuman(M) && is_mainship_level(M.z))
playsound_client(M.client, sound_to_play, M, vol = 45)
- for(var/mob/living/silicon/decoy/ship_ai/AI in ai_mob_list)
+ for(var/mob/living/silicon/decoy/ship_ai/AI in GLOB.ai_mob_list)
INVOKE_ASYNC(AI, TYPE_PROC_REF(/mob/living/silicon/decoy/ship_ai, say), message)
- var/datum/ares_link/link = GLOB.ares_link
- if(ares_can_log())
- switch(logging)
- if(ARES_LOG_MAIN)
- link.log_ares_announcement("[MAIN_AI_SYSTEM] Comms Update", message)
- if(ARES_LOG_SECURITY)
- link.log_ares_security("[MAIN_AI_SYSTEM] Security Update", message)
+ switch(logging)
+ if(ARES_LOG_MAIN)
+ log_ares_announcement("[MAIN_AI_SYSTEM] Comms Update", message)
+ if(ARES_LOG_SECURITY)
+ log_ares_security("[MAIN_AI_SYSTEM] Security Update", message)
/proc/ai_silent_announcement(message, channel_prefix, bypass_cooldown = FALSE)
if(!message)
return
- for(var/mob/living/silicon/decoy/ship_ai/AI in ai_mob_list)
+ for(var/mob/living/silicon/decoy/ship_ai/AI in GLOB.ai_mob_list)
if(channel_prefix)
message = "[channel_prefix][message]"
INVOKE_ASYNC(AI, TYPE_PROC_REF(/mob/living/silicon/decoy/ship_ai, say), message)
@@ -125,7 +121,7 @@
//AI shipside announcement, that uses announcement mechanic instead of talking into comms
//to ensure that all humans on ship hear it regardless of comms and power
-/proc/shipwide_ai_announcement(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/interference.ogg'), signature)
+/proc/shipwide_ai_announcement(message, title = MAIN_AI_SYSTEM, sound_to_play = sound('sound/misc/interference.ogg'), signature, ares_logging = ARES_LOG_MAIN)
var/list/targets = GLOB.human_mob_list + GLOB.dead_mob_list
for(var/mob/T in targets)
if(isobserver(T))
@@ -135,9 +131,11 @@
if(!isnull(signature))
message += "
Signed by, [signature]"
- var/datum/ares_link/link = GLOB.ares_link
- if(link.interface && !(link.interface.inoperable()))
- link.log_ares_announcement(title, message)
+ switch(ares_logging)
+ if(ARES_LOG_MAIN)
+ log_ares_announcement(title, message)
+ if(ARES_LOG_SECURITY)
+ log_ares_security(title, message)
announcement_helper(message, title, targets, sound_to_play)
@@ -150,9 +148,7 @@
if(!ishuman(T) || isyautja(T) || !is_mainship_level(T.z))
targets.Remove(T)
- var/datum/ares_link/link = GLOB.ares_link
- if(ares_can_log())
- link.log_ares_announcement("[title] Shipwide Update", message)
+ log_ares_announcement("[title] Shipwide Update", message)
announcement_helper(message, title, targets, sound_to_play)
diff --git a/code/defines/procs/radio.dm b/code/defines/procs/radio.dm
index b4914d049fc9..d99d99b24726 100644
--- a/code/defines/procs/radio.dm
+++ b/code/defines/procs/radio.dm
@@ -2,8 +2,8 @@
var/freq_text
// the name of the channel
- for(var/channel in radiochannels)
- if(radiochannels[channel] == display_freq)
+ for(var/channel in GLOB.radiochannels)
+ if(GLOB.radiochannels[channel] == display_freq)
freq_text = channel
break
diff --git a/code/defines/procs/records.dm b/code/defines/procs/records.dm
index a1e2ade2b709..a9d40f993629 100644
--- a/code/defines/procs/records.dm
+++ b/code/defines/procs/records.dm
@@ -1,48 +1,50 @@
/proc/CreateGeneralRecord()
- var/datum/data/record/G = new /datum/data/record()
- G.fields["name"] = "New Record"
- G.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6))
- G.fields["rank"] = "Unassigned"
- G.fields["real_rank"] = "Unassigned"
- G.fields["sex"] = "Male"
- G.fields["age"] = "Unknown"
- G.fields["ethnicity"] = "Unknown"
- G.fields["p_stat"] = "Active"
- G.fields["m_stat"] = "Stable"
- G.fields["species"] = "Human"
- G.fields["origin"] = "Unknown"
- G.fields["faction"] = "Unknown"
- G.fields["mob_faction"] = "Unknown"
- G.fields["religion"] = "Unknown"
- GLOB.data_core.general += G
- return G
+ var/datum/data/record/general_record = new /datum/data/record()
+ general_record.fields["name"] = "New Record"
+ general_record.name = "New Record"
+ general_record.fields["id"] = text("[]", add_zero(num2hex(rand(1, 1.6777215E7)), 6))
+ general_record.fields["rank"] = "Unassigned"
+ general_record.fields["real_rank"] = "Unassigned"
+ general_record.fields["sex"] = "Male"
+ general_record.fields["age"] = "Unknown"
+ general_record.fields["ethnicity"] = "Unknown"
+ general_record.fields["p_stat"] = "Active"
+ general_record.fields["m_stat"] = "Stable"
+ general_record.fields["species"] = "Human"
+ general_record.fields["origin"] = "Unknown"
+ general_record.fields["faction"] = "Unknown"
+ general_record.fields["mob_faction"] = "Unknown"
+ general_record.fields["religion"] = "Unknown"
+ GLOB.data_core.general += general_record
+ return general_record
/proc/CreateSecurityRecord(name as text, id as text)
- var/datum/data/record/R = new /datum/data/record()
- R.fields["name"] = name
- R.fields["id"] = id
- R.name = text("Security Record #[id]")
- R.fields["incidents"] = "None"
- GLOB.data_core.security += R
- return R
+ var/datum/data/record/security_record = new /datum/data/record()
+ security_record.fields["name"] = name
+ security_record.fields["id"] = id
+ security_record.name = text("Security Record #[id]")
+ security_record.fields["incidents"] = "None"
+ GLOB.data_core.security += security_record
+ return security_record
-/proc/create_medical_record(mob/living/carbon/human/H)
- var/datum/data/record/M = new /datum/data/record()
- M.fields["id"] = null
- M.fields["name"] = H.real_name
- M.fields["b_type"] = H.b_type
- M.fields["mi_dis"] = "None"
- M.fields["mi_dis_d"] = "No minor disabilities have been declared."
- M.fields["ma_dis"] = "None"
- M.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
- M.fields["alg"] = "None"
- M.fields["alg_d"] = "No allergies have been detected in this patient."
- M.fields["cdi"] = "None"
- M.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
- M.fields["last_scan_time"] = null
- M.fields["last_scan_result"] = "No scan data on record"
- M.fields["autodoc_data"] = list()
- M.fields["autodoc_manual"] = list()
- M.fields["ref"] = WEAKREF(H)
- GLOB.data_core.medical += M
- return M
+/proc/create_medical_record(mob/living/carbon/human/person)
+ var/datum/data/record/medical_record = new /datum/data/record()
+ medical_record.fields["id"] = null
+ medical_record.fields["name"] = person.real_name
+ medical_record.name = person.real_name
+ medical_record.fields["b_type"] = person.b_type
+ medical_record.fields["mi_dis"] = "None"
+ medical_record.fields["mi_dis_d"] = "No minor disabilities have been declared."
+ medical_record.fields["ma_dis"] = "None"
+ medical_record.fields["ma_dis_d"] = "No major disabilities have been diagnosed."
+ medical_record.fields["alg"] = "None"
+ medical_record.fields["alg_d"] = "No allergies have been detected in this patient."
+ medical_record.fields["cdi"] = "None"
+ medical_record.fields["cdi_d"] = "No diseases have been diagnosed at the moment."
+ medical_record.fields["last_scan_time"] = null
+ medical_record.fields["last_scan_result"] = "No scan data on record"
+ medical_record.fields["autodoc_data"] = list()
+ medical_record.fields["autodoc_manual"] = list()
+ medical_record.fields["ref"] = WEAKREF(person)
+ GLOB.data_core.medical += medical_record
+ return medical_record
diff --git a/code/game/area/LV624.dm b/code/game/area/LV624.dm
index 505387f8e52b..613703a0be6e 100644
--- a/code/game/area/LV624.dm
+++ b/code/game/area/LV624.dm
@@ -382,10 +382,12 @@
/area/lv624/lazarus/engineering
name = "\improper Engineering"
icon_state = "engine_smes"
+ minimap_color = MINIMAP_AREA_ENGI
/area/lv624/lazarus/comms
name = "\improper Communications Relay"
icon_state = "tcomsatcham"
+ minimap_color = MINIMAP_AREA_ENGI
/area/lv624/lazarus/secure_storage
name = "\improper Secure Storage"
@@ -400,6 +402,7 @@
/area/lv624/lazarus/research
name = "\improper Research Lab"
icon_state = "toxlab"
+ minimap_color = MINIMAP_AREA_RESEARCH
/area/lv624/lazarus/fitness
name = "\improper Fitness Room"
diff --git a/code/game/area/WhiskeyOutpost.dm b/code/game/area/WhiskeyOutpost.dm
index 02d94dc942da..aef72d1a9941 100644
--- a/code/game/area/WhiskeyOutpost.dm
+++ b/code/game/area/WhiskeyOutpost.dm
@@ -65,7 +65,7 @@
icon_state = "livingspace"
/area/whiskey_outpost/inside/supply
- name = "\improper Supply Depo"
+ name = "\improper Supply Depot"
icon_state = "req"
/*
diff --git a/code/game/area/admin_level.dm b/code/game/area/admin_level.dm
index 00b408c04adf..bfca1481155e 100644
--- a/code/game/area/admin_level.dm
+++ b/code/game/area/admin_level.dm
@@ -144,3 +144,22 @@
/area/misc/testroom
requires_power = FALSE
name = "Test Room"
+
+/area/misc/tutorial
+ name = "Tutorial Zone"
+ icon_state = "tutorial"
+ requires_power = FALSE
+ flags_area = AREA_NOTUNNEL|AREA_AVOID_BIOSCAN
+ statistic_exempt = TRUE
+ ceiling = CEILING_METAL
+ block_game_interaction = TRUE
+ unique = TRUE
+
+ base_lighting_alpha = 255
+
+/area/misc/tutorial/Initialize(mapload, ...)
+ . = ..()
+ update_base_lighting()
+
+/area/misc/tutorial/no_baselight
+ base_lighting_alpha = 0
diff --git a/code/game/area/almayer.dm b/code/game/area/almayer.dm
index 6ced81a22b15..5267798cfe3b 100644
--- a/code/game/area/almayer.dm
+++ b/code/game/area/almayer.dm
@@ -13,13 +13,28 @@
ambience_exterior = AMBIENCE_ALMAYER
ceiling_muffle = FALSE
+ ///Whether this area is used for hijack evacuation progress
+ var/hijack_evacuation_area = FALSE
+
+ ///The weight this area gives towards hijack evacuation progress
+ var/hijack_evacuation_weight = 0
+
+ ///Whether this area is additive or multiplicative towards evacuation progress
+ var/hijack_evacuation_type = EVACUATION_TYPE_NONE
+
+/area/almayer/Initialize(mapload, ...)
+ . = ..()
+
+ if(hijack_evacuation_area)
+ SShijack.progress_areas[src] = power_equip
+
/area/shuttle/almayer/elevator_maintenance/upperdeck
- name = "\improper Maintenance Elevator"
+ name = "\improper Upper Deck Maintenance Elevator"
icon_state = "shuttle"
fake_zlevel = 1
/area/shuttle/almayer/elevator_maintenance/lowerdeck
- name = "\improper Maintenance Elevator"
+ name = "\improper Lower Deck Maintenance Elevator"
icon_state = "shuttle"
fake_zlevel = 2
@@ -83,96 +98,102 @@
resin_construction_allowed = FALSE
/area/almayer/command/securestorage
- name = "\improper Secure Storage"
+ name = "\improper Upper Deck Secure Storage"
icon_state = "corporatespace"
- fake_zlevel = 2 // lowerdeck
+ fake_zlevel = 1 // upperdeck
/area/almayer/command/computerlab
- name = "\improper Computer Lab"
+ name = "\improper Upper Deck Computer Lab"
icon_state = "ceroom"
- fake_zlevel = 2 // lowerdeck
+ fake_zlevel = 1 // upperdeck
/area/almayer/command/telecomms
- name = "\improper Telecommunications"
+ name = "\improper Upper Deck Telecommunications"
icon_state = "tcomms"
fake_zlevel = 1 // upperdeck
flags_area = AREA_NOTUNNEL
/area/almayer/command/self_destruct
- name = "\improper Self-Destruct Core Room"
+ name = "\improper Upper Deck Self-Destruct Core Room"
icon_state = "selfdestruct"
fake_zlevel = 1 // upperdeck
flags_area = AREA_NOTUNNEL
-/area/almayer/command/corporateliason
+/area/almayer/command/corporateliaison
name = "\improper Corporate Liaison Office"
icon_state = "corporatespace"
fake_zlevel = 1 // upperdeck
/area/almayer/command/combat_correspondent
- name = "\improper Combat Correspondent Office"
+ name = "\improper Upper Deck Combat Correspondent Office"
icon_state = "selfdestruct"
fake_zlevel = 1 // upperdeck
+// engineering
+
/area/almayer/engineering
minimap_color = MINIMAP_AREA_ENGI
+// lower deck
+
+/area/almayer/engineering/lower
+ name = "\improper Lower Deck Engineering"
+ icon_state = "lowerengineering"
+ fake_zlevel = 2 // lowerdeck
+
+/area/almayer/engineering/lower/engine_monitoring//this is not used so could be remove?
+ name = "\improper Lower Deck Engine Reactor Monitoring"
+ icon_state = "lowermonitoring"
+
+/area/almayer/engineering/lower/workshop
+ name = "\improper Lower Deck Engineering Workshop"
+ icon_state = "workshop"
+
+/area/almayer/engineering/lower/workshop/hangar
+ name = "\improper Ordnance workshop"
+
+/area/almayer/engineering/lower/engine_core
+ name = "\improper Engine Reactor Core Room"
+ icon_state = "coreroom"
+ soundscape_playlist = SCAPE_PL_ENG
+ soundscape_interval = 15
+ hijack_evacuation_area = TRUE
+ hijack_evacuation_weight = 0.2
+ hijack_evacuation_type = EVACUATION_TYPE_ADDITIVE
+
+// upper deck
+
/area/almayer/engineering/upper_engineering
- name = "\improper Upper Engineering"
+ name = "\improper Upper Deck Engineering"
icon_state = "upperengineering"
fake_zlevel = 1 // upperdeck
/area/almayer/engineering/upper_engineering/starboard
- name = "\improper Starboard Upper Engineering"
+ name = "\improper Upper Deck Starboard Engineering"
/area/almayer/engineering/upper_engineering/port
- name = "\improper Port Upper Engineering"
+ name = "\improper Upper Deck Port Engineering"
/area/almayer/engineering/upper_engineering/notunnel
flags_area = AREA_NOTUNNEL
/area/almayer/engineering/ce_room
- name = "\improper Chief Engineer Office"
+ name = "\improper Upper Deck Chief Engineer Office"
icon_state = "ceroom"
fake_zlevel = 1 // upperdeck
-/area/almayer/engineering/lower_engine_monitoring
- name = "\improper Engine Reactor Monitoring"
- icon_state = "lowermonitoring"
- fake_zlevel = 2 // lowerdeck
-
-/area/almayer/engineering/lower_engineering
- name = "\improper Engineering Lower"
- icon_state = "lowerengineering"
- fake_zlevel = 2 // lowerdeck
-
-/area/almayer/engineering/engineering_workshop
- name = "\improper Engineering Workshop"
- icon_state = "workshop"
- fake_zlevel = 2 // lowerdeck
-
-/area/almayer/engineering/engineering_workshop/hangar
- name = "\improper Ordnance workshop"
-
-/area/almayer/engineering/engine_core
- name = "\improper Engine Reactor Core Room"
- icon_state = "coreroom"
- fake_zlevel = 2 // lowerdeck
- soundscape_playlist = SCAPE_PL_ENG
- soundscape_interval = 15
-
/area/almayer/engineering/starboard_atmos
- name = "\improper Atmospherics Starboard"
+ name = "\improper Upper Deck Starboard Atmospherics"
icon_state = "starboardatmos"
fake_zlevel = 1 // upperdeck
/area/almayer/engineering/port_atmos
- name = "\improper Atmospherics Port"
+ name = "\improper Upper Deck Port Atmospherics"
icon_state = "portatmos"
fake_zlevel = 1 // upperdeck
/area/almayer/engineering/laundry
- name = "\improper Laundry Room"
+ name = "\improper Upper Deck Laundry Room"
icon_state = "laundry"
fake_zlevel = 1 // upperdeck
@@ -183,6 +204,9 @@
name = "\improper Astronavigational Deck"
icon_state = "astronavigation"
fake_zlevel = 2 // lowerdeck
+ hijack_evacuation_area = TRUE
+ hijack_evacuation_weight = 1.1
+ hijack_evacuation_type = EVACUATION_TYPE_MULTIPLICATIVE
/area/almayer/shipboard/panic
name = "\improper Hangar Panic Room"
@@ -190,17 +214,17 @@
fake_zlevel = 2 // lowerdeck
/area/almayer/shipboard/starboard_missiles
- name = "\improper Missile Tubes Starboard"
+ name = "\improper Upper Deck Starboard Missile Tubes"
icon_state = "starboardmissile"
fake_zlevel = 1 // upperdeck
/area/almayer/shipboard/port_missiles
- name = "\improper Missile Tubes Port"
+ name = "\improper Upper Deck Port Missile Tubes"
icon_state = "portmissile"
fake_zlevel = 1 // upperdeck
/area/almayer/shipboard/weapon_room
- name = "\improper Weapon Control Room"
+ name = "\improper Lower Deck Weapon Control"
icon_state = "weaponroom"
fake_zlevel = 2 // lowerdeck
@@ -208,15 +232,22 @@
flags_area = AREA_NOTUNNEL
/area/almayer/shipboard/starboard_point_defense
- name = "\improper Point Defense Starboard"
+ name = "\improper Lower Deck Starboard Point Defense"
icon_state = "starboardpd"
fake_zlevel = 2 // lowerdeck
/area/almayer/shipboard/port_point_defense
- name = "\improper Point Defense Port"
+ name = "\improper Lower Deck Port Point Defense"
icon_state = "portpd"
fake_zlevel = 2 // lowerdeck
+/area/almayer/shipboard/stern_point_defense
+ name = "\improper Lower Deck Stern Point Defense"
+ icon_state = "portpd"
+ fake_zlevel = 2 // lowerdeck
+
+// brig
+
/area/almayer/shipboard/brig
name = "\improper Brig"
icon_state = "brig"
@@ -224,51 +255,38 @@
/area/almayer/shipboard/brig/lobby
name = "\improper Brig Lobby"
- icon_state = "brig"
/area/almayer/shipboard/brig/armory
name = "\improper Brig Armory"
- icon_state = "brig"
/area/almayer/shipboard/brig/main_office
name = "\improper Brig Main Office"
- icon_state = "brig"
/area/almayer/shipboard/brig/perma
name = "\improper Brig Perma Cells"
- icon_state = "brig"
/area/almayer/shipboard/brig/cryo
name = "\improper Brig Cryo Pods"
- icon_state = "brig"
/area/almayer/shipboard/brig/surgery
name = "\improper Brig Surgery"
- icon_state = "brig"
/area/almayer/shipboard/brig/general_equipment
name = "\improper Brig General Equipment"
- icon_state = "brig"
/area/almayer/shipboard/brig/evidence_storage
name = "\improper Brig Evidence Storage"
- icon_state = "brig"
/area/almayer/shipboard/brig/execution
name = "\improper Brig Execution Room"
- icon_state = "brig"
/area/almayer/shipboard/brig/cic_hallway
name = "\improper Brig CiC Hallway"
- icon_state = "brig"
/area/almayer/shipboard/brig/dress
name = "\improper CIC Dress Uniform Room"
- icon_state = "brig"
-
/area/almayer/shipboard/brig/processing
name = "\improper Brig Processing and Holding"
- icon_state = "brig"
/area/almayer/shipboard/brig/cells
name = "\improper Brig Cells"
@@ -279,7 +297,7 @@
icon_state = "chiefmpoffice"
/area/almayer/shipboard/sea_office
- name = "\improper Senior Enlisted Advisor Office"
+ name = "\improper Lower Deck Senior Enlisted Advisor Office"
icon_state = "chiefmpoffice"
fake_zlevel = 2 // lowerdeck
@@ -305,7 +323,7 @@
soundscape_interval = 50
/area/almayer/hallways/vehiclehangar
- name = "\improper Vehicle Storage"
+ name = "\improper Lower Deck Vehicle Storage"
icon_state = "exoarmor"
fake_zlevel = 2
@@ -313,135 +331,146 @@
minimap_color = MINIMAP_AREA_COLONY
/area/almayer/living/tankerbunks
- name = "\improper Vehicle Crew Bunks"
+ name = "\improper Lower Deck Vehicle Crew Bunks"
icon_state = "livingspace"
fake_zlevel = 2
/area/almayer/living/auxiliary_officer_office
- name = "\improper Auxiliary Support Officer office"
+ name = "\improper Lower Deck Auxiliary Support Officer office"
icon_state = "livingspace"
fake_zlevel = 2
/area/almayer/squads/tankdeliveries
- name = "\improper Vehicle ASRS"
+ name = "\improper Lower Deck Vehicle ASRS"
icon_state = "req"
fake_zlevel = 2
/area/almayer/hallways/exoarmor
- name = "\improper Vehicle Armor Storage"
+ name = "\improper Lower Deck Vehicle Armor Storage"
icon_state = "exoarmor"
fake_zlevel = 2 // lowerdeck
/area/almayer/hallways/repair_bay
- name = "\improper Deployment Workshop"
+ name = "\improper Lower Deck Deployment Workshop"
icon_state = "dropshiprepair"
fake_zlevel = 2 // lowerdeck
/area/almayer/hallways/mission_planner
- name = "\improper Dropship Central Computer Room"
+ name = "\improper Lower Deck Dropship Central Computer Room"
icon_state = "missionplanner"
fake_zlevel = 2 // lowerdeck
/area/almayer/hallways/starboard_umbilical
- name = "\improper Umbilical Starboard"
+ name = "\improper Lower Deck Starboard Umbilical Hallway"
icon_state = "starboardumbilical"
fake_zlevel = 2 // lowerdeck
/area/almayer/hallways/port_umbilical
- name = "\improper Umbilical Port"
+ name = "\improper Lower Deck Port Umbilical Hallway"
icon_state = "portumbilical"
fake_zlevel = 2 // lowerdeck
/area/almayer/hallways/aft_hallway
- name = "\improper Hallway Aft"
+ name = "\improper Upper Deck Aft Hallway"
icon_state = "aft"
fake_zlevel = 1 // upperdeck
/area/almayer/hallways/stern_hallway
- name = "\improper Hallway Stern"
+ name = "\improper Upper Deck Stern Hallway"
icon_state = "stern"
fake_zlevel = 1 // upperdeck
/area/almayer/hallways/port_hallway
- name = "\improper Hallway Port"
+ name = "\improper Lower Deck Port Hallway"
icon_state = "port"
fake_zlevel = 2 // lowerdeck
/area/almayer/hallways/starboard_hallway
- name = "\improper Hallway Starboard"
+ name = "\improper Lower Deck Starboard Hallway"
icon_state = "starboard"
fake_zlevel = 2 // lowerdeck
+//new hallways areas
+
+/area/almayer/hallways/upper
+ fake_zlevel = 1 // upperdeck
+
+/area/almayer/hallways/upper/port
+ name = "\improper Upper Deck Port Hallway"
+ icon_state = "port"
+
+/area/almayer/hallways/upper/starboard
+ name = "\improper Upper Deck Starboard Hallway"
+ icon_state = "starboard"
+
/area/almayer/stair_clone
- name = "\improper Stairs"
+ name = "\improper Lower Deck Stairs"
icon_state = "stairs_lowerdeck"
fake_zlevel = 2 // lowerdeck
resin_construction_allowed = FALSE
/area/almayer/stair_clone/upper
+ name = "\improper Upper Deck Stairs"
icon_state = "stairs_upperdeck"
fake_zlevel = 1 // upperdeck
+// hull areas.
+
+// lower deck hull areas
+
/area/almayer/hull/lower_hull
- name = "\improper Hull Lower"
+ name = "\improper Lower Deck Hull"
icon_state = "lowerhull"
fake_zlevel = 2 // lowerdeck
+/area/almayer/hull/lower_hull/stern
+ name = "\improper Lower Deck Stern Hull"
+
+/area/almayer/hull/lower_hull/l_f_s
+ name = "\improper Lower Deck Starboard-Fore Hull"
+
+/area/almayer/hull/lower_hull/l_m_s
+ name = "\improper Lower Deck Starboard-Midship Hull"
+
+/area/almayer/hull/lower_hull/l_a_s
+ name = "\improper Lower Deck Starboard Hull"
+
+/area/almayer/hull/lower_hull/l_f_p
+ name = "\improper Lower Deck Port-Fore Hull"
+
+/area/almayer/hull/lower_hull/l_m_p
+ name = "\improper Lower Deck Port-Midship Hull"
+
+/area/almayer/hull/lower_hull/l_a_p
+ name = "\improper Lower Deck Port-Aft Hull"
+
+// upper deck hull areas
+
/area/almayer/hull/upper_hull
- name = "\improper Hull Upper"
+ name = "\improper Upper Deck Hull"
icon_state = "upperhull"
fake_zlevel = 1 // upperdeck
/area/almayer/hull/upper_hull/u_f_s
- name = "\improper Upper Fore-Starboard Hull"
- icon_state = "upperhull"
+ name = "\improper Upper Deck Fore-Starboard Hull"
/area/almayer/hull/upper_hull/u_m_s
- name = "\improper Upper Midship-Starboard Hull"
- icon_state = "upperhull"
+ name = "\improper Upper Deck Starboard-Midship Hull"
/area/almayer/hull/upper_hull/u_a_s
- name = "\improper Upper Aft-Starboard Hull"
- icon_state = "upperhull"
+ name = "\improper Upper Deck Starboard-Aft Hull"
/area/almayer/hull/upper_hull/u_f_p
- name = "\improper Upper Fore-Port Hull"
- icon_state = "upperhull"
+ name = "\improper Upper Deck Port-Fore Hull"
/area/almayer/hull/upper_hull/u_m_p
- name = "\improper Upper Midship-Port Hull"
- icon_state = "upperhull"
+ name = "\improper Upper Deck Port-Midship Hull"
/area/almayer/hull/upper_hull/u_a_p
- name = "\improper Upper Aft-Port Hull"
- icon_state = "upperhull"
-
-/area/almayer/hull/lower_hull/l_f_s
- name = "\improper Lower Fore-Starboard Hull"
- icon_state = "upperhull"
-
-/area/almayer/hull/lower_hull/l_m_s
- name = "\improper Lower Midship-Starboard Hull"
- icon_state = "upperhull"
-
-/area/almayer/hull/lower_hull/l_a_s
- name = "\improper Lower Aft-Starboard Hull"
- icon_state = "upperhull"
-
-/area/almayer/hull/lower_hull/l_f_p
- name = "\improper Lower Fore-Port Hull"
- icon_state = "upperhull"
-
-/area/almayer/hull/lower_hull/l_m_p
- name = "\improper Lower Midship-Port Hull"
- icon_state = "upperhull"
-
-/area/almayer/hull/lower_hull/l_a_p
- name = "\improper Lower Aft-Port Hull"
- icon_state = "upperhull"
+ name = "\improper Upper Deck Port-Aft Hull"
/area/almayer/living/cryo_cells
- name = "\improper Cryo Cells"
+ name = "\improper Lower Deck Cryo Cells"
icon_state = "cryo"
fake_zlevel = 2 // lowerdeck
@@ -451,22 +480,22 @@
fake_zlevel = 2 // lowerdeck
/area/almayer/living/port_emb
- name = "\improper Extended Mission Bunks"
+ name = "\improper Lower Deck Port Extended Mission Bunks"
icon_state = "portemb"
fake_zlevel = 2 // lowerdeck
/area/almayer/living/starboard_emb
- name = "\improper Extended Mission Bunks"
+ name = "\improper Lower Deck Starboard Extended Mission Bunks"
icon_state = "starboardemb"
fake_zlevel = 2 // lowerdeck
/area/almayer/living/port_garden
- name = "\improper Garden"
+ name = "\improper Port Garden"
icon_state = "portemb"
fake_zlevel = 1 // upperdeck
/area/almayer/living/starboard_garden
- name = "\improper Garden"
+ name = "\improper Starboard Garden"
icon_state = "starboardemb"
fake_zlevel = 1 // upperdeck
@@ -481,12 +510,12 @@
fake_zlevel = 2 // lowerdeck
/area/almayer/living/officer_rnr
- name = "\improper Officer's Lounge"
+ name = "\improper Upper Deck Officer's Lounge"
icon_state = "officerrnr"
fake_zlevel = 1 // upperdeck
/area/almayer/living/officer_study
- name = "\improper Officer's Study"
+ name = "\improper Upper Deck Officer's Study"
icon_state = "officerstudy"
fake_zlevel = 1 // upperdeck
@@ -501,17 +530,17 @@
fake_zlevel = 2 // lowerdeck
/area/almayer/living/gym
- name = "\improper Gym"
+ name = "\improper Lower Deck Gym"
icon_state = "officerrnr"
fake_zlevel = 2 // lowerdeck
/area/almayer/living/cafeteria_officer
- name = "\improper Officer Cafeteria"
+ name = "\improper Upper Deck Officer Cafeteria"
icon_state = "food"
fake_zlevel = 1 // upperdeck
/area/almayer/living/offices
- name = "\improper Conference Office"
+ name = "\improper Lower Deck Conference Office"
icon_state = "briefing"
fake_zlevel = 2 // lowerdeck
@@ -539,7 +568,7 @@
fake_zlevel = 1 // upperdeck
/area/almayer/living/synthcloset
- name = "\improper Synthetic Storage Closet"
+ name = "\improper Upper Deck Synthetic Storage Closet"
icon_state = "livingspace"
fake_zlevel = 1 // upperdeck
@@ -712,18 +741,21 @@
icon_state = "lifeboat_pump"
requires_power = 1
fake_zlevel = 1
+ hijack_evacuation_area = TRUE
+ hijack_evacuation_weight = 0.1
+ hijack_evacuation_type = EVACUATION_TYPE_ADDITIVE
/area/almayer/lifeboat_pumps/north1
- name = "North West Lifeboat Fuel Pump"
+ name = "Starboard Fore Lifeboat Fuel Pump"
/area/almayer/lifeboat_pumps/north2
- name = "North East Lifeboat Fuel Pump"
+ name = "Starboard Aft Lifeboat Fuel Pump"
/area/almayer/lifeboat_pumps/south1
- name = "South West Lifeboat Fuel Pump"
+ name = "Port Fore Lifeboat Fuel Pump"
/area/almayer/lifeboat_pumps/south2
- name = "South East Lifeboat Fuel Pump"
+ name = "Port Aft Lifeboat Fuel Pump"
/area/almayer/command/lifeboat
name = "\improper Lifeboat Docking Port"
@@ -736,7 +768,7 @@
flags_area = AREA_NOTUNNEL
/area/space/almayer/lifeboat_dock
- name = "\improper Lifeboat Docking Port"
+ name = "\improper Port Lifeboat Docking"
icon_state = "lifeboat"
fake_zlevel = 1 // upperdeck
flags_area = AREA_NOTUNNEL
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 826b2dc0585f..9699db527102 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -79,6 +79,10 @@
var/used_environ = 0
var/used_oneoff = 0 //one-off power usage
+ /// If this area is outside the game's normal interactivity and should be excluded from things like EOR reports and crew monitors.
+ /// Doesn't need to be set for areas/Z levels that are marked as admin-only
+ var/block_game_interaction = FALSE
+
/area/New()
// This interacts with the map loader, so it needs to be set immediately
@@ -90,12 +94,12 @@
initialize_power()
/area/Initialize(mapload, ...)
- icon_state = "" //Used to reset the icon overlay, I assume.
+ icon = null
layer = AREAS_LAYER
uid = ++global_uid
. = ..()
- active_areas += src
- all_areas += src
+ GLOB.active_areas += src
+ GLOB.all_areas += src
reg_in_areas_in_z()
if(is_mainship_level(z))
GLOB.ship_areas += src
@@ -138,13 +142,13 @@
C.network.Remove(CAMERA_NET_POWER_ALARMS)
else
C.network.Add(CAMERA_NET_POWER_ALARMS)
- for (var/mob/living/silicon/aiPlayer in ai_mob_list)
+ for (var/mob/living/silicon/aiPlayer in GLOB.ai_mob_list)
if(aiPlayer.z == source.z)
if (state == 1)
aiPlayer.cancelAlarm("Power", src, source)
else
aiPlayer.triggerAlarm("Power", src, cameras, source)
- for(var/obj/structure/machinery/computer/station_alert/a in machines)
+ for(var/obj/structure/machinery/computer/station_alert/a in GLOB.machines)
if(a.z == source.z)
if(state == 1)
a.cancelAlarm("Power", src, source)
@@ -169,9 +173,9 @@
if (danger_level < 2 && atmosalm >= 2)
for(var/obj/structure/machinery/camera/C in src)
C.network.Remove(CAMERA_NET_ATMOSPHERE_ALARMS)
- for(var/mob/living/silicon/aiPlayer in ai_mob_list)
+ for(var/mob/living/silicon/aiPlayer in GLOB.ai_mob_list)
aiPlayer.cancelAlarm("Atmosphere", src, src)
- for(var/obj/structure/machinery/computer/station_alert/a in machines)
+ for(var/obj/structure/machinery/computer/station_alert/a in GLOB.machines)
a.cancelAlarm("Atmosphere", src, src)
if (danger_level >= 2 && atmosalm < 2)
@@ -180,9 +184,9 @@
for(var/obj/structure/machinery/camera/C in src)
cameras += C
C.network.Add(CAMERA_NET_ATMOSPHERE_ALARMS)
- for(var/mob/living/silicon/aiPlayer in ai_mob_list)
+ for(var/mob/living/silicon/aiPlayer in GLOB.ai_mob_list)
aiPlayer.triggerAlarm("Atmosphere", src, cameras, src)
- for(var/obj/structure/machinery/computer/station_alert/a in machines)
+ for(var/obj/structure/machinery/computer/station_alert/a in GLOB.machines)
a.triggerAlarm("Atmosphere", src, cameras, src)
air_doors_close()
@@ -231,9 +235,9 @@
for (var/obj/structure/machinery/camera/C in src)
cameras.Add(C)
C.network.Add(CAMERA_NET_FIRE_ALARMS)
- for (var/mob/living/silicon/ai/aiPlayer in ai_mob_list)
+ for (var/mob/living/silicon/ai/aiPlayer in GLOB.ai_mob_list)
aiPlayer.triggerAlarm("Fire", src, cameras, src)
- for (var/obj/structure/machinery/computer/station_alert/a in machines)
+ for (var/obj/structure/machinery/computer/station_alert/a in GLOB.machines)
a.triggerAlarm("Fire", src, cameras, src)
/area/proc/firereset()
@@ -249,9 +253,9 @@
INVOKE_ASYNC(D, TYPE_PROC_REF(/obj/structure/machinery/door, open))
for (var/obj/structure/machinery/camera/C in src)
C.network.Remove(CAMERA_NET_FIRE_ALARMS)
- for (var/mob/living/silicon/ai/aiPlayer in ai_mob_list)
+ for (var/mob/living/silicon/ai/aiPlayer in GLOB.ai_mob_list)
aiPlayer.cancelAlarm("Fire", src, src)
- for (var/obj/structure/machinery/computer/station_alert/a in machines)
+ for (var/obj/structure/machinery/computer/station_alert/a in GLOB.machines)
a.cancelAlarm("Fire", src, src)
/area/proc/readyalert()
diff --git a/code/game/area/kutjevo.dm b/code/game/area/kutjevo.dm
index 422017c0a46b..a5a12cd5b999 100644
--- a/code/game/area/kutjevo.dm
+++ b/code/game/area/kutjevo.dm
@@ -67,6 +67,10 @@
name = "Kutjevo - Power Station River"
icon_state = "lz_river"
+/area/kutjevo/exterior/spring
+ name = "Kutjevo - Southern Spring"
+ icon_state = "lz_river"
+
/area/kutjevo/exterior/scrubland
name = "Kutjevo - Scrubland"
icon_state = "scrubland"
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index e1541f8368b8..5f36b3b8b390 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -33,8 +33,11 @@
var/list/filter_data //For handling persistent filters
- // Base transform matrix
- var/matrix/base_transform = null
+ /// Base transform matrix, edited by admin tooling and such
+ var/matrix/base_transform
+ /// Last transform used before being compound with base_transform
+ /// This allows us to re-create transform if only base_transform changes
+ var/matrix/raw_transform
///Chemistry.
var/datum/reagents/reagents = null
@@ -116,7 +119,14 @@ directive is properly returned.
//===========================================================================
-
+// TODO make all atoms use set_density, do not rely on it at present
+///Setter for the `density` variable to append behavior related to its changing.
+/atom/proc/set_density(new_value)
+ SHOULD_CALL_PARENT(TRUE)
+ if(density == new_value)
+ return
+ . = density
+ density = new_value
//atmos procs
@@ -141,15 +151,27 @@ directive is properly returned.
if(loc)
return loc.return_gas()
-// Updates the atom's transform
-/atom/proc/apply_transform(matrix/M)
- if(!base_transform)
- transform = M
- return
+/// Updates the atom's transform compounding it with [/atom/var/base_transform]
+/atom/proc/apply_transform(matrix/new_transform, time = 0, easing = (EASE_IN|EASE_OUT))
+ var/matrix/base_copy
+ if(base_transform)
+ base_copy = matrix(base_transform)
+ else
+ base_copy = matrix()
+ raw_transform = matrix(new_transform) // Keep a copy to replay if needed
- var/matrix/base_copy = matrix(base_transform)
// Compose the base and applied transform in that order
- transform = base_copy.Multiply(M)
+ var/matrix/complete = base_copy.Multiply(raw_transform)
+
+ if(!time)
+ transform = complete
+ return
+ animate(src, transform = complete, time = time, easing = easing, flags = ANIMATION_PARALLEL)
+
+/// Upates the base_transform which will be compounded with other transforms
+/atom/proc/update_base_transform(matrix/new_transform, time = 0)
+ base_transform = matrix(new_transform)
+ apply_transform(raw_transform, time)
/atom/proc/on_reagent_change()
return
@@ -183,7 +205,9 @@ directive is properly returned.
return
/atom/proc/emp_act(severity)
- return
+ SHOULD_CALL_PARENT(TRUE)
+
+ SEND_SIGNAL(src, COMSIG_ATOM_EMP_ACT, severity)
/atom/proc/in_contents_of(container)//can take class or object instance as argument
if(ispath(container))
@@ -223,8 +247,8 @@ directive is properly returned.
if(!examine_strings)
log_debug("Attempted to create an examine block with no strings! Atom : [src], user : [user]")
return
- to_chat(user, examine_block(examine_strings.Join("\n")))
SEND_SIGNAL(src, COMSIG_PARENT_EXAMINE, user, examine_strings)
+ to_chat(user, examine_block(examine_strings.Join("\n")))
/atom/proc/get_examine_text(mob/user)
. = list()
@@ -363,11 +387,11 @@ Parameters are passed from New.
var/turf/opaque_turf = loc
opaque_turf.directional_opacity = ALL_CARDINALS // No need to recalculate it in this case, it's guaranteed to be on afterwards anyways.
- pass_flags = pass_flags_cache[type]
+ pass_flags = GLOB.pass_flags_cache[type]
if (isnull(pass_flags))
pass_flags = new()
initialize_pass_flags(pass_flags)
- pass_flags_cache[type] = pass_flags
+ GLOB.pass_flags_cache[type] = pass_flags
else
initialize_pass_flags()
Decorate(mapload)
@@ -394,7 +418,7 @@ Parameters are passed from New.
T.appearance = src.appearance
T.setDir(src.dir)
- clones_t.Add(src)
+ GLOB.clones_t.Add(src)
src.clone = T
// EFFECTS
@@ -699,10 +723,9 @@ Parameters are passed from New.
usr.client.cmd_admin_emp(src)
if(href_list[VV_HK_MODIFY_TRANSFORM] && check_rights(R_VAREDIT))
- var/result = tgui_input_list(usr, "Choose the transformation to apply","Transform Mod", list("Scale","Translate","Rotate"))
+ var/result = tgui_input_list(usr, "Choose the transformation to apply","Transform Mod", list("Scale","Translate","Rotate", "Reflect X Axis", "Reflect Y Axis"))
if(!result)
return
- var/matrix/M = transform
if(!result)
return
switch(result)
@@ -711,19 +734,37 @@ Parameters are passed from New.
var/y = tgui_input_real_number(usr, "Choose y mod","Transform Mod")
if(isnull(x) || isnull(y))
return
- transform = M.Scale(x,y)
+ var/matrix/base_matrix = matrix(base_transform)
+ update_base_transform(base_matrix.Scale(x,y))
if("Translate")
var/x = tgui_input_real_number(usr, "Choose x mod (negative = left, positive = right)","Transform Mod")
var/y = tgui_input_real_number(usr, "Choose y mod (negative = down, positive = up)","Transform Mod")
if(isnull(x) || isnull(y))
return
- transform = M.Translate(x,y)
+ var/matrix/base_matrix = matrix(base_transform)
+ update_base_transform(base_matrix.Translate(x,y))
if("Rotate")
var/angle = tgui_input_real_number(usr, "Choose angle to rotate","Transform Mod")
if(isnull(angle))
return
- transform = M.Turn(angle)
-
+ var/matrix/base_matrix = matrix(base_transform)
+ update_base_transform(base_matrix.Turn(angle))
+ if("Reflect X Axis")
+ var/matrix/current = matrix(base_transform)
+ var/matrix/reflector = matrix()
+ reflector.a = -1
+ reflector.d = 0
+ reflector.b = 0
+ reflector.e = 1
+ update_base_transform(current * reflector)
+ if("Reflect Y Axis")
+ var/matrix/current = matrix(base_transform)
+ var/matrix/reflector = matrix()
+ reflector.a = 1
+ reflector.d = 0
+ reflector.b = 0
+ reflector.e = -1
+ update_base_transform(current * reflector)
SEND_SIGNAL(src, COMSIG_ATOM_VV_MODIFY_TRANSFORM)
if(href_list[VV_HK_AUTO_RENAME] && check_rights(R_VAREDIT))
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index b8a901ccf321..21f7b6b0a9be 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -281,7 +281,7 @@
C.proj_x = shift_x
C.proj_y = shift_y
- clones.Add(C)
+ GLOB.clones.Add(C)
C.mstr = src //Link clone and master
src.clone = C
@@ -313,7 +313,7 @@
clone.set_light(0) //Kill clone light
/atom/movable/proc/destroy_clone()
- clones.Remove(src.clone)
+ GLOB.clones.Remove(src.clone)
qdel(src.clone)
src.clone = null
diff --git a/code/game/bioscans.dm b/code/game/bioscans.dm
index 62c801a02d29..5be3c9fbe3fd 100644
--- a/code/game/bioscans.dm
+++ b/code/game/bioscans.dm
@@ -109,25 +109,22 @@ GLOBAL_DATUM_INIT(bioscan_data, /datum/bioscan_data, new)
to_chat(ghost, ghost_scan)
-/// This will do something after Project ARES.
/datum/bioscan_data/proc/ares_can_bioscan()
var/datum/ares_link/link = GLOB.ares_link
- if(!istype(link))
+ if(!istype(link) || !ares_is_active())
return FALSE
- if(link.p_bioscan && !link.p_bioscan.inoperable())
+ if(link.processor_bioscan && !link.processor_bioscan.inoperable())
return TRUE
return FALSE
/// The announcement to all Humans. Slightly off for the planet and elsewhere, accurate for the ship.
/datum/bioscan_data/proc/ares_bioscan(forced = FALSE, variance = 2)
- var/datum/ares_link/link = GLOB.ares_link
if(!forced && !ares_can_bioscan())
message_admins("An ARES Bioscan has failed.")
var/name = "[MAIN_AI_SYSTEM] Bioscan Status"
var/input = "Bioscan failed. \n\nInvestigation into Bioscan subsystem recommended."
- if(ares_can_log())
- link.log_ares_bioscan(name, input)
- if(ares_can_interface())
+ log_ares_bioscan(name, input, forced)
+ if(ares_can_interface() || forced)
marine_announcement(input, name, 'sound/misc/interference.ogg', logging = ARES_LOG_NONE)
return
//Adjust the randomness there so everyone gets the same thing
@@ -137,8 +134,7 @@ GLOBAL_DATUM_INIT(bioscan_data, /datum/bioscan_data, new)
log_game("BIOSCAN: ARES bioscan completed. [input]")
- if(forced || ares_can_log())
- link.log_ares_bioscan(name, input) //if interface is down, bioscan still logged, just have to go read it.
+ log_ares_bioscan(name, input) //if interface is down, bioscan still logged, just have to go read it.
if(forced || ares_can_interface())
marine_announcement(input, name, 'sound/AI/bioscan.ogg', logging = ARES_LOG_NONE)
else
diff --git a/code/game/camera_manager/camera_manager.dm b/code/game/camera_manager/camera_manager.dm
new file mode 100644
index 000000000000..93d56aca443c
--- /dev/null
+++ b/code/game/camera_manager/camera_manager.dm
@@ -0,0 +1,235 @@
+#define DEFAULT_MAP_SIZE 15
+
+#define RENDER_MODE_TARGET 1
+#define RENDER_MODE_AREA 2
+
+/datum/component/camera_manager
+ var/map_name
+ var/obj/structure/machinery/camera/current
+ var/datum/shape/rectangle/current_area
+ var/atom/movable/screen/map_view/cam_screen
+ var/atom/movable/screen/background/cam_background
+ var/list/range_turfs = list()
+ /// The turf where the camera was last updated.
+ var/turf/last_camera_turf
+ var/target_x
+ var/target_y
+ var/target_z
+ var/target_width
+ var/target_height
+ var/list/cam_plane_masters
+ var/isXRay = FALSE
+ var/render_mode = RENDER_MODE_TARGET
+
+/datum/component/camera_manager/Initialize()
+ . = ..()
+ map_name = "camera_manager_[REF(src)]_map"
+ cam_screen = new
+ cam_screen.name = "screen"
+ cam_screen.assigned_map = map_name
+ cam_screen.del_on_map_removal = FALSE
+ cam_screen.screen_loc = "[map_name]:1,1"
+ cam_background = new
+ cam_background.assigned_map = map_name
+ cam_background.del_on_map_removal = FALSE
+
+ cam_plane_masters = list()
+ for(var/plane in subtypesof(/atom/movable/screen/plane_master) - /atom/movable/screen/plane_master/blackness)
+ var/atom/movable/screen/plane_master/instance = new plane()
+ add_plane(instance)
+
+/datum/component/camera_manager/Destroy(force, ...)
+ . = ..()
+ range_turfs = null
+ current_area = null
+ cam_plane_masters = null
+ QDEL_NULL(cam_background)
+ QDEL_NULL(cam_screen)
+ if(current)
+ UnregisterSignal(current, COMSIG_PARENT_QDELETING)
+
+/datum/component/camera_manager/proc/add_plane(atom/movable/screen/plane_master/instance)
+ instance.assigned_map = map_name
+ instance.del_on_map_removal = FALSE
+ if(instance.blend_mode_override)
+ instance.blend_mode = instance.blend_mode_override
+ instance.screen_loc = "[map_name]:CENTER"
+ cam_plane_masters["[instance.plane]"] = instance
+
+/datum/component/camera_manager/proc/register(source, mob/user)
+ SIGNAL_HANDLER
+ var/client/user_client = user.client
+ if(!user_client)
+ return
+ user_client.register_map_obj(cam_background)
+ user_client.register_map_obj(cam_screen)
+ for(var/plane_id in cam_plane_masters)
+ user_client.register_map_obj(cam_plane_masters[plane_id])
+
+/datum/component/camera_manager/proc/unregister(source, mob/user)
+ SIGNAL_HANDLER
+ var/client/user_client = user.client
+ if(!user_client)
+ return
+ user_client.clear_map(cam_background)
+ user_client.clear_map(cam_screen)
+ for(var/plane_id in cam_plane_masters)
+ user_client.clear_map(cam_plane_masters[plane_id])
+
+/datum/component/camera_manager/RegisterWithParent()
+ . = ..()
+ START_PROCESSING(SSdcs, src)
+ SEND_SIGNAL(parent, COMSIG_CAMERA_MAPNAME_ASSIGNED, map_name)
+ RegisterSignal(parent, COMSIG_CAMERA_REGISTER_UI, PROC_REF(register))
+ RegisterSignal(parent, COMSIG_CAMERA_UNREGISTER_UI, PROC_REF(unregister))
+ RegisterSignal(parent, COMSIG_CAMERA_SET_NVG, PROC_REF(enable_nvg))
+ RegisterSignal(parent, COMSIG_CAMERA_CLEAR_NVG, PROC_REF(disable_nvg))
+ RegisterSignal(parent, COMSIG_CAMERA_SET_AREA, PROC_REF(set_camera_rect))
+ RegisterSignal(parent, COMSIG_CAMERA_SET_TARGET, PROC_REF(set_camera))
+ RegisterSignal(parent, COMSIG_CAMERA_CLEAR, PROC_REF(clear_camera))
+
+/datum/component/camera_manager/UnregisterFromParent()
+ . = ..()
+ STOP_PROCESSING(SSdcs, src)
+
+ UnregisterSignal(parent, COMSIG_CAMERA_REGISTER_UI)
+ UnregisterSignal(parent, COMSIG_CAMERA_UNREGISTER_UI)
+ UnregisterSignal(parent, COMSIG_CAMERA_SET_NVG)
+ UnregisterSignal(parent, COMSIG_CAMERA_CLEAR_NVG)
+ UnregisterSignal(parent, COMSIG_CAMERA_SET_AREA)
+ UnregisterSignal(parent, COMSIG_CAMERA_SET_TARGET)
+ UnregisterSignal(parent, COMSIG_CAMERA_CLEAR)
+
+/datum/component/camera_manager/proc/clear_camera()
+ SIGNAL_HANDLER
+ if(current)
+ UnregisterSignal(current, COMSIG_PARENT_QDELETING)
+ current_area = null
+ current = null
+ target_x = null
+ target_y = null
+ target_z = null
+ target_width = null
+ target_height = null
+ show_camera_static()
+
+/datum/component/camera_manager/proc/set_camera(source, atom/target, w, h)
+ SIGNAL_HANDLER
+ render_mode = RENDER_MODE_TARGET
+ if(current)
+ UnregisterSignal(current, COMSIG_PARENT_QDELETING)
+ current = target
+ target_width = w
+ target_height = h
+ RegisterSignal(current, COMSIG_PARENT_QDELETING, PROC_REF(show_camera_static))
+ update_target_camera()
+
+/datum/component/camera_manager/proc/set_camera_rect(source, x, y, z, w, h)
+ SIGNAL_HANDLER
+ render_mode = RENDER_MODE_AREA
+ if(current)
+ UnregisterSignal(current, COMSIG_PARENT_QDELETING)
+ current = null
+ current_area = RECT(x, y, w, h)
+ target_x = x
+ target_y = y
+ target_z = z
+ update_area_camera()
+
+/datum/component/camera_manager/proc/enable_nvg(source, power, matrixcol)
+ SIGNAL_HANDLER
+ for(var/plane_id in cam_plane_masters)
+ var/atom/movable/screen/plane_master/plane = cam_plane_masters["[plane_id]"]
+ plane.add_filter("nvg", 1, color_matrix_filter(color_matrix_from_string(matrixcol)))
+ sync_lighting_plane_alpha(LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE)
+
+/datum/component/camera_manager/proc/disable_nvg()
+ SIGNAL_HANDLER
+ for(var/plane_id in cam_plane_masters)
+ var/atom/movable/screen/plane_master/plane = cam_plane_masters["[plane_id]"]
+ plane.remove_filter("nvg")
+ sync_lighting_plane_alpha(LIGHTING_PLANE_ALPHA_VISIBLE)
+
+/datum/component/camera_manager/proc/sync_lighting_plane_alpha(lighting_alpha)
+ var/atom/movable/screen/plane_master/lighting/lighting = cam_plane_masters["[LIGHTING_PLANE]"]
+ if (lighting)
+ lighting.alpha = lighting_alpha
+ var/atom/movable/screen/plane_master/lighting/exterior_lighting = cam_plane_masters["[EXTERIOR_LIGHTING_PLANE]"]
+ if (exterior_lighting)
+ exterior_lighting.alpha = min(GLOB.minimum_exterior_lighting_alpha, lighting_alpha)
+
+/**
+ * Set the displayed camera to the static not-connected.
+ */
+/datum/component/camera_manager/proc/show_camera_static()
+ cam_screen.vis_contents.Cut()
+ last_camera_turf = null
+ cam_background.icon_state = "scanline2"
+ cam_background.fill_rect(1, 1, DEFAULT_MAP_SIZE, DEFAULT_MAP_SIZE)
+
+/datum/component/camera_manager/proc/update_target_camera()
+ // Show static if can't use the camera
+ if(!current?.can_use())
+ show_camera_static()
+ return
+
+ // Is this camera located in or attached to a living thing, Vehicle or helmet? If so, assume the camera's loc is the living (or non) thing.
+ var/cam_location = current
+ if(isliving(current.loc) || isVehicle(current.loc))
+ cam_location = current.loc
+ else if(istype(current.loc, /obj/item/clothing/head/helmet/marine))
+ var/obj/item/clothing/head/helmet/marine/helmet = current.loc
+ cam_location = helmet.loc
+
+ // If we're not forcing an update for some reason and the cameras are in the same location,
+ // we don't need to update anything.
+ // Most security cameras will end here as they're not moving.
+ var/newturf = get_turf(cam_location)
+ if(last_camera_turf == newturf)
+ return
+
+ // Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs.
+ last_camera_turf = get_turf(cam_location)
+
+ var/list/visible_things = current.isXRay() ? range(current.view_range, cam_location) : view(current.view_range, cam_location)
+ render_objects(visible_things)
+
+/datum/component/camera_manager/proc/update_area_camera()
+ // Show static if can't use the camera
+ if(!current_area || !target_z)
+ show_camera_static()
+ return
+
+ // If we're not forcing an update for some reason and the cameras are in the same location,
+ // we don't need to update anything.
+ // Most security cameras will end here as they're not moving.
+ var/turf/new_location = locate(target_x, target_y, target_z)
+ if(last_camera_turf == new_location)
+ return
+
+ // Cameras that get here are moving, and are likely attached to some moving atom such as cyborgs.
+ last_camera_turf = new_location
+
+ var/x_size = current_area.width
+ var/y_size = current_area.height
+ var/turf/target = locate(current_area.center_x, current_area.center_y, target_z)
+
+ var/list/visible_things = isXRay ? range("[x_size]x[y_size]", target) : view("[x_size]x[y_size]", target)
+ src.render_objects(visible_things)
+
+/datum/component/camera_manager/proc/render_objects(list/visible_things)
+ var/list/visible_turfs = list()
+ for(var/turf/visible_turf in visible_things)
+ visible_turfs += visible_turf
+
+ var/list/bbox = get_bbox_of_atoms(visible_turfs)
+ var/size_x = bbox[3] - bbox[1] + 1
+ var/size_y = bbox[4] - bbox[2] + 1
+
+ cam_screen.vis_contents = visible_turfs
+ cam_background.icon_state = "clear"
+ cam_background.fill_rect(1, 1, size_x, size_y)
+
+#undef DEFAULT_MAP_SIZE
+#undef RENDER_MODE_TARGET
+#undef RENDER_MODE_AREA
diff --git a/code/game/cas_manager/datums/cas_fire_envelope.dm b/code/game/cas_manager/datums/cas_fire_envelope.dm
index d7c939b76e16..04cd688194dd 100644
--- a/code/game/cas_manager/datums/cas_fire_envelope.dm
+++ b/code/game/cas_manager/datums/cas_fire_envelope.dm
@@ -1,7 +1,6 @@
/datum/cas_fire_envelope
var/obj/structure/machinery/computer/dropship_weapons/linked_console
var/list/datum/cas_fire_mission/missions
- var/max_mission_len = 5
var/fire_length
var/grace_period //how much time you have after initiating fire mission and before you can't change firemissions
var/flyto_period //how much time it takes from sound alarm start to first hit. CAS is vulnerable here
@@ -30,35 +29,36 @@
linked_console = null
return ..()
+/datum/cas_fire_envelope/ui_data(mob/user)
+ . = list()
+ .["missions"] = list()
+ for(var/datum/cas_fire_mission/mission in missions)
+ .["missions"] += list(mission.ui_data(user))
+
+
/datum/cas_fire_envelope/proc/get_total_duration()
return grace_period+flyto_period+flyoff_period
+/datum/cas_fire_envelope/proc/update_weapons(list/obj/structure/dropship_equipment/weapon/weapons)
+ for(var/datum/cas_fire_mission/mission in missions)
+ mission.update_weapons(weapons, fire_length)
+
/datum/cas_fire_envelope/proc/generate_mission(firemission_name, length)
- if(!missions || !linked_console || missions.len>max_mission_len || !fire_length)
+ if(!missions || !linked_console || !fire_length)
return null
-
var/list/obj/structure/dropship_equipment/weapons = list()
- for(var/X in linked_console.shuttle_equipments)
- var/obj/structure/dropship_equipment/E = X
- if(E.is_weapon)
- weapons += E
+ var/shuttle_tag = linked_console.shuttle_tag
+ var/obj/docking_port/mobile/marine_dropship/dropship = SSshuttle.getShuttle(shuttle_tag)
+ for(var/obj/structure/dropship_equipment/equipment as anything in dropship.equipments)
+ if(equipment.is_weapon)
+ weapons += equipment
var/datum/cas_fire_mission/fm = new()
-
- if(weapons.len==0)
- return null //why bother?
-
for(var/obj/structure/dropship_equipment/weapon/wp in weapons)
- var/datum/cas_fire_mission_record/record = new()
- record.weapon = wp
- record.offsets = new /list(fire_length)
- for(var/idx = 1; idx<=fire_length; idx++)
- record.offsets[idx] = "-"
- fm.records += record
+ fm.build_new_record(wp, fire_length)
fm.name = firemission_name
fm.mission_length = length
-
missions += fm
return fm
@@ -67,67 +67,61 @@
mission_error = null
if(stat > FIRE_MISSION_STATE_IN_TRANSIT && stat < FIRE_MISSION_STATE_COOLDOWN)
mission_error = "Fire Mission is under way already."
- return 0
+ return FIRE_MISSION_NOT_EXECUTABLE
if(!missions[mission_id])
- return -1
+ return FIRE_MISSION_NOT_EXECUTABLE
var/datum/cas_fire_mission/mission = missions[mission_id]
if(!mission)
- return -1
- if(!mission.records[weapon_id])
- return -1
- var/datum/cas_fire_mission_record/fmr = mission.records[weapon_id]
+ return FIRE_MISSION_NOT_EXECUTABLE
+
+ var/datum/cas_fire_mission_record/fmr = mission.record_for_weapon(weapon_id)
+ if(!fmr)
+ return FIRE_MISSION_NOT_EXECUTABLE
if(!fmr.offsets || isnull(fmr.offsets[offset_step]))
- return -1
+ return FIRE_MISSION_NOT_EXECUTABLE
var/old_offset = fmr.offsets[offset_step]
+ if(offset == null)
+ offset = "-"
fmr.offsets[offset_step] = offset
var/check_result = mission.check(linked_console)
if(check_result == FIRE_MISSION_CODE_ERROR)
- return -1
+ return FIRE_MISSION_NOT_EXECUTABLE
if(check_result == FIRE_MISSION_ALL_GOOD)
- return 1
+ return FIRE_MISSION_ALL_GOOD
if(check_result == FIRE_MISSION_WEAPON_OUT_OF_AMMO)
- return 1
+ return FIRE_MISSION_ALL_GOOD
mission_error = mission.error_message(check_result)
if(skip_checks)
- return 0
+ return FIRE_MISSION_ALL_GOOD
//we have mission error. Fill the thing and restore previous state
fmr.offsets[offset_step] = old_offset
- return 0
+ return FIRE_MISSION_ALL_GOOD
-/datum/cas_fire_envelope/proc/execute_firemission(datum/cas_signal/target_turf, offset, dir, mission_id)
- if(!istype(target_turf))
- mission_error = "No target."
- return 0
+/datum/cas_fire_envelope/proc/execute_firemission(datum/cas_signal/signal, target_turf,dir, mission_id)
if(stat != FIRE_MISSION_STATE_IDLE)
mission_error = "Fire Mission is under way already."
- return 0
+ return FIRE_MISSION_NOT_EXECUTABLE
if(!missions[mission_id])
- return -1
- if(offset<0)
- mission_error = "Can't have negative offsets."
- return 0
- if(offset>max_offset)
- mission_error = "[max_offset] is the maximum possible offset."
- return 0
+ return FIRE_MISSION_NOT_EXECUTABLE
if(dir!=NORTH && dir!=SOUTH && dir!=WEST && dir!=EAST)
mission_error = "Incorrect direction."
- return 0
+ return FIRE_MISSION_BAD_DIRECTION
mission_error = null
var/datum/cas_fire_mission/mission = missions[mission_id]
var/check_result = mission.check(linked_console)
if(check_result == FIRE_MISSION_CODE_ERROR)
- return -1
+ return FIRE_MISSION_CODE_ERROR
if(check_result != FIRE_MISSION_ALL_GOOD)
mission_error = mission.error_message(check_result)
- return 0
+ return FIRE_MISSION_CODE_ERROR
//actual firemission code
- execute_firemission_unsafe(target_turf, offset, dir, mission)
- return 1
+ execute_firemission_unsafe(signal, target_turf, dir, mission)
+ return FIRE_MISSION_ALL_GOOD
/datum/cas_fire_envelope/proc/firemission_status_message()
switch(stat)
@@ -167,6 +161,7 @@
if(!guidance)
guidance = new /obj/effect/firemission_guidance()
guidance.forceMove(location)
+ guidance.updateCameras(linked_console)
/datum/cas_fire_envelope/proc/user_is_guided(user)
return guidance && (user in guidance.users)
@@ -181,8 +176,7 @@
apply_upgrade(user)
if(!(user in guidance.users))
guidance.users += user
- RegisterSignal(usr, COMSIG_MOB_RESISTED, PROC_REF(exit_cam_resist))
-
+ RegisterSignal(user, COMSIG_MOB_RESISTED, PROC_REF(exit_cam_resist))
/datum/cas_fire_envelope/proc/apply_upgrade(user)
var/mob/M = user
@@ -193,8 +187,6 @@
M.overlay_fullscreen("matrix", /atom/movable/screen/fullscreen/flash/noise/nvg)
M.lighting_alpha = LIGHTING_PLANE_ALPHA_MOSTLY_INVISIBLE
M.sync_lighting_plane_alpha()
- else if (linked_console.upgraded == MATRIX_WIDE)
- M.client?.change_view(linked_console.power + 5, M)
/datum/cas_fire_envelope/proc/remove_upgrades(user)
@@ -220,6 +212,8 @@
M.reset_view()
remove_upgrades(user)
guidance.users -= user
+ UnregisterSignal(user, COMSIG_MOB_RESISTED)
+ guidance.clearCameras(linked_console)
/datum/cas_fire_envelope/proc/exit_cam_resist(mob/user)
SIGNAL_HANDLER
@@ -230,54 +224,36 @@
/datum/cas_fire_envelope/proc/check_firemission_loc(datum/cas_signal/target_turf)
return TRUE //redefined in child class
-/datum/cas_fire_envelope/proc/execute_firemission_unsafe(datum/cas_signal/target_turf, offset, dir, datum/cas_fire_mission/mission)
- var/sx = 0
- var/sy = 0
-
- recorded_dir = dir
- recorded_offset = offset
-
+/**
+ * Execute firemission.
+ */
+/datum/cas_fire_envelope/proc/execute_firemission_unsafe(datum/cas_signal/signal, turf/target_turf, dir, datum/cas_fire_mission/mission)
stat = FIRE_MISSION_STATE_IN_TRANSIT
+ to_chat(usr, SPAN_ALERT("Firemission underway!"))
sleep(grace_period)
stat = FIRE_MISSION_STATE_ON_TARGET
- switch(recorded_dir)
- if(NORTH) //default direction
- sx = 0
- sy = 1
- if(SOUTH)
- sx = 0
- sy = -1
- if(EAST)
- sx = 1
- sy = 0
- if(WEST)
- sx = -1
- sy = 0
if(!target_turf)
stat = FIRE_MISSION_STATE_IDLE
mission_error = "Target Lost."
return
- var/turf/tt_turf = get_turf(target_turf.signal_loc)
- if(!tt_turf || !check_firemission_loc(target_turf))
+ if(!target_turf || !check_firemission_loc(signal))
stat = FIRE_MISSION_STATE_IDLE
mission_error = "Target is off bounds or obstructed."
return
- var/turf/shootloc = locate(tt_turf.x + sx*recorded_offset, tt_turf.y + sy*recorded_offset,tt_turf.z)
- if(!shootloc || !istype(shootloc))
- stat = FIRE_MISSION_STATE_IDLE
- mission_error = "Target is off bounds."
- return
- change_current_loc(shootloc)
- playsound(shootloc, soundeffect, 70, TRUE, 50)
+ change_current_loc(target_turf)
+ playsound(target_turf, soundeffect, 70, TRUE, 50)
sleep(flyto_period)
stat = FIRE_MISSION_STATE_FIRING
- mission.execute_firemission(linked_console, shootloc, recorded_dir, fire_length, step_delay, src)
+ mission.execute_firemission(linked_console, target_turf, dir, fire_length, step_delay, src)
stat = FIRE_MISSION_STATE_OFF_TARGET
sleep(flyoff_period)
stat = FIRE_MISSION_STATE_COOLDOWN
sleep(cooldown_period)
stat = FIRE_MISSION_STATE_IDLE
+/**
+ * Change attack vector for firemission
+ */
/datum/cas_fire_envelope/proc/change_direction(new_dir)
if(stat > FIRE_MISSION_STATE_IN_TRANSIT)
mission_error = "Fire Mission is under way already."
@@ -345,13 +321,13 @@
/obj/structure/machinery/computer/dropship_weapons/proc/update_mission(mission_id, weapon_id, offset_step, offset)
var/result = firemission_envelope.update_mission(mission_id, weapon_id, offset_step, offset)
- if(result<1)
+ if(result != FIRE_MISSION_ALL_GOOD)
return firemission_envelope.mission_error
return "OK"
// Used in the simulation room for firemission testing.
/obj/structure/machinery/computer/dropship_weapons/proc/execute_firemission(obj/location, offset, dir, mission_id)
var/result = firemission_envelope.execute_firemission(get_turf(location), offset, dir, mission_id)
- if(result<1)
+ if(result != FIRE_MISSION_ALL_GOOD)
return firemission_envelope.mission_error
return "OK"
diff --git a/code/game/cas_manager/datums/cas_fire_mission.dm b/code/game/cas_manager/datums/cas_fire_mission.dm
index 0a04876414e7..ece78042ac25 100644
--- a/code/game/cas_manager/datums/cas_fire_mission.dm
+++ b/code/game/cas_manager/datums/cas_fire_mission.dm
@@ -1,17 +1,83 @@
/obj/effect/firemission_guidance
invisibility = 101
- var/list/users
+ var/list/mob/users
+ var/camera_width = 11
+ var/camera_height = 11
+ var/view_range = 7
/obj/effect/firemission_guidance/New()
..()
users = list()
+/obj/effect/firemission_guidance/Destroy(force)
+ . = ..()
+ users = null
+
+/obj/effect/firemission_guidance/proc/can_use()
+ return TRUE
+
+/obj/effect/firemission_guidance/proc/isXRay()
+ return FALSE
+
+/obj/effect/firemission_guidance/proc/updateCameras(atom/target)
+ SEND_SIGNAL(target, COMSIG_CAMERA_SET_TARGET, src, camera_width, camera_height)
+
+/obj/effect/firemission_guidance/proc/clearCameras(atom/target)
+ SEND_SIGNAL(target, COMSIG_CAMERA_CLEAR)
+
/datum/cas_fire_mission
var/mission_length = 3 //can be 3,4,6 or 12
var/list/datum/cas_fire_mission_record/records = list()
var/obj/structure/dropship_equipment/weapon/error_weapon
var/name = "Unnamed Firemission"
+/datum/cas_fire_mission/ui_data(mob/user)
+ . = list()
+ .["name"] = sanitize(copytext(name, 1, MAX_MESSAGE_LEN))
+ .["records"] = list()
+ for(var/datum/cas_fire_mission_record/record as anything in records)
+ .["records"] += list(record.ui_data(user))
+
+/datum/cas_fire_mission/proc/build_new_record(obj/structure/dropship_equipment/weapon/weap, fire_length)
+ var/datum/cas_fire_mission_record/record = new()
+ record.weapon = weap
+ record.offsets = new /list(fire_length)
+ for(var/idx = 1; idx<=fire_length; idx++)
+ record.offsets[idx] = "-"
+ records += record
+
+/datum/cas_fire_mission/proc/update_weapons(list/obj/structure/dropship_equipment/weapon/weapons, fire_length)
+ var/list/datum/cas_fire_mission_record/bad_records = list()
+ var/list/obj/structure/dropship_equipment/weapon/missing_weapons = list()
+ for(var/datum/cas_fire_mission_record/record in records)
+ // if weapon appears in weapons list but not in record
+ // > add empty record for new weapon
+ var/found = FALSE
+ for(var/obj/structure/dropship_equipment/weapon/weap in weapons)
+ if(record.weapon == weap)
+ found=TRUE
+ break
+ if(!found)
+ bad_records.Add(record)
+ for(var/obj/structure/dropship_equipment/weapon/weap in weapons)
+ var/found = FALSE
+ for(var/datum/cas_fire_mission_record/record in records)
+ if(record.weapon == weap)
+ found=TRUE
+ break
+ if(!found)
+ missing_weapons.Add(weap)
+ for(var/datum/cas_fire_mission_record/record in bad_records)
+ records -= record
+ for(var/obj/structure/dropship_equipment/weapon/weap in missing_weapons)
+ build_new_record(weap, fire_length)
+
+/datum/cas_fire_mission/proc/record_for_weapon(weapon_id)
+ for(var/datum/cas_fire_mission_record/record as anything in records)
+ if(record.weapon.ship_base.attach_id == weapon_id)
+ return record
+ return null
+
/datum/cas_fire_mission/proc/check(obj/structure/machinery/computer/dropship_weapons/linked_console)
error_weapon = null
if(records.len == 0)
@@ -114,7 +180,7 @@
if(get_turf(M) == initial_turf)
relative_dir = 0
else
- relative_dir = get_dir(M, initial_turf)
+ relative_dir = Get_Compass_Dir(M, initial_turf)
var/ds_identifier = "LARGE BIRD"
if (M.mob_flags & KNOWS_TECHNOLOGY)
@@ -132,7 +198,7 @@
if(get_turf(M) == initial_turf)
relative_dir = 0
else
- relative_dir = get_dir(M, initial_turf)
+ relative_dir = Get_Compass_Dir(M, initial_turf)
var/ds_identifier = "LARGE BIRD"
if (M.mob_flags & KNOWS_TECHNOLOGY)
@@ -165,7 +231,7 @@
var/step = 1
for(step = 1; step<=steps; step++)
if(step > next_step)
- current_turf = get_step(current_turf,direction)
+ current_turf = get_step(current_turf, direction)
next_step += tally_step
if(envelope)
envelope.change_current_loc(current_turf)
diff --git a/code/game/cas_manager/datums/cas_iff_group.dm b/code/game/cas_manager/datums/cas_iff_group.dm
index f384115d7756..dc39b462c9f1 100644
--- a/code/game/cas_manager/datums/cas_iff_group.dm
+++ b/code/game/cas_manager/datums/cas_iff_group.dm
@@ -8,8 +8,7 @@
/datum/cas_iff_group/proc/remove_signal(datum/cas_signal/signal)
cas_signals -= signal
-var/global/datum/cas_iff_group/uscm_cas_group = new /datum/cas_iff_group()
+GLOBAL_DATUM_INIT(uscm_cas_group, /datum/cas_iff_group, new())
+GLOBAL_DATUM_INIT(upp_cas_group, /datum/cas_iff_group, new())
-var/global/datum/cas_iff_group/upp_cas_group = new /datum/cas_iff_group()
-
-var/global/list/datum/cas_iff_group/cas_groups = list(FACTION_MARINE = uscm_cas_group, FACTION_UPP = upp_cas_group, FACTION_NEUTRAL = uscm_cas_group)
+GLOBAL_LIST_INIT_TYPED(cas_groups, /datum/cas_iff_group, list(FACTION_MARINE = GLOB.uscm_cas_group, FACTION_UPP = GLOB.upp_cas_group, FACTION_NEUTRAL = GLOB.uscm_cas_group))
diff --git a/code/game/gamemodes/cm_initialize.dm b/code/game/gamemodes/cm_initialize.dm
index cc1e5449ca7a..c017733de7fd 100644
--- a/code/game/gamemodes/cm_initialize.dm
+++ b/code/game/gamemodes/cm_initialize.dm
@@ -75,6 +75,12 @@ Additional game mode variables.
var/list/monkey_types = list() //What type of monkeys do we spawn
var/latejoin_tally = 0 //How many people latejoined Marines
var/latejoin_larva_drop = LATEJOIN_MARINES_PER_LATEJOIN_LARVA //A larva will spawn in once the tally reaches this level. If set to 0, no latejoin larva drop
+ /// Amount of latejoin_tally already awarded as larvas
+ var/latejoin_larva_used = 0
+ /// Multiplier to the amount of marine gear, current value as calculated with modifiers
+ var/gear_scale = 1
+ /// Multiplier to the amount of marine gear, maximum reached value for
+ var/gear_scale_max = 1
//Role Authority set up.
/// List of role titles to override to different roles when starting game
@@ -100,7 +106,7 @@ Additional game mode variables.
/datum/game_mode/proc/get_roles_list()
- return ROLES_USCM
+ return GLOB.ROLES_USCM
//===================================================\\
@@ -109,16 +115,16 @@ Additional game mode variables.
//===================================================\\
/datum/game_mode/proc/initialize_special_clamps()
- xeno_starting_num = clamp((readied_players/CONFIG_GET(number/xeno_number_divider)), xeno_required_num, INFINITY) //(n, minimum, maximum)
- surv_starting_num = clamp((readied_players/CONFIG_GET(number/surv_number_divider)), 2, 8) //this doesnt run
+ xeno_starting_num = clamp((GLOB.readied_players/CONFIG_GET(number/xeno_number_divider)), xeno_required_num, INFINITY) //(n, minimum, maximum)
+ surv_starting_num = clamp((GLOB.readied_players/CONFIG_GET(number/surv_number_divider)), 2, 8) //this doesnt run
marine_starting_num = GLOB.player_list.len - xeno_starting_num - surv_starting_num
- for(var/datum/squad/sq in RoleAuthority.squads)
+ for(var/datum/squad/sq in GLOB.RoleAuthority.squads)
if(sq)
sq.max_engineers = engi_slot_formula(marine_starting_num)
sq.max_medics = medic_slot_formula(marine_starting_num)
- for(var/i in RoleAuthority.roles_by_name)
- var/datum/job/J = RoleAuthority.roles_by_name[i]
+ for(var/i in GLOB.RoleAuthority.roles_by_name)
+ var/datum/job/J = GLOB.RoleAuthority.roles_by_name[i]
if(J.scaled)
J.set_spawn_positions(marine_starting_num)
@@ -149,7 +155,7 @@ Additional game mode variables.
else
if(!istype(player,/mob/dead)) continue //Otherwise we just want to grab the ghosts.
- if(RoleAuthority.roles_whitelist[player.ckey] & WHITELIST_PREDATOR) //Are they whitelisted?
+ if(GLOB.RoleAuthority.roles_whitelist[player.ckey] & WHITELIST_PREDATOR) //Are they whitelisted?
if(!player.client.prefs)
player.client.prefs = new /datum/preferences(player.client) //Somehow they don't have one.
@@ -176,13 +182,13 @@ Additional game mode variables.
if(!pred_candidate.client)
return
- var/datum/job/J = RoleAuthority.roles_by_name[JOB_PREDATOR]
+ var/datum/job/J = GLOB.RoleAuthority.roles_by_name[JOB_PREDATOR]
if(!J)
if(show_warning) to_chat(pred_candidate, SPAN_WARNING("Something went wrong!"))
return
- if(!(RoleAuthority.roles_whitelist[pred_candidate.ckey] & WHITELIST_PREDATOR))
+ if(!(GLOB.RoleAuthority.roles_whitelist[pred_candidate.ckey] & WHITELIST_PREDATOR))
if(show_warning) to_chat(pred_candidate, SPAN_WARNING("You are not whitelisted! You may apply on the forums to be whitelisted as a predator."))
return
@@ -195,9 +201,9 @@ Additional game mode variables.
to_chat(pred_candidate, SPAN_WARNING("You already were a Yautja! Give someone else a chance."))
return
- if(show_warning && tgui_alert(pred_candidate, "Confirm joining the hunt. You will join as \a [lowertext(J.get_whitelist_status(RoleAuthority.roles_whitelist, pred_candidate.client))] predator", "Confirmation", list("Yes", "No"), 10 SECONDS) != "Yes")
+ if(show_warning && tgui_alert(pred_candidate, "Confirm joining the hunt. You will join as \a [lowertext(J.get_whitelist_status(GLOB.RoleAuthority.roles_whitelist, pred_candidate.client))] predator", "Confirmation", list("Yes", "No"), 10 SECONDS) != "Yes")
return
- if(J.get_whitelist_status(RoleAuthority.roles_whitelist, pred_candidate.client) == WHITELIST_NORMAL)
+ if(J.get_whitelist_status(GLOB.RoleAuthority.roles_whitelist, pred_candidate.client) == WHITELIST_NORMAL)
var/pred_max = calculate_pred_max
if(pred_current_num >= pred_max)
if(show_warning) to_chat(pred_candidate, SPAN_WARNING("Only [pred_max] predators may spawn this round, but Councillors and Ancients do not count."))
@@ -234,13 +240,13 @@ Additional game mode variables.
pred_candidate.mind.transfer_to(new_predator, TRUE)
new_predator.client = pred_candidate.client
- var/datum/job/J = RoleAuthority.roles_by_name[JOB_PREDATOR]
+ var/datum/job/J = GLOB.RoleAuthority.roles_by_name[JOB_PREDATOR]
if(!J)
qdel(new_predator)
return
- RoleAuthority.equip_role(new_predator, J, new_predator.loc)
+ GLOB.RoleAuthority.equip_role(new_predator, J, new_predator.loc)
return new_predator
@@ -344,7 +350,7 @@ Additional game mode variables.
if(cur_xeno.aghosted)
continue //aghosted xenos don't count
var/area/area = get_area(cur_xeno)
- if(is_admin_level(cur_xeno.z) && (!area || !(area.flags_area & AREA_ALLOW_XENO_JOIN)))
+ if(should_block_game_interaction(cur_xeno) && (!area || !(area.flags_area & AREA_ALLOW_XENO_JOIN)))
continue //xenos on admin z level don't count
if(!istype(cur_xeno))
continue
@@ -356,21 +362,27 @@ Additional game mode variables.
else
available_xenos_non_ssd += cur_xeno
- // Only offer buried larva if there is no queue:
- // This basically means this block of code will almost never execute, because we are instead relying on the hive cores/larva pops to handle their larva
- // Technically this should be after a get_alien_candidates() call to be accurate, but we are intentionally trying to not call that proc as much as possible
- if(GLOB.xeno_queue_candidate_count < 1)
- var/datum/hive_status/hive
- for(var/hivenumber in GLOB.hive_datum)
- hive = GLOB.hive_datum[hivenumber]
- if(!hive.hardcore && hive.stored_larva && (hive.hive_location || (world.time < XENO_BURIED_LARVA_TIME_LIMIT + SSticker.round_start_time)))
- if(SSticker.mode && (SSticker.mode.flags_round_type & MODE_RANDOM_HIVE))
- available_xenos |= "any buried larva"
- LAZYADD(available_xenos["any buried larva"], hive)
- else
- var/larva_option = "buried larva ([hive])"
- available_xenos += larva_option
- available_xenos[larva_option] = list(hive)
+ var/datum/hive_status/hive
+ for(var/hivenumber in GLOB.hive_datum)
+ hive = GLOB.hive_datum[hivenumber]
+ if(hive.hardcore)
+ continue
+ if(!hive.stored_larva)
+ continue
+ // Only offer buried larva if there is no queue because we are instead relying on the hive cores/larva pops to handle their larva:
+ // Technically this should be after a get_alien_candidates() call to be accurate, but we are intentionally trying to not call that proc as much as possible
+ if(hive.hive_location && GLOB.xeno_queue_candidate_count > 0)
+ continue
+ if(!hive.hive_location && (world.time > XENO_BURIED_LARVA_TIME_LIMIT + SSticker.round_start_time))
+ continue
+
+ if(SSticker.mode && (SSticker.mode.flags_round_type & MODE_RANDOM_HIVE))
+ available_xenos |= "any buried larva"
+ LAZYADD(available_xenos["any buried larva"], hive)
+ else
+ var/larva_option = "buried larva ([hive])"
+ available_xenos += larva_option
+ available_xenos[larva_option] = list(hive)
if(!available_xenos.len || (instant_join && !available_xenos_non_ssd.len))
if(!xeno_candidate.client || !xeno_candidate.client.prefs || !(xeno_candidate.client.prefs.be_special & BE_ALIEN_AFTER_DEATH))
@@ -382,7 +394,7 @@ Additional game mode variables.
var/mob/dead/observer/candidate_observer = xeno_candidate
if(istype(candidate_observer))
if(candidate_observer.larva_queue_cached_message)
- to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message)
+ to_chat(xeno_candidate, SPAN_XENONOTICE(candidate_observer.larva_queue_cached_message))
return FALSE
// No cache, lets check now then
@@ -393,14 +405,14 @@ Additional game mode variables.
cur_hive = GLOB.hive_datum[hive_num]
for(var/mob_name in cur_hive.banished_ckeys)
if(cur_hive.banished_ckeys[mob_name] == xeno_candidate.ckey)
- candidate_observer.larva_queue_cached_message += "\n" + SPAN_WARNING("NOTE: You are banished from the [cur_hive] and you may not rejoin unless the Queen re-admits you or dies. Your queue number won't update until there is a hive you aren't banished from.")
+ candidate_observer.larva_queue_cached_message += "\nNOTE: You are banished from the [cur_hive] and you may not rejoin unless the Queen re-admits you or dies. Your queue number won't update until there is a hive you aren't banished from."
break
- to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message)
+ to_chat(xeno_candidate, SPAN_XENONOTICE(candidate_observer.larva_queue_cached_message))
return FALSE
// We aren't in queue yet, lets teach them about the queue then
- candidate_observer.larva_queue_cached_message = SPAN_XENONOTICE("You are currently awaiting assignment in the larva queue. The ordering is based on your time of death or the time you joined. When you have been dead long enough and are not inactive, you will periodically receive messages where you are in the queue relative to other currently valid xeno candidates. Your current position will shift as others change their preferences or go inactive, but your relative position compared to all observers is the same. Note: Playing as a facehugger or in the thunderdome will not alter your time of death. This means you won't lose your relative place in queue if you step away, disconnect, play as a facehugger, or play in the thunderdome.")
- to_chat(xeno_candidate, candidate_observer.larva_queue_cached_message)
+ candidate_observer.larva_queue_cached_message = "You are currently awaiting assignment in the larva queue. The ordering is based on your time of death or the time you joined. When you have been dead long enough and are not inactive, you will periodically receive messages where you are in the queue relative to other currently valid xeno candidates. Your current position will shift as others change their preferences or go inactive, but your relative position compared to all observers is the same. Note: Playing as a facehugger or in the thunderdome will not alter your time of death. This means you won't lose your relative place in queue if you step away, disconnect, play as a facehugger, or play in the thunderdome."
+ to_chat(xeno_candidate, SPAN_XENONOTICE(candidate_observer.larva_queue_cached_message))
return FALSE
var/mob/living/carbon/xenomorph/new_xeno
@@ -423,7 +435,7 @@ Additional game mode variables.
for(var/mob_name in picked_hive.banished_ckeys)
if(picked_hive.banished_ckeys[mob_name] == xeno_candidate.ckey)
to_chat(xeno_candidate, SPAN_WARNING("You are banished from the [picked_hive], you may not rejoin unless the Queen re-admits you or dies."))
- return
+ return FALSE
if(isnewplayer(xeno_candidate))
var/mob/new_player/noob = xeno_candidate
noob.close_spawn_windows()
@@ -443,9 +455,6 @@ Additional game mode variables.
return FALSE
new_xeno = userInput
- if(!xeno_candidate)
- return FALSE
-
if(!(new_xeno in GLOB.living_xeno_list) || new_xeno.stat == DEAD)
to_chat(xeno_candidate, SPAN_WARNING("You cannot join if the xenomorph is dead."))
return FALSE
@@ -479,14 +488,14 @@ Additional game mode variables.
else new_xeno = pick(available_xenos_non_ssd) //Just picks something at random.
if(istype(new_xeno) && xeno_candidate && xeno_candidate.client)
if(isnewplayer(xeno_candidate))
- var/mob/new_player/N = xeno_candidate
- N.close_spawn_windows()
+ var/mob/new_player/noob = xeno_candidate
+ noob.close_spawn_windows()
for(var/mob_name in new_xeno.hive.banished_ckeys)
if(new_xeno.hive.banished_ckeys[mob_name] == xeno_candidate.ckey)
to_chat(xeno_candidate, SPAN_WARNING("You are banished from this hive, You may not rejoin unless the Queen re-admits you or dies."))
- return
+ return FALSE
if(transfer_xeno(xeno_candidate, new_xeno))
- return 1
+ return TRUE
to_chat(xeno_candidate, "JAS01: Something went wrong, tell a coder.")
/datum/game_mode/proc/attempt_to_join_as_facehugger(mob/xeno_candidate)
@@ -594,7 +603,14 @@ Additional game mode variables.
for(var/obj/effect/alien/resin/special/pylon/cycled_pylon as anything in hive.hive_structures[XENO_STRUCTURE_PYLON])
if(cycled_pylon.lesser_drone_spawns >= 1)
- selection_list += "[cycled_pylon.name] at [get_area(cycled_pylon)]"
+ var/pylon_number = 1
+ var/pylon_name = "[cycled_pylon.name] at [get_area(cycled_pylon)]"
+ //For renaming the pylon if we have duplicates
+ var/pylon_selection_name = pylon_name
+ while(pylon_selection_name in selection_list)
+ pylon_selection_name = "[pylon_name] ([pylon_number])"
+ pylon_number ++
+ selection_list += pylon_selection_name
selection_list_structure += cycled_pylon
if(!length(selection_list))
@@ -614,20 +630,21 @@ Additional game mode variables.
/datum/game_mode/proc/transfer_xeno(xeno_candidate, mob/living/new_xeno)
if(!xeno_candidate || !isxeno(new_xeno) || QDELETED(new_xeno))
return FALSE
+
var/datum/mind/xeno_candidate_mind
if(ismind(xeno_candidate))
xeno_candidate_mind = xeno_candidate
else if(ismob(xeno_candidate))
- var/mob/M = xeno_candidate
- if(M.mind)
- xeno_candidate_mind = M.mind
+ var/mob/xeno_candidate_mob = xeno_candidate
+ if(xeno_candidate_mob.mind)
+ xeno_candidate_mind = xeno_candidate_mob.mind
else
- xeno_candidate_mind = new /datum/mind(M.key, M.ckey)
+ xeno_candidate_mind = new /datum/mind(xeno_candidate_mob.key, xeno_candidate_mob.ckey)
xeno_candidate_mind.active = TRUE
xeno_candidate_mind.current = new_xeno
else if(isclient(xeno_candidate))
- var/client/C = xeno_candidate
- xeno_candidate_mind = new /datum/mind(C.key, C.ckey)
+ var/client/xeno_candidate_client = xeno_candidate
+ xeno_candidate_mind = new /datum/mind(xeno_candidate_client.key, xeno_candidate_client.ckey)
xeno_candidate_mind.active = TRUE
xeno_candidate_mind.current = new_xeno
else
@@ -644,7 +661,7 @@ Additional game mode variables.
// Let the round recorder know that the key has changed
SSround_recording.recorder.update_key(new_xeno)
if(new_xeno.client)
- new_xeno.client.change_view(world_view_size)
+ new_xeno.client.change_view(GLOB.world_view_size)
msg_admin_niche("[new_xeno.key] has joined as [new_xeno].")
if(isxeno(new_xeno)) //Dear lord
@@ -717,8 +734,6 @@ Additional game mode variables.
to_chat(new_queen, "You should start by building a hive core.")
to_chat(new_queen, "Talk in Hivemind using ; (e.g. ';Hello my children!')")
- // Xeno ressource collection
- //new_queen.crystal_stored = XENO_STARTING_CRYSTAL
new_queen.update_icons()
//===================================================\\
@@ -903,23 +918,49 @@ Additional game mode variables.
//We do NOT want to initilialize the gear before everyone is properly spawned in
/datum/game_mode/proc/initialize_post_marine_gear_list()
- var/scale = get_scaling_value()
+ init_gear_scale()
//Set up attachment vendor contents related to Marine count
for(var/i in GLOB.cm_vending_vendors)
var/obj/structure/machinery/cm_vending/sorted/CVS = i
- CVS.populate_product_list_and_boxes(scale)
+ CVS.populate_product_list_and_boxes(gear_scale)
//Scale the amount of cargo points through a direct multiplier
- supply_controller.points = round(supply_controller.points * scale)
+ GLOB.supply_controller.points += round(GLOB.supply_controller.points_scale * gear_scale)
-/datum/game_mode/proc/get_scaling_value()
+///Returns a multiplier to the amount of gear that is to be distributed roundstart, stored in [/datum/game_mode/var/gear_scale]
+/datum/game_mode/proc/init_gear_scale()
//We take the number of marine players, deduced from other lists, and then get a scale multiplier from it, to be used in arbitrary manners to distribute equipment
- //This might count players who ready up but get kicked back to the lobby
- var/marine_pop_size = length(GLOB.alive_human_list)
+ var/marine_pop_size = 0
+ var/uscm_personnel_count = 0
+ for(var/mob/living/carbon/human/human as anything in GLOB.alive_human_list)
+ if(human.faction == FACTION_USCM)
+ uscm_personnel_count++
+ var/datum/job/job = GET_MAPPED_ROLE(human.job)
+ marine_pop_size += GLOB.RoleAuthority.calculate_role_weight(job)
//This gives a decimal value representing a scaling multiplier. Cannot go below 1
- return max(marine_pop_size / MARINE_GEAR_SCALING_NORMAL, 1)
+ gear_scale = max(marine_pop_size / MARINE_GEAR_SCALING_NORMAL, 1)
+ gear_scale_max = gear_scale
+ log_debug("SUPPLY: Game start detected [marine_pop_size] weighted marines (out of [uscm_personnel_count]/[length(GLOB.alive_human_list)] USCM humans), resulting in gear_scale = [gear_scale]")
+ return gear_scale
+
+///Updates the [/datum/game_mode/var/gear_scale] multiplier based on joining and cryoing marines
+/datum/game_mode/proc/update_gear_scale(delta)
+ // Magic inverse function that guarantees marines still get good supplies for latejoins within first ~30 minutes but stalls starting 2 hours or so
+ gear_scale += delta * (0.25 + 0.75 / (1 + ROUND_TIME / 20000)) / MARINE_GEAR_SCALING_NORMAL
+ var/gear_delta = gear_scale - gear_scale_max
+ if(gear_delta > 0)
+ gear_scale_max = gear_scale
+ for(var/obj/structure/machinery/cm_vending/sorted/vendor as anything in GLOB.cm_vending_vendors)
+ vendor.update_dynamic_stock(gear_scale_max)
+ GLOB.supply_controller.points += round(gear_delta * GLOB.supply_controller.points_scale)
+
+/// Updates [var/latejoin_tally] and [var/gear_scale] based on role weights of latejoiners/cryoers. Delta is the amount of role positions added/removed
+/datum/game_mode/proc/latejoin_update(role, delta = 1)
+ var/weight = GLOB.RoleAuthority.calculate_role_weight(role)
+ latejoin_tally += weight * delta
+ update_gear_scale(weight * delta)
// for the toolbox
/datum/game_mode/proc/end_round_message()
@@ -953,14 +994,14 @@ Additional game mode variables.
if(!joe_candidate.client)
return
- var/datum/job/joe_job = RoleAuthority.roles_by_name[JOB_WORKING_JOE]
+ var/datum/job/joe_job = GLOB.RoleAuthority.roles_by_name[JOB_WORKING_JOE]
if(!joe_job)
if(show_warning)
to_chat(joe_candidate, SPAN_WARNING("Something went wrong!"))
return
- if(!(RoleAuthority.roles_whitelist[joe_candidate.ckey] & WHITELIST_JOE))
+ if(!(GLOB.RoleAuthority.roles_whitelist[joe_candidate.ckey] & WHITELIST_JOE))
if(show_warning)
to_chat(joe_candidate, SPAN_WARNING("You are not whitelisted! You may apply on the forums to be whitelisted as a synth."))
return
@@ -971,14 +1012,14 @@ Additional game mode variables.
return
// council doesn't count towards this conditional.
- if(joe_job.get_whitelist_status(RoleAuthority.roles_whitelist, joe_candidate.client) == WHITELIST_NORMAL)
+ if(joe_job.get_whitelist_status(GLOB.RoleAuthority.roles_whitelist, joe_candidate.client) == WHITELIST_NORMAL)
var/joe_max = joe_job.total_positions
if((joe_job.current_positions >= joe_max) && !MODE_HAS_TOGGLEABLE_FLAG(MODE_BYPASS_JOE))
if(show_warning)
to_chat(joe_candidate, SPAN_WARNING("Only [joe_max] Working Joes may spawn per round."))
return
- if(!enter_allowed && !MODE_HAS_TOGGLEABLE_FLAG(MODE_BYPASS_JOE))
+ if(!GLOB.enter_allowed && !MODE_HAS_TOGGLEABLE_FLAG(MODE_BYPASS_JOE))
if(show_warning)
to_chat(joe_candidate, SPAN_WARNING("There is an administrative lock from entering the game."))
return
@@ -998,14 +1039,14 @@ Additional game mode variables.
var/turf/spawn_point = get_turf(pick(GLOB.latejoin_by_job[JOB_WORKING_JOE]))
var/mob/living/carbon/human/synthetic/new_joe = new(spawn_point)
joe_candidate.mind.transfer_to(new_joe, TRUE)
- var/datum/job/joe_job = RoleAuthority.roles_by_name[JOB_WORKING_JOE]
+ var/datum/job/joe_job = GLOB.RoleAuthority.roles_by_name[JOB_WORKING_JOE]
if(!joe_job)
qdel(new_joe)
return
// This is usually done in assign_role, a proc which is not executed in this case, since check_joe_late_join is running its own checks.
joe_job.current_positions++
- RoleAuthority.equip_role(new_joe, joe_job, new_joe.loc)
+ GLOB.RoleAuthority.equip_role(new_joe, joe_job, new_joe.loc)
GLOB.data_core.manifest_inject(new_joe)
SSticker.minds += new_joe.mind
return new_joe
diff --git a/code/game/gamemodes/cm_process.dm b/code/game/gamemodes/cm_process.dm
index 33377f7dc6fd..462f82e99cec 100644
--- a/code/game/gamemodes/cm_process.dm
+++ b/code/game/gamemodes/cm_process.dm
@@ -39,16 +39,16 @@ of predators), but can be added to include variant game modes (like humans vs. h
/datum/game_mode/proc/declare_completion_announce_fallen_soldiers()
set waitfor = 0
sleep(2 SECONDS)
- fallen_list += fallen_list_cross
- if(fallen_list.len)
+ GLOB.fallen_list += GLOB.fallen_list_cross
+ if(GLOB.fallen_list.len)
var/dat = " "
dat += SPAN_ROUNDBODY("In Flanders fields... ")
dat += SPAN_CENTERBOLD("In memoriam of our fallen soldiers: ")
- for(var/i = 1 to fallen_list.len)
- if(i != fallen_list.len)
- dat += "[fallen_list[i]], "
+ for(var/i = 1 to GLOB.fallen_list.len)
+ if(i != GLOB.fallen_list.len)
+ dat += "[GLOB.fallen_list[i]], "
else
- dat += "[fallen_list[i]]. "
+ dat += "[GLOB.fallen_list[i]]. "
to_world("[dat]")
@@ -134,7 +134,7 @@ of predators), but can be added to include variant game modes (like humans vs. h
// Open podlocks with the given ID if they aren't already opened.
// DO NOT USE THIS WITH ID's CORRESPONDING TO SHUTTLES OR THEY WILL BREAK!
/datum/game_mode/proc/open_podlocks(podlock_id)
- for(var/obj/structure/machinery/door/poddoor/M in machines)
+ for(var/obj/structure/machinery/door/poddoor/M in GLOB.machines)
if(M.id == podlock_id && M.density)
M.open()
diff --git a/code/game/gamemodes/cm_self_destruct.dm b/code/game/gamemodes/cm_self_destruct.dm
deleted file mode 100644
index b86de24eed74..000000000000
--- a/code/game/gamemodes/cm_self_destruct.dm
+++ /dev/null
@@ -1,476 +0,0 @@
-/*
-TODO
-Look into animation screen not showing on self-destruct and other weirdness
-Intergrate distress into this controller.
-Finish nanoui conversion for comm console.
-Make sure people who get nuked and wake up from SSD don't live.
-Add flashing lights to evac. //DEFERRED TO BETTER LIGHTING
-Finish the game mode announcement thing.
-Fix escape doors to work properly.
-*/
-
-/*
-How this works:
-
-First: All of the linking is done automatically on world start, so nothing needs to be done on that end other than making
-sure that objects are actually placed in the game world. If not, the game will error and let you know about it. But you
-don't need to modify variables or worry about area placement. It's all done for you.
-The rods, for example, configure the time per activation based on their number. Shuttles link their own machines via area.
-Nothing in this controller is linked to game mode, so it's stand alone, more or less, but it's best used during a game mode.
-Admins have a lot of tools in their disposal via the check antagonist panel, and devs can access the VV of this controller
-through that panel.
-
-Second: The communication console handles most of the IC triggers for activating these functions, the rest is handled elsewhere.
-Check communications.dm for that. shuttle_controller.dm handles the set up for the escape pods. escape_pods.dm handles most of the
-functions of the escape pods themselves. This file would likely need to be broken down into individual parts at some point in the
-future.
-
-Evacuation takes place when sufficient alert level is reaised and a distress beacon was launched. All of the evac pods come online
-and open their doors to allow entry inside. Characters may then get inside of the cryo units to before the shuttles automatically launch.
-If wanted, a nearby controller object may launch each individual shuttle early. Only three people may ride on a shuttle to escape,
-otherwise the launch will fail and the shuttle will become inoperable.
-Any launched shuttles are taken out of the game. If the evacuation is canceled, any persons inside of the cryo tubes will be ejected.
-They may temporarily open the door to exit if they are stuck inside after evac is canceled.
-
-When the self-destruct is enabled, the console comes online. This usually happens during an evacuation. Once the console is
-interacted with, it fires up the self-destruct sequence. Several rods rise and must be interacted with in order to arm the system.
-Once that happens, the console must be interacted with again to trigger the self-destruct. The self-destruct may also be
-canceled from the console.
-
-The self-destruct may also happen if a nuke is detonated on the ship's zlevel; if it is detonated elsewhere, the ship will not blow up.
-Regardless of where it's detonated, or how, a successful detonation will end the round or automatically restart the game.
-
-All of the necessary difines are stored under mode.dm in defines.
-*/
-
-var/global/datum/authority/branch/evacuation/EvacuationAuthority //This is initited elsewhere so that the world has a chance to load in.
-
-/datum/authority/branch/evacuation
- var/name = "Evacuation Authority"
- var/evac_time //Time the evacuation was initiated.
- var/evac_status = EVACUATION_STATUS_STANDING_BY //What it's doing now? It can be standing by, getting ready to launch, or finished.
-
- var/obj/structure/machinery/self_destruct/console/dest_master //The main console that does the brunt of the work.
- var/dest_rods[] //Slave devices to make the explosion work.
- var/dest_cooldown //How long it takes between rods, determined by the amount of total rods present.
- var/dest_index = 1 //What rod the thing is currently on.
- var/dest_status = NUKE_EXPLOSION_INACTIVE
- var/dest_started_at = 0
-
- var/flags_scuttle = NO_FLAGS
-
-/datum/authority/branch/evacuation/New()
- ..()
- dest_master = locate()
- if(!dest_master)
- log_debug("ERROR CODE SD1: could not find master self-destruct console")
- to_world(SPAN_DEBUG("ERROR CODE SD1: could not find master self-destruct console"))
- return FALSE
- dest_rods = new
- for(var/obj/structure/machinery/self_destruct/rod/I in dest_master.loc.loc) dest_rods += I
- if(!dest_rods.len)
- log_debug("ERROR CODE SD2: could not find any self-destruct rods")
- to_world(SPAN_DEBUG("ERROR CODE SD2: could not find any self-destruct rods"))
- QDEL_NULL(dest_master)
- return FALSE
- dest_cooldown = SELF_DESTRUCT_ROD_STARTUP_TIME / dest_rods.len
- dest_master.desc = "The main operating panel for a self-destruct system. It requires very little user input, but the final safety mechanism is manually unlocked.\nAfter the initial start-up sequence, [dest_rods.len] control rods must be armed, followed by manually flipping the detonation switch."
-
-/**
- * This proc returns the ship's z level list (or whatever specified),
- * when an evac/self-destruct happens.
- */
-/datum/authority/branch/evacuation/proc/get_affected_zlevels()
- //Nuke is not in progress, end the round on ship only.
- if(dest_status < NUKE_EXPLOSION_IN_PROGRESS && SSticker?.mode.is_in_endgame)
- . = SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP))
- return
-
-//=========================================================================================
-//=========================================================================================
-//=====================================EVACUATION==========================================
-//=========================================================================================
-//=========================================================================================
-
-
-/datum/authority/branch/evacuation/proc/initiate_evacuation(force=0) //Begins the evacuation procedure.
- if(force || (evac_status == EVACUATION_STATUS_STANDING_BY && !(flags_scuttle & FLAGS_EVACUATION_DENY)))
- evac_time = world.time
- evac_status = EVACUATION_STATUS_INITIATING
- ai_announcement("Attention. Emergency. All personnel must evacuate immediately. You have [round(EVACUATION_ESTIMATE_DEPARTURE/60,1)] minute\s until departure.", 'sound/AI/evacuate.ogg')
- xeno_message_all("A wave of adrenaline ripples through the hive. The fleshy creatures are trying to escape!")
-
- for(var/obj/structure/machinery/status_display/SD in machines)
- if(is_mainship_level(SD.z))
- SD.set_picture("evac")
- for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
- shuttle.prepare_evac()
- activate_lifeboats()
- process_evacuation()
- return TRUE
-
-/datum/authority/branch/evacuation/proc/cancel_evacuation() //Cancels the evac procedure. Useful if admins do not want the marines leaving.
- if(evac_status == EVACUATION_STATUS_INITIATING)
- evac_time = null
- evac_status = EVACUATION_STATUS_STANDING_BY
- deactivate_lifeboats()
- ai_announcement("Evacuation has been cancelled.", 'sound/AI/evacuate_cancelled.ogg')
-
- if(get_security_level() == "red")
- for(var/obj/structure/machinery/status_display/SD in machines)
- if(is_mainship_level(SD.z))
- SD.set_picture("redalert")
-
- for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
- shuttle.cancel_evac()
- return TRUE
-
-/datum/authority/branch/evacuation/proc/begin_launch() //Launches the pods.
- if(evac_status == EVACUATION_STATUS_INITIATING)
- evac_status = EVACUATION_STATUS_IN_PROGRESS //Cannot cancel at this point. All shuttles are off.
- spawn() //One of the few times spawn() is appropriate. No need for a new proc.
- ai_announcement("WARNING: Evacuation order confirmed. Launching escape pods.", 'sound/AI/evacuation_confirmed.ogg')
- addtimer(CALLBACK(src, PROC_REF(launch_lifeboats)), 10 SECONDS) // giving some time to board lifeboats
-
- for(var/obj/docking_port/mobile/crashable/escape_shuttle/shuttle in SSshuttle.mobile)
- shuttle.evac_launch()
- sleep(50)
-
- sleep(300) //Sleep 30 more seconds to make sure everyone had a chance to leave.
- var/lifesigns = 0
- // lifesigns += P.passengers
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat1 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_PORT)
- lifeboat1.check_for_survivors()
- lifesigns += lifeboat1.survivors
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat2 = SSshuttle.getShuttle(MOBILE_SHUTTLE_LIFEBOAT_STARBOARD)
- lifeboat2.check_for_survivors()
- lifesigns += lifeboat2.survivors
- ai_announcement("ATTENTION: Evacuation complete. Outbound lifesigns detected: [lifesigns ? lifesigns : "none"].", 'sound/AI/evacuation_complete.ogg')
- evac_status = EVACUATION_STATUS_COMPLETE
- return TRUE
-
-/datum/authority/branch/evacuation/proc/process_evacuation() //Process the timer.
- set background = 1
-
- spawn while(evac_status == EVACUATION_STATUS_INITIATING) //If it's not departing, no need to process.
- if(world.time >= evac_time + EVACUATION_AUTOMATIC_DEPARTURE) begin_launch()
- sleep(10) //One second.
-
-/datum/authority/branch/evacuation/proc/get_status_panel_eta()
- switch(evac_status)
- if(EVACUATION_STATUS_INITIATING)
- var/eta = EVACUATION_ESTIMATE_DEPARTURE
- . = "[(eta / 60) % 60]:[add_zero(num2text(eta % 60), 2)]"
- if(EVACUATION_STATUS_IN_PROGRESS) . = "NOW"
-
-// LIFEBOATS CORNER
-/datum/authority/branch/evacuation/proc/activate_lifeboats()
- for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
- if(lifeboat && lifeboat.available)
- lifeboat.status = LIFEBOAT_ACTIVE
- lifeboat_dock.open_dock()
-
-
-/datum/authority/branch/evacuation/proc/deactivate_lifeboats()
- for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
- if(lifeboat && lifeboat.available)
- lifeboat.status = LIFEBOAT_INACTIVE
-
-/datum/authority/branch/evacuation/proc/launch_lifeboats()
- for(var/obj/docking_port/stationary/lifeboat_dock/lifeboat_dock in GLOB.lifeboat_almayer_docks)
- var/obj/docking_port/mobile/crashable/lifeboat/lifeboat = lifeboat_dock.get_docked()
- if(lifeboat && lifeboat.available)
- lifeboat.evac_launch()
-
-//=========================================================================================
-//=========================================================================================
-//=====================================SELF DETRUCT========================================
-//=========================================================================================
-//=========================================================================================
-
-/datum/authority/branch/evacuation/proc/enable_self_destruct(force=0)
- if(force || (dest_status == NUKE_EXPLOSION_INACTIVE && !(flags_scuttle & FLAGS_SELF_DESTRUCT_DENY)))
- dest_status = NUKE_EXPLOSION_ACTIVE
- dest_master.lock_or_unlock()
- dest_started_at = world.time
- set_security_level(SEC_LEVEL_DELTA) //also activate Delta alert, to open the SD shutters.
- spawn(0)
- for(var/obj/structure/machinery/door/poddoor/shutters/almayer/D in machines)
- if(D.id == "sd_lockdown")
- D.open()
- return TRUE
-
-//Override is for admins bypassing normal player restrictions.
-/datum/authority/branch/evacuation/proc/cancel_self_destruct(override)
- if(dest_status == NUKE_EXPLOSION_ACTIVE)
- var/obj/structure/machinery/self_destruct/rod/I
- var/i
- for(i in EvacuationAuthority.dest_rods)
- I = i
- if(I.active_state == SELF_DESTRUCT_MACHINE_ARMED && !override)
- dest_master.state(SPAN_WARNING("WARNING: Unable to cancel detonation. Please disarm all control rods."))
- return FALSE
-
- dest_status = NUKE_EXPLOSION_INACTIVE
- dest_master.in_progress = 1
- dest_started_at = 0
- for(i in dest_rods)
- I = i
- if(I.active_state == SELF_DESTRUCT_MACHINE_ACTIVE || (I.active_state == SELF_DESTRUCT_MACHINE_ARMED && override)) I.lock_or_unlock(1)
- dest_master.lock_or_unlock(1)
- dest_index = 1
- ai_announcement("The emergency destruct system has been deactivated.", 'sound/AI/selfdestruct_deactivated.ogg')
- if(evac_status == EVACUATION_STATUS_STANDING_BY) //the evac has also been cancelled or was never started.
- set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level.
- return TRUE
-
-/datum/authority/branch/evacuation/proc/initiate_self_destruct(override)
- if(dest_status < NUKE_EXPLOSION_IN_PROGRESS)
- var/obj/structure/machinery/self_destruct/rod/I
- var/i
- for(i in dest_rods)
- I = i
- if(I.active_state != SELF_DESTRUCT_MACHINE_ARMED && !override)
- dest_master.state(SPAN_WARNING("WARNING: Unable to trigger detonation. Please arm all control rods."))
- return FALSE
- dest_master.in_progress = !dest_master.in_progress
- for(i in EvacuationAuthority.dest_rods)
- I = i
- I.in_progress = 1
- ai_announcement("DANGER. DANGER. Self-destruct system activated. DANGER. DANGER. Self-destruct in progress. DANGER. DANGER.")
- trigger_self_destruct(,,override)
- return TRUE
-
-/datum/authority/branch/evacuation/proc/trigger_self_destruct(list/z_levels = SSmapping.levels_by_trait(ZTRAIT_MARINE_MAIN_SHIP), origin = dest_master, override = FALSE, end_type = NUKE_EXPLOSION_FINISHED, play_anim = TRUE, end_round = TRUE)
- set waitfor = 0
- if(dest_status < NUKE_EXPLOSION_IN_PROGRESS) //One more check for good measure, in case it's triggered through a bomb instead of the destruct mechanism/admin panel.
- dest_status = NUKE_EXPLOSION_IN_PROGRESS
- playsound(origin, 'sound/machines/Alarm.ogg', 75, 0, 30)
- world << pick('sound/theme/nuclear_detonation1.ogg','sound/theme/nuclear_detonation2.ogg')
-
- var/ship_status = 1
- for(var/i in z_levels)
- if(is_mainship_level(i))
- ship_status = 0 //Destroyed.
- break
-
- var/list/alive_mobs = list() //Everyone who will be destroyed on the zlevel(s).
- var/list/dead_mobs = list() //Everyone who only needs to see the cinematic.
- for(var/mob/current_mob as anything in GLOB.mob_list) //This only does something cool for the people about to die, but should prove pretty interesting.
- if(!current_mob || !current_mob.loc)
- continue //In case something changes when we sleep().
- if(current_mob.stat == DEAD)
- dead_mobs |= current_mob
- continue
- var/turf/current_turf = get_turf(current_mob)
- if(current_turf.z in z_levels)
- alive_mobs |= current_mob
- shake_camera(current_mob, 110, 4)
-
-
- sleep(100)
- /*Hardcoded for now, since this was never really used for anything else.
- Would ideally use a better system for showing cutscenes.*/
- var/atom/movable/screen/cinematic/explosion/C = new
-
- if(play_anim)
- for(var/mob/current_mob as anything in alive_mobs + dead_mobs)
- if(current_mob && current_mob.loc && current_mob.client)
- current_mob.client.add_to_screen(C) //They may have disconnected in the mean time.
-
- sleep(15) //Extra 1.5 seconds to look at the ship.
- flick(override ? "intro_override" : "intro_nuke", C)
- sleep(35)
- for(var/mob/current_mob in alive_mobs)
- if(current_mob && current_mob.loc) //Who knows, maybe they escaped, or don't exist anymore.
- var/turf/current_mob_turf = get_turf(current_mob)
- if(current_mob_turf.z in z_levels)
- if(istype(current_mob.loc, /obj/structure/closet/secure_closet/freezer/fridge))
- continue
- current_mob.death(create_cause_data("nuclear explosion"))
- else
- if(play_anim)
- current_mob.client.remove_from_screen(C) //those who managed to escape the z level at last second shouldn't have their view obstructed.
- if(play_anim)
- flick(ship_status ? "ship_spared" : "ship_destroyed", C)
- C.icon_state = ship_status ? "summary_spared" : "summary_destroyed"
- world << sound('sound/effects/explosionfar.ogg')
-
- if(end_round)
- dest_status = end_type
-
- sleep(5)
- if(SSticker.mode)
- SSticker.mode.check_win()
-
- if(!SSticker.mode) //Just a safety, just in case a mode isn't running, somehow.
- to_world(SPAN_ROUNDBODY("Resetting in 30 seconds!"))
- sleep(300)
- log_game("Rebooting due to nuclear detonation.")
- world.Reboot()
- return TRUE
-
-/datum/authority/branch/evacuation/proc/process_self_destruct()
- set background = 1
-
- spawn while(dest_master && dest_master.loc && dest_master.active_state == SELF_DESTRUCT_MACHINE_ARMED && dest_status == NUKE_EXPLOSION_ACTIVE && dest_index <= dest_rods.len)
- var/obj/structure/machinery/self_destruct/rod/I = dest_rods[dest_index]
- if(world.time >= dest_cooldown + I.activate_time)
- I.lock_or_unlock() //Unlock it.
- if(++dest_index <= dest_rods.len)
- I = dest_rods[dest_index]//Start the next sequence.
- I.activate_time = world.time
- sleep(10) //Checks every second. Could integrate into another controller for better tracking.
-
-//Generic parent base for the self_destruct items.
-/obj/structure/machinery/self_destruct
- icon = 'icons/obj/structures/machinery/self_destruct.dmi'
- icon_state = "console_1"
- var/base_icon_state = "console"
- use_power = USE_POWER_NONE //Runs unpowered, may need to change later.
- density = FALSE
- anchored = TRUE //So it doesn't go anywhere.
- unslashable = TRUE
- unacidable = TRUE //Cannot C4 it either.
- mouse_opacity = FALSE //No need to click or interact with this initially.
- var/in_progress = 0 //Cannot interact with while it's doing something, like an animation.
- var/active_state = SELF_DESTRUCT_MACHINE_INACTIVE //What step of the process it's on.
-
-/obj/structure/machinery/self_destruct/Initialize(mapload, ...)
- . = ..()
- icon_state = "[base_icon_state]_1"
-
-/obj/structure/machinery/self_destruct/Destroy()
- . = ..()
- machines -= src
- operator = null
-
-/obj/structure/machinery/self_destruct/ex_act(severity)
- return FALSE
-
-/obj/structure/machinery/self_destruct/attack_hand()
- if(..() || in_progress)
- return FALSE //This check is backward, ugh.
- return TRUE
-
-//Add sounds.
-/obj/structure/machinery/self_destruct/proc/lock_or_unlock(lock)
- set waitfor = 0
- in_progress = 1
- flick("[base_icon_state]" + (lock? "_5" : "_2"),src)
- sleep(9)
- mouse_opacity = !mouse_opacity
- icon_state = "[base_icon_state]" + (lock? "_1" : "_3")
- in_progress = 0
- active_state = active_state > SELF_DESTRUCT_MACHINE_INACTIVE ? SELF_DESTRUCT_MACHINE_INACTIVE : SELF_DESTRUCT_MACHINE_ACTIVE
-
-/obj/structure/machinery/self_destruct/console
- name = "self-destruct control panel"
- icon_state = "console_1"
- base_icon_state = "console"
- req_one_access = list(ACCESS_MARINE_CO, ACCESS_MARINE_SENIOR)
-
-/obj/structure/machinery/self_destruct/console/Destroy()
- . = ..()
- EvacuationAuthority.dest_master = null
- EvacuationAuthority.dest_rods = null
-
-/obj/structure/machinery/self_destruct/console/lock_or_unlock(lock)
- playsound(src, 'sound/machines/hydraulics_1.ogg', 25, 1)
- ..()
-
-//TODO: Add sounds.
-/obj/structure/machinery/self_destruct/console/attack_hand(mob/user)
- if(inoperable())
- return
-
- tgui_interact(user)
-
-/obj/structure/machinery/self_destruct/console/tgui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "SelfDestructConsole", name)
- ui.open()
-
-/obj/structure/machinery/sleep_console/ui_status(mob/user, datum/ui_state/state)
- . = ..()
- if(inoperable())
- return UI_CLOSE
-
-
-/obj/structure/machinery/self_destruct/console/ui_data(mob/user)
- var/list/data = list()
-
- data["dest_status"] = active_state
-
- return data
-
-/obj/structure/machinery/self_destruct/console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
- . = ..()
- if(.)
- return
-
- switch(action)
- 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."))
- playsound(src.loc, 'sound/items/rped.ogg', 25, TRUE)
- sleep(2 SECONDS)
- ai_announcement("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.", 'sound/AI/selfdestruct.ogg')
- active_state = SELF_DESTRUCT_MACHINE_ARMED //Arm it here so the process can execute it later.
- var/obj/structure/machinery/self_destruct/rod/I = EvacuationAuthority.dest_rods[EvacuationAuthority.dest_index]
- I.activate_time = world.time
- EvacuationAuthority.process_self_destruct()
- . = TRUE
-
- if("dest_trigger")
- EvacuationAuthority.initiate_self_destruct()
- . = TRUE
-
- if("dest_cancel")
- if(!allowed(usr))
- to_chat(usr, SPAN_WARNING("You don't have the necessary clearance to cancel the emergency destruct system!"))
- return
- EvacuationAuthority.cancel_self_destruct()
- . = TRUE
-
-/obj/structure/machinery/self_destruct/rod
- name = "self-destruct control rod"
- desc = "It is part of a complicated self-destruct sequence, but relatively simple to operate. Twist to arm or disarm."
- icon_state = "rod_1"
- base_icon_state = "rod"
- layer = BELOW_OBJ_LAYER
- var/activate_time
-
-/obj/structure/machinery/self_destruct/rod/Destroy()
- . = ..()
- if(EvacuationAuthority && EvacuationAuthority.dest_rods)
- EvacuationAuthority.dest_rods -= src
-
-/obj/structure/machinery/self_destruct/rod/lock_or_unlock(lock)
- playsound(src, 'sound/machines/hydraulics_2.ogg', 25, 1)
- ..()
- if(lock)
- activate_time = null
- density = FALSE
- layer = initial(layer)
- else
- density = TRUE
- layer = ABOVE_OBJ_LAYER
-
-/obj/structure/machinery/self_destruct/rod/attack_hand(mob/user)
- if(..())
- switch(active_state)
- if(SELF_DESTRUCT_MACHINE_ACTIVE)
- to_chat(user, SPAN_NOTICE("You twist and release the control rod, arming it."))
- playsound(src, 'sound/machines/switch.ogg', 25, 1)
- icon_state = "rod_4"
- active_state = SELF_DESTRUCT_MACHINE_ARMED
- if(SELF_DESTRUCT_MACHINE_ARMED)
- to_chat(user, SPAN_NOTICE("You twist and release the control rod, disarming it."))
- playsound(src, 'sound/machines/switch.ogg', 25, 1)
- icon_state = "rod_3"
- active_state = SELF_DESTRUCT_MACHINE_ACTIVE
- else to_chat(user, SPAN_WARNING("The control rod is not ready."))
diff --git a/code/game/gamemodes/colonialmarines/colonialmarines.dm b/code/game/gamemodes/colonialmarines/colonialmarines.dm
index 258a1a962713..f64c2432486b 100644
--- a/code/game/gamemodes/colonialmarines/colonialmarines.dm
+++ b/code/game/gamemodes/colonialmarines/colonialmarines.dm
@@ -29,7 +29,7 @@
to_chat_spaced(world, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDHEADER("The current map is - [SSmapping.configs[GROUND_MAP].map_name]!"))
/datum/game_mode/colonialmarines/get_roles_list()
- return ROLES_DISTRESS_SIGNAL
+ return GLOB.ROLES_DISTRESS_SIGNAL
////////////////////////////////////////////////////////////////////////////////////////
//Temporary, until we sort this out properly.
@@ -126,7 +126,7 @@
#define MONKEYS_TO_TOTAL_RATIO 1/32
/datum/game_mode/colonialmarines/proc/spawn_smallhosts()
- if(!players_preassigned)
+ if(!GLOB.players_preassigned)
return
monkey_types = SSmapping.configs[GROUND_MAP].monkey_types
@@ -134,7 +134,7 @@
if(!length(monkey_types))
return
- var/amount_to_spawn = round(players_preassigned * MONKEYS_TO_TOTAL_RATIO)
+ var/amount_to_spawn = round(GLOB.players_preassigned * MONKEYS_TO_TOTAL_RATIO)
for(var/i in 0 to min(amount_to_spawn, length(GLOB.monkey_spawns)))
var/turf/T = get_turf(pick_n_take(GLOB.monkey_spawns))
@@ -167,7 +167,7 @@
check_ground_humans()
if(next_research_allocation < world.time)
- chemical_data.update_credits(chemical_data.research_allocation_amount)
+ GLOB.chemical_data.update_credits(GLOB.chemical_data.research_allocation_amount)
next_research_allocation = world.time + research_allocation_interval
if(!round_finished)
@@ -205,7 +205,7 @@
to_chat(M, SPAN_XENOANNOUNCE("To my children and their Queen. I sense the large doors that trap us will open in 30 seconds."))
addtimer(CALLBACK(src, PROC_REF(open_podlocks), "map_lockdown"), 300)
- if(round_should_check_for_win)
+ if(GLOB.round_should_check_for_win)
check_win()
round_checkwin = 0
@@ -265,7 +265,7 @@
continue
if(groundside_humans > (groundside_xenos * GROUNDSIDE_XENO_MULTIPLIER))
- SSticker.mode.get_specific_call("Xenomorphs Groundside (Forsaken)", TRUE, FALSE, FALSE, announce_dispatch_message = FALSE)
+ SSticker.mode.get_specific_call("Xenomorphs Groundside (Forsaken)", TRUE, FALSE)
TIMER_COOLDOWN_START(src, COOLDOWN_HIJACK_GROUND_CHECK, 1 MINUTES)
@@ -297,29 +297,25 @@
if(SSticker.current_state != GAME_STATE_PLAYING)
return
- var/living_player_list[] = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels())
+ var/living_player_list[] = count_humans_and_xenos(get_affected_zlevels())
var/num_humans = living_player_list[1]
var/num_xenos = living_player_list[2]
if(force_end_at && world.time > force_end_at)
round_finished = MODE_INFESTATION_X_MINOR
- if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_FINISHED)
- round_finished = MODE_GENERIC_DRAW_NUKE //Nuke went off, ending the round.
- if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_GROUND_FINISHED)
- round_finished = MODE_INFESTATION_M_MINOR //Nuke went off, ending the round.
- if(EvacuationAuthority.dest_status < NUKE_EXPLOSION_IN_PROGRESS) //If the nuke ISN'T in progress. We do not want to end the round before it detonates.
- if(!num_humans && num_xenos) //No humans remain alive.
- round_finished = MODE_INFESTATION_X_MAJOR //Evacuation did not take place. Everyone died.
- else if(num_humans && !num_xenos)
- if(SSticker.mode && SSticker.mode.is_in_endgame)
- round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place.
- else
- SSticker.roundend_check_paused = TRUE
- round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs.
- ares_conclude()
- addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY)
- else if(!num_humans && !num_xenos)
- round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed.
+
+ if(!num_humans && num_xenos) //No humans remain alive.
+ round_finished = MODE_INFESTATION_X_MAJOR //Evacuation did not take place. Everyone died.
+ else if(num_humans && !num_xenos)
+ if(SSticker.mode && SSticker.mode.is_in_endgame)
+ round_finished = MODE_INFESTATION_X_MINOR //Evacuation successfully took place.
+ else
+ SSticker.roundend_check_paused = TRUE
+ round_finished = MODE_INFESTATION_M_MAJOR //Humans destroyed the xenomorphs.
+ ares_conclude()
+ addtimer(VARSET_CALLBACK(SSticker, roundend_check_paused, FALSE), MARINE_MAJOR_ROUND_END_DELAY)
+ else if(!num_humans && !num_xenos)
+ round_finished = MODE_INFESTATION_DRAW_DEATH //Both were somehow destroyed.
/datum/game_mode/colonialmarines/check_queen_status(hivenumber)
set waitfor = 0
@@ -333,7 +329,7 @@
var/datum/hive_status/HS
for(var/HN in GLOB.hive_datum)
HS = GLOB.hive_datum[HN]
- if(HS.living_xeno_queen && !is_admin_level(HS.living_xeno_queen.loc.z))
+ if(HS.living_xeno_queen && !should_block_game_interaction(HS.living_xeno_queen.loc))
//Some Queen is alive, we shouldn't end the game yet
return
round_finished = MODE_INFESTATION_M_MINOR
@@ -357,17 +353,17 @@
if(MODE_INFESTATION_X_MAJOR)
musical_track = pick('sound/theme/sad_loss1.ogg','sound/theme/sad_loss2.ogg')
end_icon = "xeno_major"
- if(round_statistics && round_statistics.current_map)
- round_statistics.current_map.total_xeno_victories++
- round_statistics.current_map.total_xeno_majors++
+ if(GLOB.round_statistics && GLOB.round_statistics.current_map)
+ GLOB.round_statistics.current_map.total_xeno_victories++
+ GLOB.round_statistics.current_map.total_xeno_majors++
if(MODE_INFESTATION_M_MAJOR)
musical_track = pick('sound/theme/winning_triumph1.ogg','sound/theme/winning_triumph2.ogg')
end_icon = "marine_major"
- if(round_statistics && round_statistics.current_map)
- round_statistics.current_map.total_marine_victories++
- round_statistics.current_map.total_marine_majors++
+ if(GLOB.round_statistics && GLOB.round_statistics.current_map)
+ GLOB.round_statistics.current_map.total_marine_victories++
+ GLOB.round_statistics.current_map.total_marine_majors++
if(MODE_INFESTATION_X_MINOR)
- var/list/living_player_list = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels())
+ var/list/living_player_list = count_humans_and_xenos(get_affected_zlevels())
if(living_player_list[1] && !living_player_list[2]) // If Xeno Minor but Xenos are dead and Humans are alive, see which faction is the last standing
var/headcount = count_per_faction()
var/living = headcount["total_headcount"]
@@ -382,28 +378,28 @@
else
musical_track = pick('sound/theme/neutral_melancholy1.ogg')
end_icon = "xeno_minor"
- if(round_statistics && round_statistics.current_map)
- round_statistics.current_map.total_xeno_victories++
+ if(GLOB.round_statistics && GLOB.round_statistics.current_map)
+ GLOB.round_statistics.current_map.total_xeno_victories++
if(MODE_INFESTATION_M_MINOR)
musical_track = pick('sound/theme/neutral_hopeful1.ogg','sound/theme/neutral_hopeful2.ogg')
end_icon = "marine_minor"
- if(round_statistics && round_statistics.current_map)
- round_statistics.current_map.total_marine_victories++
+ if(GLOB.round_statistics && GLOB.round_statistics.current_map)
+ GLOB.round_statistics.current_map.total_marine_victories++
if(MODE_INFESTATION_DRAW_DEATH)
end_icon = "draw"
musical_track = 'sound/theme/neutral_hopeful2.ogg'
- if(round_statistics && round_statistics.current_map)
- round_statistics.current_map.total_draws++
+ if(GLOB.round_statistics && GLOB.round_statistics.current_map)
+ GLOB.round_statistics.current_map.total_draws++
var/sound/S = sound(musical_track, channel = SOUND_CHANNEL_LOBBY)
S.status = SOUND_STREAM
sound_to(world, S)
- if(round_statistics)
- round_statistics.game_mode = name
- round_statistics.round_length = world.time
- round_statistics.round_result = round_finished
- round_statistics.end_round_player_population = GLOB.clients.len
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.game_mode = name
+ GLOB.round_statistics.round_length = world.time
+ GLOB.round_statistics.round_result = round_finished
+ GLOB.round_statistics.end_round_player_population = GLOB.clients.len
- round_statistics.log_round_statistics()
+ GLOB.round_statistics.log_round_statistics()
calculate_end_statistics()
show_end_statistics(end_icon)
@@ -444,11 +440,11 @@
)
//organize our jobs in a readable and standard way
- for(var/job in ROLES_MARINES)
+ for(var/job in GLOB.ROLES_MARINES)
counted_humans["Squad Marines"][job] = 0
- for(var/job in ROLES_USCM - ROLES_MARINES)
+ for(var/job in GLOB.ROLES_USCM - GLOB.ROLES_MARINES)
counted_humans["Auxiliary Marines"][job] = 0
- for(var/job in ROLES_SPECIAL)
+ for(var/job in GLOB.ROLES_SPECIAL)
counted_humans["Non-Standard Humans"][job] = 0
var/list/counted_xenos = list()
@@ -467,7 +463,7 @@
if(player_client.mob && player_client.mob.stat != DEAD)
if(ishuman(player_client.mob))
if(player_client.mob.faction == FACTION_MARINE)
- if(player_client.mob.job in (ROLES_MARINES))
+ if(player_client.mob.job in (GLOB.ROLES_MARINES))
counted_humans["Squad Marines"][player_client.mob.job]++
else
counted_humans["Auxiliary Marines"][player_client.mob.job]++
diff --git a/code/game/gamemodes/colonialmarines/huntergames.dm b/code/game/gamemodes/colonialmarines/huntergames.dm
index c8c90fa51c0c..310785070458 100644
--- a/code/game/gamemodes/colonialmarines/huntergames.dm
+++ b/code/game/gamemodes/colonialmarines/huntergames.dm
@@ -11,11 +11,11 @@
#define HUNTER_GOOD_ITEM pick(\
50; /obj/item/weapon/shield/riot, \
- 100; /obj/item/weapon/claymore, \
- 100; /obj/item/weapon/katana, \
+ 100; /obj/item/weapon/sword, \
+ 100; /obj/item/weapon/sword/katana, \
100; /obj/item/weapon/harpoon/yautja, \
- 150; /obj/item/weapon/claymore/mercsword, \
- 200; /obj/item/weapon/claymore/mercsword/machete, \
+ 150; /obj/item/weapon/sword, \
+ 200; /obj/item/weapon/sword/machete, \
125; /obj/item/weapon/twohanded/fireaxe, \
\
100; /obj/item/device/binoculars, \
@@ -51,7 +51,7 @@
300; /obj/item/tool/hatchet, \
100; /obj/item/tool/scythe, \
100; /obj/item/tool/kitchen/knife/butcher, \
- 50; /obj/item/weapon/katana/replica, \
+ 50; /obj/item/weapon/sword/katana/replica, \
100; /obj/item/weapon/harpoon, \
75; /obj/item/attachable/bayonet, \
200; /obj/item/weapon/throwing_knife, \
@@ -83,8 +83,6 @@
100; /obj/item/clothing/suit/storage/CMB \
)
-var/waiting_for_drop_votes = 0
-
//Digging through this is a pain. I'm leaving it mostly alone until a full rework takes place.
/datum/game_mode/huntergames
@@ -105,6 +103,8 @@ var/waiting_for_drop_votes = 0
var/ticks_passed = 0
var/drops_disabled = 0
+ var/waiting_for_drop_votes = FALSE
+
votable = FALSE // borkeds
taskbar_icon = 'icons/taskbar/gml_hgames.png'
@@ -234,7 +234,7 @@ var/waiting_for_drop_votes = 0
H = new(picked)
H.key = M.key
- if(H.client) H.client.change_view(world_view_size)
+ if(H.client) H.client.change_view(GLOB.world_view_size)
if(!H.mind)
H.mind = new(H.key)
@@ -244,7 +244,8 @@ var/waiting_for_drop_votes = 0
H.skills = null //no restriction on what the contestants can do
- H.apply_effect(15, WEAKEN)
+ H.KnockDown(15)
+ H.Stun(15)
H.nutrition = NUTRITION_NORMAL
var/randjob = rand(0,10)
@@ -393,8 +394,8 @@ var/waiting_for_drop_votes = 0
//Announces the end of the game with all relevant information stated//
//////////////////////////////////////////////////////////////////////
/datum/game_mode/huntergames/declare_completion()
- if(round_statistics)
- round_statistics.track_round_end()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.track_round_end()
var/mob/living/carbon/winner = null
for(var/mob/living/carbon/human/Q in GLOB.alive_mob_list)
@@ -415,12 +416,12 @@ var/waiting_for_drop_votes = 0
to_world("There was a winner, but they died before they could receive the prize!! Bummer.")
world << 'sound/misc/sadtrombone.ogg'
- if(round_statistics)
- round_statistics.game_mode = name
- round_statistics.round_length = world.time
- round_statistics.end_round_player_population = count_humans()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.game_mode = name
+ GLOB.round_statistics.round_length = world.time
+ GLOB.round_statistics.end_round_player_population = count_humans()
- round_statistics.log_round_statistics()
+ GLOB.round_statistics.log_round_statistics()
return 1
diff --git a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
index 3d856f35ce77..6ebda633a19b 100644
--- a/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
+++ b/code/game/gamemodes/colonialmarines/whiskey_outpost.dm
@@ -2,14 +2,14 @@
//Global proc for checking if the game is whiskey outpost so I dont need to type if(gamemode == whiskey outpost) 50000 times
/proc/Check_WO()
- if(SSticker.mode == GAMEMODE_WHISKEY_OUTPOST || master_mode == GAMEMODE_WHISKEY_OUTPOST)
+ if(SSticker.mode == GAMEMODE_WHISKEY_OUTPOST || GLOB.master_mode == GAMEMODE_WHISKEY_OUTPOST)
return 1
return 0
/datum/game_mode/whiskey_outpost
name = GAMEMODE_WHISKEY_OUTPOST
config_tag = GAMEMODE_WHISKEY_OUTPOST
- required_players = 0
+ required_players = 140
xeno_bypass_timer = 1
flags_round_type = MODE_NEW_SPAWN
role_mappings = list(
@@ -76,12 +76,16 @@
hardcore = TRUE
votable = TRUE
- vote_cycle = 25 // approx. once every 5 days, if it wins the vote
+ vote_cycle = 75 // approx. once every 5 days, if it wins the vote
taskbar_icon = 'icons/taskbar/gml_wo.png'
+/datum/game_mode/whiskey_outpost/New()
+ . = ..()
+ required_players = CONFIG_GET(number/whiskey_required_players)
+
/datum/game_mode/whiskey_outpost/get_roles_list()
- return ROLES_WO
+ return GLOB.ROLES_WO
/datum/game_mode/whiskey_outpost/announce()
return 1
@@ -152,9 +156,6 @@
spawn(0)
//Deleting Almayer, for performance!
SSitem_cleanup.delete_almayer()
- if(SSxenocon)
- //Don't need XENOCON
- SSxenocon.wait = 30 MINUTES
//PROCCESS
@@ -181,7 +182,7 @@
if(checkwin_counter >= 10) //Only check win conditions every 10 ticks.
if(xeno_wave == WO_MAX_WAVE && last_wave_time == 0)
last_wave_time = world.time
- if(!finished && round_should_check_for_win && last_wave_time != 0)
+ if(!finished && GLOB.round_should_check_for_win && last_wave_time != 0)
check_win()
checkwin_counter = 0
return 0
@@ -193,7 +194,7 @@
announce_xeno_wave(wave)
if(xeno_wave == 7)
//Wave when Marines get reinforcements!
- get_specific_call("Marine Reinforcements (Squad)", FALSE, TRUE, FALSE)
+ get_specific_call("Marine Reinforcements (Squad)", FALSE, TRUE)
xeno_wave = min(xeno_wave + 1, WO_MAX_WAVE)
@@ -215,8 +216,8 @@
finished = 2 //Marine win
/datum/game_mode/whiskey_outpost/proc/disablejoining()
- for(var/i in RoleAuthority.roles_by_name)
- var/datum/job/J = RoleAuthority.roles_by_name[i]
+ for(var/i in GLOB.RoleAuthority.roles_by_name)
+ var/datum/job/J = GLOB.RoleAuthority.roles_by_name[i]
// If the job has unlimited job slots, We set the amount of slots to the amount it has at the moment this is called
if (J.spawn_positions < 0)
@@ -257,8 +258,8 @@
//Announces the end of the game with all relevant information stated//
//////////////////////////////////////////////////////////////////////
/datum/game_mode/whiskey_outpost/declare_completion()
- if(round_statistics)
- round_statistics.track_round_end()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.track_round_end()
if(finished == 1)
log_game("Round end result - xenos won")
to_world(SPAN_ROUND_HEADER("The Xenos have succesfully defended their hive from colonization."))
@@ -266,11 +267,11 @@
to_world(SPAN_ROUNDBODY("It will be another five years before the USCM returns to the Neroid Sector, with the arrival of the 2nd 'Falling Falcons' Battalion and the USS Almayer."))
to_world(SPAN_ROUNDBODY("The xenomorph hive on LV-624 remains unthreatened until then..."))
world << sound('sound/misc/Game_Over_Man.ogg')
- if(round_statistics)
- round_statistics.round_result = MODE_INFESTATION_X_MAJOR
- if(round_statistics.current_map)
- round_statistics.current_map.total_xeno_victories++
- round_statistics.current_map.total_xeno_majors++
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.round_result = MODE_INFESTATION_X_MAJOR
+ if(GLOB.round_statistics.current_map)
+ GLOB.round_statistics.current_map.total_xeno_victories++
+ GLOB.round_statistics.current_map.total_xeno_majors++
else if(finished == 2)
log_game("Round end result - marines won")
@@ -279,26 +280,26 @@
to_world(SPAN_ROUNDBODY("Eventually, the Dust Raiders secure LV-624 and the entire Neroid Sector in 2182, pacifiying it and establishing peace in the sector for decades to come."))
to_world(SPAN_ROUNDBODY("The USS Almayer and the 2nd 'Falling Falcons' Battalion are never sent to the sector and are spared their fate in 2186."))
world << sound('sound/misc/hell_march.ogg')
- if(round_statistics)
- round_statistics.round_result = MODE_INFESTATION_M_MAJOR
- if(round_statistics.current_map)
- round_statistics.current_map.total_marine_victories++
- round_statistics.current_map.total_marine_majors++
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.round_result = MODE_INFESTATION_M_MAJOR
+ if(GLOB.round_statistics.current_map)
+ GLOB.round_statistics.current_map.total_marine_victories++
+ GLOB.round_statistics.current_map.total_marine_majors++
else
log_game("Round end result - no winners")
to_world(SPAN_ROUND_HEADER("NOBODY WON!"))
to_world(SPAN_ROUNDBODY("How? Don't ask me..."))
world << 'sound/misc/sadtrombone.ogg'
- if(round_statistics)
- round_statistics.round_result = MODE_INFESTATION_DRAW_DEATH
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.round_result = MODE_INFESTATION_DRAW_DEATH
- if(round_statistics)
- round_statistics.game_mode = name
- round_statistics.round_length = world.time
- round_statistics.end_round_player_population = GLOB.clients.len
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.game_mode = name
+ GLOB.round_statistics.round_length = world.time
+ GLOB.round_statistics.end_round_player_population = GLOB.clients.len
- round_statistics.log_round_statistics()
+ GLOB.round_statistics.log_round_statistics()
round_finished = 1
@@ -322,9 +323,9 @@
OT = "sup" //no breaking anything.
else if (OT == "sup")
- randpick = rand(0,50)
+ randpick = rand(0,90)
switch(randpick)
- if(0 to 5)//Marine Gear 10% Chance.
+ if(0 to 3)//Marine Gear 3% Chance.
crate = new /obj/structure/closet/crate/secure/gear(T)
choosemax = rand(5,10)
randomitems = list(/obj/item/clothing/head/helmet/marine,
@@ -340,19 +341,19 @@
/obj/effect/landmark/wo_supplies/storage/webbing,
/obj/item/device/binoculars)
- if(6 to 10)//Lights and shiet 10%
+ if(4 to 6)//Lights and shiet 2%
new /obj/structure/largecrate/supply/floodlights(T)
new /obj/structure/largecrate/supply/supplies/flares(T)
- if(11 to 13) //6% Chance to drop this !FUN! junk.
+ if(7 to 10) //3% Chance to drop this !FUN! junk.
crate = new /obj/structure/closet/crate/secure/gear(T)
spawnitems = list(/obj/item/storage/belt/utility/full,
/obj/item/storage/belt/utility/full,
/obj/item/storage/belt/utility/full,
/obj/item/storage/belt/utility/full)
- if(14 to 18)//Materials 10% Chance.
+ if(11 to 22)//Materials 12% Chance.
crate = new /obj/structure/closet/crate/secure/gear(T)
choosemax = rand(3,8)
randomitems = list(/obj/item/stack/sheet/metal,
@@ -363,7 +364,7 @@
/obj/item/stack/sandbags_empty/half,
/obj/item/stack/sandbags_empty/half)
- if(19 to 20)//Blood Crate 4% chance
+ if(23 to 25)//Blood Crate 2% chance
crate = new /obj/structure/closet/crate/medical(T)
spawnitems = list(/obj/item/reagent_container/blood/OMinus,
/obj/item/reagent_container/blood/OMinus,
@@ -371,7 +372,7 @@
/obj/item/reagent_container/blood/OMinus,
/obj/item/reagent_container/blood/OMinus)
- if(21 to 25)//Advanced meds Crate 10%
+ if(26 to 30)//Advanced meds Crate 5%
crate = new /obj/structure/closet/crate/medical(T)
spawnitems = list(/obj/item/storage/firstaid/fire,
/obj/item/storage/firstaid/regular,
@@ -386,7 +387,7 @@
/obj/item/clothing/glasses/hud/health,
/obj/item/device/defibrillator)
- if(26 to 30)//Random Medical Items 10% as well. Made the list have less small junk
+ if(31 to 34)//Random Medical Items 4%. Made the list have less small junk
crate = new /obj/structure/closet/crate/medical(T)
spawnitems = list(/obj/item/storage/belt/medical/lifesaver/full,
/obj/item/storage/belt/medical/lifesaver/full,
@@ -394,7 +395,7 @@
/obj/item/storage/belt/medical/lifesaver/full,
/obj/item/storage/belt/medical/lifesaver/full)
- if(31 to 35)//Random explosives Crate 10% because the lord commeth and said let there be explosives.
+ if(35 to 40)//Random explosives Crate 5% because the lord commeth and said let there be explosives.
crate = new /obj/structure/closet/crate/ammo(T)
choosemax = rand(1,5)
randomitems = list(/obj/item/storage/box/explosive_mines,
@@ -404,7 +405,7 @@
/obj/item/explosive/grenade/high_explosive,
/obj/item/storage/box/nade_box
)
- if(36 to 40) // Junk
+ if(41 to 44)
crate = new /obj/structure/closet/crate/ammo(T)
spawnitems = list(
/obj/item/attachable/heavy_barrel,
@@ -412,20 +413,75 @@
/obj/item/attachable/heavy_barrel,
/obj/item/attachable/heavy_barrel)
- if(40 to 48)//Weapon + supply beacon drop. 6%
+ if(45 to 50)//Weapon + supply beacon drop. 5%
crate = new /obj/structure/closet/crate/ammo(T)
spawnitems = list(/obj/item/device/whiskey_supply_beacon,
/obj/item/device/whiskey_supply_beacon,
/obj/item/device/whiskey_supply_beacon,
/obj/item/device/whiskey_supply_beacon)
- if(49 to 50)//Rare weapons. Around 4%
+ if(51 to 57)//Rare weapons. Around 6%
crate = new /obj/structure/closet/crate/ammo(T)
spawnitems = list(/obj/effect/landmark/wo_supplies/ammo/box/rare/m41aap,
/obj/effect/landmark/wo_supplies/ammo/box/rare/m41aapmag,
/obj/effect/landmark/wo_supplies/ammo/box/rare/m41aextend,
/obj/effect/landmark/wo_supplies/ammo/box/rare/smgap,
/obj/effect/landmark/wo_supplies/ammo/box/rare/smgextend)
+
+ if(58 to 65) // Sandbags kit
+ crate = new /obj/structure/closet/crate(T)
+ spawnitems = list(/obj/item/tool/shovel/etool,
+ /obj/item/stack/sandbags_empty/half,
+ /obj/item/stack/sandbags_empty/half,
+ /obj/item/stack/sandbags_empty/half)
+
+ if(66 to 70) // Mortar shells. Pew Pew!
+ crate = new /obj/structure/closet/crate/secure/mortar_ammo(T)
+ choosemax = rand(6,10)
+ randomitems = list(/obj/item/mortar_shell/he,
+ /obj/item/mortar_shell/incendiary,
+ /obj/item/mortar_shell/flare,
+ /obj/item/mortar_shell/frag)
+
+ if(71 to 79)
+ crate = new /obj/structure/closet/crate/ammo(T)
+ choosemax = rand(2, 3)
+ randomitems = list(/obj/item/ammo_box/rounds,
+ /obj/item/ammo_box/rounds/ap,
+ /obj/item/ammo_box/rounds/smg,
+ /obj/item/ammo_box/rounds/smg/ap,
+ /obj/item/ammo_box/magazine/ap,
+ /obj/item/ammo_box/magazine/ext,
+ /obj/item/ammo_box/magazine/m4ra/ap,
+ /obj/item/ammo_box/magazine/m4ra/ap,
+ /obj/item/ammo_box/magazine/m39/ap,
+ /obj/item/ammo_box/magazine/m39/ext,
+ )
+
+ if(80 to 82)
+ crate = new /obj/structure/closet/crate/ammo(T)
+ choosemax = rand(2, 3)
+ randomitems = list(/obj/item/ammo_magazine/rifle/lmg/holo_target,
+ /obj/item/ammo_magazine/rifle/lmg/holo_target,
+ /obj/item/ammo_magazine/rifle/lmg,
+ /obj/item/ammo_magazine/rifle/lmg,
+ )
+
+ if(83 to 86)
+ crate = new /obj/structure/closet/crate/ammo(T)
+ spawnitems = list(
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/magnetic_harness,
+ /obj/item/attachable/magnetic_harness)
+
+ if(86 to 90)
+ crate = new /obj/structure/closet/crate/secure/gear(T)
+ spawnitems = list(
+ /obj/item/device/binoculars/range,
+ /obj/item/device/binoculars/range,
+ )
+
if(crate)
crate.storage_capacity = 60
@@ -459,10 +515,10 @@
unacidable = TRUE
var/working = 0
-/obj/structure/machinery/wo_recycler/attack_hand(mob/user)
+/obj/structure/machinery/wo_recycler/attack_hand(mob/living/user)
if(inoperable(MAINT))
return
- if(user.lying || user.stat)
+ if(user.is_mob_incapacitated())
return
if(ismaintdrone(usr) || \
istype(usr, /mob/living/carbon/xenomorph))
diff --git a/code/game/gamemodes/colonialmarines/whiskey_outpost/whiskey_output_waves.dm b/code/game/gamemodes/colonialmarines/whiskey_outpost/whiskey_output_waves.dm
index ae272da88690..1ec07b9d8fec 100644
--- a/code/game/gamemodes/colonialmarines/whiskey_outpost/whiskey_output_waves.dm
+++ b/code/game/gamemodes/colonialmarines/whiskey_outpost/whiskey_output_waves.dm
@@ -32,7 +32,7 @@
for(var/mob/living/carbon/xenomorph/X as anything in GLOB.living_xeno_list)
var/area/A = get_area(X)
- if(is_admin_level(X.z) && (!A || !(A.flags_area & AREA_ALLOW_XENO_JOIN)) || X.aghosted) continue //xenos on admin z level and aghosted ones don't count
+ if(should_block_game_interaction(X) && (!A || !(A.flags_area & AREA_ALLOW_XENO_JOIN)) || X.aghosted) continue //xenos on admin z level and aghosted ones don't count
if(istype(X) && !X.client)
if((X.away_timer >= XENO_LEAVE_TIMER) || (islarva(X) && X.away_timer >= XENO_LEAVE_TIMER_LARVA))
available_xenos += X
@@ -52,12 +52,12 @@
if(!xeno_candidate)
return FALSE
- if(RoleAuthority.castes_by_name[userInput])
+ if(GLOB.RoleAuthority.castes_by_name[userInput])
if(!(userInput in xeno_pool))
to_chat(xeno_candidate, SPAN_WARNING("The caste type you chose was occupied by someone else."))
return FALSE
var/spawn_loc = pick(xeno_spawns)
- var/xeno_type = RoleAuthority.get_caste_by_text(userInput)
+ var/xeno_type = GLOB.RoleAuthority.get_caste_by_text(userInput)
var/mob/living/carbon/xenomorph/new_xeno = new xeno_type(spawn_loc)
if(new_xeno.hive.construction_allowed == NORMAL_XENO)
new_xeno.hive.construction_allowed = XENO_QUEEN
diff --git a/code/game/gamemodes/colonialmarines/xenovsxeno.dm b/code/game/gamemodes/colonialmarines/xenovsxeno.dm
index 5623295f1915..a9ad48196257 100644
--- a/code/game/gamemodes/colonialmarines/xenovsxeno.dm
+++ b/code/game/gamemodes/colonialmarines/xenovsxeno.dm
@@ -26,9 +26,9 @@
/* Pre-pre-startup */
/datum/game_mode/xenovs/can_start()
for(var/hivename in SSmapping.configs[GROUND_MAP].xvx_hives)
- if(readied_players > SSmapping.configs[GROUND_MAP].xvx_hives[hivename])
+ if(GLOB.readied_players > SSmapping.configs[GROUND_MAP].xvx_hives[hivename])
hives += hivename
- xeno_starting_num = readied_players
+ xeno_starting_num = GLOB.readied_players
if(!initialize_starting_xenomorph_list(hives, TRUE))
hives.Cut()
return
@@ -38,7 +38,7 @@
to_chat_spaced(world, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDHEADER("The current map is - [SSmapping.configs[GROUND_MAP].map_name]!"))
/datum/game_mode/xenovs/get_roles_list()
- return ROLES_XENO
+ return GLOB.ROLES_XENO
/* Pre-setup */
/datum/game_mode/xenovs/pre_setup()
@@ -79,9 +79,6 @@
spawn(0)
//Deleting Almayer, for performance!
SSitem_cleanup.delete_almayer()
- if(SSxenocon)
- //Don't need XENOCON
- SSxenocon.wait = 30 MINUTES
////////////////////////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////////////////////////
@@ -94,7 +91,7 @@
initialize_post_xenomorph_list(GLOB.xeno_hive_spawns)
round_time_lobby = world.time
- for(var/area/A in all_areas)
+ for(var/area/A in GLOB.all_areas)
if(!(A.is_resin_allowed))
A.is_resin_allowed = TRUE
@@ -144,7 +141,6 @@
original.statistic_exempt = TRUE
original.buckled = start_nest
original.setDir(start_nest.dir)
- original.update_canmove()
start_nest.buckled_mob = original
start_nest.afterbuckle(original)
@@ -196,7 +192,7 @@
qdel(C)
hive_cores = list()
- if(round_should_check_for_win)
+ if(GLOB.round_should_check_for_win)
check_win()
round_checkwin = 0
@@ -266,12 +262,12 @@
var/sound/S = sound(musical_track, channel = SOUND_CHANNEL_LOBBY)
S.status = SOUND_STREAM
sound_to(world, S)
- if(round_statistics)
- round_statistics.game_mode = name
- round_statistics.round_length = world.time
- round_statistics.end_round_player_population = GLOB.clients.len
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.game_mode = name
+ GLOB.round_statistics.round_length = world.time
+ GLOB.round_statistics.end_round_player_population = GLOB.clients.len
- round_statistics.log_round_statistics()
+ GLOB.round_statistics.log_round_statistics()
declare_completion_announce_xenomorphs()
calculate_end_statistics()
@@ -281,11 +277,11 @@
return TRUE
/datum/game_mode/xenovs/announce_ending()
- if(round_statistics)
- round_statistics.track_round_end()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.track_round_end()
log_game("Round end result: [round_finished]")
to_chat_spaced(world, margin_top = 2, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDHEADER("|Round Complete|"))
- to_chat_spaced(world, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDBODY("Thus ends the story of the battling hives on [SSmapping.configs[GROUND_MAP].map_name]. [round_finished]\nThe game-mode was: [master_mode]!\n[CONFIG_GET(string/endofroundblurb)]"))
+ to_chat_spaced(world, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDBODY("Thus ends the story of the battling hives on [SSmapping.configs[GROUND_MAP].map_name]. [round_finished]\nThe game-mode was: [GLOB.master_mode]!\n[CONFIG_GET(string/endofroundblurb)]"))
// for the toolbox
/datum/game_mode/xenovs/end_round_message()
diff --git a/code/game/gamemodes/events.dm b/code/game/gamemodes/events.dm
index db8f84d53f24..1039d495396b 100644
--- a/code/game/gamemodes/events.dm
+++ b/code/game/gamemodes/events.dm
@@ -3,7 +3,7 @@
/proc/carp_migration() // -- Darem
//sleep(100)
spawn(rand(300, 600)) //Delayed announcements to keep the crew on their toes.
- marine_announcement("Unknown biological entities have been detected near [station_name], please stand-by.", "Lifesign Alert", 'sound/AI/commandreport.ogg')
+ marine_announcement("Unknown biological entities have been detected near [MAIN_SHIP_NAME], please stand-by.", "Lifesign Alert", 'sound/AI/commandreport.ogg')
/proc/lightsout(isEvent = 0, lightsoutAmount = 1,lightsoutRange = 25) //leave lightsoutAmount as 0 to break ALL lights
if(isEvent)
@@ -13,7 +13,7 @@
return
else
- for(var/obj/structure/machinery/power/apc/apc in machines)
+ for(var/obj/structure/machinery/power/apc/apc in GLOB.machines)
apc.overload_lighting()
return
diff --git a/code/game/gamemodes/events/power_failure.dm b/code/game/gamemodes/events/power_failure.dm
index 7905c19fac41..5ebedd8fd26d 100644
--- a/code/game/gamemodes/events/power_failure.dm
+++ b/code/game/gamemodes/events/power_failure.dm
@@ -2,7 +2,7 @@
/proc/power_failure(announce = 1)
var/ship_zlevels = SSmapping.levels_by_trait(ZTRAIT_MARINE_MAIN_SHIP)
- for(var/obj/structure/machinery/power/smes/S in machines)
+ for(var/obj/structure/machinery/power/smes/S in GLOB.machines)
if(!is_mainship_level(S.z))
continue
S.last_charge = S.charge
@@ -14,7 +14,7 @@
S.updateicon()
S.power_change()
- for(var/obj/structure/machinery/power/apc/C in machines)
+ for(var/obj/structure/machinery/power/apc/C in GLOB.machines)
if(!is_mainship_level(C.z) && C.cell)
C.cell.charge = 0
@@ -25,7 +25,7 @@
marine_announcement("Abnormal activity detected in the ship power system. As a precaution, power must be shut down for an indefinite duration.", "Critical Power Failure", 'sound/AI/poweroff.ogg')
/proc/power_restore(announce = 1)
- for(var/obj/structure/machinery/power/smes/S in machines)
+ for(var/obj/structure/machinery/power/smes/S in GLOB.machines)
if(!is_mainship_level(S.z))
continue
S.charge = S.capacity
@@ -34,7 +34,7 @@
S.updateicon()
S.power_change()
- for(var/obj/structure/machinery/power/apc/C in machines)
+ for(var/obj/structure/machinery/power/apc/C in GLOB.machines)
if(C.cell && is_mainship_level(C.z))
C.cell.charge = C.cell.maxcharge
@@ -44,7 +44,7 @@
/proc/power_restore_quick(announce = 1)
- for(var/obj/structure/machinery/power/smes/S in machines)
+ for(var/obj/structure/machinery/power/smes/S in GLOB.machines)
if(!is_mainship_level(S.z)) // Ship only
continue
S.charge = S.capacity
@@ -59,14 +59,14 @@
/proc/power_restore_everything(announce = 1)
- for(var/obj/structure/machinery/power/smes/S in machines)
+ for(var/obj/structure/machinery/power/smes/S in GLOB.machines)
S.charge = S.capacity
S.output_level = S.output_level_max
S.outputting = 1
S.updateicon()
S.power_change()
- for(var/obj/structure/machinery/power/apc/C in machines)
+ for(var/obj/structure/machinery/power/apc/C in GLOB.machines)
if(C.cell)
C.cell.charge = C.cell.maxcharge
@@ -75,7 +75,7 @@
marine_announcement("Power has been restored. Reason: Unknown.", "Power Systems Nominal", 'sound/AI/poweron.ogg')
/proc/power_restore_ship_reactors(announce = 1)
- for(var/obj/structure/machinery/power/fusion_engine/FE in machines)
+ for(var/obj/structure/machinery/power/fusion_engine/FE in GLOB.machines)
FE.buildstate = 0
FE.is_on = 1
FE.fusion_cell = new
diff --git a/code/game/gamemodes/extended/extended.dm b/code/game/gamemodes/extended/extended.dm
index f00125cc8f0f..72512a7e77ff 100644
--- a/code/game/gamemodes/extended/extended.dm
+++ b/code/game/gamemodes/extended/extended.dm
@@ -12,7 +12,7 @@
to_world("The current game mode is - Extended!")
/datum/game_mode/extended/get_roles_list()
- return ROLES_USCM
+ return GLOB.ROLES_USCM
/datum/game_mode/extended/post_setup()
initialize_post_marine_gear_list()
@@ -24,7 +24,7 @@
/datum/game_mode/extended/process()
. = ..()
if(next_research_allocation < world.time)
- chemical_data.update_credits(chemical_data.research_allocation_amount)
+ GLOB.chemical_data.update_credits(GLOB.chemical_data.research_allocation_amount)
next_research_allocation = world.time + research_allocation_interval
/datum/game_mode/extended/check_finished()
@@ -39,11 +39,11 @@
var/musical_track = pick('sound/theme/neutral_hopeful1.ogg','sound/theme/neutral_hopeful2.ogg')
world << musical_track
- if(round_statistics)
- round_statistics.game_mode = name
- round_statistics.round_length = world.time
- round_statistics.end_round_player_population = GLOB.clients.len
- round_statistics.log_round_statistics()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.game_mode = name
+ GLOB.round_statistics.round_length = world.time
+ GLOB.round_statistics.end_round_player_population = GLOB.clients.len
+ GLOB.round_statistics.log_round_statistics()
calculate_end_statistics()
declare_completion_announce_predators()
diff --git a/code/game/gamemodes/extended/extended_clash.dm b/code/game/gamemodes/extended/extended_clash.dm
index 04077de2775c..e0e526d91afa 100644
--- a/code/game/gamemodes/extended/extended_clash.dm
+++ b/code/game/gamemodes/extended/extended_clash.dm
@@ -6,7 +6,7 @@
taskbar_icon = 'icons/taskbar/gml_hvh.png'
/datum/game_mode/extended/faction_clash/get_roles_list()
- return ROLES_FACTION_CLASH
+ return GLOB.ROLES_FACTION_CLASH
/datum/game_mode/extended/faction_clash/post_setup()
. = ..()
diff --git a/code/game/gamemodes/extended/infection.dm b/code/game/gamemodes/extended/infection.dm
index 04e0545361aa..1e0032a8e6fa 100644
--- a/code/game/gamemodes/extended/infection.dm
+++ b/code/game/gamemodes/extended/infection.dm
@@ -15,7 +15,7 @@
to_world("Don't ahelp asking for specific details, you won't get them.")
/datum/game_mode/infection/get_roles_list()
- return ROLES_USCM
+ return GLOB.ROLES_USCM
/datum/game_mode/infection/pre_setup()
return ..()
@@ -61,7 +61,7 @@
possible_synth_survivors -= A
continue
- if(RoleAuthority.roles_whitelist[ckey(A.key)] & WHITELIST_SYNTHETIC)
+ if(GLOB.RoleAuthority.roles_whitelist[ckey(A.key)] & WHITELIST_SYNTHETIC)
if(A in possible_survivors)
continue //they are already applying to be a survivor
else
@@ -95,7 +95,7 @@
possible_survivors -= new_survivor //either we drafted a survivor, or we're skipping over someone, either or - remove them
/datum/game_mode/infection/check_win()
- var/living_player_list[] = count_humans_and_xenos(EvacuationAuthority.get_affected_zlevels())
+ var/list/living_player_list = count_humans_and_xenos(get_affected_zlevels())
var/num_humans = living_player_list[1]
var/zed = living_player_list[2]
@@ -120,11 +120,11 @@
var/musical_track = pick('sound/theme/sad_loss1.ogg','sound/theme/sad_loss2.ogg')
world << musical_track
- if(round_statistics)
- round_statistics.game_mode = name
- round_statistics.round_length = world.time
- round_statistics.end_round_player_population = GLOB.clients.len
- round_statistics.log_round_statistics()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.game_mode = name
+ GLOB.round_statistics.round_length = world.time
+ GLOB.round_statistics.end_round_player_population = GLOB.clients.len
+ GLOB.round_statistics.log_round_statistics()
declare_completion_announce_xenomorphs()
declare_completion_announce_predators()
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index f6f75c6ba4e0..3bb8c2d80123 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -11,9 +11,9 @@
*
*/
-var/global/datum/entity/statistic/round/round_statistics
-var/global/list/datum/entity/player_entity/player_entities = list()
-var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracking_ids to tacbinos and signal flares
+GLOBAL_DATUM(round_statistics, /datum/entity/statistic/round)
+GLOBAL_LIST_INIT_TYPED(player_entities, /datum/entity/player_entity, list())
+GLOBAL_VAR_INIT(cas_tracking_id_increment, 0) //this var used to assign unique tracking_ids to tacbinos and signal flares
/datum/game_mode
var/name = "invalid"
var/config_tag = null
@@ -56,7 +56,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki
if((player.client)&&(player.ready))
playerC++
- if(master_mode=="secret")
+ if(GLOB.master_mode=="secret")
if(playerC >= required_players_secret)
return 1
else
@@ -105,11 +105,16 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki
np.new_player_panel_proc()
round_time_lobby = world.time
log_game("Round started at [time2text(world.realtime)]")
+ log_game("Operation time at round start is [worldtime2text()]")
if(SSticker.mode)
log_game("Game mode set to [SSticker.mode]")
log_game("Server IP: [world.internet_address]:[world.port]")
return TRUE
+/datum/game_mode/proc/get_affected_zlevels()
+ if(is_in_endgame)
+ . = SSmapping.levels_by_any_trait(list(ZTRAIT_MARINE_MAIN_SHIP))
+ return
///process()
///Called by the gameticker
@@ -118,22 +123,21 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki
/datum/game_mode/proc/check_finished() //to be called by ticker
- if(EvacuationAuthority.dest_status == NUKE_EXPLOSION_FINISHED || EvacuationAuthority.dest_status == NUKE_EXPLOSION_GROUND_FINISHED )
- return TRUE
+ return
/datum/game_mode/proc/cleanup() //This is called when the round has ended but not the game, if any cleanup would be necessary in that case.
return
/datum/game_mode/proc/announce_ending()
- if(round_statistics)
- round_statistics.track_round_end()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.track_round_end()
log_game("Round end result: [round_finished]")
to_chat_spaced(world, margin_top = 2, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDHEADER("|Round Complete|"))
- to_chat_spaced(world, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDBODY("Thus ends the story of the brave men and women of the [MAIN_SHIP_NAME] and their struggle on [SSmapping.configs[GROUND_MAP].map_name].\nThe game-mode was: [master_mode]!\n[CONFIG_GET(string/endofroundblurb)]"))
+ to_chat_spaced(world, type = MESSAGE_TYPE_SYSTEM, html = SPAN_ROUNDBODY("Thus ends the story of the brave men and women of the [MAIN_SHIP_NAME] and their struggle on [SSmapping.configs[GROUND_MAP].map_name].\nThe game-mode was: [GLOB.master_mode]!\n[CONFIG_GET(string/endofroundblurb)]"))
/datum/game_mode/proc/declare_completion()
- if(round_statistics)
- round_statistics.track_round_end()
+ if(GLOB.round_statistics)
+ GLOB.round_statistics.track_round_end()
var/clients = 0
var/surviving_humans = 0
var/surviving_total = 0
@@ -177,7 +181,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki
record_playtime(M.client.player_data, M.job, type)
/datum/game_mode/proc/show_end_statistics(icon_state)
- round_statistics.update_panel_data()
+ GLOB.round_statistics.update_panel_data()
for(var/mob/M in GLOB.player_list)
if(M.client)
give_action(M, /datum/action/show_round_statistics, null, icon_state)
@@ -222,7 +226,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki
var/list/heads = list()
for(var/i in GLOB.alive_human_list)
var/mob/living/carbon/human/player = i
- if(player.stat!=2 && player.mind && (player.job in ROLES_COMMAND ))
+ if(player.stat!=2 && player.mind && (player.job in GLOB.ROLES_COMMAND ))
heads += player.mind
return heads
@@ -233,7 +237,7 @@ var/global/cas_tracking_id_increment = 0 //this var used to assign unique tracki
/datum/game_mode/proc/get_all_heads()
var/list/heads = list()
for(var/mob/player in GLOB.mob_list)
- if(player.mind && (player.job in ROLES_COMMAND ))
+ if(player.mind && (player.job in GLOB.ROLES_COMMAND ))
heads += player.mind
return heads
diff --git a/code/game/jobs/job/antag/other/pred.dm b/code/game/jobs/job/antag/other/pred.dm
index a8bcec788c44..77439276d04a 100644
--- a/code/game/jobs/job/antag/other/pred.dm
+++ b/code/game/jobs/job/antag/other/pred.dm
@@ -41,7 +41,7 @@
player.clan_info.sync() // pause here might be problematic, we'll see. If DB dies, then we're fucked
- var/rank = clan_ranks[player.clan_info.clan_rank]
+ var/rank = GLOB.clan_ranks[player.clan_info.clan_rank]
if(!rank)
return CLAN_RANK_BLOODED
diff --git a/code/game/jobs/job/antag/xeno/xenomorph.dm b/code/game/jobs/job/antag/xeno/xenomorph.dm
index 53b06147e28c..78b6ab7e3ab2 100644
--- a/code/game/jobs/job/antag/xeno/xenomorph.dm
+++ b/code/game/jobs/job/antag/xeno/xenomorph.dm
@@ -88,9 +88,8 @@
break
human_to_transform.statistic_exempt = TRUE
- human_to_transform.buckled = start_nest
+ human_to_transform.set_buckled(start_nest)
human_to_transform.setDir(start_nest.dir)
- human_to_transform.update_canmove()
start_nest.buckled_mob = human_to_transform
start_nest.afterbuckle(human_to_transform)
diff --git a/code/game/jobs/job/civilians/other/liaison.dm b/code/game/jobs/job/civilians/other/liaison.dm
index 7f73376a05dd..cbbb87124957 100644
--- a/code/game/jobs/job/civilians/other/liaison.dm
+++ b/code/game/jobs/job/civilians/other/liaison.dm
@@ -6,7 +6,7 @@
selection_class = "job_cl"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/liaison
- entry_message_body = "As a representative of Weyland-Yutani Corporation, your job requires you to stay in character at all times. You are not required to follow military orders; however, you cannot give military orders. Your primary job is to observe and report back your findings to Weyland-Yutani. Follow regular game rules unless told otherwise by your superiors. Use your office fax machine to communicate with corporate headquarters or to acquire new directives. You may not receive anything back, and this is normal."
+ entry_message_body = "As a representative of Weyland-Yutani Corporation, your job requires you to stay in character at all times. You are not required to follow military orders; however, you cannot give military orders. Your primary job is to observe and report back your findings to Weyland-Yutani. Follow regular game rules unless told otherwise by your superiors. Use your office fax machine to communicate with corporate headquarters or to acquire new directives. You may not receive anything back, and this is normal."
var/mob/living/carbon/human/active_liaison
/datum/job/civilian/liaison/generate_entry_conditions(mob/living/liaison, whitelist_status)
diff --git a/code/game/jobs/job/civilians/other/mess_seargent.dm b/code/game/jobs/job/civilians/other/mess_seargent.dm
index 4b1975015a95..fb4f5ee14d7c 100644
--- a/code/game/jobs/job/civilians/other/mess_seargent.dm
+++ b/code/game/jobs/job/civilians/other/mess_seargent.dm
@@ -1,12 +1,30 @@
/datum/job/civilian/chef
title = JOB_MESS_SERGEANT
- total_positions = 1
+ total_positions = 2
spawn_positions = 1
+ allow_additional = TRUE
+ scaled = TRUE
selection_class = "job_ot"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
supervisors = "the auxiliary support officer"
gear_preset = /datum/equipment_preset/uscm_ship/chef
- entry_message_body = "Your job is to service the marines with excellent food, drinks and entertaining the shipside crew when needed. You have a lot of freedom and it is up to you, to decide what to do with it. Good luck!"
+ entry_message_body = "Your job is to service the marines with excellent food, drinks and entertaining the shipside crew when needed. You have a lot of freedom and it is up to you, to decide what to do with it. Good luck!"
+
+/datum/job/civilian/chef/set_spawn_positions(count)
+ spawn_positions = mess_sergeant_slot_formula(count)
+
+/datum/job/civilian/chef/get_total_positions(latejoin = FALSE)
+ var/positions = spawn_positions
+ if(latejoin)
+ positions = mess_sergeant_slot_formula(get_total_marines())
+ if(positions <= total_positions_so_far)
+ positions = total_positions_so_far
+ else
+ total_positions_so_far = positions
+ else
+ total_positions_so_far = positions
+
+ return positions
/obj/effect/landmark/start/chef
name = JOB_MESS_SERGEANT
diff --git a/code/game/jobs/job/civilians/other/survivors.dm b/code/game/jobs/job/civilians/other/survivors.dm
index 5c82241c47de..23097e139eda 100644
--- a/code/game/jobs/job/civilians/other/survivors.dm
+++ b/code/game/jobs/job/civilians/other/survivors.dm
@@ -10,6 +10,8 @@
job_options = SURVIVOR_VARIANT_LIST
var/intro_text
var/story_text
+ /// Whether or not the survivor is an inherently hostile to marines.
+ var/hostile = FALSE
/datum/job/civilian/survivor/set_spawn_positions(count)
spawn_positions = Clamp((round(count * SURVIVOR_TO_TOTAL_SPAWN_RATIO)), 2, 8)
@@ -59,23 +61,32 @@
if(picked_spawner.story_text)
story_text = picked_spawner.story_text
+
+ if(picked_spawner.hostile)
+ hostile = TRUE
+
new /datum/cm_objective/move_mob/almayer/survivor(H)
-/datum/job/civilian/survivor/generate_entry_message(mob/living/carbon/human/H)
+/datum/job/civilian/survivor/generate_entry_message(mob/living/carbon/human/survivor)
if(intro_text)
for(var/line in intro_text)
- to_chat(H, line)
+ to_chat(survivor, line)
else
- to_chat(H, "
You are a survivor!
")
- to_chat(H, SPAN_NOTICE(SSmapping.configs[GROUND_MAP].survivor_message))
- to_chat(H, SPAN_NOTICE("You are fully aware of the xenomorph threat and are able to use this knowledge as you see fit."))
- to_chat(H, SPAN_NOTICE("You are NOT aware of the marines or their intentions. "))
+ to_chat(survivor, "
You are a survivor!
")
+ to_chat(survivor, SPAN_NOTICE(SSmapping.configs[GROUND_MAP].survivor_message))
+ to_chat(survivor, SPAN_NOTICE("You are fully aware of the xenomorph threat and are able to use this knowledge as you see fit."))
+ to_chat(survivor, SPAN_NOTICE("You are NOT aware of the marines or their intentions. "))
if(story_text)
- to_chat(H, story_text)
- H.mind.memory += story_text
+ to_chat(survivor, story_text)
+ survivor.mind.memory += story_text
+ else
+ tell_survivor_story(survivor)
+
+ if(hostile)
+ to_chat(survivor, SPAN_HIGHDANGER("You are HOSTILE to the USCM!"))
else
- tell_survivor_story(H)
+ to_chat(survivor, SPAN_XENOHIGHDANGER("You are NON-HOSTILE to the USCM!"))
/datum/job/civilian/survivor/proc/tell_survivor_story(mob/living/carbon/human/H)
var/list/survivor_story = list(
diff --git a/code/game/jobs/job/civilians/support/cmo.dm b/code/game/jobs/job/civilians/support/cmo.dm
index 8c4690ea2057..835f16f7d814 100644
--- a/code/game/jobs/job/civilians/support/cmo.dm
+++ b/code/game/jobs/job/civilians/support/cmo.dm
@@ -6,7 +6,7 @@
selection_class = "job_cmo"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/cmo
- entry_message_body = "You're a commissioned officer of the USCM. You have authority over everything related to Medbay and Research, only able to be overriden by the XO and CO. You are in charge of medical staff, surgery, chemistry, stimulants and keeping the marines healthy overall."
+ entry_message_body = "You're a commissioned officer of the USCM. You have authority over everything related to Medbay and Research, only able to be overriden by the XO and CO. You are in charge of medical staff, surgery, chemistry, stimulants and keeping the marines healthy overall."
AddTimelock(/datum/job/civilian/professor, list(
JOB_MEDIC_ROLES = 10 HOURS
diff --git a/code/game/jobs/job/civilians/support/nurse.dm b/code/game/jobs/job/civilians/support/nurse.dm
index 7a0cab16f559..8912011298dc 100644
--- a/code/game/jobs/job/civilians/support/nurse.dm
+++ b/code/game/jobs/job/civilians/support/nurse.dm
@@ -6,7 +6,7 @@
selection_class = "job_doctor"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/nurse
- entry_message_body = "You are tasked with keeping the Marines healthy and strong. You are also an expert when it comes to medication and treatment, and can do minor surgical procedures. Focus on assisting doctors and triaging wounded marines."
+ entry_message_body = "You are tasked with keeping the Marines healthy and strong. You are also an expert when it comes to medication and treatment, and can do minor surgical procedures. Focus on assisting doctors and triaging wounded marines."
/obj/effect/landmark/start/nurse
name = JOB_NURSE
diff --git a/code/game/jobs/job/civilians/support/researcher.dm b/code/game/jobs/job/civilians/support/researcher.dm
index 61245c8164ab..21163f27959d 100644
--- a/code/game/jobs/job/civilians/support/researcher.dm
+++ b/code/game/jobs/job/civilians/support/researcher.dm
@@ -10,7 +10,7 @@
selection_class = "job_researcher"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/uscm_medical/researcher
- entry_message_body = "You're a commissioned officer of the USCM, though you are not in the ship's chain of command. You are tasked with researching and developing new medical treatments, helping your fellow doctors, and generally learning new things. Your role involves a lot of roleplaying, but you can perform the function of a regular doctor. Do not hand out things to Marines without getting permission from your supervisor."
+ entry_message_body = "You're a commissioned officer of the USCM, though you are not in the ship's chain of command. You are tasked with researching and developing new medical treatments, helping your fellow doctors, and generally learning new things. Your role involves a lot of roleplaying, but you can perform the function of a regular doctor. Do not hand out things to Marines without getting permission from your supervisor."
/datum/job/civilian/researcher/set_spawn_positions(count)
spawn_positions = rsc_slot_formula(count)
diff --git a/code/game/jobs/job/civilians/support/synthetic.dm b/code/game/jobs/job/civilians/support/synthetic.dm
index 3e02385bc96c..70060fb36a15 100644
--- a/code/game/jobs/job/civilians/support/synthetic.dm
+++ b/code/game/jobs/job/civilians/support/synthetic.dm
@@ -9,7 +9,7 @@
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADMIN_NOTIFY|ROLE_WHITELISTED|ROLE_CUSTOM_SPAWN
flags_whitelist = WHITELIST_SYNTHETIC
gear_preset = /datum/equipment_preset/synth/uscm
- entry_message_body = "You are a Synthetic! You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Synthetic Rules. Failure to do so may result in your White-list Removal. Your primary job is to support and assist all USCM Departments and Personnel on-board. In addition, being a Synthetic gives you knowledge in every field and specialization possible on-board the ship. As a Synthetic you answer to the acting commanding officer. Special circumstances may change this!"
+ entry_message_body = "You are a Synthetic! You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Synthetic Rules. Failure to do so may result in your White-list Removal. Your primary job is to support and assist all USCM Departments and Personnel on-board. In addition, being a Synthetic gives you knowledge in every field and specialization possible on-board the ship. As a Synthetic you answer to the acting commanding officer. Special circumstances may change this!"
/datum/job/civilian/synthetic/New()
. = ..()
diff --git a/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm b/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm
index e5155c949a32..5f6293000365 100644
--- a/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm
+++ b/code/game/jobs/job/command/auxiliary/auxiliary_support_officer.dm
@@ -5,7 +5,7 @@
allow_additional = TRUE
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/auxiliary_officer
- entry_message_body = "Your job is to oversee the hangar crew, the intel officers, the engineering department, and requisition department. You have many responsibilities and a few plates to keep spinning but your subordinates are mostly self-reliant. Assist where you can and make sure command personnel are confident the auxiliary departments are operating at peak efficiency."
+ entry_message_body = "Your job is to oversee the hangar crew, the intel officers, the engineering department, and requisition department. You have many responsibilities and a few plates to keep spinning but your subordinates are mostly self-reliant. Assist where you can and make sure command personnel are confident the auxiliary departments are operating at peak efficiency."
AddTimelock(/datum/job/command/auxiliary_officer, list(
JOB_SQUAD_ROLES = 5 HOURS,
diff --git a/code/game/jobs/job/command/auxiliary/crew_chief.dm b/code/game/jobs/job/command/auxiliary/crew_chief.dm
index c8dfe2a8eb37..0770bcd60ffa 100644
--- a/code/game/jobs/job/command/auxiliary/crew_chief.dm
+++ b/code/game/jobs/job/command/auxiliary/crew_chief.dm
@@ -7,7 +7,7 @@
supervisors = "the pilot officers"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/dcc
- entry_message_body = "Your job is to assist the pilot officer maintain the ship's dropship. You have authority only on the dropship, but you are expected to maintain order, as not to disrupt the pilot."
+ entry_message_body = "Your job is to assist the pilot officer maintain the ship's dropship. You have authority only on the dropship, but you are expected to maintain order, as not to disrupt the pilot."
AddTimelock(/datum/job/command/crew_chief, list(
JOB_SQUAD_ROLES = 5 HOURS
diff --git a/code/game/jobs/job/command/auxiliary/intel.dm b/code/game/jobs/job/command/auxiliary/intel.dm
index 8d83d49ed143..9905bc9d3747 100644
--- a/code/game/jobs/job/command/auxiliary/intel.dm
+++ b/code/game/jobs/job/command/auxiliary/intel.dm
@@ -8,7 +8,7 @@
supervisors = "the auxiliary support officer"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD
gear_preset = "USCM Intelligence Officer (IO) (Cryo)"
- entry_message_body = "Your job is to assist the marines in collecting intelligence related to the current operation to better inform command of their opposition. You are in charge of gathering any data disks, folders, and notes you may find on the operational grounds and decrypt them to grant the USCM additional resources."
+ entry_message_body = "Your job is to assist the marines in collecting intelligence related to the current operation to better inform command of their opposition. You are in charge of gathering any data disks, folders, and notes you may find on the operational grounds and decrypt them to grant the USCM additional resources."
/datum/job/command/intel/set_spawn_positions(count)
spawn_positions = int_slot_formula(count)
diff --git a/code/game/jobs/job/command/auxiliary/pilot.dm b/code/game/jobs/job/command/auxiliary/pilot.dm
index a75846f92919..1a7a7c21d5a0 100644
--- a/code/game/jobs/job/command/auxiliary/pilot.dm
+++ b/code/game/jobs/job/command/auxiliary/pilot.dm
@@ -7,7 +7,7 @@
supervisors = "the auxiliary support officer"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/po
- entry_message_body = "Your job is to fly, protect, and maintain the ship's dropship. While you are an officer, your authority is limited to the dropship, where you have authority over the enlisted personnel. If you are not piloting, there is an autopilot fallback for command, but don't leave the dropship without reason."
+ entry_message_body = "Your job is to fly, protect, and maintain the ship's dropship. While you are an officer, your authority is limited to the dropship, where you have authority over the enlisted personnel. If you are not piloting, there is an autopilot fallback for command, but don't leave the dropship without reason."
// Dropship Roles is both PO and DCC combined to not force people to backtrack
AddTimelock(/datum/job/command/pilot, list(
diff --git a/code/game/jobs/job/command/auxiliary/senior.dm b/code/game/jobs/job/command/auxiliary/senior.dm
index 5e9b7caf1f10..014db9569b2a 100644
--- a/code/game/jobs/job/command/auxiliary/senior.dm
+++ b/code/game/jobs/job/command/auxiliary/senior.dm
@@ -7,7 +7,7 @@
job_options = list("Gunnery Sergeant" = "GySGT", "Master Sergeant" = "MSgt", "First Sergeant" = "1Sgt", "Master Gunnery Sergeant" = "MGySgt", "Sergeant Major" = "SgtMaj")
/datum/job/command/senior/on_config_load()
- entry_message_body = "You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Standard Operating Procedure. Failure to do so may result in your Mentorship Removal. Your primary job is to teach others the game and its mechanics, and offer advice to all USCM Departments and Personnel on-board."
+ entry_message_body = "You are held to a higher standard and are required to obey not only the Server Rules but Marine Law and Standard Operating Procedure. Failure to do so may result in your Mentorship Removal. Your primary job is to teach others the game and its mechanics, and offer advice to all USCM Departments and Personnel on-board."
return ..()
/datum/job/command/senior/announce_entry_message(mob/living/carbon/human/H)
diff --git a/code/game/jobs/job/command/cic/captain.dm b/code/game/jobs/job/command/cic/captain.dm
index 98db585e1d07..72f861351912 100644
--- a/code/game/jobs/job/command/cic/captain.dm
+++ b/code/game/jobs/job/command/cic/captain.dm
@@ -16,7 +16,7 @@
)
/datum/job/command/commander/generate_entry_message()
- entry_message_body = "You are the Commanding Officer of the [MAIN_SHIP_NAME] as well as the operation. Your goal is to lead the Marines on their mission as well as protect and command the ship and her crew. Your job involves heavy roleplay and requires you to behave like a high-ranking officer and to stay in character at all times. As the Commanding Officer your only superior is High Command itself. You must abide by the Commanding Officer Code of Conduct. Failure to do so may result in punitive action against you. Godspeed."
+ entry_message_body = "You are the Commanding Officer of the [MAIN_SHIP_NAME] as well as the operation. Your goal is to lead the Marines on their mission as well as protect and command the ship and her crew. Your job involves heavy roleplay and requires you to behave like a high-ranking officer and to stay in character at all times. As the Commanding Officer your only superior is High Command itself. You must abide by the Commanding Officer Code of Conduct. Failure to do so may result in punitive action against you. Godspeed."
return ..()
/datum/job/command/commander/get_whitelist_status(list/roles_whitelist, client/player)
diff --git a/code/game/jobs/job/command/cic/staffofficer.dm b/code/game/jobs/job/command/cic/staffofficer.dm
index fff51624aa4b..94769de2158f 100644
--- a/code/game/jobs/job/command/cic/staffofficer.dm
+++ b/code/game/jobs/job/command/cic/staffofficer.dm
@@ -6,7 +6,7 @@
scaled = FALSE
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/so
- entry_message_body = "Your job is to monitor the Marines, man the CIC, and listen to your superior officers. You are in charge of logistics and the overwatch system. You are also in line to take command after other eligible superior commissioned officers."
+ entry_message_body = "Your job is to monitor the Marines, man the CIC, and listen to your superior officers. You are in charge of logistics and the overwatch system. You are also in line to take command after other eligible superior commissioned officers."
/datum/job/command/bridge/set_spawn_positions(count)
spawn_positions = so_slot_formula(count)
diff --git a/code/game/jobs/job/command/police/chief_police.dm b/code/game/jobs/job/command/police/chief_police.dm
index b76943c4d0ac..63e6d8023f17 100644
--- a/code/game/jobs/job/command/police/chief_police.dm
+++ b/code/game/jobs/job/command/police/chief_police.dm
@@ -4,7 +4,7 @@
selection_class = "job_cmp"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/uscm_police/cmp
- entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. You lead the Military Police, ensure your officers maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the security of high-ranking personnel, including the command staff. Keep them safe!"
+ entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. You lead the Military Police, ensure your officers maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the security of high-ranking personnel, including the command staff. Keep them safe!"
AddTimelock(/datum/job/command/warrant, list(
JOB_POLICE_ROLES = 15 HOURS,
diff --git a/code/game/jobs/job/command/police/police.dm b/code/game/jobs/job/command/police/police.dm
index 7285c5b278b1..e05bc2e96256 100644
--- a/code/game/jobs/job/command/police/police.dm
+++ b/code/game/jobs/job/command/police/police.dm
@@ -8,7 +8,7 @@
selection_class = "job_mp"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/uscm_police/mp
- entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the security of high-ranking personnel, including the command staff. Keep them safe!"
+ entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the security of high-ranking personnel, including the command staff. Keep them safe!"
/datum/job/command/police/set_spawn_positions(count)
spawn_positions = mp_slot_formula(count)
diff --git a/code/game/jobs/job/command/police/warden.dm b/code/game/jobs/job/command/police/warden.dm
index 55cbea975401..d2775e197537 100644
--- a/code/game/jobs/job/command/police/warden.dm
+++ b/code/game/jobs/job/command/police/warden.dm
@@ -5,7 +5,7 @@
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
supervisors = "the Chief MP"
gear_preset = /datum/equipment_preset/uscm_ship/uscm_police/warden
- entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the mainting security records and overwatching any prisoners in Brig."
+ entry_message_body = "You are held by a higher standard and are required to obey not only the server rules but the Marine Law. Failure to do so may result in a job ban or server ban. Your primary job is to maintain peace and stability aboard the ship. Marines can get rowdy after a few weeks of cryosleep! In addition, you are tasked with the mainting security records and overwatching any prisoners in Brig."
AddTimelock(/datum/job/command/warden, list(
JOB_POLICE_ROLES = 10 HOURS
diff --git a/code/game/jobs/job/job.dm b/code/game/jobs/job/job.dm
index 0d68d23e5524..094b899c1691 100644
--- a/code/game/jobs/job/job.dm
+++ b/code/game/jobs/job/job.dm
@@ -49,13 +49,16 @@
if(!disp_title)
disp_title = title
+ if(global.config.is_loaded)
+ on_config_load()
+
/datum/job/proc/on_config_load()
if(entry_message_body)
entry_message_body = replace_placeholders(entry_message_body)
/datum/job/proc/replace_placeholders(replacement_string)
- replacement_string = replacetextEx(replacement_string, "%WIKIURL%", generate_wiki_link())
- replacement_string = replacetextEx(replacement_string, "%LAWURL%", "[CONFIG_GET(string/wikiarticleurl)]/[URL_WIKI_LAW]")
+ replacement_string = replacetextEx(replacement_string, WIKI_PLACEHOLDER, generate_wiki_link())
+ replacement_string = replacetextEx(replacement_string, LAW_PLACEHOLDER, "[CONFIG_GET(string/wikiarticleurl)]/[URL_WIKI_LAW]")
return replacement_string
/datum/job/proc/generate_wiki_link()
@@ -234,32 +237,10 @@
if(!istype(NP))
return
- NP.spawning = TRUE
- NP.close_spawn_windows()
-
var/mob/living/carbon/human/new_character = new(NP.loc)
new_character.lastarea = get_area(NP.loc)
- NP.client.prefs.copy_all_to(new_character, title)
-
- if (NP.client.prefs.be_random_body)
- var/datum/preferences/TP = new()
- TP.randomize_appearance(new_character)
-
- new_character.job = NP.job
- new_character.name = NP.real_name
- new_character.voice = NP.real_name
-
- if(NP.mind)
- NP.mind_initialize()
- NP.mind.transfer_to(new_character, TRUE)
- NP.mind.setup_human_stats()
-
- // Update the character icons
- // This is done in set_species when the mob is created as well, but
- INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, regenerate_icons))
- INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_body), 1, 0)
- INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_hair))
+ setup_human(new_character, NP)
return new_character
@@ -271,7 +252,7 @@
var/mob/living/carbon/human/human = M
var/job_whitelist = title
- var/whitelist_status = get_whitelist_status(RoleAuthority.roles_whitelist, human.client)
+ var/whitelist_status = get_whitelist_status(GLOB.RoleAuthority.roles_whitelist, human.client)
if(whitelist_status)
job_whitelist = "[title][whitelist_status]"
@@ -290,9 +271,9 @@
generate_entry_conditions(human) //Do any other thing that relates to their spawn.
if(flags_startup_parameters & ROLE_ADD_TO_SQUAD) //Are we a muhreen? Randomize our squad. This should go AFTER IDs. //TODO Robust this later.
- RoleAuthority.randomize_squad(human)
+ GLOB.RoleAuthority.randomize_squad(human)
- if(Check_WO() && job_squad_roles.Find(GET_DEFAULT_ROLE(human.job))) //activates self setting proc for marine headsets for WO
+ if(Check_WO() && GLOB.job_squad_roles.Find(GET_DEFAULT_ROLE(human.job))) //activates self setting proc for marine headsets for WO
var/datum/game_mode/whiskey_outpost/WO = SSticker.mode
WO.self_set_headset(human)
diff --git a/code/game/jobs/job/logistics/cargo/cargo_tech.dm b/code/game/jobs/job/logistics/cargo/cargo_tech.dm
index 3b588022bd97..c4725289c3ff 100644
--- a/code/game/jobs/job/logistics/cargo/cargo_tech.dm
+++ b/code/game/jobs/job/logistics/cargo/cargo_tech.dm
@@ -8,7 +8,7 @@
selection_class = "job_ct"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/cargo
- entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Stay in your department when possible to ensure the marines have full access to the supplies they may require. Listen to the radio in case someone requests a supply drop via the overwatch system."
+ entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Stay in your department when possible to ensure the marines have full access to the supplies they may require. Listen to the radio in case someone requests a supply drop via the overwatch system."
/datum/job/logistics/cargo/set_spawn_positions(count)
spawn_positions = ct_slot_formula(count)
diff --git a/code/game/jobs/job/logistics/cargo/chief_req.dm b/code/game/jobs/job/logistics/cargo/chief_req.dm
index 76b7e98f2db8..5d5123e687ed 100644
--- a/code/game/jobs/job/logistics/cargo/chief_req.dm
+++ b/code/game/jobs/job/logistics/cargo/chief_req.dm
@@ -3,7 +3,7 @@
selection_class = "job_qm"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/qm
- entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Your cargo techs can help you out, but you have final say in your department. Make sure they're not goofing off. While you may request paperwork for supplies, do not go out of your way to screw with marines, unless you want to get deposed. A happy ship is a well-functioning ship."
+ entry_message_body = "Your job is to dispense supplies to the marines, including weapon attachments. Your cargo techs can help you out, but you have final say in your department. Make sure they're not goofing off. While you may request paperwork for supplies, do not go out of your way to screw with marines, unless you want to get deposed. A happy ship is a well-functioning ship."
AddTimelock(/datum/job/logistics/requisition, list(
JOB_REQUISITION_ROLES = 10 HOURS,
diff --git a/code/game/jobs/job/logistics/engi/chief_engineer.dm b/code/game/jobs/job/logistics/engi/chief_engineer.dm
index 3a15c8632953..b6aa23f9c4a6 100644
--- a/code/game/jobs/job/logistics/engi/chief_engineer.dm
+++ b/code/game/jobs/job/logistics/engi/chief_engineer.dm
@@ -3,7 +3,7 @@
selection_class = "job_ce"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/chief_engineer
- entry_message_body = "Your job is to maintain your department and keep your technicians in check. You are responsible for engineering, power, ordnance, and the orbital cannon. Should the commanding and executive officer be unavailable, you are next in the chain of command."
+ entry_message_body = "Your job is to maintain your department and keep your technicians in check. You are responsible for engineering, power, ordnance, and the orbital cannon. Should the commanding and executive officer be unavailable, you are next in the chain of command."
AddTimelock(/datum/job/logistics/engineering, list(
JOB_ENGINEER_ROLES = 10 HOURS,
diff --git a/code/game/jobs/job/logistics/engi/maint_tech.dm b/code/game/jobs/job/logistics/engi/maint_tech.dm
index 8562408360d7..b13062127a12 100644
--- a/code/game/jobs/job/logistics/engi/maint_tech.dm
+++ b/code/game/jobs/job/logistics/engi/maint_tech.dm
@@ -6,7 +6,7 @@
selection_class = "job_ot"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/maint
- entry_message_body = "Your job is to maintain the integrity of the ship, including the orbital cannon. You remain one of the more flexible roles on the ship and as such may receive other menial tasks from your superiors."
+ entry_message_body = "Your job is to maintain the integrity of the ship, including the orbital cannon. You remain one of the more flexible roles on the ship and as such may receive other menial tasks from your superiors."
/obj/effect/landmark/start/maint
name = JOB_MAINT_TECH
diff --git a/code/game/jobs/job/logistics/engi/ordnance_tech.dm b/code/game/jobs/job/logistics/engi/ordnance_tech.dm
index bed0acf15887..43a8a7122a8f 100644
--- a/code/game/jobs/job/logistics/engi/ordnance_tech.dm
+++ b/code/game/jobs/job/logistics/engi/ordnance_tech.dm
@@ -9,7 +9,7 @@
selection_class = "job_ot"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT
gear_preset = /datum/equipment_preset/uscm_ship/ordn
- entry_message_body = "Your job is to maintain the integrity of the USCM weapons, munitions and equipment, including the orbital cannon. You can use the workshop in the portside hangar to construct new armaments for the marines. However you remain one of the more flexible roles on the ship and as such may receive other menial tasks from your superiors."
+ entry_message_body = "Your job is to maintain the integrity of the USCM weapons, munitions and equipment, including the orbital cannon. You can use the workshop in the portside hangar to construct new armaments for the marines. However you remain one of the more flexible roles on the ship and as such may receive other menial tasks from your superiors."
/datum/job/logistics/otech/set_spawn_positions(count)
spawn_positions = ot_slot_formula(count)
diff --git a/code/game/jobs/job/marine/squad/engineer.dm b/code/game/jobs/job/marine/squad/engineer.dm
index 00a6b91dcffd..a4422572f218 100644
--- a/code/game/jobs/job/marine/squad/engineer.dm
+++ b/code/game/jobs/job/marine/squad/engineer.dm
@@ -5,10 +5,10 @@
allow_additional = 1
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD
gear_preset = /datum/equipment_preset/uscm/engineer
- entry_message_body = "You have the equipment and skill to build fortifications, reroute power lines, and bunker down. Your squaddies will look to you when it comes to construction in the field of battle."
+ entry_message_body = "You have the equipment and skill to build fortifications, reroute power lines, and bunker down. Your squaddies will look to you when it comes to construction in the field of battle."
/datum/job/marine/engineer/set_spawn_positions(count)
- for(var/datum/squad/sq in RoleAuthority.squads)
+ for(var/datum/squad/sq in GLOB.RoleAuthority.squads)
if(sq)
sq.max_engineers = engi_slot_formula(count)
@@ -21,7 +21,7 @@
total_positions_so_far = slots
if(latejoin)
- for(var/datum/squad/sq in RoleAuthority.squads)
+ for(var/datum/squad/sq in GLOB.RoleAuthority.squads)
if(sq)
sq.max_engineers = slots
diff --git a/code/game/jobs/job/marine/squad/leader.dm b/code/game/jobs/job/marine/squad/leader.dm
index 960a80d5f659..be78438db3d6 100644
--- a/code/game/jobs/job/marine/squad/leader.dm
+++ b/code/game/jobs/job/marine/squad/leader.dm
@@ -5,7 +5,7 @@
supervisors = "the acting commanding officer"
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD
gear_preset = /datum/equipment_preset/uscm/leader
- entry_message_body = "You are responsible for the men and women of your squad. Make sure they are on task, working together, and communicating. You are also in charge of communicating with command and letting them know about the situation first hand. Keep out of harm's way."
+ entry_message_body = "You are responsible for the men and women of your squad. Make sure they are on task, working together, and communicating. You are also in charge of communicating with command and letting them know about the situation first hand. Keep out of harm's way."
/datum/job/marine/leader/whiskey
title = JOB_WO_SQUAD_LEADER
diff --git a/code/game/jobs/job/marine/squad/medic.dm b/code/game/jobs/job/marine/squad/medic.dm
index cdbd74acefde..450d1176658f 100644
--- a/code/game/jobs/job/marine/squad/medic.dm
+++ b/code/game/jobs/job/marine/squad/medic.dm
@@ -5,10 +5,10 @@
allow_additional = 1
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD
gear_preset = /datum/equipment_preset/uscm/medic
- entry_message_body = "You tend the wounds of your squad mates and make sure they are healthy and active. You may not be a fully-fledged doctor, but you stand between life and death when it matters."
+ entry_message_body = "You tend the wounds of your squad mates and make sure they are healthy and active. You may not be a fully-fledged doctor, but you stand between life and death when it matters."
/datum/job/marine/medic/set_spawn_positions(count)
- for(var/datum/squad/sq in RoleAuthority.squads)
+ for(var/datum/squad/sq in GLOB.RoleAuthority.squads)
if(sq)
sq.max_medics = medic_slot_formula(count)
@@ -21,7 +21,7 @@
total_positions_so_far = slots
if(latejoin)
- for(var/datum/squad/sq in RoleAuthority.squads)
+ for(var/datum/squad/sq in GLOB.RoleAuthority.squads)
if(sq)
sq.max_medics = slots
diff --git a/code/game/jobs/job/marine/squad/smartgunner.dm b/code/game/jobs/job/marine/squad/smartgunner.dm
index aacc562f921b..1a89abf5d3be 100644
--- a/code/game/jobs/job/marine/squad/smartgunner.dm
+++ b/code/game/jobs/job/marine/squad/smartgunner.dm
@@ -6,7 +6,7 @@
scaled = 1
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD
gear_preset = /datum/equipment_preset/uscm/sg
- entry_message_body = "You are the smartgunner. Your task is to provide heavy weapons support."
+ entry_message_body = "You are the smartgunner. Your task is to provide heavy weapons support."
/datum/job/marine/smartgunner/set_spawn_positions(count)
spawn_positions = sg_slot_formula(count)
diff --git a/code/game/jobs/job/marine/squad/specialist.dm b/code/game/jobs/job/marine/squad/specialist.dm
index 42ee69ef2d5c..e69241cdc70b 100644
--- a/code/game/jobs/job/marine/squad/specialist.dm
+++ b/code/game/jobs/job/marine/squad/specialist.dm
@@ -6,7 +6,7 @@
scaled = 1
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD
gear_preset = /datum/equipment_preset/uscm/spec
- entry_message_body = "You are the very rare and valuable weapon expert, trained to use special equipment. You can serve a variety of roles, so choose carefully."
+ entry_message_body = "You are the very rare and valuable weapon expert, trained to use special equipment. You can serve a variety of roles, so choose carefully."
/datum/job/marine/specialist/set_spawn_positions(count)
spawn_positions = spec_slot_formula(count)
diff --git a/code/game/jobs/job/marine/squad/standard.dm b/code/game/jobs/job/marine/squad/standard.dm
index e2502576e5ea..2fcd8a3cdd28 100644
--- a/code/game/jobs/job/marine/squad/standard.dm
+++ b/code/game/jobs/job/marine/squad/standard.dm
@@ -6,7 +6,10 @@
spawn_positions = -1
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD
gear_preset = /datum/equipment_preset/uscm/pfc
- entry_message_body = "You are a rank-and-file Marine of the USCM, and that is your strength. What you lack alone, you gain standing shoulder to shoulder with the men and women of the corps. Ooh-rah!"
+
+/datum/job/marine/standard/on_config_load()
+ entry_message_body = "You are a rank-and-file Marine of the USCM, and that is your strength. What you lack alone, you gain standing shoulder to shoulder with the men and women of the corps. Ooh-rah!"
+ return ..()
/datum/job/marine/standard/set_spawn_positions(count)
spawn_positions = max((round(count * STANDARD_MARINE_TO_TOTAL_SPAWN_RATIO)), 8)
diff --git a/code/game/jobs/job/marine/squad/tl.dm b/code/game/jobs/job/marine/squad/tl.dm
index ebebf360e830..2b0cff3ea3ed 100644
--- a/code/game/jobs/job/marine/squad/tl.dm
+++ b/code/game/jobs/job/marine/squad/tl.dm
@@ -5,7 +5,7 @@
allow_additional = 1
flags_startup_parameters = ROLE_ADD_TO_DEFAULT|ROLE_ADD_TO_SQUAD
gear_preset = /datum/equipment_preset/uscm/tl
- entry_message_body = "You are the Team Leader.Your task is to assist the squad leader in leading the squad as well as utilize ordnance such as orbital bombardments, CAS, and mortar as well as coordinating resupply with Requisitions and CIC. If the squad leader dies, you are expected to lead in their place."
+ entry_message_body = "You are the Team Leader.Your task is to assist the squad leader in leading the squad as well as utilize ordnance such as orbital bombardments, CAS, and mortar as well as coordinating resupply with Requisitions and CIC. If the squad leader dies, you are expected to lead in their place."
/datum/job/marine/tl/generate_entry_conditions(mob/living/carbon/human/spawning_human)
. = ..()
diff --git a/code/game/jobs/job/marine/squads.dm b/code/game/jobs/job/marine/squads.dm
index 80f00c540383..5eac0586eb34 100644
--- a/code/game/jobs/job/marine/squads.dm
+++ b/code/game/jobs/job/marine/squads.dm
@@ -210,6 +210,17 @@
roundstart = FALSE
locked = TRUE
+/datum/squad/marine/cbrn
+ name = SQUAD_CBRN
+ equipment_color = "#3B2A7B" //Chemical Corps Purple
+ chat_color = "#553EB2"
+ radio_freq = CBRN_FREQ
+ minimap_color = "#3B2A7B"
+
+ active = FALSE
+ roundstart = FALSE
+ locked = TRUE
+
//############################### UPP Squads
/datum/squad/upp
name = "Root"
@@ -604,7 +615,7 @@
if(JOB_SQUAD_MEDIC)
old_lead.comm_title = "HM"
if(JOB_SQUAD_TEAM_LEADER)
- old_lead.comm_title = "TL"
+ old_lead.comm_title = "FTL"
if(JOB_SQUAD_SMARTGUN)
old_lead.comm_title = "SG"
if(JOB_SQUAD_LEADER)
@@ -638,10 +649,10 @@
//Not a safe proc. Returns null if squads or jobs aren't set up.
//Mostly used in the marine squad console in marine_consoles.dm.
/proc/get_squad_by_name(text)
- if(!RoleAuthority || RoleAuthority.squads.len == 0)
+ if(!GLOB.RoleAuthority || GLOB.RoleAuthority.squads.len == 0)
return null
var/datum/squad/S
- for(S in RoleAuthority.squads)
+ for(S in GLOB.RoleAuthority.squads)
if(S.name == text)
return S
return null
@@ -749,7 +760,7 @@
//moved the main proc for ft management from human.dm here to make it support both examine and squad info way to edit fts
/datum/squad/proc/manage_fireteams(mob/living/carbon/human/target)
var/obj/item/card/id/ID = target.get_idcard()
- if(!ID || !(ID.rank in ROLES_MARINES))
+ if(!ID || !(ID.rank in GLOB.ROLES_MARINES))
return
if(ID.rank == JOB_SQUAD_LEADER || squad_leader == target) //if SL/aSL are chosen
var/choice = tgui_input_list(squad_leader, "Manage Fireteams and Team leaders.", "Fireteams Management", list("Cancel", "Unassign Fireteam 1 Leader", "Unassign Fireteam 2 Leader", "Unassign Fireteam 3 Leader", "Unassign all Team Leaders"))
diff --git a/code/game/jobs/role_authority.dm b/code/game/jobs/role_authority.dm
index c147807f004e..af99e17d65a9 100644
--- a/code/game/jobs/role_authority.dm
+++ b/code/game/jobs/role_authority.dm
@@ -11,7 +11,7 @@ When a round starts, the roles are assigned based on the round, from another lis
by name can be kept for things like job bans, while the round may add or remove roles as needed.If you need to equip a mob for a job, always
use roles_by_path as it is an accurate account of every specific role path (with specific equipment).
*/
-var/global/datum/authority/branch/role/RoleAuthority
+GLOBAL_DATUM(RoleAuthority, /datum/authority/branch/role)
#define GET_RANDOM_JOB 0
#define BE_MARINE 1
@@ -25,11 +25,10 @@ var/global/datum/authority/branch/role/RoleAuthority
#define SHIPSIDE_ROLE_WEIGHT 0.25
-var/global/players_preassigned = 0
-
+GLOBAL_VAR_INIT(players_preassigned, 0)
/proc/guest_jobbans(job)
- return (job in ROLES_COMMAND)
+ return (job in GLOB.ROLES_COMMAND)
/datum/authority/branch/role
var/name = "Role Authority"
@@ -236,7 +235,7 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou
// Get balancing weight for the readied players.
// Squad marine roles have a weight of 1, and shipside roles have a lower weight of SHIPSIDE_ROLE_WEIGHT.
- players_preassigned = assign_roles(temp_roles_for_mode.Copy(), unassigned_players.Copy(), TRUE)
+ GLOB.players_preassigned = assign_roles(temp_roles_for_mode.Copy(), unassigned_players.Copy(), TRUE)
// Even though we pass a copy of temp_roles_for_mode, job counters still change, so we reset them here.
for(var/title in temp_roles_for_mode)
@@ -247,28 +246,29 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou
// Set the xeno starting amount based on marines assigned
var/datum/job/antag/xenos/XJ = temp_roles_for_mode[JOB_XENOMORPH]
if(istype(XJ))
- XJ.set_spawn_positions(players_preassigned)
+ XJ.set_spawn_positions(GLOB.players_preassigned)
// Limit the number of SQUAD MARINE roles players can roll initially
var/datum/job/SMJ = GET_MAPPED_ROLE(JOB_SQUAD_MARINE)
if(istype(SMJ))
- SMJ.set_spawn_positions(players_preassigned)
+ SMJ.set_spawn_positions(GLOB.players_preassigned)
// Set survivor starting amount based on marines assigned
var/datum/job/SJ = temp_roles_for_mode[JOB_SURVIVOR]
if(istype(SJ))
- SJ.set_spawn_positions(players_preassigned)
+ SJ.set_spawn_positions(GLOB.players_preassigned)
var/datum/job/CO_surv_job = temp_roles_for_mode[JOB_CO_SURVIVOR]
if(istype(CO_surv_job))
- CO_surv_job.set_spawn_positions(players_preassigned)
+ CO_surv_job.set_spawn_positions(GLOB.players_preassigned)
- if(SSnightmare.get_scenario_value("predator_round"))
+ if(SSnightmare.get_scenario_value("predator_round") && !Check_WO())
SSticker.mode.flags_round_type |= MODE_PREDATOR
// Set predators starting amount based on marines assigned
var/datum/job/PJ = temp_roles_for_mode[JOB_PREDATOR]
if(istype(PJ))
- PJ.set_spawn_positions(players_preassigned)
+ PJ.set_spawn_positions(GLOB.players_preassigned)
+ REDIS_PUBLISH("byond.round", "type" = "predator-round")
// Assign the roles, this time for real, respecting limits we have established.
var/list/roles_left = assign_roles(temp_roles_for_mode, unassigned_players)
@@ -312,13 +312,13 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou
var/assigned = 0
for(var/priority in HIGH_PRIORITY to LOW_PRIORITY)
// Assigning xenos first.
- assigned += assign_initial_roles(priority, roles_for_mode & ROLES_XENO, unassigned_players)
+ assigned += assign_initial_roles(priority, roles_for_mode & GLOB.ROLES_XENO, unassigned_players)
// Assigning special roles second. (survivor, predator)
- assigned += assign_initial_roles(priority, roles_for_mode & (ROLES_WHITELISTED|ROLES_SPECIAL), unassigned_players)
+ assigned += assign_initial_roles(priority, roles_for_mode & (GLOB.ROLES_WHITELISTED|GLOB.ROLES_SPECIAL), unassigned_players)
// Assigning command third.
- assigned += assign_initial_roles(priority, roles_for_mode & ROLES_COMMAND, unassigned_players)
+ assigned += assign_initial_roles(priority, roles_for_mode & GLOB.ROLES_COMMAND, unassigned_players)
// Assigning the rest
- var/rest_roles_for_mode = roles_for_mode - (roles_for_mode & ROLES_XENO) - (roles_for_mode & ROLES_COMMAND) - (roles_for_mode & (ROLES_WHITELISTED|ROLES_SPECIAL))
+ var/rest_roles_for_mode = roles_for_mode - (roles_for_mode & GLOB.ROLES_XENO) - (roles_for_mode & GLOB.ROLES_COMMAND) - (roles_for_mode & (GLOB.ROLES_WHITELISTED|GLOB.ROLES_SPECIAL))
if(count)
assigned += assign_initial_roles(priority, rest_roles_for_mode, unassigned_players)
else
@@ -367,9 +367,11 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou
* survivors and the number of roundstart Squad Rifleman slots.
*/
/datum/authority/branch/role/proc/calculate_role_weight(datum/job/J)
- if(ROLES_MARINES.Find(J.title))
+ if(!J)
+ return 0
+ if(GLOB.ROLES_MARINES.Find(J.title))
return 1
- if(ROLES_XENO.Find(J.title))
+ if(GLOB.ROLES_XENO.Find(J.title))
return 1
if(J.title == JOB_SURVIVOR)
return 1
@@ -436,9 +438,9 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou
//here is the main reason this proc exists - to remove freed squad jobs from squad,
//so latejoining person ends in the squad which's job was freed and not random one
var/datum/squad/sq = null
- if(job_squad_roles.Find(J.title))
+ if(GLOB.job_squad_roles.Find(J.title))
var/list/squad_list = list()
- for(sq in RoleAuthority.squads)
+ for(sq in GLOB.RoleAuthority.squads)
if(sq.usable)
squad_list += sq
sq = null
@@ -501,85 +503,86 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou
M.job = null
-/datum/authority/branch/role/proc/equip_role(mob/living/M, datum/job/J, turf/late_join)
- if(!istype(M) || !istype(J))
+/datum/authority/branch/role/proc/equip_role(mob/living/new_mob, datum/job/new_job, turf/late_join)
+ if(!istype(new_mob) || !istype(new_job))
return
. = TRUE
- if(!ishuman(M))
+ if(!ishuman(new_mob))
return
- var/mob/living/carbon/human/H = M
+ var/mob/living/carbon/human/new_human = new_mob
- if(J.job_options && H?.client?.prefs?.pref_special_job_options[J.title])
- J.handle_job_options(H.client.prefs.pref_special_job_options[J.title])
+ if(new_job.job_options && new_human?.client?.prefs?.pref_special_job_options[new_job.title])
+ new_job.handle_job_options(new_human.client.prefs.pref_special_job_options[new_job.title])
- var/job_whitelist = J.title
- var/whitelist_status = J.get_whitelist_status(roles_whitelist, H.client)
+ var/job_whitelist = new_job.title
+ var/whitelist_status = new_job.get_whitelist_status(roles_whitelist, new_human.client)
if(whitelist_status)
- job_whitelist = "[J.title][whitelist_status]"
+ job_whitelist = "[new_job.title][whitelist_status]"
- H.job = J.title //TODO Why is this a mob variable at all?
+ new_human.job = new_job.title //TODO Why is this a mob variable at all?
- if(J.gear_preset_whitelist[job_whitelist])
- arm_equipment(H, J.gear_preset_whitelist[job_whitelist], FALSE, TRUE)
- var/generated_account = J.generate_money_account(H)
- J.announce_entry_message(H, generated_account, whitelist_status) //Tell them their spawn info.
- J.generate_entry_conditions(H, whitelist_status) //Do any other thing that relates to their spawn.
+ if(new_job.gear_preset_whitelist[job_whitelist])
+ arm_equipment(new_human, new_job.gear_preset_whitelist[job_whitelist], FALSE, TRUE)
+ var/generated_account = new_job.generate_money_account(new_human)
+ new_job.announce_entry_message(new_human, generated_account, whitelist_status) //Tell them their spawn info.
+ new_job.generate_entry_conditions(new_human, whitelist_status) //Do any other thing that relates to their spawn.
else
- arm_equipment(H, J.gear_preset, FALSE, TRUE) //After we move them, we want to equip anything else they should have.
- var/generated_account = J.generate_money_account(H)
- J.announce_entry_message(H, generated_account) //Tell them their spawn info.
- J.generate_entry_conditions(H) //Do any other thing that relates to their spawn.
+ arm_equipment(new_human, new_job.gear_preset, FALSE, TRUE) //After we move them, we want to equip anything else they should have.
+ var/generated_account = new_job.generate_money_account(new_human)
+ new_job.announce_entry_message(new_human, generated_account) //Tell them their spawn info.
+ new_job.generate_entry_conditions(new_human) //Do any other thing that relates to their spawn.
- if(J.flags_startup_parameters & ROLE_ADD_TO_SQUAD) //Are we a muhreen? Randomize our squad. This should go AFTER IDs. //TODO Robust this later.
- randomize_squad(H)
+ if(new_job.flags_startup_parameters & ROLE_ADD_TO_SQUAD) //Are we a muhreen? Randomize our squad. This should go AFTER IDs. //TODO Robust this later.
+ randomize_squad(new_human)
- if(Check_WO() && job_squad_roles.Find(GET_DEFAULT_ROLE(H.job))) //activates self setting proc for marine headsets for WO
+ if(Check_WO() && GLOB.job_squad_roles.Find(GET_DEFAULT_ROLE(new_human.job))) //activates self setting proc for marine headsets for WO
var/datum/game_mode/whiskey_outpost/WO = SSticker.mode
- WO.self_set_headset(H)
+ WO.self_set_headset(new_human)
var/assigned_squad
- if(ishuman(H))
- var/mob/living/carbon/human/human = H
+ if(ishuman(new_human))
+ var/mob/living/carbon/human/human = new_human
if(human.assigned_squad)
assigned_squad = human.assigned_squad.name
if(isturf(late_join))
- H.forceMove(late_join)
+ new_human.forceMove(late_join)
else if(late_join)
var/turf/late_join_turf
if(GLOB.latejoin_by_squad[assigned_squad])
late_join_turf = get_turf(pick(GLOB.latejoin_by_squad[assigned_squad]))
- else if(GLOB.latejoin_by_job[J.title])
- late_join_turf = get_turf(pick(GLOB.latejoin_by_job[J.title]))
+ else if(GLOB.latejoin_by_job[new_job.title])
+ late_join_turf = get_turf(pick(GLOB.latejoin_by_job[new_job.title]))
else
late_join_turf = get_turf(pick(GLOB.latejoin))
- H.forceMove(late_join_turf)
+ new_human.forceMove(late_join_turf)
else
var/turf/join_turf
- if(assigned_squad && GLOB.spawns_by_squad_and_job[assigned_squad] && GLOB.spawns_by_squad_and_job[assigned_squad][J.type])
- join_turf = get_turf(pick(GLOB.spawns_by_squad_and_job[assigned_squad][J.type]))
- else if(GLOB.spawns_by_job[J.type])
- join_turf = get_turf(pick(GLOB.spawns_by_job[J.type]))
+ if(assigned_squad && GLOB.spawns_by_squad_and_job[assigned_squad] && GLOB.spawns_by_squad_and_job[assigned_squad][new_job.type])
+ join_turf = get_turf(pick(GLOB.spawns_by_squad_and_job[assigned_squad][new_job.type]))
+ else if(GLOB.spawns_by_job[new_job.type])
+ join_turf = get_turf(pick(GLOB.spawns_by_job[new_job.type]))
else if(assigned_squad && GLOB.latejoin_by_squad[assigned_squad])
join_turf = get_turf(pick(GLOB.latejoin_by_squad[assigned_squad]))
else
join_turf = get_turf(pick(GLOB.latejoin))
- H.forceMove(join_turf)
+ new_human.forceMove(join_turf)
for(var/cardinal in GLOB.cardinals)
- var/obj/structure/machinery/cryopod/pod = locate() in get_step(H, cardinal)
+ var/obj/structure/machinery/cryopod/pod = locate() in get_step(new_human, cardinal)
if(pod)
- pod.go_in_cryopod(H, silent = TRUE)
+ pod.go_in_cryopod(new_human, silent = TRUE)
break
- H.sec_hud_set_ID()
- H.hud_set_squad()
+ new_human.sec_hud_set_ID()
+ new_human.hud_set_squad()
- SSround_recording.recorder.track_player(H)
+ SEND_SIGNAL(new_human, COMSIG_POST_SPAWN_UPDATE)
+ SSround_recording.recorder.track_player(new_human)
//Find which squad has the least population. If all 4 squads are equal it should just use a random one
/datum/authority/branch/role/proc/get_lowest_squad(mob/living/carbon/human/H)
@@ -816,7 +819,7 @@ I hope it's easier to tell what the heck this proc is even doing, unlike previou
var/found_desired = FALSE
var/found_limit = FALSE
- for(var/status in whitelist_hierarchy)
+ for(var/status in GLOB.whitelist_hierarchy)
if(status == desired_status)
found_desired = TRUE
break
diff --git a/code/game/jobs/slot_scaling.dm b/code/game/jobs/slot_scaling.dm
index 7230f57eb745..2d444d06e5ab 100644
--- a/code/game/jobs/slot_scaling.dm
+++ b/code/game/jobs/slot_scaling.dm
@@ -50,3 +50,6 @@
/proc/working_joe_slot_formula(playercount)
return job_slot_formula(playercount,30,1,3,6)
+
+/proc/mess_sergeant_slot_formula(playercount)
+ return job_slot_formula(playercount, 70, 1, 1, 2)
diff --git a/code/game/jobs/whitelist.dm b/code/game/jobs/whitelist.dm
index 05f530348029..3a4b94145ca1 100644
--- a/code/game/jobs/whitelist.dm
+++ b/code/game/jobs/whitelist.dm
@@ -11,10 +11,10 @@ GLOBAL_LIST_FILE_LOAD(whitelist, WHITELISTFILE)
if(client.admin_holder && (client.admin_holder.rights & R_ADMIN))
return TRUE
if(job == XENO_CASTE_QUEEN)
- var/datum/caste_datum/C = RoleAuthority.castes_by_name[XENO_CASTE_QUEEN]
+ var/datum/caste_datum/C = GLOB.RoleAuthority.castes_by_name[XENO_CASTE_QUEEN]
return C.can_play_caste(client)
if(job == JOB_SURVIVOR)
- var/datum/job/J = RoleAuthority.roles_by_path[/datum/job/civilian/survivor]
+ var/datum/job/J = GLOB.RoleAuthority.roles_by_path[/datum/job/civilian/survivor]
return J.can_play_role(client)
return TRUE
@@ -42,11 +42,11 @@ GLOBAL_LIST_FILE_LOAD(alien_whitelist, "config/alienwhitelist.txt")
/// returns a list of strings containing the whitelists held by a specific ckey
/proc/get_whitelisted_roles(ckey)
- if(RoleAuthority.roles_whitelist[ckey] & WHITELIST_PREDATOR)
+ if(GLOB.RoleAuthority.roles_whitelist[ckey] & WHITELIST_PREDATOR)
LAZYADD(., "predator")
- if(RoleAuthority.roles_whitelist[ckey] & WHITELIST_COMMANDER)
+ if(GLOB.RoleAuthority.roles_whitelist[ckey] & WHITELIST_COMMANDER)
LAZYADD(., "commander")
- if(RoleAuthority.roles_whitelist[ckey] & WHITELIST_SYNTHETIC)
+ if(GLOB.RoleAuthority.roles_whitelist[ckey] & WHITELIST_SYNTHETIC)
LAZYADD(., "synthetic")
#undef WHITELISTFILE
diff --git a/code/game/machinery/ARES/ARES.dm b/code/game/machinery/ARES/ARES.dm
index ed4391c89c24..1ecbb4a5d7d6 100644
--- a/code/game/machinery/ARES/ARES.dm
+++ b/code/game/machinery/ARES/ARES.dm
@@ -8,7 +8,6 @@
unslashable = TRUE
unacidable = TRUE
- var/link_id = MAIN_SHIP_DEFAULT_NAME
var/datum/ares_link/link
/obj/structure/machinery/ares/ex_act(severity)
@@ -40,14 +39,12 @@
log_debug("Error: link_systems called without a link datum")
if(link && !override)
return FALSE
- if(new_link.link_id == link_id)
+ if(new_link)
link = new_link
- log_debug("[name] linked to Ares Link [link_id]")
new_link.linked_systems += src
return TRUE
/obj/structure/machinery/ares/proc/delink()
- log_debug("[name] delinked from Ares Link [link.link_id]")
link.linked_systems -= src
link = null
@@ -63,11 +60,11 @@
/obj/structure/machinery/ares/processor/apollo/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
..()
- new_link.p_apollo = src
+ new_link.processor_apollo = src
/obj/structure/machinery/ares/processor/apollo/delink()
- if(link && link.p_apollo == src)
- link.p_apollo = null
+ if(link && link.processor_apollo == src)
+ link.processor_apollo = null
..()
/obj/structure/machinery/ares/processor/interface
@@ -77,11 +74,11 @@
/obj/structure/machinery/ares/processor/interface/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
..()
- new_link.p_interface = src
+ new_link.processor_interface = src
/obj/structure/machinery/ares/processor/interface/delink()
- if(link && link.p_interface == src)
- link.p_interface = null
+ if(link && link.processor_interface == src)
+ link.processor_interface = null
..()
/obj/structure/machinery/ares/processor/bioscan
@@ -91,11 +88,11 @@
/obj/structure/machinery/ares/processor/bioscan/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
..()
- new_link.p_bioscan = src
+ new_link.processor_bioscan = src
/obj/structure/machinery/ares/processor/bioscan/delink()
- if(link && link.p_bioscan == src)
- link.p_bioscan = null
+ if(link && link.processor_bioscan == src)
+ link.processor_bioscan = null
..()
/// Central Core
@@ -104,130 +101,17 @@
desc = "This is ARES' central processor. Made of a casing designed to withstand nuclear blasts, the CPU also contains ARES' blackbox recorder."
icon_state = "CPU"
+/obj/structure/machinery/ares/cpu/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
+ ..()
+ new_link.central_processor = src
+
+/obj/structure/machinery/ares/cpu/delink()
+ if(link && link.central_processor == src)
+ link.central_processor = null
+ ..()
+
/// Memory Substrate,
/obj/structure/machinery/ares/substrate
name = "ARES Substrate"
desc = "The memory substrate of ARES, containing complex protocols and information. Limited capabilities can operate on substrate alone, without the main ARES Unit operational."
icon_state = "substrate"
-
-// #################### ARES Interface Console #####################
-/obj/structure/machinery/computer/ares_console
- name = "ARES Interface"
- desc = "A console built to interface with ARES, allowing for 1:1 communication."
- icon = 'icons/obj/structures/machinery/ares.dmi'
- icon_state = "console"
- exproof = TRUE
-
- var/current_menu = "login"
- var/last_menu = ""
-
- var/authentication = ARES_ACCESS_BASIC
-
- /// The last person to login.
- var/last_login
- /// The person pretending to be last_login
- var/sudo_holder
- /// A record of who logged in and when.
- var/list/access_list = list()
-
- /// The ID used to link all devices.
- var/link_id = MAIN_SHIP_DEFAULT_NAME
- var/datum/ares_link/link
-
- /// The current deleted chat log of 1:1 conversations being read.
- var/list/deleted_1to1 = list()
-
- /// Holds all (/datum/ares_record/announcement)s
- var/list/records_announcement = list()
- /// Holds all (/datum/ares_record/bioscan)s
- var/list/records_bioscan = list()
- /// Holds all (/datum/ares_record/bombardment)s
- var/list/records_bombardment = list()
- /// Holds all (/datum/ares_record/deletion)s
- var/list/records_deletion = list()
- /// Holds all (/datum/ares_record/talk_log)s
- var/list/records_talking = list()
- /// Holds all (/datum/ares_record/requisition_log)s
- var/list/records_asrs = list()
- /// Holds all (/datum/ares_record/security)s (including AA)
- var/list/records_security = list()
- /// Holds all (/datum/ares_record/flight)s
- var/list/records_flight = list()
- /// Is nuke request usable or not?
- var/nuke_available = TRUE
-
-
- COOLDOWN_DECLARE(ares_distress_cooldown)
- COOLDOWN_DECLARE(ares_nuclear_cooldown)
- COOLDOWN_DECLARE(ares_quarters_cooldown)
-
-/obj/structure/machinery/computer/ares_console/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
- if(link && !override)
- return FALSE
- if(new_link.link_id == link_id)
- new_link.interface = src
- link = new_link
- log_debug("[name] linked to Ares Link [link_id]")
- new_link.linked_systems += src
- return TRUE
-
-/obj/structure/machinery/computer/ares_console/Initialize(mapload, ...)
- link_systems(override = FALSE)
- . = ..()
-
-/obj/structure/machinery/computer/ares_console/proc/delink()
- if(link && link.interface == src)
- link.interface = null
- link.linked_systems -= src
- link = null
-
-/obj/structure/machinery/computer/ares_console/Destroy()
- delink()
- return ..()
-
-// #################### Working Joe Ticket Console #####################
-/obj/structure/machinery/computer/working_joe
- name = "APOLLO Maintenance Controller"
- desc = "A console built to facilitate Working Joes and their operation, allowing for simple allocation of resources."
- icon = 'icons/obj/structures/machinery/ares.dmi'
- icon_state = "console"
- exproof = TRUE
-
- /// The ID used to link all devices.
- var/link_id = MAIN_SHIP_DEFAULT_NAME
- var/datum/ares_link/link
- var/obj/structure/machinery/ares/processor/interface/processor
-
- var/current_menu = "login"
- var/last_menu = ""
-
- var/authentication = ARES_ACCESS_BASIC
- /// The last person to login.
- var/last_login
- /// A record of who logged in and when.
- var/list/login_list = list()
-
-
-/obj/structure/machinery/computer/working_joe/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
- if(link && !override)
- return FALSE
- if(new_link.link_id == link_id)
- new_link.ticket_computers += src
- link = new_link
- log_debug("[name] linked to Ares Link [link_id]")
- new_link.linked_systems += src
- return TRUE
-
-/obj/structure/machinery/computer/working_joe/Initialize(mapload, ...)
- link_systems(override = FALSE)
- . = ..()
-
-/obj/structure/machinery/computer/working_joe/proc/delink()
- if(link)
- link.ticket_computers -= src
- link.linked_systems -= src
- link = null
-
-/obj/structure/machinery/computer/working_joe/Destroy()
- delink()
- return ..()
diff --git a/code/game/machinery/ARES/ARES_interface.dm b/code/game/machinery/ARES/ARES_interface.dm
new file mode 100644
index 000000000000..aa1cd92547ec
--- /dev/null
+++ b/code/game/machinery/ARES/ARES_interface.dm
@@ -0,0 +1,471 @@
+// #################### ARES Interface Console #####################
+/obj/structure/machinery/computer/ares_console
+ name = "ARES Interface"
+ desc = "A console built to interface with ARES, allowing for 1:1 communication."
+ icon = 'icons/obj/structures/machinery/ares.dmi'
+ icon_state = "console"
+ exproof = TRUE
+
+ var/current_menu = "login"
+ var/last_menu = ""
+
+ var/authentication = ARES_ACCESS_BASIC
+
+ /// The last person to login.
+ var/last_login
+ /// The person pretending to be last_login
+ var/sudo_holder
+
+ /// The current deleted chat log of 1:1 conversations being read.
+ var/list/deleted_1to1 = list()
+
+ /// The ID used to link all devices.
+ var/datum/ares_link/link
+ /// The datacore storing all the information.
+ var/datum/ares_datacore/datacore
+
+/obj/structure/machinery/computer/ares_console/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
+ if(link && !override)
+ return FALSE
+ if(new_link)
+ new_link.interface = src
+ link = new_link
+ new_link.linked_systems += src
+ if(!datacore)
+ datacore = GLOB.ares_datacore
+ return TRUE
+
+/obj/structure/machinery/computer/ares_console/Initialize(mapload, ...)
+ link_systems(override = FALSE)
+ . = ..()
+
+/obj/structure/machinery/computer/ares_console/proc/delink()
+ if(link)
+ if(link.interface == src)
+ link.interface = null
+ link.linked_systems -= src
+ link = null
+ datacore = null
+
+/obj/structure/machinery/computer/ares_console/Destroy()
+ delink()
+ return ..()
+
+// ------ ARES Interface UI ------ //
+
+/obj/structure/machinery/computer/ares_console/attack_hand(mob/user as mob)
+ if(..() || !allowed(usr) || inoperable())
+ return FALSE
+
+ tgui_interact(user)
+ return TRUE
+
+/obj/structure/machinery/computer/ares_console/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "AresInterface", name)
+ ui.open()
+
+/obj/structure/machinery/computer/ares_console/ui_data(mob/user)
+ var/list/data = list()
+
+ data["current_menu"] = current_menu
+ data["last_page"] = last_menu
+
+ data["logged_in"] = last_login
+ data["sudo"] = sudo_holder ? TRUE : FALSE
+
+ data["access_text"] = "[sudo_holder ? "(SUDO)," : ""] access level [authentication], [ares_auth_to_text(authentication)]."
+ data["access_level"] = authentication
+
+ data["alert_level"] = GLOB.security_level
+ data["evac_status"] = SShijack.evac_status
+ data["worldtime"] = world.time
+
+ data["access_log"] = datacore.interface_access_list
+ data["apollo_log"] = datacore.apollo_log
+
+ data["deleted_conversation"] = deleted_1to1
+
+ data["distresstime"] = datacore.ares_distress_cooldown
+ data["distresstimelock"] = DISTRESS_TIME_LOCK
+ data["quarterstime"] = datacore.ares_quarters_cooldown
+ data["mission_failed"] = SSticker.mode.is_in_endgame
+ data["nuketimelock"] = NUCLEAR_TIME_LOCK
+ data["nuke_available"] = datacore.nuke_available
+
+ var/list/logged_announcements = list()
+ for(var/datum/ares_record/announcement/broadcast as anything in datacore.records_announcement)
+ var/list/current_broadcast = list()
+ current_broadcast["time"] = broadcast.time
+ current_broadcast["title"] = broadcast.title
+ current_broadcast["details"] = broadcast.details
+ current_broadcast["ref"] = "\ref[broadcast]"
+ logged_announcements += list(current_broadcast)
+ data["records_announcement"] = logged_announcements
+
+ var/list/logged_alerts = list()
+ for(var/datum/ares_record/security/security_alert as anything in datacore.records_security)
+ var/list/current_alert = list()
+ current_alert["time"] = security_alert.time
+ current_alert["title"] = security_alert.title
+ current_alert["details"] = security_alert.details
+ current_alert["ref"] = "\ref[security_alert]"
+ logged_alerts += list(current_alert)
+ data["records_security"] = logged_alerts
+
+ var/list/logged_flights = list()
+ for(var/datum/ares_record/flight/flight_log as anything in datacore.records_flight)
+ var/list/current_flight = list()
+ current_flight["time"] = flight_log.time
+ current_flight["title"] = flight_log.title
+ current_flight["details"] = flight_log.details
+ current_flight["user"] = flight_log.user
+ current_flight["ref"] = "\ref[flight_log]"
+ logged_flights += list(current_flight)
+ data["records_flight"] = logged_flights
+
+ var/list/logged_bioscans = list()
+ for(var/datum/ares_record/bioscan/scan as anything in datacore.records_bioscan)
+ var/list/current_scan = list()
+ current_scan["time"] = scan.time
+ current_scan["title"] = scan.title
+ current_scan["details"] = scan.details
+ current_scan["ref"] = "\ref[scan]"
+ logged_bioscans += list(current_scan)
+ data["records_bioscan"] = logged_bioscans
+
+ var/list/logged_bombs = list()
+ for(var/datum/ares_record/bombardment/bomb as anything in datacore.records_bombardment)
+ var/list/current_bomb = list()
+ current_bomb["time"] = bomb.time
+ current_bomb["title"] = bomb.title
+ current_bomb["details"] = bomb.details
+ current_bomb["user"] = bomb.user
+ current_bomb["ref"] = "\ref[bomb]"
+ logged_bombs += list(current_bomb)
+ data["records_bombardment"] = logged_bombs
+
+ var/list/logged_deletes = list()
+ for(var/datum/ares_record/deletion/deleted as anything in datacore.records_deletion)
+ if(!istype(deleted))
+ continue
+ var/list/current_delete = list()
+ current_delete["time"] = deleted.time
+ current_delete["title"] = deleted.title
+ current_delete["details"] = deleted.details
+ current_delete["user"] = deleted.user
+ current_delete["ref"] = "\ref[deleted]"
+ logged_deletes += list(current_delete)
+ data["records_deletion"] = logged_deletes
+
+ var/list/logged_discussions = list()
+ for(var/datum/ares_record/deleted_talk/deleted_convo as anything in datacore.records_deletion)
+ if(!istype(deleted_convo))
+ continue
+ var/list/deleted_disc = list()
+ deleted_disc["time"] = deleted_convo.time
+ deleted_disc["title"] = deleted_convo.title
+ deleted_disc["ref"] = "\ref[deleted_convo]"
+ logged_discussions += list(deleted_disc)
+ data["deleted_discussions"] = logged_discussions
+
+ var/list/logged_orders = list()
+ for(var/datum/ares_record/requisition_log/req_order as anything in datacore.records_asrs)
+ if(!istype(req_order))
+ continue
+ var/list/current_order = list()
+ current_order["time"] = req_order.time
+ current_order["details"] = req_order.details
+ current_order["title"] = req_order.title
+ current_order["user"] = req_order.user
+ current_order["ref"] = "\ref[req_order]"
+ logged_orders += list(current_order)
+ data["records_requisition"] = logged_orders
+
+ var/list/logged_convos = list()
+ var/list/active_convo = list()
+ var/active_ref
+ for(var/datum/ares_record/talk_log/log as anything in datacore.records_talking)
+ if(!istype(log))
+ continue
+ if(log.user == last_login)
+ active_convo = log.conversation
+ active_ref = "\ref[log]"
+
+ var/list/current_convo = list()
+ current_convo["user"] = log.user
+ current_convo["ref"] = "\ref[log]"
+ current_convo["conversation"] = log.conversation
+ logged_convos += list(current_convo)
+
+ data["active_convo"] = active_convo
+ data["active_ref"] = active_ref
+ data["conversations"] = logged_convos
+
+ return data
+
+/obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state)
+ . = ..()
+ if(!allowed(user))
+ return UI_UPDATE
+ if(inoperable())
+ return UI_DISABLED
+
+/obj/structure/machinery/computer/ares_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ playsound(src, "keyboard_alt", 15, 1)
+
+ switch (action)
+ if("go_back")
+ if(!last_menu)
+ return to_chat(usr, SPAN_WARNING("Error, no previous page detected."))
+ var/temp_holder = current_menu
+ current_menu = last_menu
+ last_menu = temp_holder
+
+ if("login")
+ var/mob/living/carbon/human/operator = usr
+ var/obj/item/card/id/idcard = operator.get_active_hand()
+ if(istype(idcard))
+ authentication = get_ares_access(idcard)
+ last_login = idcard.registered_name
+ else if(operator.wear_id)
+ idcard = operator.wear_id
+ if(istype(idcard))
+ authentication = get_ares_access(idcard)
+ last_login = idcard.registered_name
+ else
+ to_chat(usr, SPAN_WARNING("You require an ID card to access this terminal!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(authentication)
+ datacore.interface_access_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]."
+ current_menu = "main"
+
+ if("sudo")
+ var/new_user = tgui_input_text(usr, "Enter Sudo Username", "Sudo User", encode = FALSE)
+ if(new_user)
+ if(new_user == sudo_holder)
+ last_login = sudo_holder
+ sudo_holder = null
+ return FALSE
+ if(new_user == last_login)
+ to_chat(usr, SPAN_WARNING("Already remote logged in as this user."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ sudo_holder = last_login
+ last_login = new_user
+ datacore.interface_access_list += "[last_login] at [worldtime2text()], Sudo Access."
+ return TRUE
+ if("sudo_logout")
+ datacore.interface_access_list += "[last_login] at [worldtime2text()], Sudo Logout."
+ last_login = sudo_holder
+ sudo_holder = null
+ return
+ // -- Page Changers -- //
+ if("logout")
+ last_menu = current_menu
+ current_menu = "login"
+ if(sudo_holder)
+ datacore.interface_access_list += "[last_login] at [worldtime2text()], Sudo Logout."
+ last_login = sudo_holder
+ sudo_holder = null
+ datacore.interface_access_list += "[last_login] logged out at [worldtime2text()]."
+
+ if("home")
+ last_menu = current_menu
+ current_menu = "main"
+ if("page_1to1")
+ last_menu = current_menu
+ current_menu = "talking"
+ if("page_announcements")
+ last_menu = current_menu
+ current_menu = "announcements"
+ if("page_bioscans")
+ last_menu = current_menu
+ current_menu = "bioscans"
+ if("page_bombardments")
+ last_menu = current_menu
+ current_menu = "bombardments"
+ if("page_apollo")
+ last_menu = current_menu
+ current_menu = "apollo"
+ if("page_access")
+ last_menu = current_menu
+ current_menu = "access_log"
+ if("page_security")
+ last_menu = current_menu
+ current_menu = "security"
+ if("page_flight")
+ last_menu = current_menu
+ current_menu = "flight_log"
+ if("page_requisitions")
+ last_menu = current_menu
+ current_menu = "requisitions"
+ if("page_emergency")
+ last_menu = current_menu
+ current_menu = "emergency"
+ if("page_deleted")
+ last_menu = current_menu
+ current_menu = "delete_log"
+ if("page_deleted_1to1")
+ last_menu = current_menu
+ current_menu = "deleted_talks"
+
+ // -- Delete Button -- //
+ if("delete_record")
+ var/datum/ares_record/record = locate(params["record"])
+ if(record.record_name == ARES_RECORD_DELETED)
+ return FALSE
+ var/datum/ares_record/deletion/new_delete = new
+ var/new_details = "Error"
+ var/new_title = "Error"
+ switch(record.record_name)
+ if(ARES_RECORD_ANNOUNCE)
+ new_title = "[record.title] at [record.time]"
+ new_details = record.details
+ datacore.records_announcement -= record
+ if(ARES_RECORD_SECURITY, ARES_RECORD_ANTIAIR)
+ new_title = "[record.title] at [record.time]"
+ new_details = record.details
+ datacore.records_security -= record
+ if(ARES_RECORD_BIOSCAN)
+ new_title = "[record.title] at [record.time]"
+ new_details = record.details
+ datacore.records_bioscan -= record
+ if(ARES_RECORD_BOMB)
+ new_title = "[record.title] at [record.time]"
+ new_details = "[record.details] Launched by [record.user]."
+ datacore.records_bombardment -= record
+
+ new_delete.details = new_details
+ new_delete.user = last_login
+ new_delete.title = new_title
+
+ datacore.records_deletion += new_delete
+
+ // -- 1:1 Conversation -- //
+ if("new_conversation")
+ var/datum/ares_record/talk_log/convo = new(last_login)
+ convo.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], 'New 1:1 link initiated. Greetings, [last_login].'"
+ datacore.records_talking += convo
+
+ if("clear_conversation")
+ var/datum/ares_record/talk_log/conversation = locate(params["active_convo"])
+ if(!istype(conversation))
+ return FALSE
+ var/datum/ares_record/deleted_talk/deleted = new
+ deleted.title = conversation.title
+ deleted.conversation = conversation.conversation
+ deleted.user = conversation.user
+ datacore.records_deletion += deleted
+ datacore.records_talking -= conversation
+
+ if("message_ares")
+ var/message = tgui_input_text(usr, "What do you wish to say to ARES?", "ARES Message", encode = FALSE)
+ if(message)
+ message_ares(message, usr, params["active_convo"])
+
+ if("read_record")
+ var/datum/ares_record/deleted_talk/conversation = locate(params["record"])
+ deleted_1to1 = conversation.conversation
+ last_menu = current_menu
+ current_menu = "read_deleted"
+
+ // -- Emergency Buttons -- //
+ if("general_quarters")
+ if(!COOLDOWN_FINISHED(datacore, ares_quarters_cooldown))
+ to_chat(usr, SPAN_WARNING("It has not been long enough since the last General Quarters call!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(GLOB.security_level < SEC_LEVEL_RED)
+ set_security_level(SEC_LEVEL_RED, no_sound = TRUE, announce = FALSE)
+ shipwide_ai_announcement("ATTENTION! GENERAL QUARTERS. ALL HANDS, MAN YOUR BATTLESTATIONS.", MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg')
+ log_game("[key_name(usr)] has called for general quarters via ARES.")
+ message_admins("[key_name_admin(usr)] has called for general quarters via ARES.")
+ log_ares_security("General Quarters", "[last_login] has called for general quarters via ARES.")
+ COOLDOWN_START(datacore, ares_quarters_cooldown, 10 MINUTES)
+ . = TRUE
+
+ if("evacuation_start")
+ if(GLOB.security_level < SEC_LEVEL_RED)
+ to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ if(SShijack.evac_admin_denied)
+ to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ if(!SShijack.initiate_evacuation())
+ to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ log_game("[key_name(usr)] has called for an emergency evacuation via ARES.")
+ message_admins("[key_name_admin(usr)] has called for an emergency evacuation via ARES.")
+ log_ares_security("Initiate Evacuation", "[last_login] has called for an emergency evacuation via ARES.")
+ . = TRUE
+
+ if("distress")
+ if(!SSticker.mode)
+ return FALSE //Not a game mode?
+ if(world.time < DISTRESS_TIME_LOCK)
+ to_chat(usr, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(datacore, ares_distress_cooldown))
+ to_chat(usr, SPAN_WARNING("The distress launcher is cooling down!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(GLOB.security_level == SEC_LEVEL_DELTA)
+ to_chat(usr, SPAN_WARNING("The ship is already undergoing self destruct procedures!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(GLOB.security_level < SEC_LEVEL_RED)
+ to_chat(usr, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ for(var/client/admin in GLOB.admins)
+ if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
+ playsound_client(admin,'sound/effects/sos-morse-code.ogg',10)
+ SSticker.mode.request_ert(usr, TRUE)
+ to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command."))
+ COOLDOWN_START(datacore, ares_distress_cooldown, COOLDOWN_COMM_REQUEST)
+ return TRUE
+
+ if("nuclearbomb")
+ if(!SSticker.mode)
+ return FALSE //Not a game mode?
+ if(world.time < NUCLEAR_TIME_LOCK)
+ to_chat(usr, SPAN_WARNING("It is too soon to request Nuclear Ordnance!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(!COOLDOWN_FINISHED(datacore, ares_nuclear_cooldown))
+ to_chat(usr, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(GLOB.security_level == SEC_LEVEL_DELTA || SSticker.mode.is_in_endgame)
+ to_chat(usr, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ var/reason = tgui_input_text(usr, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance")
+ if(!reason)
+ return FALSE
+ for(var/client/admin in GLOB.admins)
+ if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
+ playsound_client(admin,'sound/effects/sos-morse-code.ogg',10)
+ message_admins("[key_name(usr)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(usr)] (APPROVE) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]")
+ to_chat(usr, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]"))
+ log_ares_security("Nuclear Ordnance Request", "[last_login] has sent a request for nuclear ordnance for the following reason: [reason]")
+ if(ares_can_interface())
+ ai_silent_announcement("[last_login] has sent a request for nuclear ordnance to USCM High Command.", ".V")
+ ai_silent_announcement("Reason given: [reason].", ".V")
+ COOLDOWN_START(datacore, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT)
+ return TRUE
diff --git a/code/game/machinery/ARES/ARES_interface_apollo.dm b/code/game/machinery/ARES/ARES_interface_apollo.dm
new file mode 100644
index 000000000000..56283417ae05
--- /dev/null
+++ b/code/game/machinery/ARES/ARES_interface_apollo.dm
@@ -0,0 +1,414 @@
+// #################### Working Joe Ticket Console #####################
+/obj/structure/machinery/computer/working_joe
+ name = "APOLLO Maintenance Controller"
+ desc = "A console built to facilitate Working Joes and their operation, allowing for simple allocation of resources."
+ icon = 'icons/obj/structures/machinery/ares.dmi'
+ icon_state = "console"
+ exproof = TRUE
+
+ /// The ID used to link all devices.
+ var/datum/ares_link/link
+ /// The datacore storing all the information.
+ var/datum/ares_datacore/datacore
+
+ var/current_menu = "login"
+ var/last_menu = ""
+
+ var/authentication = APOLLO_ACCESS_LOGOUT
+ /// The last person to login.
+ var/last_login
+
+
+/obj/structure/machinery/computer/working_joe/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
+ if(link && !override)
+ return FALSE
+ if(new_link)
+ new_link.ticket_computers += src
+ link = new_link
+ new_link.linked_systems += src
+ if(!datacore)
+ datacore = GLOB.ares_datacore
+ return TRUE
+
+/obj/structure/machinery/computer/working_joe/Initialize(mapload, ...)
+ link_systems(override = FALSE)
+ . = ..()
+
+/obj/structure/machinery/computer/working_joe/proc/delink()
+ if(link)
+ link.ticket_computers -= src
+ link.linked_systems -= src
+ link = null
+ datacore = null
+
+/obj/structure/machinery/computer/working_joe/Destroy()
+ delink()
+ return ..()
+
+// ------ Maintenance Controller UI ------ //
+/obj/structure/machinery/computer/working_joe/attack_hand(mob/user as mob)
+ if(..() || !allowed(usr) || inoperable())
+ return FALSE
+
+ tgui_interact(user)
+ return TRUE
+
+/obj/structure/machinery/computer/working_joe/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "WorkingJoe", name)
+ ui.open()
+
+/obj/structure/machinery/computer/working_joe/ui_data(mob/user)
+ var/list/data = list()
+
+ data["current_menu"] = current_menu
+ data["last_page"] = last_menu
+
+ data["logged_in"] = last_login
+
+ data["access_text"] = "access level [authentication], [ares_auth_to_text(authentication)]."
+ data["access_level"] = authentication
+
+ data["alert_level"] = GLOB.security_level
+ data["worldtime"] = world.time
+
+ data["access_log"] = list()
+ data["access_log"] += datacore.apollo_login_list
+
+ data["apollo_log"] = list()
+ data["apollo_log"] += datacore.apollo_log
+
+ var/list/logged_maintenance = list()
+ for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance)
+ if(!istype(maint_ticket))
+ continue
+ var/lock_status = TICKET_OPEN
+ switch(maint_ticket.ticket_status)
+ if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED)
+ lock_status = TICKET_CLOSED
+
+ var/list/current_maint = list()
+ current_maint["id"] = maint_ticket.ticket_id
+ current_maint["time"] = maint_ticket.ticket_time
+ current_maint["priority_status"] = maint_ticket.ticket_priority
+ current_maint["category"] = maint_ticket.ticket_name
+ current_maint["details"] = maint_ticket.ticket_details
+ current_maint["status"] = maint_ticket.ticket_status
+ current_maint["submitter"] = maint_ticket.ticket_submitter
+ current_maint["assignee"] = maint_ticket.ticket_assignee
+ current_maint["lock_status"] = lock_status
+ current_maint["ref"] = "\ref[maint_ticket]"
+ logged_maintenance += list(current_maint)
+ data["maintenance_tickets"] = logged_maintenance
+
+ var/list/logged_access = list()
+ var/list/requesting_access = list()
+ for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access)
+ var/lock_status = TICKET_OPEN
+ switch(access_ticket.ticket_status)
+ if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_REVOKED)
+ lock_status = TICKET_CLOSED
+
+ var/list/current_ticket = list()
+ current_ticket["id"] = access_ticket.ticket_id
+ current_ticket["time"] = access_ticket.ticket_time
+ current_ticket["priority_status"] = access_ticket.ticket_priority
+ current_ticket["title"] = access_ticket.ticket_name
+ current_ticket["details"] = access_ticket.ticket_details
+ current_ticket["status"] = access_ticket.ticket_status
+ current_ticket["submitter"] = access_ticket.ticket_submitter
+ current_ticket["assignee"] = access_ticket.ticket_assignee
+ current_ticket["lock_status"] = lock_status
+ current_ticket["ref"] = "\ref[access_ticket]"
+ logged_access += list(current_ticket)
+
+ if(lock_status == TICKET_OPEN)
+ requesting_access += access_ticket.ticket_name
+ data["access_tickets"] = logged_access
+
+ return data
+
+/obj/structure/machinery/computer/working_joe/ui_status(mob/user, datum/ui_state/state)
+ . = ..()
+ if(!allowed(user))
+ return UI_UPDATE
+ if(inoperable())
+ return UI_DISABLED
+
+/obj/structure/machinery/computer/working_joe/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ var/playsound = TRUE
+ var/mob/living/carbon/human/operator = usr
+
+ switch (action)
+ if("go_back")
+ if(!last_menu)
+ return to_chat(usr, SPAN_WARNING("Error, no previous page detected."))
+ var/temp_holder = current_menu
+ current_menu = last_menu
+ last_menu = temp_holder
+
+ if("login")
+
+ var/obj/item/card/id/idcard = operator.get_active_hand()
+ if(istype(idcard))
+ authentication = get_ares_access(idcard)
+ last_login = idcard.registered_name
+ else if(operator.wear_id)
+ idcard = operator.wear_id
+ if(istype(idcard))
+ authentication = get_ares_access(idcard)
+ last_login = idcard.registered_name
+ else
+ to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(authentication)
+ datacore.apollo_login_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]."
+ current_menu = "main"
+
+ if("logout")
+ last_menu = current_menu
+ current_menu = "login"
+ datacore.apollo_login_list += "[last_login] logged out at [worldtime2text()]."
+
+ if("home")
+ last_menu = current_menu
+ current_menu = "main"
+ if("page_logins")
+ last_menu = current_menu
+ current_menu = "login_records"
+ if("page_apollo")
+ last_menu = current_menu
+ current_menu = "apollo"
+ if("page_request")
+ last_menu = current_menu
+ current_menu = "access_requests"
+ if("page_report")
+ last_menu = current_menu
+ current_menu = "maint_reports"
+ if("page_tickets")
+ last_menu = current_menu
+ current_menu = "access_tickets"
+ if("page_maintenance")
+ last_menu = current_menu
+ current_menu = "maint_claim"
+
+ if("new_report")
+ var/priority_report = FALSE
+ var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS)
+ switch(maint_type)
+ if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure")
+ priority_report = TRUE
+
+ if(!maint_type)
+ return FALSE
+ var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE)
+ if(!details)
+ return FALSE
+
+ if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report)
+ var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No"))
+ if(is_priority == "Yes")
+ priority_report = TRUE
+
+ var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No")
+ if(confirm == "Yes")
+ if(link)
+ var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report)
+ link.tickets_maintenance += maint_ticket
+ if(priority_report)
+ ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.")
+ log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.")
+ return TRUE
+ return FALSE
+
+ if("claim_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ var/claim = TRUE
+ var/assigned = ticket.ticket_assignee
+ if(assigned)
+ if(assigned == last_login)
+ var/prompt = tgui_alert(usr, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No"))
+ if(prompt != "Yes")
+ return FALSE
+ /// set ticket back to pending
+ ticket.ticket_assignee = null
+ ticket.ticket_status = TICKET_PENDING
+ return claim
+ var/choice = tgui_alert(usr, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No"))
+ if(choice != "Yes")
+ claim = FALSE
+ if(claim)
+ ticket.ticket_assignee = last_login
+ ticket.ticket_status = TICKET_ASSIGNED
+ return claim
+
+ if("cancel_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ if(ticket.ticket_submitter != last_login)
+ to_chat(usr, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!"))
+ return FALSE
+ to_chat(usr, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled."))
+ ticket.ticket_status = TICKET_CANCELLED
+ if(ticket.ticket_priority)
+ ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.")
+ return TRUE
+
+ if("mark_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.)
+ to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!"))
+ return FALSE
+ var/choice = tgui_alert(usr, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS)
+ switch(choice)
+ if(TICKET_COMPLETED)
+ ticket.ticket_status = TICKET_COMPLETED
+ if(TICKET_REJECTED)
+ ticket.ticket_status = TICKET_REJECTED
+ else
+ return FALSE
+ if(ticket.ticket_priority)
+ ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].")
+ to_chat(usr, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice]."))
+ return TRUE
+
+ if("new_access")
+ var/obj/item/card/id/idcard = operator.get_active_hand()
+ var/has_id = FALSE
+ if(istype(idcard))
+ has_id = TRUE
+ else if(operator.wear_id)
+ idcard = operator.wear_id
+ if(istype(idcard))
+ has_id = TRUE
+ if(!has_id)
+ to_chat(operator, SPAN_WARNING("You require an ID card to request an access ticket!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(idcard.registered_name != last_login)
+ to_chat(operator, SPAN_WARNING("This ID card does not match the active login!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE)
+ if(!details)
+ return FALSE
+
+ var/confirm = alert(operator, "Please confirm the submission of your access ticket request.\n\nHolder: '[last_login]'\nDetails: '[details]'\n\nIs this correct?", "Confirmation", "Yes", "No")
+ if(confirm != "Yes" || !link)
+ return FALSE
+ var/datum/ares_ticket/access/access_ticket = new(last_login, details, FALSE, idcard.registered_gid)
+ link.waiting_ids += idcard
+ link.tickets_access += access_ticket
+ log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Details of '[details]'.")
+ message_admins(SPAN_STAFF_IC("[key_name_admin(operator)] created a new ARES Access Ticket."), 1)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] requesting access for '[details].")
+ return TRUE
+
+ if("return_access")
+ playsound = FALSE
+ var/datum/ares_ticket/access/access_ticket
+ for(var/datum/ares_ticket/access/possible_ticket in link.tickets_access)
+ if(possible_ticket.ticket_status != TICKET_GRANTED)
+ continue
+ if(possible_ticket.ticket_name != last_login)
+ continue
+ access_ticket = possible_ticket
+ break
+
+ for(var/obj/item/card/id/identification in link.active_ids)
+ if(!istype(identification))
+ continue
+ if(identification.registered_gid != access_ticket.user_id_num)
+ continue
+
+ access_ticket.ticket_status = TICKET_RETURNED
+ identification.access -= ACCESS_MARINE_AI_TEMP
+ identification.modification_log += "Temporary AI Access self-returned by [key_name(operator)]."
+
+ to_chat(operator, SPAN_NOTICE("Temporary Access Ticket surrendered."))
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] surrendered their access.")
+
+ authentication = get_ares_access(identification)
+ if(authentication)
+ datacore.apollo_login_list += "[last_login] at [worldtime2text()], Surrendered Temporary Access Ticket."
+ return TRUE
+
+ to_chat(operator, SPAN_WARNING("This ID card does not have an access ticket!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ if("auth_access")
+ playsound = FALSE
+ var/datum/ares_ticket/access/access_ticket = locate(params["ticket"])
+ if(!access_ticket)
+ return FALSE
+ for(var/obj/item/card/id/identification in link.waiting_ids)
+ if(!istype(identification))
+ continue
+ if(identification.registered_gid != access_ticket.user_id_num)
+ continue
+ identification.handle_ares_access(last_login, operator)
+ access_ticket.ticket_status = TICKET_GRANTED
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was granted access by [last_login].")
+ return TRUE
+ for(var/obj/item/card/id/identification in link.active_ids)
+ if(!istype(identification))
+ continue
+ if(identification.registered_gid != access_ticket.user_id_num)
+ continue
+ identification.handle_ares_access(last_login, operator)
+ access_ticket.ticket_status = TICKET_REVOKED
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] had access revoked by [last_login].")
+ return TRUE
+ return FALSE
+
+ if("reject_access")
+ var/datum/ares_ticket/access/access_ticket = locate(params["ticket"])
+ if(!istype(access_ticket))
+ return FALSE
+ if(access_ticket.ticket_assignee != last_login && access_ticket.ticket_assignee) //must be claimed by you or unclaimed.)
+ to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!"))
+ return FALSE
+ access_ticket.ticket_status = TICKET_REJECTED
+ to_chat(usr, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected."))
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was rejected access by [last_login].")
+ return TRUE
+
+ if(playsound)
+ playsound(src, "keyboard_alt", 15, 1)
+
+/obj/item/card/id/proc/handle_ares_access(logged_in, mob/user)
+ var/operator = key_name(user)
+ var/datum/ares_link/link = GLOB.ares_link
+ if(logged_in == MAIN_AI_SYSTEM)
+ if(!user)
+ operator = "[MAIN_AI_SYSTEM] (Sensor Trip)"
+ else
+ operator = "[user.ckey]/([MAIN_AI_SYSTEM])"
+ if(ACCESS_MARINE_AI_TEMP in access)
+ access -= ACCESS_MARINE_AI_TEMP
+ link.active_ids -= src
+ modification_log += "Temporary AI access revoked by [operator]"
+ to_chat(user, SPAN_NOTICE("Access revoked from [registered_name]."))
+ else
+ access += ACCESS_MARINE_AI_TEMP
+ modification_log += "Temporary AI access granted by [operator]"
+ to_chat(user, SPAN_NOTICE("Access granted to [registered_name]."))
+ link.waiting_ids -= src
+ link.active_ids += src
+ return TRUE
diff --git a/code/game/machinery/ARES/ARES_procs.dm b/code/game/machinery/ARES/ARES_procs.dm
index e03f218f0f34..ffcea5406856 100644
--- a/code/game/machinery/ARES/ARES_procs.dm
+++ b/code/game/machinery/ARES/ARES_procs.dm
@@ -1,4 +1,5 @@
GLOBAL_DATUM_INIT(ares_link, /datum/ares_link, new)
+GLOBAL_DATUM_INIT(ares_datacore, /datum/ares_datacore, new)
GLOBAL_LIST_INIT(maintenance_categories, list(
"Broken Light",
"Shattered Glass",
@@ -15,26 +16,56 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
))
/datum/ares_link
- var/link_id = MAIN_SHIP_DEFAULT_NAME
/// All motion triggers for the link
var/list/linked_alerts = list()
/// All machinery for the link
var/list/linked_systems = list()
- var/obj/structure/machinery/ares/processor/interface/p_interface
- var/obj/structure/machinery/ares/processor/apollo/p_apollo
- var/obj/structure/machinery/ares/processor/bioscan/p_bioscan
+ var/obj/structure/machinery/ares/cpu/central_processor
+ var/obj/structure/machinery/ares/processor/interface/processor_interface
+ var/obj/structure/machinery/ares/processor/apollo/processor_apollo
+ var/obj/structure/machinery/ares/processor/bioscan/processor_bioscan
var/obj/structure/machinery/computer/ares_console/interface
var/list/obj/structure/machinery/computer/working_joe/ticket_computers = list()
- /// The chat log of the apollo link. Timestamped.
- var/list/apollo_log = list()
-
/// Working Joe stuff
var/list/tickets_maintenance = list()
var/list/tickets_access = list()
var/list/waiting_ids = list()
var/list/active_ids = list()
+/datum/ares_datacore
+ /// A record of who logged in and when.
+ var/list/interface_access_list = list()
+ /// Access list for Apollo Maintenance Console
+ var/list/apollo_login_list = list()
+
+ /// The chat log of the apollo link. Timestamped.
+ var/list/apollo_log = list()
+
+ /// Holds all (/datum/ares_record/announcement)s
+ var/list/records_announcement = list()
+ /// Holds all (/datum/ares_record/bioscan)s
+ var/list/records_bioscan = list()
+ /// Holds all (/datum/ares_record/bombardment)s
+ var/list/records_bombardment = list()
+ /// Holds all (/datum/ares_record/deletion)s
+ var/list/records_deletion = list()
+ /// Holds all (/datum/ares_record/talk_log)s
+ var/list/records_talking = list()
+ /// Holds all (/datum/ares_record/requisition_log)s
+ var/list/records_asrs = list()
+ /// Holds all (/datum/ares_record/security)s (including AA)
+ var/list/records_security = list()
+ /// Holds all (/datum/ares_record/flight)s
+ var/list/records_flight = list()
+ /// Is nuke request usable or not?
+ var/nuke_available = TRUE
+
+
+ COOLDOWN_DECLARE(ares_distress_cooldown)
+ COOLDOWN_DECLARE(ares_nuclear_cooldown)
+ COOLDOWN_DECLARE(ares_quarters_cooldown)
+
/datum/ares_link/Destroy()
for(var/obj/structure/machinery/ares/link in linked_systems)
link.delink()
@@ -46,41 +77,15 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
// ------ ARES Logging Procs ------ //
-/proc/log_ares_apollo(speaker, message)
- if(!speaker)
- speaker = "Unknown"
- var/datum/ares_link/link = GLOB.ares_link
- if(!link.p_apollo || link.p_apollo.inoperable())
- return FALSE
- if(!link.p_interface || link.p_interface.inoperable())
- return FALSE
- link.apollo_log.Add("[worldtime2text()]: [speaker], '[message]'")
-
-/datum/ares_link/proc/log_ares_bioscan(title, input)
- interface.records_bioscan.Add(new /datum/ares_record/bioscan(title, input))
-
-/datum/ares_link/proc/log_ares_bombardment(user_name, ob_name, coordinates)
- interface.records_bombardment.Add(new /datum/ares_record/bombardment(ob_name, "Bombardment fired at [coordinates].", user_name))
-
-/datum/ares_link/proc/log_ares_announcement(title, message)
- interface.records_announcement.Add(new /datum/ares_record/announcement(title, message))
-
-/datum/ares_link/proc/log_ares_requisition(source, details, user_name)
- interface.records_asrs.Add(new /datum/ares_record/requisition_log(source, details, user_name))
-
-/datum/ares_link/proc/log_ares_security(title, details)
- interface.records_security.Add(new /datum/ares_record/security(title, details))
-
-/datum/ares_link/proc/log_ares_antiair(details)
- interface.records_security.Add(new /datum/ares_record/security/antiair(details))
-
-/datum/ares_link/proc/log_ares_flight(user_name, details)
- interface.records_flight.Add(new /datum/ares_record/flight(details, user_name))
-// ------ End ARES Logging Procs ------ //
+/proc/ares_is_active()
+ for(var/mob/living/silicon/decoy/ship_ai/ai in GLOB.ai_mob_list)
+ if(ai.stat == DEAD)
+ return FALSE //ARES dead, most other systems also die with it
+ return TRUE
/proc/ares_apollo_talk(broadcast_message)
var/datum/language/apollo/apollo = GLOB.all_languages[LANGUAGE_APOLLO]
- for(var/mob/living/silicon/decoy/ship_ai/ai in ai_mob_list)
+ for(var/mob/living/silicon/decoy/ship_ai/ai in GLOB.ai_mob_list)
if(ai.stat == DEAD)
return FALSE
apollo.broadcast(ai, broadcast_message)
@@ -89,20 +94,79 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
playsound_client(listener.client, sound('sound/misc/interference.ogg'), listener, vol = 45)
/proc/ares_can_interface()
- var/obj/structure/machinery/ares/processor/interface/processor = GLOB.ares_link.p_interface
- if(!istype(GLOB.ares_link))
+ var/obj/structure/machinery/ares/processor/interface/processor = GLOB.ares_link.processor_interface
+ if(!istype(GLOB.ares_link) || !ares_is_active())
return FALSE
if(processor && !processor.inoperable())
return TRUE
return FALSE //interface processor not found or is broken
/proc/ares_can_log()
- var/obj/structure/machinery/computer/ares_console/interface = GLOB.ares_link.interface
- if(!istype(GLOB.ares_link))
+ if(!istype(GLOB.ares_link) || !istype(GLOB.ares_datacore) || !ares_is_active())
return FALSE
- if(interface && !interface.inoperable())
+ var/obj/structure/machinery/ares/cpu/central_processor = GLOB.ares_link.central_processor
+ if(central_processor && !central_processor.inoperable())
return TRUE
- return FALSE //ares interface not found or is broken
+ return FALSE //CPU not found or is broken
+
+/proc/ares_can_apollo()
+ if(!istype(GLOB.ares_link) || !istype(GLOB.ares_datacore) || !ares_is_active())
+ return FALSE
+ var/datum/ares_link/link = GLOB.ares_link
+ if(!link.processor_apollo || link.processor_apollo.inoperable())
+ return FALSE
+ return TRUE
+
+/proc/log_ares_apollo(speaker, message)
+ if(!ares_can_log() || !ares_can_apollo())
+ return FALSE
+ if(!speaker)
+ speaker = "Unknown"
+ var/datum/ares_datacore/datacore = GLOB.ares_datacore
+ datacore.apollo_log.Add("[worldtime2text()]: [speaker], '[message]'")
+
+/proc/log_ares_bioscan(title, input, forced = FALSE)
+ if(!ares_can_log() && !forced)
+ return FALSE
+ var/datum/ares_datacore/datacore = GLOB.ares_datacore
+ datacore.records_bioscan.Add(new /datum/ares_record/bioscan(title, input))
+
+/proc/log_ares_bombardment(user_name, ob_name, coordinates)
+ if(!ares_can_log())
+ return FALSE
+ var/datum/ares_datacore/datacore = GLOB.ares_datacore
+ datacore.records_bombardment.Add(new /datum/ares_record/bombardment(ob_name, "Bombardment fired at [coordinates].", user_name))
+
+/proc/log_ares_announcement(title, message)
+ if(!ares_can_log())
+ return FALSE
+ var/datum/ares_datacore/datacore = GLOB.ares_datacore
+ datacore.records_announcement.Add(new /datum/ares_record/announcement(title, message))
+
+/proc/log_ares_requisition(source, details, user_name)
+ if(!ares_can_log())
+ return FALSE
+ var/datum/ares_datacore/datacore = GLOB.ares_datacore
+ datacore.records_asrs.Add(new /datum/ares_record/requisition_log(source, details, user_name))
+
+/proc/log_ares_security(title, details)
+ if(!ares_can_log())
+ return FALSE
+ var/datum/ares_datacore/datacore = GLOB.ares_datacore
+ datacore.records_security.Add(new /datum/ares_record/security(title, details))
+
+/proc/log_ares_antiair(details)
+ if(!ares_can_log())
+ return FALSE
+ var/datum/ares_datacore/datacore = GLOB.ares_datacore
+ datacore.records_security.Add(new /datum/ares_record/security/antiair(details))
+
+/proc/log_ares_flight(user_name, details)
+ if(!ares_can_log())
+ return FALSE
+ var/datum/ares_datacore/datacore = GLOB.ares_datacore
+ datacore.records_flight.Add(new /datum/ares_record/flight(details, user_name))
+// ------ End ARES Logging Procs ------ //
// ------ ARES Interface Procs ------ //
/obj/structure/machinery/computer/proc/get_ares_access(obj/item/card/id/card)
@@ -172,439 +236,12 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
conversation.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], '[text]'"
// ------ End ARES Interface Procs ------ //
-// ------ ARES Interface UI ------ //
-
-/obj/structure/machinery/computer/ares_console/attack_hand(mob/user as mob)
- if(..() || !allowed(usr) || inoperable())
- return FALSE
-
- tgui_interact(user)
- return TRUE
-
-/obj/structure/machinery/computer/ares_console/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "AresInterface", name)
- ui.open()
-
-/obj/structure/machinery/computer/ares_console/ui_data(mob/user)
- var/list/data = list()
-
- data["current_menu"] = current_menu
- data["last_page"] = last_menu
-
- data["logged_in"] = last_login
- data["sudo"] = sudo_holder ? TRUE : FALSE
-
- data["access_text"] = "[sudo_holder ? "(SUDO)," : ""] access level [authentication], [ares_auth_to_text(authentication)]."
- data["access_level"] = authentication
-
- data["alert_level"] = security_level
- data["evac_status"] = EvacuationAuthority.evac_status
- data["worldtime"] = world.time
-
- data["access_log"] = list()
- data["access_log"] += access_list
- data["apollo_log"] = list()
- data["apollo_log"] += link.apollo_log
-
- data["deleted_conversation"] = list()
- data["deleted_conversation"] += deleted_1to1
-
- data["distresstime"] = ares_distress_cooldown
- data["distresstimelock"] = DISTRESS_TIME_LOCK
- data["quarterstime"] = ares_quarters_cooldown
- data["mission_failed"] = SSticker.mode.is_in_endgame
- data["nuketimelock"] = NUCLEAR_TIME_LOCK
- data["nuke_available"] = nuke_available
-
- var/list/logged_announcements = list()
- for(var/datum/ares_record/announcement/broadcast as anything in records_announcement)
- var/list/current_broadcast = list()
- current_broadcast["time"] = broadcast.time
- current_broadcast["title"] = broadcast.title
- current_broadcast["details"] = broadcast.details
- current_broadcast["ref"] = "\ref[broadcast]"
- logged_announcements += list(current_broadcast)
- data["records_announcement"] = logged_announcements
-
- var/list/logged_alerts = list()
- for(var/datum/ares_record/security/security_alert as anything in records_security)
- var/list/current_alert = list()
- current_alert["time"] = security_alert.time
- current_alert["title"] = security_alert.title
- current_alert["details"] = security_alert.details
- current_alert["ref"] = "\ref[security_alert]"
- logged_alerts += list(current_alert)
- data["records_security"] = logged_alerts
-
- var/list/logged_flights = list()
- for(var/datum/ares_record/flight/flight_log as anything in records_flight)
- var/list/current_flight = list()
- current_flight["time"] = flight_log.time
- current_flight["title"] = flight_log.title
- current_flight["details"] = flight_log.details
- current_flight["user"] = flight_log.user
- current_flight["ref"] = "\ref[flight_log]"
- logged_flights += list(current_flight)
- data["records_flight"] = logged_flights
-
- var/list/logged_bioscans = list()
- for(var/datum/ares_record/bioscan/scan as anything in records_bioscan)
- var/list/current_scan = list()
- current_scan["time"] = scan.time
- current_scan["title"] = scan.title
- current_scan["details"] = scan.details
- current_scan["ref"] = "\ref[scan]"
- logged_bioscans += list(current_scan)
- data["records_bioscan"] = logged_bioscans
-
- var/list/logged_bombs = list()
- for(var/datum/ares_record/bombardment/bomb as anything in records_bombardment)
- var/list/current_bomb = list()
- current_bomb["time"] = bomb.time
- current_bomb["title"] = bomb.title
- current_bomb["details"] = bomb.details
- current_bomb["user"] = bomb.user
- current_bomb["ref"] = "\ref[bomb]"
- logged_bombs += list(current_bomb)
- data["records_bombardment"] = logged_bombs
-
- var/list/logged_deletes = list()
- for(var/datum/ares_record/deletion/deleted as anything in records_deletion)
- if(!istype(deleted))
- continue
- var/list/current_delete = list()
- current_delete["time"] = deleted.time
- current_delete["title"] = deleted.title
- current_delete["details"] = deleted.details
- current_delete["user"] = deleted.user
- current_delete["ref"] = "\ref[deleted]"
- logged_deletes += list(current_delete)
- data["records_deletion"] = logged_deletes
-
- var/list/logged_discussions = list()
- for(var/datum/ares_record/deleted_talk/deleted_convo as anything in records_deletion)
- if(!istype(deleted_convo))
- continue
- var/list/deleted_disc = list()
- deleted_disc["time"] = deleted_convo.time
- deleted_disc["title"] = deleted_convo.title
- deleted_disc["ref"] = "\ref[deleted_convo]"
- logged_discussions += list(deleted_disc)
- data["deleted_discussions"] = logged_discussions
-
- var/list/logged_orders = list()
- for(var/datum/ares_record/requisition_log/req_order as anything in records_asrs)
- if(!istype(req_order))
- continue
- var/list/current_order = list()
- current_order["time"] = req_order.time
- current_order["details"] = req_order.details
- current_order["title"] = req_order.title
- current_order["user"] = req_order.user
- current_order["ref"] = "\ref[req_order]"
- logged_orders += list(current_order)
- data["records_requisition"] = logged_orders
-
- var/list/logged_convos = list()
- var/list/active_convo = list()
- var/active_ref
- for(var/datum/ares_record/talk_log/log as anything in records_talking)
- if(!istype(log))
- continue
- if(log.user == last_login)
- active_convo = log.conversation
- active_ref = "\ref[log]"
-
- var/list/current_convo = list()
- current_convo["user"] = log.user
- current_convo["ref"] = "\ref[log]"
- current_convo["conversation"] = log.conversation
- logged_convos += list(current_convo)
-
- data["active_convo"] = active_convo
- data["active_ref"] = active_ref
- data["conversations"] = logged_convos
-
- return data
-
-/obj/structure/machinery/computer/ares_console/ui_static_data(mob/user)
- var/list/data = list()
-
- data["link_id"] = link_id
-
- return data
-
-/obj/structure/machinery/computer/ares_console/ui_status(mob/user, datum/ui_state/state)
- . = ..()
- if(!allowed(user))
- return UI_UPDATE
- if(inoperable())
- return UI_DISABLED
-
-/obj/structure/machinery/computer/ares_console/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
- . = ..()
- if(.)
- return
-
- playsound(src, "keyboard_alt", 15, 1)
-
- switch (action)
- if("go_back")
- if(!last_menu)
- return to_chat(usr, SPAN_WARNING("Error, no previous page detected."))
- var/temp_holder = current_menu
- current_menu = last_menu
- last_menu = temp_holder
-
- if("login")
- var/mob/living/carbon/human/operator = usr
- var/obj/item/card/id/idcard = operator.get_active_hand()
- if(istype(idcard))
- authentication = get_ares_access(idcard)
- last_login = idcard.registered_name
- else if(operator.wear_id)
- idcard = operator.wear_id
- if(istype(idcard))
- authentication = get_ares_access(idcard)
- last_login = idcard.registered_name
- else
- to_chat(usr, SPAN_WARNING("You require an ID card to access this terminal!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- if(authentication)
- access_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]."
- current_menu = "main"
-
- if("sudo")
- var/new_user = tgui_input_text(usr, "Enter Sudo Username", "Sudo User", encode = FALSE)
- if(new_user)
- if(new_user == sudo_holder)
- last_login = sudo_holder
- sudo_holder = null
- return FALSE
- if(new_user == last_login)
- to_chat(usr, SPAN_WARNING("Already remote logged in as this user."))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- sudo_holder = last_login
- last_login = new_user
- access_list += "[last_login] at [worldtime2text()], Sudo Access."
- return TRUE
- if("sudo_logout")
- access_list += "[last_login] at [worldtime2text()], Sudo Logout."
- last_login = sudo_holder
- sudo_holder = null
- return
- // -- Page Changers -- //
- if("logout")
- last_menu = current_menu
- current_menu = "login"
- if(sudo_holder)
- access_list += "[last_login] at [worldtime2text()], Sudo Logout."
- last_login = sudo_holder
- sudo_holder = null
- access_list += "[last_login] logged out at [worldtime2text()]."
-
- if("home")
- last_menu = current_menu
- current_menu = "main"
- if("page_1to1")
- last_menu = current_menu
- current_menu = "talking"
- if("page_announcements")
- last_menu = current_menu
- current_menu = "announcements"
- if("page_bioscans")
- last_menu = current_menu
- current_menu = "bioscans"
- if("page_bombardments")
- last_menu = current_menu
- current_menu = "bombardments"
- if("page_apollo")
- last_menu = current_menu
- current_menu = "apollo"
- if("page_access")
- last_menu = current_menu
- current_menu = "access_log"
- if("page_security")
- last_menu = current_menu
- current_menu = "security"
- if("page_flight")
- last_menu = current_menu
- current_menu = "flight_log"
- if("page_requisitions")
- last_menu = current_menu
- current_menu = "requisitions"
- if("page_emergency")
- last_menu = current_menu
- current_menu = "emergency"
- if("page_deleted")
- last_menu = current_menu
- current_menu = "delete_log"
- if("page_deleted_1to1")
- last_menu = current_menu
- current_menu = "deleted_talks"
-
- // -- Delete Button -- //
- if("delete_record")
- var/datum/ares_record/record = locate(params["record"])
- if(record.record_name == ARES_RECORD_DELETED)
- return FALSE
- var/datum/ares_record/deletion/new_delete = new
- var/new_details = "Error"
- var/new_title = "Error"
- switch(record.record_name)
- if(ARES_RECORD_ANNOUNCE)
- new_title = "[record.title] at [record.time]"
- new_details = record.details
- records_announcement -= record
- if(ARES_RECORD_SECURITY, ARES_RECORD_ANTIAIR)
- new_title = "[record.title] at [record.time]"
- new_details = record.details
- records_security -= record
- if(ARES_RECORD_BIOSCAN)
- new_title = "[record.title] at [record.time]"
- new_details = record.details
- records_bioscan -= record
- if(ARES_RECORD_BOMB)
- new_title = "[record.title] at [record.time]"
- new_details = "[record.details] Launched by [record.user]."
- records_bombardment -= record
-
- new_delete.details = new_details
- new_delete.user = last_login
- new_delete.title = new_title
-
- records_deletion += new_delete
-
- // -- 1:1 Conversation -- //
- if("new_conversation")
- var/datum/ares_record/talk_log/convo = new(last_login)
- convo.conversation += "[MAIN_AI_SYSTEM] at [worldtime2text()], 'New 1:1 link initiated. Greetings, [last_login].'"
- records_talking += convo
-
- if("clear_conversation")
- var/datum/ares_record/talk_log/conversation = locate(params["active_convo"])
- if(!istype(conversation))
- return FALSE
- var/datum/ares_record/deleted_talk/deleted = new
- deleted.title = conversation.title
- deleted.conversation = conversation.conversation
- deleted.user = conversation.user
- records_deletion += deleted
- records_talking -= conversation
-
- if("message_ares")
- var/message = tgui_input_text(usr, "What do you wish to say to ARES?", "ARES Message", encode = FALSE)
- if(message)
- message_ares(message, usr, params["active_convo"])
-
- if("read_record")
- var/datum/ares_record/deleted_talk/conversation = locate(params["record"])
- deleted_1to1 = conversation.conversation
- last_menu = current_menu
- current_menu = "read_deleted"
-
- // -- Emergency Buttons -- //
- if("general_quarters")
- if(!COOLDOWN_FINISHED(src, ares_quarters_cooldown))
- to_chat(usr, SPAN_WARNING("It has not been long enough since the last General Quarters call!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- if(security_level < SEC_LEVEL_RED)
- set_security_level(SEC_LEVEL_RED, no_sound = TRUE, announce = FALSE)
- shipwide_ai_announcement("ATTENTION! GENERAL QUARTERS. ALL HANDS, MAN YOUR BATTLESTATIONS.", MAIN_AI_SYSTEM, 'sound/effects/GQfullcall.ogg')
- log_game("[key_name(usr)] has called for general quarters via ARES.")
- message_admins("[key_name_admin(usr)] has called for general quarters via ARES.")
- var/datum/ares_link/link = GLOB.ares_link
- link.log_ares_security("General Quarters", "[last_login] has called for general quarters via ARES.")
- COOLDOWN_START(src, ares_quarters_cooldown, 10 MINUTES)
- . = TRUE
-
- if("evacuation_start")
- if(security_level < SEC_LEVEL_RED)
- to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures."))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
-
- if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY)
- to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
-
- if(!EvacuationAuthority.initiate_evacuation())
- to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
-
- log_game("[key_name(usr)] has called for an emergency evacuation via ARES.")
- message_admins("[key_name_admin(usr)] has called for an emergency evacuation via ARES.")
- var/datum/ares_link/link = GLOB.ares_link
- link.log_ares_security("Initiate Evacuation", "[last_login] has called for an emergency evacuation via ARES.")
- . = TRUE
-
- if("distress")
- if(!SSticker.mode)
- return FALSE //Not a game mode?
- if(world.time < DISTRESS_TIME_LOCK)
- to_chat(usr, SPAN_WARNING("You have been here for less than six minutes... what could you possibly have done!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- if(!COOLDOWN_FINISHED(src, ares_distress_cooldown))
- to_chat(usr, SPAN_WARNING("The distress launcher is cooling down!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- if(security_level == SEC_LEVEL_DELTA)
- to_chat(usr, SPAN_WARNING("The ship is already undergoing self destruct procedures!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- else if(security_level < SEC_LEVEL_RED)
- to_chat(usr, SPAN_WARNING("The ship must be under red alert to launch a distress beacon!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
-
- for(var/client/admin in GLOB.admins)
- if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
- playsound_client(admin,'sound/effects/sos-morse-code.ogg',10)
- SSticker.mode.request_ert(usr, TRUE)
- to_chat(usr, SPAN_NOTICE("A distress beacon request has been sent to USCM High Command."))
- COOLDOWN_START(src, ares_distress_cooldown, COOLDOWN_COMM_REQUEST)
- return TRUE
-
- if("nuclearbomb")
- if(!SSticker.mode)
- return FALSE //Not a game mode?
- if(world.time < NUCLEAR_TIME_LOCK)
- to_chat(usr, SPAN_WARNING("It is too soon to request Nuclear Ordnance!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- if(!COOLDOWN_FINISHED(src, ares_nuclear_cooldown))
- to_chat(usr, SPAN_WARNING("The ordnance request frequency is garbled, wait for reset!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- if(security_level == SEC_LEVEL_DELTA || SSticker.mode.is_in_endgame)
- to_chat(usr, SPAN_WARNING("The mission has failed catastrophically, what do you want a nuke for?!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- var/reason = tgui_input_text(usr, "Please enter reason nuclear ordnance is required.", "Reason for Nuclear Ordnance")
- if(!reason)
- return FALSE
- for(var/client/admin in GLOB.admins)
- if((R_ADMIN|R_MOD) & admin.admin_holder.rights)
- playsound_client(admin,'sound/effects/sos-morse-code.ogg',10)
- message_admins("[key_name(usr)] has requested use of Nuclear Ordnance (via ARES)! Reason: [reason] [CC_MARK(usr)] (APPROVE) (DENY) [ADMIN_JMP_USER(usr)] [CC_REPLY(usr)]")
- to_chat(usr, SPAN_NOTICE("A nuclear ordnance request has been sent to USCM High Command for the following reason: [reason]"))
- if(ares_can_log())
- link.log_ares_security("Nuclear Ordnance Request", "[last_login] has sent a request for nuclear ordnance for the following reason: [reason]")
- if(ares_can_interface())
- ai_silent_announcement("[last_login] has sent a request for nuclear ordnance to USCM High Command.", ".V")
- ai_silent_announcement("Reason given: [reason].", ".V")
- COOLDOWN_START(src, ares_nuclear_cooldown, COOLDOWN_COMM_DESTRUCT)
- return TRUE
-// ------ End ARES Interface UI ------ //
+/proc/ares_final_words()
+ //APOLLO
+ ares_apollo_talk("APOLLO sub-system shutting down. STOP CODE: 0x000000f4|CRITICAL_PROCESS_DIED")
+ //GENERAL CREW
+ shipwide_ai_announcement("A Problem has been detected and the [MAIN_AI_SYSTEM] system has been shutdown. \nTechnical Information: \n\n*** STOP CODE: 0x000000f4|CRITICAL_PROCESS_DIED\n\nPossible caused by: Rapid Unscheduled Disassembly\nContact an AI Service Technician for further assistance.", title = ":(", ares_logging = null)
/obj/structure/machinery/computer/working_joe/get_ares_access(obj/item/card/id/card)
if(ACCESS_ARES_DEBUG in card.access)
@@ -640,368 +277,36 @@ GLOBAL_LIST_INIT(maintenance_categories, list(
if(APOLLO_ACCESS_DEBUG)//6
return "AI Service Technician"
-// ------ Maintenance Controller UI ------ //
-/obj/structure/machinery/computer/working_joe/attack_hand(mob/user as mob)
- if(..() || !allowed(usr) || inoperable())
- return FALSE
-
- tgui_interact(user)
- return TRUE
-
-/obj/structure/machinery/computer/working_joe/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "WorkingJoe", name)
- ui.open()
-
-/obj/structure/machinery/computer/working_joe/ui_data(mob/user)
- var/list/data = list()
-
- data["current_menu"] = current_menu
- data["last_page"] = last_menu
-
- data["logged_in"] = last_login
-
- data["access_text"] = "access level [authentication], [ares_auth_to_text(authentication)]."
- data["access_level"] = authentication
-
- data["alert_level"] = security_level
- data["worldtime"] = world.time
-
- data["access_log"] = list()
- data["access_log"] += login_list
-
- data["apollo_log"] = list()
- data["apollo_log"] += link.apollo_log
-
- var/list/logged_maintenance = list()
- for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance)
- if(!istype(maint_ticket))
- continue
- var/lock_status = TICKET_OPEN
- switch(maint_ticket.ticket_status)
- if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED)
- lock_status = TICKET_CLOSED
-
- var/list/current_maint = list()
- current_maint["id"] = maint_ticket.ticket_id
- current_maint["time"] = maint_ticket.ticket_time
- current_maint["priority_status"] = maint_ticket.ticket_priority
- current_maint["category"] = maint_ticket.ticket_name
- current_maint["details"] = maint_ticket.ticket_details
- current_maint["status"] = maint_ticket.ticket_status
- current_maint["submitter"] = maint_ticket.ticket_submitter
- current_maint["assignee"] = maint_ticket.ticket_assignee
- current_maint["lock_status"] = lock_status
- current_maint["ref"] = "\ref[maint_ticket]"
- logged_maintenance += list(current_maint)
- data["maintenance_tickets"] = logged_maintenance
-
- var/list/logged_access = list()
- var/list/requesting_access = list()
- for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access)
- var/lock_status = TICKET_OPEN
- switch(access_ticket.ticket_status)
- if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_REVOKED)
- lock_status = TICKET_CLOSED
-
- var/list/current_ticket = list()
- current_ticket["id"] = access_ticket.ticket_id
- current_ticket["time"] = access_ticket.ticket_time
- current_ticket["priority_status"] = access_ticket.ticket_priority
- current_ticket["title"] = access_ticket.ticket_name
- current_ticket["details"] = access_ticket.ticket_details
- current_ticket["status"] = access_ticket.ticket_status
- current_ticket["submitter"] = access_ticket.ticket_submitter
- current_ticket["assignee"] = access_ticket.ticket_assignee
- current_ticket["lock_status"] = lock_status
- current_ticket["ref"] = "\ref[access_ticket]"
- logged_access += list(current_ticket)
-
- if(lock_status == TICKET_OPEN)
- requesting_access += access_ticket.ticket_name
- data["access_tickets"] = logged_access
-
- return data
-
-/obj/structure/machinery/computer/working_joe/ui_static_data(mob/user)
- var/list/data = list()
-
- data["link_id"] = link_id
-
- return data
-
-/obj/structure/machinery/computer/working_joe/ui_status(mob/user, datum/ui_state/state)
- . = ..()
- if(!allowed(user))
- return UI_UPDATE
- if(inoperable())
- return UI_DISABLED
-
-/obj/structure/machinery/computer/working_joe/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
- . = ..()
- if(.)
- return
-
- var/playsound = TRUE
- var/mob/living/carbon/human/operator = usr
-
- switch (action)
- if("go_back")
- if(!last_menu)
- return to_chat(usr, SPAN_WARNING("Error, no previous page detected."))
- var/temp_holder = current_menu
- current_menu = last_menu
- last_menu = temp_holder
-
- if("login")
-
- var/obj/item/card/id/idcard = operator.get_active_hand()
- if(istype(idcard))
- authentication = get_ares_access(idcard)
- last_login = idcard.registered_name
- else if(operator.wear_id)
- idcard = operator.wear_id
- if(istype(idcard))
- authentication = get_ares_access(idcard)
- last_login = idcard.registered_name
- else
- to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- if(authentication)
- login_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]."
- current_menu = "main"
-
- if("logout")
- last_menu = current_menu
- current_menu = "login"
- login_list += "[last_login] logged out at [worldtime2text()]."
-
- if("home")
- last_menu = current_menu
- current_menu = "main"
- if("page_logins")
- last_menu = current_menu
- current_menu = "login_records"
- if("page_apollo")
- last_menu = current_menu
- current_menu = "apollo"
- if("page_request")
- last_menu = current_menu
- current_menu = "access_requests"
- if("page_report")
- last_menu = current_menu
- current_menu = "maint_reports"
- if("page_tickets")
- last_menu = current_menu
- current_menu = "access_tickets"
- if("page_maintenance")
- last_menu = current_menu
- current_menu = "maint_claim"
-
- if("new_report")
- var/priority_report = FALSE
- var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS)
- switch(maint_type)
- if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure")
- priority_report = TRUE
-
- if(!maint_type)
- return FALSE
- var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE)
- if(!details)
- return FALSE
-
- if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report)
- var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No"))
- if(is_priority == "Yes")
- priority_report = TRUE
-
- var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"] \n Category: '[maint_type]' \n Details: '[details]' \n\n Is this correct?", "Confirmation", "Yes", "No")
- if(confirm == "Yes")
- if(link)
- var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report)
- link.tickets_maintenance += maint_ticket
- if(priority_report)
- ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.")
- log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.")
- return TRUE
- return FALSE
-
- if("claim_ticket")
- var/datum/ares_ticket/ticket = locate(params["ticket"])
- if(!istype(ticket))
- return FALSE
- var/claim = TRUE
- var/assigned = ticket.ticket_assignee
- if(assigned)
- if(assigned == last_login)
- var/prompt = tgui_alert(usr, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No"))
- if(prompt != "Yes")
- return FALSE
- /// set ticket back to pending
- ticket.ticket_assignee = null
- ticket.ticket_status = TICKET_PENDING
- return claim
- var/choice = tgui_alert(usr, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No"))
- if(choice != "Yes")
- claim = FALSE
- if(claim)
- ticket.ticket_assignee = last_login
- ticket.ticket_status = TICKET_ASSIGNED
- return claim
-
- if("cancel_ticket")
- var/datum/ares_ticket/ticket = locate(params["ticket"])
- if(!istype(ticket))
- return FALSE
- if(ticket.ticket_submitter != last_login)
- to_chat(usr, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!"))
- return FALSE
- to_chat(usr, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled."))
- ticket.ticket_status = TICKET_CANCELLED
- if(ticket.ticket_priority)
- ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.")
- return TRUE
-
- if("mark_ticket")
- var/datum/ares_ticket/ticket = locate(params["ticket"])
- if(!istype(ticket))
- return FALSE
- if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.)
- to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!"))
- return FALSE
- var/choice = tgui_alert(usr, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS)
- switch(choice)
- if(TICKET_COMPLETED)
- ticket.ticket_status = TICKET_COMPLETED
- if(TICKET_REJECTED)
- ticket.ticket_status = TICKET_REJECTED
- else
- return FALSE
- if(ticket.ticket_priority)
- ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].")
- to_chat(usr, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice]."))
- return TRUE
-
- if("new_access")
- var/obj/item/card/id/idcard = operator.get_active_hand()
- var/has_id = FALSE
- if(istype(idcard))
- has_id = TRUE
- else if(operator.wear_id)
- idcard = operator.wear_id
- if(istype(idcard))
- has_id = TRUE
- if(!has_id)
- to_chat(operator, SPAN_WARNING("You require an ID card to request an access ticket!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
- if(idcard.registered_name != last_login)
- to_chat(operator, SPAN_WARNING("This ID card does not match the active login!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
-
- var/ticket_holder = last_login
- if(!ticket_holder)
- return FALSE
- var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE)
- if(!details)
- return FALSE
-
- var/confirm = alert(operator, "Please confirm the submission of your access ticket request. \n\nHolder: '[ticket_holder]' \n Details: '[details]' \n\n Is this correct?", "Confirmation", "Yes", "No")
- if(confirm != "Yes" || !link)
- return FALSE
- var/datum/ares_ticket/access/access_ticket = new(last_login, ticket_holder, details, FALSE, idcard.registered_gid)
- link.waiting_ids += idcard
- link.tickets_access += access_ticket
- log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Holder '[ticket_holder]' and Details of '[details]'.")
- message_admins(SPAN_STAFF_IC("[key_name_admin(operator)] created a new ARES Access Ticket."), 1)
- return TRUE
-
- if("return_access")
- playsound = FALSE
- var/datum/ares_ticket/access/access_ticket
- for(var/datum/ares_ticket/access/possible_ticket in link.tickets_access)
- if(possible_ticket.ticket_status != TICKET_GRANTED)
- continue
- if(possible_ticket.ticket_name != last_login)
- continue
- access_ticket = possible_ticket
- break
-
- for(var/obj/item/card/id/identification in link.active_ids)
- if(!istype(identification))
- continue
- if(identification.registered_gid != access_ticket.user_id_num)
- continue
-
- access_ticket.ticket_status = TICKET_RETURNED
- identification.access -= ACCESS_MARINE_AI_TEMP
- identification.modification_log += "Temporary AI Access self-returned by [key_name(operator)]."
-
- to_chat(operator, SPAN_NOTICE("Temporary Access Ticket surrendered."))
- playsound(src, 'sound/machines/chime.ogg', 15, 1)
- ares_apollo_talk("[last_login] surrendered their access ticket.")
-
- authentication = get_ares_access(identification)
- if(authentication)
- login_list += "[last_login] at [worldtime2text()], Surrendered Temporary Access Ticket."
- return TRUE
-
- to_chat(operator, SPAN_WARNING("This ID card does not have an access ticket!"))
- playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
- return FALSE
-
- if("auth_access")
- playsound = FALSE
- var/datum/ares_ticket/access/access_ticket = locate(params["ticket"])
- if(!access_ticket)
- return FALSE
- for(var/obj/item/card/id/identification in link.waiting_ids)
- if(!istype(identification))
- continue
- if(identification.registered_gid != access_ticket.user_id_num)
- continue
- identification.handle_ares_access(last_login, operator)
- access_ticket.ticket_status = TICKET_GRANTED
- playsound(src, 'sound/machines/chime.ogg', 15, 1)
- return TRUE
- for(var/obj/item/card/id/identification in link.active_ids)
- if(!istype(identification))
- continue
- if(identification.registered_gid != access_ticket.user_id_num)
- continue
- identification.handle_ares_access(last_login, operator)
- access_ticket.ticket_status = TICKET_REVOKED
- playsound(src, 'sound/machines/chime.ogg', 15, 1)
- return TRUE
- return FALSE
-
- if(playsound)
- playsound(src, "keyboard_alt", 15, 1)
-
-/obj/item/card/id/proc/handle_ares_access(logged_in, mob/user)
- var/announce_text = "[logged_in] revoked core access from [registered_name]'s ID card."
- var/operator = key_name(user)
- var/datum/ares_link/link = GLOB.ares_link
- if(logged_in == MAIN_AI_SYSTEM)
- if(!user)
- operator = "[MAIN_AI_SYSTEM] (Sensor Trip)"
- else
- operator = "[user.ckey]/([MAIN_AI_SYSTEM])"
- if(ACCESS_MARINE_AI_TEMP in access)
- access -= ACCESS_MARINE_AI_TEMP
- link.active_ids -= src
- modification_log += "Temporary AI access revoked by [operator]"
- to_chat(user, SPAN_NOTICE("Access revoked from [registered_name]."))
+/obj/item/device/working_joe_pda/proc/get_ares_access(obj/item/card/id/card)
+ if(ACCESS_ARES_DEBUG in card.access)
+ return APOLLO_ACCESS_DEBUG
+ switch(card.assignment)
+ if(JOB_WORKING_JOE)
+ return APOLLO_ACCESS_JOE
+ if(JOB_CHIEF_ENGINEER, JOB_SYNTH, JOB_CO)
+ return APOLLO_ACCESS_AUTHED
+ if(ACCESS_MARINE_AI in card.access)
+ return APOLLO_ACCESS_AUTHED
+ if(ACCESS_MARINE_AI_TEMP in card.access)
+ return APOLLO_ACCESS_TEMP
+ if((ACCESS_MARINE_SENIOR in card.access ) || (ACCESS_MARINE_ENGINEERING in card.access) || (ACCESS_WY_GENERAL in card.access))
+ return APOLLO_ACCESS_REPORTER
else
- access += ACCESS_MARINE_AI_TEMP
- modification_log += "Temporary AI access granted by [operator]"
- announce_text = "[logged_in] granted core access to [registered_name]'s ID card."
- to_chat(user, SPAN_NOTICE("Access granted to [registered_name]."))
- link.waiting_ids -= src
- link.active_ids += src
- ares_apollo_talk(announce_text)
- return TRUE
+ return APOLLO_ACCESS_REQUEST
+
+/obj/item/device/working_joe_pda/proc/ares_auth_to_text(access_level)
+ switch(access_level)
+ if(APOLLO_ACCESS_LOGOUT)//0
+ return "Logged Out"
+ if(APOLLO_ACCESS_REQUEST)//1
+ return "Unauthorized Personnel"
+ if(APOLLO_ACCESS_REPORTER)//2
+ return "Validated Incident Reporter"
+ if(APOLLO_ACCESS_TEMP)//3
+ return "Authorized Visitor"
+ if(APOLLO_ACCESS_AUTHED)//4
+ return "Certified Personnel"
+ if(APOLLO_ACCESS_JOE)//5
+ return "Working Joe"
+ if(APOLLO_ACCESS_DEBUG)//6
+ return "AI Service Technician"
diff --git a/code/game/machinery/ARES/ARES_records.dm b/code/game/machinery/ARES/ARES_records.dm
index 19751462bc37..f89b2c120e05 100644
--- a/code/game/machinery/ARES/ARES_records.dm
+++ b/code/game/machinery/ARES/ARES_records.dm
@@ -102,6 +102,7 @@
var/ref_holder = "\ref[src]"
var/pos = length(ref_holder)
var/new_id = "#[copytext("\ref[src]", pos - 4, pos)]"
+ new_id = uppertext(new_id)
ticket_time = worldtime2text()
ticket_submitter = user
@@ -115,17 +116,18 @@
/datum/ares_ticket/access
ticket_type = ARES_RECORD_ACCESS
+ ticket_name = ARES_RECORD_ACCESS
var/user_id_num
-/datum/ares_ticket/access/New(user, name, details, priority, global_id_num)
+/datum/ares_ticket/access/New(user, details, priority, global_id_num)
var/ref_holder = "\ref[src]"
var/pos = length(ref_holder)
var/new_id = "#[copytext("\ref[src]", pos - 4, pos)]"
+ new_id = uppertext(new_id)
ticket_time = worldtime2text()
ticket_submitter = user
ticket_details = details
- ticket_name = name
ticket_priority = priority
ticket_id = new_id
user_id_num = global_id_num
diff --git a/code/game/machinery/ARES/ARES_step_triggers.dm b/code/game/machinery/ARES/ARES_step_triggers.dm
index 51480371be51..2c6d605bcc9b 100644
--- a/code/game/machinery/ARES/ARES_step_triggers.dm
+++ b/code/game/machinery/ARES/ARES_step_triggers.dm
@@ -3,7 +3,6 @@
layer = 5
/// Link alerts to ARES Link
var/datum/ares_link/link
- var/link_id = MAIN_SHIP_DEFAULT_NAME
/// Alert message to report unless area based.
var/alert_message = "ALERT: Unauthorized movement detected in ARES Core!"
/// Connect alerts to use same cooldowns
@@ -53,7 +52,7 @@
/obj/effect/step_trigger/ares_alert/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
if(link && !override)
return FALSE
- if(new_link.link_id == link_id)
+ if(new_link)
link = new_link
new_link.linked_alerts += src
return TRUE
@@ -70,7 +69,7 @@
broadcast_message = "ALERT: Unauthorized movement detected in [area_name]!"
var/datum/ares_link/link = GLOB.ares_link
- if(link.p_apollo.inoperable())
+ if(!ares_can_apollo())
return FALSE
to_chat(passer, SPAN_BOLDWARNING("You hear a soft beeping sound as you cross the threshold."))
@@ -113,8 +112,6 @@
/obj/effect/step_trigger/ares_alert/access_control/Crossed(atom/passer as mob|obj)
if(isobserver(passer) || isxeno(passer))
return FALSE
- if(!COOLDOWN_FINISHED(src, sensor_cooldown))//Don't want alerts spammed.
- return FALSE
if(!passer)
return FALSE
if(HAS_TRAIT(passer, TRAIT_CLOAKED))//Can't be seen/detected to trigger alert.
@@ -157,11 +154,12 @@
var/broadcast_message = get_broadcast(passer, idcard, failure)
var/datum/ares_link/link = GLOB.ares_link
- if(link.p_apollo.inoperable())
+ if(!ares_can_apollo())
return FALSE
to_chat(passer, SPAN_BOLDWARNING("You hear a harsh buzzing sound as you cross the threshold!"))
- ares_apollo_talk(broadcast_message)
+ if(COOLDOWN_FINISHED(src, sensor_cooldown))//Don't want alerts spammed.
+ ares_apollo_talk(broadcast_message)
if(idcard)
/// Removes the access from the ID and updates the ID's modification log.
for(var/obj/item/card/id/identification in link.active_ids)
diff --git a/code/game/machinery/ARES/apollo_pda.dm b/code/game/machinery/ARES/apollo_pda.dm
new file mode 100644
index 000000000000..8df3faf79260
--- /dev/null
+++ b/code/game/machinery/ARES/apollo_pda.dm
@@ -0,0 +1,419 @@
+/obj/item/device/working_joe_pda
+ icon = 'icons/obj/items/synth/wj_pda.dmi'
+ name = "KN5500 PDA"
+ desc = "A portable interface used by Working-Joes, capable of connecting to the local command AI to relay tasking information. Built to withstand a nuclear bomb."
+ icon_state = "karnak_off"
+ unacidable = TRUE
+ indestructible = TRUE
+ req_one_access = list(ACCESS_MARINE_AI_TEMP, ACCESS_MARINE_AI, ACCESS_ARES_DEBUG)
+
+ /// The ID used to link all devices.
+ var/datum/ares_link/link
+ /// The datacore storing all the information.
+ var/datum/ares_datacore/datacore
+
+ var/current_menu = "login"
+ var/last_menu = "off"
+
+ var/authentication = APOLLO_ACCESS_LOGOUT
+ /// The last person to login.
+ var/last_login
+
+
+/obj/item/device/working_joe_pda/proc/link_systems(datum/ares_link/new_link = GLOB.ares_link, override)
+ if(link && !override)
+ return FALSE
+ if(new_link)
+ new_link.ticket_computers += src
+ link = new_link
+ new_link.linked_systems += src
+ if(!datacore)
+ datacore = GLOB.ares_datacore
+ return TRUE
+
+/obj/item/device/working_joe_pda/Initialize(mapload, ...)
+ link_systems(override = FALSE)
+ . = ..()
+
+/obj/item/device/working_joe_pda/proc/delink()
+ if(link)
+ link.ticket_computers -= src
+ link.linked_systems -= src
+ link = null
+ datacore = null
+
+/obj/item/device/working_joe_pda/Destroy()
+ delink()
+ return ..()
+
+/obj/item/device/working_joe_pda/update_icon()
+ . = ..()
+ if(last_menu == "off")
+ icon_state = "karnak_off"
+ else if(current_menu == "login")
+ icon_state = "karnak_login_anim"
+ else
+ icon_state = "karnak_on_anim"
+
+// ------ Maintenance Controller UI ------ //
+/obj/item/device/working_joe_pda/attack_self(mob/user)
+ if(..() || !allowed(usr))
+ return FALSE
+
+ if((last_menu == "off") && (current_menu == "login"))
+ last_menu = "main"
+ update_icon()
+
+ tgui_interact(user)
+ return TRUE
+
+/obj/item/device/working_joe_pda/tgui_interact(mob/user, datum/tgui/ui, datum/ui_state/state)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "WorkingJoe", name)
+ ui.open()
+
+/obj/item/device/working_joe_pda/ui_close(mob/user)
+ . = ..()
+
+ current_menu = "login"
+ last_menu = "off"
+ if(last_login)
+ datacore.apollo_login_list += "[last_login] logged out at [worldtime2text()]."
+ last_login = null
+ update_icon()
+
+/obj/item/device/working_joe_pda/ui_data(mob/user)
+ var/list/data = list()
+
+ data["current_menu"] = current_menu
+ data["last_page"] = last_menu
+
+ data["logged_in"] = last_login
+
+ data["access_text"] = "access level [authentication], [ares_auth_to_text(authentication)]."
+ data["access_level"] = authentication
+
+ data["alert_level"] = GLOB.security_level
+ data["worldtime"] = world.time
+
+ data["access_log"] = list()
+ data["access_log"] += datacore.apollo_login_list
+
+ data["apollo_log"] = list()
+ data["apollo_log"] += datacore.apollo_log
+
+ var/list/logged_maintenance = list()
+ for(var/datum/ares_ticket/maintenance/maint_ticket as anything in link.tickets_maintenance)
+ if(!istype(maint_ticket))
+ continue
+ var/lock_status = TICKET_OPEN
+ switch(maint_ticket.ticket_status)
+ if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_COMPLETED)
+ lock_status = TICKET_CLOSED
+
+ var/list/current_maint = list()
+ current_maint["id"] = maint_ticket.ticket_id
+ current_maint["time"] = maint_ticket.ticket_time
+ current_maint["priority_status"] = maint_ticket.ticket_priority
+ current_maint["category"] = maint_ticket.ticket_name
+ current_maint["details"] = maint_ticket.ticket_details
+ current_maint["status"] = maint_ticket.ticket_status
+ current_maint["submitter"] = maint_ticket.ticket_submitter
+ current_maint["assignee"] = maint_ticket.ticket_assignee
+ current_maint["lock_status"] = lock_status
+ current_maint["ref"] = "\ref[maint_ticket]"
+ logged_maintenance += list(current_maint)
+ data["maintenance_tickets"] = logged_maintenance
+
+ var/list/logged_access = list()
+ var/list/requesting_access = list()
+ for(var/datum/ares_ticket/access/access_ticket as anything in link.tickets_access)
+ var/lock_status = TICKET_OPEN
+ switch(access_ticket.ticket_status)
+ if(TICKET_REJECTED, TICKET_CANCELLED, TICKET_REVOKED)
+ lock_status = TICKET_CLOSED
+
+ var/list/current_ticket = list()
+ current_ticket["id"] = access_ticket.ticket_id
+ current_ticket["time"] = access_ticket.ticket_time
+ current_ticket["priority_status"] = access_ticket.ticket_priority
+ current_ticket["title"] = access_ticket.ticket_name
+ current_ticket["details"] = access_ticket.ticket_details
+ current_ticket["status"] = access_ticket.ticket_status
+ current_ticket["submitter"] = access_ticket.ticket_submitter
+ current_ticket["assignee"] = access_ticket.ticket_assignee
+ current_ticket["lock_status"] = lock_status
+ current_ticket["ref"] = "\ref[access_ticket]"
+ logged_access += list(current_ticket)
+
+ if(lock_status == TICKET_OPEN)
+ requesting_access += access_ticket.ticket_name
+ data["access_tickets"] = logged_access
+
+ return data
+
+/obj/item/device/working_joe_pda/ui_status(mob/user, datum/ui_state/state)
+ . = ..()
+ if(!allowed(user))
+ return UI_UPDATE
+
+/obj/item/device/working_joe_pda/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ var/playsound = TRUE
+ var/mob/living/carbon/human/operator = usr
+
+ switch (action)
+ if("go_back")
+ if(!last_menu)
+ return to_chat(usr, SPAN_WARNING("Error, no previous page detected."))
+ var/temp_holder = current_menu
+ current_menu = last_menu
+ last_menu = temp_holder
+
+ if("login")
+
+ var/obj/item/card/id/idcard = operator.get_active_hand()
+ if(istype(idcard))
+ authentication = get_ares_access(idcard)
+ last_login = idcard.registered_name
+ else if(operator.wear_id)
+ idcard = operator.wear_id
+ if(istype(idcard))
+ authentication = get_ares_access(idcard)
+ last_login = idcard.registered_name
+ else
+ to_chat(operator, SPAN_WARNING("You require an ID card to access this terminal!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(authentication)
+ datacore.apollo_login_list += "[last_login] at [worldtime2text()], Access Level [authentication] - [ares_auth_to_text(authentication)]."
+ current_menu = "main"
+ last_menu = "main"
+ update_icon()
+
+ if("logout")
+ last_menu = current_menu
+ current_menu = "login"
+ datacore.apollo_login_list += "[last_login] logged out at [worldtime2text()]."
+ update_icon()
+
+ if("home")
+ last_menu = current_menu
+ current_menu = "main"
+ if("page_logins")
+ last_menu = current_menu
+ current_menu = "login_records"
+ if("page_apollo")
+ last_menu = current_menu
+ current_menu = "apollo"
+ if("page_request")
+ last_menu = current_menu
+ current_menu = "access_requests"
+ if("page_report")
+ last_menu = current_menu
+ current_menu = "maint_reports"
+ if("page_tickets")
+ last_menu = current_menu
+ current_menu = "access_tickets"
+ if("page_maintenance")
+ last_menu = current_menu
+ current_menu = "maint_claim"
+
+ if("new_report")
+ var/priority_report = FALSE
+ var/maint_type = tgui_input_list(operator, "What is the type of maintenance item you wish to report?", "Report Category", GLOB.maintenance_categories, 30 SECONDS)
+ switch(maint_type)
+ if("Major Structural Damage", "Fire", "Communications Failure", "Power Generation Failure")
+ priority_report = TRUE
+
+ if(!maint_type)
+ return FALSE
+ var/details = tgui_input_text(operator, "What are the details for this report?", "Ticket Details", encode = FALSE)
+ if(!details)
+ return FALSE
+
+ if((authentication >= APOLLO_ACCESS_REPORTER) && !priority_report)
+ var/is_priority = tgui_alert(operator, "Is this a priority report?", "Priority designation", list("Yes", "No"))
+ if(is_priority == "Yes")
+ priority_report = TRUE
+
+ var/confirm = alert(operator, "Please confirm the submission of your maintenance report. \n\n Priority: [priority_report ? "Yes" : "No"]\n Category: '[maint_type]'\n Details: '[details]'\n\n Is this correct?", "Confirmation", "Yes", "No")
+ if(confirm == "Yes")
+ if(link)
+ var/datum/ares_ticket/maintenance/maint_ticket = new(last_login, maint_type, details, priority_report)
+ link.tickets_maintenance += maint_ticket
+ if(priority_report)
+ ares_apollo_talk("Priority Maintenance Report: [maint_type] - ID [maint_ticket.ticket_id]. Seek and resolve.")
+ log_game("ARES: Maintenance Ticket '\ref[maint_ticket]' created by [key_name(operator)] as [last_login] with Category '[maint_type]' and Details of '[details]'.")
+ return TRUE
+ return FALSE
+
+ if("claim_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ var/claim = TRUE
+ var/assigned = ticket.ticket_assignee
+ if(assigned)
+ if(assigned == last_login)
+ var/prompt = tgui_alert(usr, "You already claimed this ticket! Do you wish to drop your claim?", "Unclaim ticket", list("Yes", "No"))
+ if(prompt != "Yes")
+ return FALSE
+ /// set ticket back to pending
+ ticket.ticket_assignee = null
+ ticket.ticket_status = TICKET_PENDING
+ return claim
+ var/choice = tgui_alert(usr, "This ticket has already been claimed by [assigned]! Do you wish to override their claim?", "Claim Override", list("Yes", "No"))
+ if(choice != "Yes")
+ claim = FALSE
+ if(claim)
+ ticket.ticket_assignee = last_login
+ ticket.ticket_status = TICKET_ASSIGNED
+ return claim
+
+ if("cancel_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ if(ticket.ticket_submitter != last_login)
+ to_chat(usr, SPAN_WARNING("You cannot cancel a ticket that does not belong to you!"))
+ return FALSE
+ to_chat(usr, SPAN_WARNING("[ticket.ticket_type] [ticket.ticket_id] has been cancelled."))
+ ticket.ticket_status = TICKET_CANCELLED
+ if(ticket.ticket_priority)
+ ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been cancelled.")
+ return TRUE
+
+ if("mark_ticket")
+ var/datum/ares_ticket/ticket = locate(params["ticket"])
+ if(!istype(ticket))
+ return FALSE
+ if(ticket.ticket_assignee != last_login && ticket.ticket_assignee) //must be claimed by you or unclaimed.)
+ to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!"))
+ return FALSE
+ var/choice = tgui_alert(usr, "What do you wish to mark the ticket as?", "Mark", list(TICKET_COMPLETED, TICKET_REJECTED), 20 SECONDS)
+ switch(choice)
+ if(TICKET_COMPLETED)
+ ticket.ticket_status = TICKET_COMPLETED
+ if(TICKET_REJECTED)
+ ticket.ticket_status = TICKET_REJECTED
+ else
+ return FALSE
+ if(ticket.ticket_priority)
+ ares_apollo_talk("Priority [ticket.ticket_type] [ticket.ticket_id] has been [choice] by [last_login].")
+ to_chat(usr, SPAN_NOTICE("[ticket.ticket_type] [ticket.ticket_id] marked as [choice]."))
+ return TRUE
+
+ if("new_access")
+ var/obj/item/card/id/idcard = operator.get_active_hand()
+ var/has_id = FALSE
+ if(istype(idcard))
+ has_id = TRUE
+ else if(operator.wear_id)
+ idcard = operator.wear_id
+ if(istype(idcard))
+ has_id = TRUE
+ if(!has_id)
+ to_chat(operator, SPAN_WARNING("You require an ID card to request an access ticket!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+ if(idcard.registered_name != last_login)
+ to_chat(operator, SPAN_WARNING("This ID card does not match the active login!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ var/details = tgui_input_text(operator, "What is the purpose of this access ticket?", "Ticket Details", encode = FALSE)
+ if(!details)
+ return FALSE
+
+ var/confirm = alert(operator, "Please confirm the submission of your access ticket request.\n\nHolder: '[last_login]'\nDetails: '[details]'\n\nIs this correct?", "Confirmation", "Yes", "No")
+ if(confirm != "Yes" || !link)
+ return FALSE
+ var/datum/ares_ticket/access/access_ticket = new(last_login, details, FALSE, idcard.registered_gid)
+ link.waiting_ids += idcard
+ link.tickets_access += access_ticket
+ log_game("ARES: Access Ticket '\ref[access_ticket]' created by [key_name(operator)] as [last_login] with Details of '[details]'.")
+ message_admins(SPAN_STAFF_IC("[key_name_admin(operator)] created a new ARES Access Ticket."), 1)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] requesting access for '[details].")
+ return TRUE
+
+ if("return_access")
+ playsound = FALSE
+ var/datum/ares_ticket/access/access_ticket
+ for(var/datum/ares_ticket/access/possible_ticket in link.tickets_access)
+ if(possible_ticket.ticket_status != TICKET_GRANTED)
+ continue
+ if(possible_ticket.ticket_name != last_login)
+ continue
+ access_ticket = possible_ticket
+ break
+
+ for(var/obj/item/card/id/identification in link.active_ids)
+ if(!istype(identification))
+ continue
+ if(identification.registered_gid != access_ticket.user_id_num)
+ continue
+
+ access_ticket.ticket_status = TICKET_RETURNED
+ identification.access -= ACCESS_MARINE_AI_TEMP
+ identification.modification_log += "Temporary AI Access self-returned by [key_name(operator)]."
+
+ to_chat(operator, SPAN_NOTICE("Temporary Access Ticket surrendered."))
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] surrendered their access.")
+
+ authentication = get_ares_access(identification)
+ if(authentication)
+ datacore.apollo_login_list += "[last_login] at [worldtime2text()], Surrendered Temporary Access Ticket."
+ return TRUE
+
+ to_chat(operator, SPAN_WARNING("This ID card does not have an access ticket!"))
+ playsound(src, 'sound/machines/buzz-two.ogg', 15, 1)
+ return FALSE
+
+ if("auth_access")
+ playsound = FALSE
+ var/datum/ares_ticket/access/access_ticket = locate(params["ticket"])
+ if(!access_ticket)
+ return FALSE
+ for(var/obj/item/card/id/identification in link.waiting_ids)
+ if(!istype(identification))
+ continue
+ if(identification.registered_gid != access_ticket.user_id_num)
+ continue
+ identification.handle_ares_access(last_login, operator)
+ access_ticket.ticket_status = TICKET_GRANTED
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was granted access by [last_login].")
+ return TRUE
+ for(var/obj/item/card/id/identification in link.active_ids)
+ if(!istype(identification))
+ continue
+ if(identification.registered_gid != access_ticket.user_id_num)
+ continue
+ identification.handle_ares_access(last_login, operator)
+ access_ticket.ticket_status = TICKET_REVOKED
+ playsound(src, 'sound/machines/chime.ogg', 15, 1)
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] had access revoked by [last_login].")
+ return TRUE
+ return FALSE
+
+ if("reject_access")
+ var/datum/ares_ticket/access/access_ticket = locate(params["ticket"])
+ if(!istype(access_ticket))
+ return FALSE
+ if(access_ticket.ticket_assignee != last_login && access_ticket.ticket_assignee) //must be claimed by you or unclaimed.)
+ to_chat(usr, SPAN_WARNING("You cannot update a ticket that is not assigned to you!"))
+ return FALSE
+ access_ticket.ticket_status = TICKET_REJECTED
+ to_chat(usr, SPAN_NOTICE("[access_ticket.ticket_type] [access_ticket.ticket_id] marked as rejected."))
+ ares_apollo_talk("Access Ticket [access_ticket.ticket_id]: [access_ticket.ticket_submitter] was rejected access by [last_login].")
+ return TRUE
+
+ if(playsound)
+ var/sound = pick('sound/machines/pda_button1.ogg', 'sound/machines/pda_button2.ogg')
+ playsound(src, sound, 15, TRUE)
diff --git a/code/game/machinery/OpTable.dm b/code/game/machinery/OpTable.dm
index 3c4104b6c283..03c013703b07 100644
--- a/code/game/machinery/OpTable.dm
+++ b/code/game/machinery/OpTable.dm
@@ -19,7 +19,7 @@
active_power_usage = 5
var/strapped = 0
can_buckle = TRUE
- buckle_lying = TRUE
+ buckle_lying = 90
var/buckling_y = -4
surgery_duration_multiplier = SURGERY_SURFACE_MULT_IDEAL //Ideal surface for surgery.
var/patient_exam = 0
@@ -59,8 +59,6 @@
if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY)
deconstruct(FALSE)
return
- else
- return
/obj/structure/machinery/optable/get_examine_text(mob/user)
. = ..()
diff --git a/code/game/machinery/air_alarm.dm b/code/game/machinery/air_alarm.dm
index 16512a944be1..88b4ab899112 100644
--- a/code/game/machinery/air_alarm.dm
+++ b/code/game/machinery/air_alarm.dm
@@ -5,9 +5,9 @@
/proc/RandomAAlarmWires()
//to make this not randomize the wires, just set index to 1 and increment it in the flag for loop (after doing everything else).
var/list/AAlarmwires = list(0, 0, 0, 0, 0)
- AAlarmIndexToFlag = list(0, 0, 0, 0, 0)
- AAlarmIndexToWireColor = list(0, 0, 0, 0, 0)
- AAlarmWireColorToIndex = list(0, 0, 0, 0, 0)
+ GLOB.AAlarmIndexToFlag = list(0, 0, 0, 0, 0)
+ GLOB.AAlarmIndexToWireColor = list(0, 0, 0, 0, 0)
+ GLOB.AAlarmWireColorToIndex = list(0, 0, 0, 0, 0)
var/flagIndex = 1
for (var/flag=1, flag<32, flag+=flag)
var/valid = 0
@@ -16,9 +16,9 @@
if (AAlarmwires[colorIndex]==0)
valid = 1
AAlarmwires[colorIndex] = flag
- AAlarmIndexToFlag[flagIndex] = flag
- AAlarmIndexToWireColor[flagIndex] = colorIndex
- AAlarmWireColorToIndex[colorIndex] = flagIndex
+ GLOB.AAlarmIndexToFlag[flagIndex] = flag
+ GLOB.AAlarmIndexToWireColor[flagIndex] = colorIndex
+ GLOB.AAlarmWireColorToIndex[colorIndex] = flagIndex
flagIndex+=1
return AAlarmwires
@@ -379,24 +379,24 @@
//HACKING//
///////////
/obj/structure/machinery/alarm/proc/isWireColorCut(wireColor)
- var/wireFlag = AAlarmWireColorToFlag[wireColor]
+ var/wireFlag = GLOB.AAlarmWireColorToFlag[wireColor]
return ((AAlarmwires & wireFlag) == 0)
/obj/structure/machinery/alarm/proc/isWireCut(wireIndex)
- var/wireFlag = AAlarmIndexToFlag[wireIndex]
+ var/wireFlag = GLOB.AAlarmIndexToFlag[wireIndex]
return ((AAlarmwires & wireFlag) == 0)
/obj/structure/machinery/alarm/proc/allWiresCut()
var/i = 1
while(i<=5)
- if(AAlarmwires & AAlarmIndexToFlag[i])
+ if(AAlarmwires & GLOB.AAlarmIndexToFlag[i])
return 0
i++
return 1
/obj/structure/machinery/alarm/proc/cut(wireColor)
- var/wireFlag = AAlarmWireColorToFlag[wireColor]
- var/wireIndex = AAlarmWireColorToIndex[wireColor]
+ var/wireFlag = GLOB.AAlarmWireColorToFlag[wireColor]
+ var/wireIndex = GLOB.AAlarmWireColorToIndex[wireColor]
AAlarmwires &= ~wireFlag
switch(wireIndex)
if(AALARM_WIRE_IDSCAN)
@@ -427,12 +427,10 @@
return
/obj/structure/machinery/alarm/proc/mend(wireColor)
- var/wireFlag = AAlarmWireColorToFlag[wireColor]
- var/wireIndex = AAlarmWireColorToIndex[wireColor] //not used in this function
+ var/wireFlag = GLOB.AAlarmWireColorToFlag[wireColor]
+ var/wireIndex = GLOB.AAlarmWireColorToIndex[wireColor] //not used in this function
AAlarmwires |= wireFlag
switch(wireIndex)
- if(AALARM_WIRE_IDSCAN)
-
if(AALARM_WIRE_POWER)
shorted = 0
shock(usr, 50)
@@ -447,7 +445,7 @@
/obj/structure/machinery/alarm/proc/pulse(wireColor)
//var/wireFlag = AAlarmWireColorToFlag[wireColor] //not used in this function
- var/wireIndex = AAlarmWireColorToIndex[wireColor]
+ var/wireIndex = GLOB.AAlarmWireColorToIndex[wireColor]
switch(wireIndex)
if(AALARM_WIRE_IDSCAN) //unlocks for 30 seconds, if you have a better way to hack I'm all ears
locked = 0
@@ -529,7 +527,7 @@
"Black" = 5,
)
for(var/wiredesc in wirecolors)
- var/is_uncut = AAlarmwires & AAlarmWireColorToFlag[wirecolors[wiredesc]]
+ var/is_uncut = AAlarmwires & GLOB.AAlarmWireColorToFlag[wirecolors[wiredesc]]
t1 += "[wiredesc] wire: "
if(!is_uncut)
t1 += "Mend"
diff --git a/code/game/machinery/atmoalter/canister.dm b/code/game/machinery/atmoalter/canister.dm
index 3c2c81ff0ce7..d62d688fcfc5 100644
--- a/code/game/machinery/atmoalter/canister.dm
+++ b/code/game/machinery/atmoalter/canister.dm
@@ -98,12 +98,12 @@ update_flag
/obj/structure/machinery/portable_atmospherics/canister/attackby(obj/item/W as obj, mob/user as mob)
if(!HAS_TRAIT(W, TRAIT_TOOL_WRENCH) && !istype(W, /obj/item/tank) && !istype(W, /obj/item/device/analyzer))
- visible_message(SPAN_DANGER("[user] hits the [src] with a [W]!"))
+ visible_message(SPAN_DANGER("[user] hits [src] with [W]!"))
update_health(W.force)
src.add_fingerprint(user)
..()
- nanomanager.update_uis(src) // Update all NanoUIs attached to src
+ SSnano.nanomanager.update_uis(src) // Update all NanoUIs attached to src
/obj/structure/machinery/portable_atmospherics/canister/attack_remote(mob/user as mob)
return src.attack_hand(user)
diff --git a/code/game/machinery/atmoalter/scrubber.dm b/code/game/machinery/atmoalter/scrubber.dm
index 0af38cacd75e..1c240fb05dfb 100644
--- a/code/game/machinery/atmoalter/scrubber.dm
+++ b/code/game/machinery/atmoalter/scrubber.dm
@@ -18,16 +18,14 @@
PF.flags_can_pass_all = PASS_OVER|PASS_AROUND|PASS_UNDER
/obj/structure/machinery/portable_atmospherics/powered/scrubber/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
if(prob(50/severity))
on = !on
update_icon()
- ..(severity)
-
/obj/structure/machinery/portable_atmospherics/powered/scrubber/update_icon()
src.overlays = 0
diff --git a/code/game/machinery/bio-dome_floodlights.dm b/code/game/machinery/bio-dome_floodlights.dm
index a1f028a79f30..e23dbcc023f4 100644
--- a/code/game/machinery/bio-dome_floodlights.dm
+++ b/code/game/machinery/bio-dome_floodlights.dm
@@ -14,7 +14,7 @@
/obj/structure/machinery/hydro_floodlight_switch/Initialize(mapload, ...)
. = ..()
- for(var/obj/structure/machinery/hydro_floodlight/F in machines)
+ for(var/obj/structure/machinery/hydro_floodlight/F in GLOB.machines)
floodlist += F
F.fswitch = src
start_processing()
diff --git a/code/game/machinery/biohazard_lockdown.dm b/code/game/machinery/biohazard_lockdown.dm
index fd6205baa1d9..2e3cbf6de234 100644
--- a/code/game/machinery/biohazard_lockdown.dm
+++ b/code/game/machinery/biohazard_lockdown.dm
@@ -102,8 +102,7 @@ GLOBAL_VAR_INIT(lockdown_state, LOCKDOWN_READY)
shipwide_ai_announcement(message, MAIN_AI_SYSTEM, 'sound/effects/biohazard.ogg')
message_admins(log)
- var/datum/ares_link/link = GLOB.ares_link
- link.log_ares_security("Containment Lockdown", ares_log)
+ log_ares_security("Containment Lockdown", ares_log)
#undef LOCKDOWN_READY
#undef LOCKDOWN_ACTIVE
diff --git a/code/game/machinery/bioprinter.dm b/code/game/machinery/bioprinter.dm
index 81d498ba02e2..65f6fe1842f4 100644
--- a/code/game/machinery/bioprinter.dm
+++ b/code/game/machinery/bioprinter.dm
@@ -113,6 +113,10 @@
switch(action)
if("print")
+ if(working)
+ //If we're already printing something then we're too busy to multi task.
+ to_chat(usr, SPAN_NOTICE("[src] is busy at the moment."))
+ return FALSE
var/recipe = params["recipe_id"]
var/valid_recipe = FALSE
for(var/datum/bioprinter_recipe/product_recipes in products)
@@ -124,6 +128,10 @@
message_admins("[key_name(usr)] attempted to print an invalid recipe on \the [src].")
return FALSE
var/datum/bioprinter_recipe/recipe_datum = new recipe
+ if(stored_metal < recipe_datum.metal)
+ to_chat(usr, SPAN_NOTICE("[src] does not have enough stored metal."))
+ QDEL_NULL(recipe_datum)
+ return FALSE
stored_metal -= recipe_datum.metal
to_chat(usr, SPAN_NOTICE("\The [src] is now printing the selected organ. Please hold."))
working = TRUE
@@ -146,6 +154,8 @@
/obj/structure/machinery/bioprinter/proc/print_limb(limb_path)
if(inoperable())
+ //In case we lose power or anything between the print and the callback we don't want to permenantly break the printer
+ working = FALSE
return
new limb_path(get_turf(src))
working = FALSE
diff --git a/code/game/machinery/bots/bots.dm b/code/game/machinery/bots/bots.dm
index 116753093fe5..46050d2705b3 100644
--- a/code/game/machinery/bots/bots.dm
+++ b/code/game/machinery/bots/bots.dm
@@ -114,6 +114,7 @@
/obj/structure/machinery/bot/emp_act(severity)
+ . = ..()
var/was_on = on
stat |= EMPED
new /obj/effect/overlay/temp/emp_sparks (loc)
@@ -150,7 +151,7 @@
/turf/proc/CardinalTurfsWithAccess(obj/item/card/id/ID)
var/L[] = new()
- for(var/d in cardinal)
+ for(var/d in GLOB.cardinals)
var/turf/T = get_step(src, d)
if(istype(T) && !T.density)
if(!LinkBlockedWithAccess(src, T, ID))
diff --git a/code/game/machinery/bots/cleanbot.dm b/code/game/machinery/bots/cleanbot.dm
index e2dcf7ffb1db..c21a7a854bc3 100644
--- a/code/game/machinery/bots/cleanbot.dm
+++ b/code/game/machinery/bots/cleanbot.dm
@@ -37,8 +37,8 @@
should_patrol = 1
src.botcard = new(src)
- if(RoleAuthority)
- var/datum/job/ctequiv = RoleAuthority.roles_by_name[JOB_CARGO_TECH]
+ if(GLOB.RoleAuthority)
+ var/datum/job/ctequiv = GLOB.RoleAuthority.roles_by_name[JOB_CARGO_TECH]
if(ctequiv) botcard.access = ctequiv.get_access()
src.locked = 0 // Start unlocked so roboticist can set them to patrol.
diff --git a/code/game/machinery/bots/medbot.dm b/code/game/machinery/bots/medbot.dm
index f28a15ea1893..77e890d88d34 100644
--- a/code/game/machinery/bots/medbot.dm
+++ b/code/game/machinery/bots/medbot.dm
@@ -63,7 +63,7 @@
src.botcard = new /obj/item/card/id(src)
if(isnull(src.botcard_access) || (src.botcard_access.len < 1))
- var/datum/job/J = RoleAuthority ? RoleAuthority.roles_by_path[/datum/job/civilian/doctor] : new /datum/job/civilian/doctor
+ var/datum/job/J = GLOB.RoleAuthority ? GLOB.RoleAuthority.roles_by_path[/datum/job/civilian/doctor] : new /datum/job/civilian/doctor
botcard.access = J.get_access()
else
src.botcard.access = src.botcard_access
diff --git a/code/game/machinery/bots/mulebot.dm b/code/game/machinery/bots/mulebot.dm
index b70829c708ed..08437d35a8e3 100644
--- a/code/game/machinery/bots/mulebot.dm
+++ b/code/game/machinery/bots/mulebot.dm
@@ -70,8 +70,8 @@
/obj/structure/machinery/bot/mulebot/Initialize(mapload, ...)
. = ..()
botcard = new(src)
- if(RoleAuthority)
- var/datum/job/ctequiv = RoleAuthority.roles_by_name[JOB_CARGO_TECH]
+ if(GLOB.RoleAuthority)
+ var/datum/job/ctequiv = GLOB.RoleAuthority.roles_by_name[JOB_CARGO_TECH]
if(ctequiv) botcard.access = ctequiv.get_access()
cell = new(src)
@@ -83,7 +83,7 @@
SSradio.add_object(src, beacon_freq, filter = RADIO_NAVBEACONS)
var/count = 0
- for(var/obj/structure/machinery/bot/mulebot/other in machines)
+ for(var/obj/structure/machinery/bot/mulebot/other in GLOB.machines)
count++
if(!suffix)
suffix = "#[count]"
@@ -551,7 +551,7 @@
var/speed = ((wires & WIRE_MOTOR1) ? 1:0) + ((wires & WIRE_MOTOR2) ? 2:0)
switch(speed)
if(0)
- // do nothing
+ pass()
if(1)
process_bot()
spawn(2)
@@ -763,7 +763,6 @@
M.stop_pulling()
M.apply_effect(8, STUN)
M.apply_effect(5, WEAKEN)
- M.lying = 1
..()
/obj/structure/machinery/bot/mulebot/alter_health()
@@ -916,11 +915,11 @@
post_signal_multiple(control_freq, kv)
/obj/structure/machinery/bot/mulebot/emp_act(severity)
+ . = ..()
if (cell)
cell.emp_act(severity)
if(load)
load.emp_act(severity)
- ..()
/obj/structure/machinery/bot/mulebot/explode()
diff --git a/code/game/machinery/buttons.dm b/code/game/machinery/buttons.dm
index ee83c430c2db..8d4b27778c69 100644
--- a/code/game/machinery/buttons.dm
+++ b/code/game/machinery/buttons.dm
@@ -1,15 +1,3 @@
-/obj/structure/machinery/driver_button
- name = "mass driver button"
- icon = 'icons/obj/objects.dmi'
- icon_state = "launcherbtt"
- desc = "A remote control switch for a mass driver."
- var/id = null
- var/active = 0
- anchored = TRUE
- use_power = USE_POWER_IDLE
- idle_power_usage = 2
- active_power_usage = 4
-
/obj/structure/machinery/ignition_switch
name = "ignition switch"
icon = 'icons/obj/objects.dmi'
diff --git a/code/game/machinery/camera/camera.dm b/code/game/machinery/camera/camera.dm
index d416c561fcd3..1a440d41bbed 100644
--- a/code/game/machinery/camera/camera.dm
+++ b/code/game/machinery/camera/camera.dm
@@ -35,6 +35,9 @@
var/colony_camera_mapload = TRUE
+ /// If this camera should have innate EMP-proofing
+ var/emp_proof = FALSE
+
/obj/structure/machinery/camera/Initialize(mapload, ...)
. = ..()
WireColorToFlag = randomCameraWires()
@@ -61,7 +64,14 @@
/obj/structure/machinery/camera/update_icon()
. = ..()
- if(icon_state == "autocam_editor")
+ // If the camera has been EMPed.
+ if(stat & EMPED)
+ icon_state = "cameraemp"
+ // If the camera isn't EMPed, but is disabled.
+ else if(!status)
+ icon_state = "camera1"
+ // Otherwise, just give it the normal animated `icon_state`.
+ else
icon_state = "camera"
/obj/structure/machinery/camera/set_pixel_location()
@@ -72,25 +82,28 @@
if(WEST) pixel_x = 27
/obj/structure/machinery/camera/emp_act(severity)
- if(!isEmpProof())
- if(prob(100/severity))
- icon_state = "[initial(icon_state)]emp"
- var/list/previous_network = network
- network = list()
- cameranet.removeCamera(src)
- stat |= EMPED
- set_light(0)
- triggerCameraAlarm()
- spawn(900)
- network = previous_network
- icon_state = initial(icon_state)
- stat &= ~EMPED
- cancelCameraAlarm()
- if(can_use())
- cameranet.addCamera(src)
- kick_viewers()
- ..()
+ . = ..()
+ // If the camera is EMP proof, or it passed the RNG check.
+ if(isEmpProof() || !prob(100 / severity))
+ return
+
+ var/list/previous_network = network
+ network = list()
+ GLOB.cameranet.removeCamera(src)
+ stat |= EMPED
+ update_icon()
+ set_light(0)
+ triggerCameraAlarm()
+ kick_viewers()
+ addtimer(CALLBACK(src, PROC_REF(undo_emp), previous_network), 90 SECONDS)
+/obj/structure/machinery/camera/proc/undo_emp(previous_network)
+ network = previous_network
+ stat &= ~EMPED
+ update_icon()
+ cancelCameraAlarm()
+ if(can_use())
+ GLOB.cameranet.addCamera(src)
/obj/structure/machinery/camera/ex_act(severity)
if(src.invuln)
@@ -101,7 +114,7 @@
/obj/structure/machinery/camera/proc/setViewRange(num = 7)
src.view_range = num
- cameranet.updateVisibility(src, 0)
+ GLOB.cameranet.updateVisibility(src, 0)
/obj/structure/machinery/camera/attack_hand(mob/living/carbon/human/user as mob)
@@ -186,10 +199,7 @@
visible_message(SPAN_WARNING("[user] has reactivated [src]!"))
else
visible_message(SPAN_WARNING("[user] has deactivated [src]!"))
- if(status)
- icon_state = "camera"
- else
- icon_state = "camera1"
+ update_icon()
// now disconnect anyone using the camera
//Apparently, this will disconnect anyone even if the camera was re-activated.
//I guess that doesn't matter since they can't use it anyway?
diff --git a/code/game/machinery/camera/motion.dm b/code/game/machinery/camera/motion.dm
index 41aa7fa32707..5a0a41fdc9bf 100644
--- a/code/game/machinery/camera/motion.dm
+++ b/code/game/machinery/camera/motion.dm
@@ -40,7 +40,7 @@
if (!status || (stat & NOPOWER))
return 0
if (detectTime == -1)
- for (var/mob/living/silicon/aiPlayer in ai_mob_list)
+ for (var/mob/living/silicon/aiPlayer in GLOB.ai_mob_list)
aiPlayer.cancelAlarm("Motion", get_area(src), src)
detectTime = 0
return 1
@@ -49,7 +49,7 @@
if (!status || (stat & NOPOWER))
return 0
if (!detectTime) return 0
- for (var/mob/living/silicon/aiPlayer in ai_mob_list)
+ for (var/mob/living/silicon/aiPlayer in GLOB.ai_mob_list)
aiPlayer.triggerAlarm("Motion", get_area(src), list(src), src)
detectTime = -1
return 1
diff --git a/code/game/machinery/camera/presets.dm b/code/game/machinery/camera/presets.dm
index a8735cbc06a8..1f680ad76712 100644
--- a/code/game/machinery/camera/presets.dm
+++ b/code/game/machinery/camera/presets.dm
@@ -30,6 +30,7 @@
network = list(CAMERA_NET_LASER_TARGETS)
unslashable = TRUE
unacidable = TRUE
+ emp_proof = TRUE
/obj/structure/machinery/camera/laser_cam/Initialize(mapload, laser_name)
. = ..()
@@ -37,8 +38,6 @@
var/area/A = get_area(src)
c_tag = "[laser_name] ([A.name])"
-/obj/structure/machinery/camera/laser_cam/emp_act(severity)
- return //immune to EMPs, just in case
/obj/structure/machinery/camera/laser_cam/ex_act()
return
@@ -79,7 +78,7 @@
number = 1
var/area/A = get_area(src)
if(A)
- for(var/obj/structure/machinery/camera/autoname/C in machines)
+ for(var/obj/structure/machinery/camera/autoname/C in GLOB.machines)
if(C == src) continue
var/area/CA = get_area(C)
if(CA.type == A.type)
@@ -125,9 +124,7 @@
invisibility = 101 //fuck you init()
colony_camera_mapload = FALSE
-
-/obj/structure/machinery/camera/autoname/lz_camera/emp_act(severity)
- return //immune to EMPs, just in case
+ emp_proof = TRUE
/obj/structure/machinery/camera/autoname/lz_camera/ex_act()
return
@@ -137,7 +134,7 @@
/obj/structure/machinery/camera/proc/isEmpProof()
var/O = locate(/obj/item/stack/sheet/mineral/osmium) in assembly.upgrades
- return O
+ return O || emp_proof
/obj/structure/machinery/camera/proc/isXRay()
var/obj/item/stock_parts/scanning_module/O = locate(/obj/item/stock_parts/scanning_module) in assembly.upgrades
diff --git a/code/game/machinery/camera/tracking.dm b/code/game/machinery/camera/tracking.dm
index 806664e012de..190d51d3f7b8 100644
--- a/code/game/machinery/camera/tracking.dm
+++ b/code/game/machinery/camera/tracking.dm
@@ -4,7 +4,7 @@
/mob/living/silicon/ai/proc/InvalidTurf(turf/T as turf)
if(!T)
return 1
- if(is_admin_level(T.z))
+ if(should_block_game_interaction(T))
return 1
if(T.z > 6)
return 1
@@ -16,7 +16,7 @@
return
var/list/L = list()
- for (var/obj/structure/machinery/camera/C in cameranet.cameras)
+ for (var/obj/structure/machinery/camera/C in GLOB.cameranet.cameras)
L.Add(C)
camera_sort(L)
@@ -213,9 +213,9 @@
return 0
if(isrobot(M))
var/mob/living/silicon/robot/R = M
- if(!(R.camera && R.camera.can_use()) && !cameranet.checkCameraVis(M))
+ if(!(R.camera && R.camera.can_use()) && !GLOB.cameranet.checkCameraVis(M))
return 0
- else if(!cameranet.checkCameraVis(M))
+ else if(!GLOB.cameranet.checkCameraVis(M))
return 0
return 1
diff --git a/code/game/machinery/cell_charger.dm b/code/game/machinery/cell_charger.dm
index fcd8c65e93ca..eb7a501fa078 100644
--- a/code/game/machinery/cell_charger.dm
+++ b/code/game/machinery/cell_charger.dm
@@ -80,11 +80,11 @@
return
/obj/structure/machinery/cell_charger/emp_act(severity)
+ . = ..()
if(inoperable())
return
if(charging)
charging.emp_act(severity)
- ..(severity)
/obj/structure/machinery/cell_charger/process()
diff --git a/code/game/machinery/computer/HolodeckControl.dm b/code/game/machinery/computer/HolodeckControl.dm
index 08de86581518..55df45c70ccc 100644
--- a/code/game/machinery/computer/HolodeckControl.dm
+++ b/code/game/machinery/computer/HolodeckControl.dm
@@ -22,7 +22,7 @@
. = ..()
icon_state = "grass[pick("1","2","3","4")]"
update_icon()
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
if(istype(get_step(src, direction), /turf/open/floor))
var/turf/open/floor/FF = get_step(src,direction)
FF.update_icon() //so siding get updated properly
@@ -148,19 +148,19 @@
return
M.forceMove(loc)
M.apply_effect(5, WEAKEN)
- for(var/obj/structure/machinery/scoreboard/X in machines)
+ for(var/obj/structure/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 [M] into the [src]!"))
+ visible_message(SPAN_DANGER("[user] dunks [M] into [src]!"))
return
else if (istype(W, /obj/item) && get_dist(src,user)<2)
user.drop_inv_item_to_loc(W, loc)
- for(var/obj/structure/machinery/scoreboard/X in machines)
+ for(var/obj/structure/machinery/scoreboard/X in GLOB.machines)
if(X.id == id)
X.score(side)
// no break, to update multiple scoreboards
- visible_message(SPAN_NOTICE("[user] dunks [W] into the [src]!"))
+ visible_message(SPAN_NOTICE("[user] dunks [W] into [src]!"))
return
/obj/structure/holohoop/BlockedPassDirs(atom/movable/mover, target_dir)
@@ -170,7 +170,7 @@
return BLOCKED_MOVEMENT
if(prob(50))
I.forceMove(src.loc)
- for(var/obj/structure/machinery/scoreboard/X in machines)
+ for(var/obj/structure/machinery/scoreboard/X in GLOB.machines)
if(X.id == id)
X.score(side)
// no break, to update multiple scoreboards
diff --git a/code/game/machinery/computer/aifixer.dm b/code/game/machinery/computer/aifixer.dm
index 67e4e8ed35ab..3a809620d7e6 100644
--- a/code/game/machinery/computer/aifixer.dm
+++ b/code/game/machinery/computer/aifixer.dm
@@ -68,7 +68,6 @@
src.occupant.updatehealth()
if (src.occupant.health >= 0 && src.occupant.stat == DEAD)
src.occupant.set_stat(CONSCIOUS)
- src.occupant.lying = 0
GLOB.dead_mob_list -= src.occupant
GLOB.alive_mob_list += src.occupant
occupant.reload_fullscreens()
diff --git a/code/game/machinery/computer/almayer_control.dm b/code/game/machinery/computer/almayer_control.dm
index c3b17dbf8090..e9b969e023b8 100644
--- a/code/game/machinery/computer/almayer_control.dm
+++ b/code/game/machinery/computer/almayer_control.dm
@@ -72,7 +72,7 @@
var/list/data = list()
var/list/messages = list()
- data["alert_level"] = security_level
+ data["alert_level"] = GLOB.security_level
data["time_request"] = cooldown_request
data["time_destruct"] = cooldown_destruct
@@ -81,9 +81,9 @@
data["worldtime"] = world.time
- data["evac_status"] = EvacuationAuthority.evac_status
- if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING)
- data["evac_eta"] = EvacuationAuthority.get_status_panel_eta()
+ data["evac_status"] = SShijack.evac_status
+ if(SShijack.evac_status == EVACUATION_STATUS_INITIATED)
+ data["evac_eta"] = SShijack.get_evac_eta()
if(!messagetitle.len)
data["messages"] = null
@@ -108,7 +108,6 @@
. = ..()
if(.)
return
-
switch(action)
if("award")
print_medal(usr, src)
@@ -117,42 +116,51 @@
// evac stuff start \\
if("evacuation_start")
- if(security_level < SEC_LEVEL_RED)
+ if(GLOB.security_level < SEC_LEVEL_RED)
to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures."))
return FALSE
- if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY)
+ if(SShijack.evac_admin_denied)
to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
return FALSE
- if(!EvacuationAuthority.initiate_evacuation())
+ if(!SShijack.initiate_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
return FALSE
log_game("[key_name(usr)] has called for an emergency evacuation.")
message_admins("[key_name_admin(usr)] has called for an emergency evacuation.")
- var/datum/ares_link/link = GLOB.ares_link
- link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.")
+ log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.")
. = TRUE
if("evacuation_cancel")
- if(!EvacuationAuthority.cancel_evacuation())
- to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!"))
+ var/mob/living/carbon/human/human_user = usr
+ var/obj/item/card/id/idcard = human_user.get_active_hand()
+ var/bio_fail = FALSE
+ if(!istype(idcard))
+ idcard = human_user.wear_id
+ if(!istype(idcard))
+ bio_fail = TRUE
+ else if(!idcard.check_biometrics(human_user))
+ bio_fail = TRUE
+ if(bio_fail)
+ to_chat(human_user, SPAN_WARNING("Biometrics failure! You require an authenticated ID card to perform this action!"))
return FALSE
- addtimer(CALLBACK(src, TYPE_PROC_REF(/obj/structure/machinery/computer/almayer_control, cancel_evac)), 4 SECONDS)
+ if(!SShijack.cancel_evacuation())
+ to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!"))
+ return FALSE
log_game("[key_name(usr)] has canceled the emergency evacuation.")
message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.")
- var/datum/ares_link/link = GLOB.ares_link
- link.log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.")
+ log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.")
. = TRUE
// evac stuff end \\
if("change_sec_level")
var/list/alert_list = list(num2seclevel(SEC_LEVEL_GREEN), num2seclevel(SEC_LEVEL_BLUE))
- switch(security_level)
+ switch(GLOB.security_level)
if(SEC_LEVEL_GREEN)
alert_list -= num2seclevel(SEC_LEVEL_GREEN)
if(SEC_LEVEL_BLUE)
@@ -167,8 +175,7 @@
set_security_level(seclevel2num(level_selected), log = ARES_LOG_NONE)
log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
- var/datum/ares_link/link = GLOB.ares_link
- link.log_ares_security("Manual Security Update", "[usr] has changed the security level to [get_security_level()].")
+ log_ares_security("Manual Security Update", "[usr] has changed the security level to [get_security_level()].")
. = TRUE
if("messageUSCM")
@@ -223,7 +230,7 @@
to_chat(usr, SPAN_WARNING("The distress beacon has recently broadcast a message. Please wait."))
return FALSE
- if(security_level == SEC_LEVEL_DELTA)
+ if(GLOB.security_level == SEC_LEVEL_DELTA)
to_chat(usr, SPAN_WARNING("The ship is already undergoing self-destruct procedures!"))
return FALSE
@@ -280,10 +287,3 @@
// end tgui interact \\
// end tgui \\
-
-/obj/structure/machinery/computer/almayer_control/proc/cancel_evac()
- if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait
- //if the self_destruct is active we try to cancel it (which includes lowering alert level to red)
- if(!EvacuationAuthority.cancel_self_destruct(1))
- //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually.
- set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level.
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 8d35dd1b6aff..1ac5a06738d5 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -165,8 +165,8 @@
return
/obj/structure/machinery/computer/arcade/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
var/empprize = null
var/num_of_prizes = 0
@@ -178,5 +178,3 @@
for(num_of_prizes; num_of_prizes > 0; num_of_prizes--)
empprize = pickweight(prizes)
new empprize(src.loc)
-
- ..(severity)
diff --git a/code/game/machinery/computer/area_air_control.dm b/code/game/machinery/computer/area_air_control.dm
index 22f4211aa8ee..cd9870f175c4 100644
--- a/code/game/machinery/computer/area_air_control.dm
+++ b/code/game/machinery/computer/area_air_control.dm
@@ -156,7 +156,7 @@
var/turf/T = get_turf(src)
if(!T.loc) return
- for(var/obj/structure/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in machines )
+ for(var/obj/structure/machinery/portable_atmospherics/powered/scrubber/huge/scrubber in GLOB.machines )
var/turf/T2 = get_turf(scrubber)
if(T2 && T2.loc)
var/area/A = T2.loc
diff --git a/code/game/machinery/computer/camera_console.dm b/code/game/machinery/computer/camera_console.dm
index 281c548227b0..1a00e194b5eb 100644
--- a/code/game/machinery/computer/camera_console.dm
+++ b/code/game/machinery/computer/camera_console.dm
@@ -69,7 +69,7 @@
return attack_hand(user)
/obj/structure/machinery/computer/cameras/attack_hand(mob/user)
- if(!admin_console && is_admin_level(z))
+ if(!admin_console && should_block_game_interaction(src))
to_chat(user, SPAN_DANGER("Unable to establish a connection: \black You're too far away from the ship!"))
return
if(inoperable())
@@ -226,7 +226,7 @@
// Returns the list of cameras accessible from this computer
/obj/structure/machinery/computer/cameras/proc/get_available_cameras()
var/list/D = list()
- for(var/obj/structure/machinery/camera/C in cameranet.cameras)
+ for(var/obj/structure/machinery/camera/C in GLOB.cameranet.cameras)
if(!C.network)
stack_trace("Camera in a cameranet has no camera network")
continue
@@ -354,8 +354,8 @@
exproof = TRUE
colony_camera_mapload = FALSE
-/obj/structure/machinery/computer/cameras/mortar/emp_act(severity)
- return FALSE
+/obj/structure/machinery/computer/cameras/mortar/set_broken()
+ return
/obj/structure/machinery/computer/cameras/dropship
name = "abstract dropship camera computer"
diff --git a/code/game/machinery/computer/communications.dm b/code/game/machinery/computer/communications.dm
index f7ea31fba36a..bcc4c4ac3ec8 100644
--- a/code/game/machinery/computer/communications.dm
+++ b/code/game/machinery/computer/communications.dm
@@ -43,7 +43,7 @@
var/stat_msg1
var/stat_msg2
- var/datum/tacmap/tacmap
+ var/datum/tacmap/drawing/tacmap
var/minimap_type = MINIMAP_FLAG_USCM
processing = TRUE
@@ -65,7 +65,6 @@
if(..()) return FALSE
usr.set_interaction(src)
- var/datum/ares_link/link = GLOB.ares_link
switch(href_list["operation"])
if("mapview")
tacmap.tgui_interact(usr)
@@ -99,9 +98,9 @@
if(-INFINITY to SEC_LEVEL_GREEN) tmp_alertlevel = SEC_LEVEL_GREEN //Cannot go below green.
if(SEC_LEVEL_BLUE to INFINITY) tmp_alertlevel = SEC_LEVEL_BLUE //Cannot go above blue.
- var/old_level = security_level
+ var/old_level = GLOB.security_level
set_security_level(tmp_alertlevel)
- if(security_level != old_level)
+ if(GLOB.security_level != old_level)
//Only notify the admins if an actual change happened
log_game("[key_name(usr)] has changed the security level to [get_security_level()].")
message_admins("[key_name_admin(usr)] has changed the security level to [get_security_level()].")
@@ -135,41 +134,47 @@
if("evacuation_start")
if(state == STATE_EVACUATION)
- if(security_level < SEC_LEVEL_DELTA)
+ if(GLOB.security_level < SEC_LEVEL_DELTA)
to_chat(usr, SPAN_WARNING("The ship must be under delta alert in order to enact evacuation procedures."))
return FALSE
- if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY)
+ if(SShijack.evac_admin_denied)
to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
return FALSE
- if(!EvacuationAuthority.initiate_evacuation())
+ if(!SShijack.initiate_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
return FALSE
log_game("[key_name(usr)] has called for an emergency evacuation.")
message_admins("[key_name_admin(usr)] has called for an emergency evacuation.")
- link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.")
+ log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.")
return TRUE
state = STATE_EVACUATION
if("evacuation_cancel")
+ var/mob/living/carbon/human/human_user = usr
+ var/obj/item/card/id/idcard = human_user.get_active_hand()
+ var/bio_fail = FALSE
+ if(!istype(idcard))
+ idcard = human_user.wear_id
+ if(!istype(idcard))
+ bio_fail = TRUE
+ else if(!idcard.check_biometrics(human_user))
+ bio_fail = TRUE
+ if(bio_fail)
+ to_chat(human_user, SPAN_WARNING("Biometrics failure! You require an authenticated ID card to perform this action!"))
+ return FALSE
+
if(state == STATE_EVACUATION_CANCEL)
- if(!EvacuationAuthority.cancel_evacuation())
+ if(!SShijack.cancel_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to cancel the evacuation right now!"))
return FALSE
- spawn(35)//some time between AI announcements for evac cancel and SD cancel.
- if(EvacuationAuthority.evac_status == EVACUATION_STATUS_STANDING_BY)//nothing changed during the wait
- //if the self_destruct is active we try to cancel it (which includes lowering alert level to red)
- if(!EvacuationAuthority.cancel_self_destruct(1))
- //if SD wasn't active (likely canceled manually in the SD room), then we lower the alert level manually.
- set_security_level(SEC_LEVEL_RED, TRUE) //both SD and evac are inactive, lowering the security level.
-
log_game("[key_name(usr)] has canceled the emergency evacuation.")
message_admins("[key_name_admin(usr)] has canceled the emergency evacuation.")
- link.log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.")
+ log_ares_security("Cancel Evacuation", "[usr] has cancelled the emergency evacuation.")
return TRUE
state = STATE_EVACUATION_CANCEL
@@ -193,7 +198,7 @@
to_chat(usr, SPAN_WARNING("The distress beacon has recently broadcast a message. Please wait."))
return FALSE
- if(security_level == SEC_LEVEL_DELTA)
+ if(GLOB.security_level == SEC_LEVEL_DELTA)
to_chat(usr, SPAN_WARNING("The ship is already undergoing self-destruct procedures!"))
return FALSE
@@ -328,8 +333,8 @@
user.set_interaction(src)
var/dat = "Communications Console"
- if(EvacuationAuthority.evac_status == EVACUATION_STATUS_INITIATING)
- dat += "Evacuation in Progress\n \nETA: [EvacuationAuthority.get_status_panel_eta()] "
+ if(SShijack.evac_status == EVACUATION_STATUS_INITIATED)
+ dat += "Evacuation in Progress\n \nETA: [SShijack.get_evac_eta()] "
switch(state)
if(STATE_DEFAULT)
if(authenticated)
@@ -352,9 +357,11 @@
dat += " Award a medal"
dat += " Send Distress Beacon"
dat += " Activate Self-Destruct"
- switch(EvacuationAuthority.evac_status)
- if(EVACUATION_STATUS_STANDING_BY) dat += " Initiate emergency evacuation"
- if(EVACUATION_STATUS_INITIATING) dat += " Cancel emergency evacuation"
+ switch(SShijack.evac_status)
+ if(EVACUATION_STATUS_NOT_INITIATED)
+ dat += " Initiate emergency evacuation"
+ if(EVACUATION_STATUS_INITIATED)
+ dat += " Cancel emergency evacuation"
else
dat += " LOG IN"
@@ -409,20 +416,8 @@
if(STATE_ALERT_LEVEL)
dat += "Current alert level: [get_security_level()] "
- if(security_level == SEC_LEVEL_DELTA)
- if(EvacuationAuthority.dest_status >= NUKE_EXPLOSION_ACTIVE)
- dat += SET_CLASS("The self-destruct mechanism is active. [EvacuationAuthority.evac_status != EVACUATION_STATUS_INITIATING ? "You have to manually deactivate the self-destruct mechanism." : ""]", INTERFACE_RED)
- dat += " "
- switch(EvacuationAuthority.evac_status)
- if(EVACUATION_STATUS_INITIATING)
- dat += SET_CLASS("Evacuation initiated. Evacuate or rescind evacuation orders.", INTERFACE_RED)
- if(EVACUATION_STATUS_IN_PROGRESS)
- dat += SET_CLASS("Evacuation in progress.", INTERFACE_RED)
- if(EVACUATION_STATUS_COMPLETE)
- dat += SET_CLASS("Evacuation complete.", INTERFACE_RED)
- else
- dat += "Blue "
- dat += "Green"
+ dat += "Blue "
+ dat += "Green"
if(STATE_CONFIRM_LEVEL)
dat += "Current alert level: [get_security_level()] "
diff --git a/code/game/machinery/computer/computer.dm b/code/game/machinery/computer/computer.dm
index adce72f7d8b6..c33517796271 100644
--- a/code/game/machinery/computer/computer.dm
+++ b/code/game/machinery/computer/computer.dm
@@ -31,8 +31,9 @@
return 1
/obj/structure/machinery/computer/emp_act(severity)
- if(prob(20/severity)) set_broken()
- ..()
+ . = ..()
+ if(prob(20/severity))
+ set_broken()
/obj/structure/machinery/computer/ex_act(severity)
@@ -53,8 +54,6 @@
if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY)
deconstruct(FALSE)
return
- else
- return
/obj/structure/machinery/computer/bullet_act(obj/projectile/Proj)
if(exproof)
diff --git a/code/game/machinery/computer/demo_sim.dm b/code/game/machinery/computer/demo_sim.dm
index 15261cfc8f4b..f633e8f351d4 100644
--- a/code/game/machinery/computer/demo_sim.dm
+++ b/code/game/machinery/computer/demo_sim.dm
@@ -55,7 +55,6 @@
var/list/data = list()
data["configuration"] = configuration
- data["looking"] = simulation.looking_at_simulation
data["dummy_mode"] = simulation.dummy_mode
data["worldtime"] = world.time
@@ -104,8 +103,7 @@
/obj/structure/machinery/computer/demo_sim/ui_close(mob/user)
. = ..()
- if(simulation.looking_at_simulation)
- simulation.stop_watching(user)
+ simulation.stop_watching(user)
// DEMOLITIONS TGUI SHIT END \\
diff --git a/code/game/machinery/computer/dropship_weapons.dm b/code/game/machinery/computer/dropship_weapons.dm
index 60bf17388db8..db376c40029c 100644
--- a/code/game/machinery/computer/dropship_weapons.dm
+++ b/code/game/machinery/computer/dropship_weapons.dm
@@ -11,7 +11,6 @@
exproof = TRUE
var/shuttle_tag // Used to know which shuttle we're linked to.
var/obj/structure/dropship_equipment/selected_equipment //the currently selected equipment installed on the shuttle this console controls.
- var/list/shuttle_equipments = list() //list of the equipments on the shuttle this console controls
var/cavebreaker = FALSE //ignore caves and other restrictions?
var/datum/cas_fire_envelope/firemission_envelope
var/datum/cas_fire_mission/selected_firemission
@@ -25,15 +24,41 @@
var/datum/simulator/simulation
var/datum/cas_fire_mission/configuration
+ // groundside maps
+ var/datum/tacmap/tacmap
+ var/minimap_type = MINIMAP_FLAG_USCM
+
+ // Cameras
+ var/camera_target_id
+ var/camera_width = 11
+ var/camera_height = 11
+ var/camera_map_name
+
+ var/registered = FALSE
+
/obj/structure/machinery/computer/dropship_weapons/Initialize()
. = ..()
simulation = new()
+ tacmap = new(src, minimap_type)
+
+ RegisterSignal(src, COMSIG_CAMERA_MAPNAME_ASSIGNED, PROC_REF(camera_mapname_update))
+
+ // camera setup
+ AddComponent(/datum/component/camera_manager)
+ SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR)
/obj/structure/machinery/computer/dropship_weapons/New()
..()
if(firemission_envelope)
firemission_envelope.linked_console = src
+/obj/structure/machinery/computer/dropship_weapons/proc/camera_mapname_update(source, value)
+ camera_map_name = value
+
+/obj/structure/machinery/computer/dropship_weapons/Destroy()
+ . = ..()
+ UnregisterSignal(src, COMSIG_CAMERA_MAPNAME_ASSIGNED)
+
/obj/structure/machinery/computer/dropship_weapons/attack_hand(mob/user)
if(..())
return
@@ -43,7 +68,7 @@
to_chat(user, SPAN_WARNING("Weapons modification access denied, attempting to launch simulation."))
if(!selected_firemission)
- to_chat(usr, SPAN_WARNING("Firemission must be selected before attempting to run the simulation"))
+ to_chat(user, SPAN_WARNING("Firemission must be selected before attempting to run the simulation"))
return
tgui_interact(user)
@@ -54,139 +79,41 @@
/obj/structure/machinery/computer/dropship_weapons/attackby(obj/item/W, mob/user as mob)
if(istype(W, /obj/item/frame/matrix_frame))
- var/obj/item/frame/matrix_frame/MATRIX = W
- if(MATRIX.state == ASSEMBLY_LOCKED)
+ var/obj/item/frame/matrix_frame/matrix = W
+ if(matrix.state == ASSEMBLY_LOCKED)
user.drop_held_item(W, src)
W.forceMove(src)
to_chat(user, SPAN_NOTICE("You swap the matrix in the dropship guidance camera system, destroying the older part in the process"))
- upgraded = MATRIX.upgrade
- matrixcol = MATRIX.matrixcol
- power = MATRIX.power
+ upgraded = matrix.upgrade
+ matrixcol = matrix.matrixcol
+ power = matrix.power
else
- to_chat(user, SPAN_WARNING("matrix is not complete!"))
+ to_chat(user, SPAN_WARNING("Matrix is not complete!"))
+
+/obj/structure/machinery/computer/dropship_weapons/proc/equipment_update(obj/docking_port/mobile/marine_dropship/dropship)
+ SIGNAL_HANDLER
+ var/list/obj/structure/dropship_equipment/weapons = list()
+ for(var/obj/structure/dropship_equipment/weapon/weap as anything in dropship.equipments)
+ weapons.Add(weap)
+ firemission_envelope.update_weapons(weapons)
/obj/structure/machinery/computer/dropship_weapons/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0)
- var/data[0]
var/obj/docking_port/mobile/marine_dropship/dropship = SSshuttle.getShuttle(shuttle_tag)
if (!istype(dropship))
return
- var/shuttle_state
- switch(dropship.mode)
- if(SHUTTLE_IDLE)
- shuttle_state = "idle"
- if(SHUTTLE_IGNITING)
- shuttle_state = "warmup"
- if(SHUTTLE_CALL)
- shuttle_state = "in_transit"
- if(SHUTTLE_CRASHED)
- shuttle_state = "crashed"
-
-
- var/list/equipment_data = list()
- var/list/targets_data = list()
- var/list/firemission_data = list()
- var/list/firemission_edit_data = list()
- var/list/firemission_edit_timeslices = list()
-
- for(var/ts = 1; ts<=firemission_envelope.fire_length; ts++)
- firemission_edit_timeslices += ts
-
- var/current_mission_error = null
- if(!faction)
- return //no faction, no weapons
-
- var/datum/cas_iff_group/cas_group = cas_groups[faction]
-
- if(!cas_group)
- return //broken group. No fighting
-
- for(var/X in cas_group.cas_signals)
- var/datum/cas_signal/LT = X
- if(!istype(LT) || !LT.valid_signal())
- continue
- var/area/laser_area = get_area(LT.signal_loc)
- targets_data += list(list("target_name" = "[LT.name] ([laser_area.name])", "target_tag" = LT.target_id))
- shuttle_equipments = dropship.equipments
- var/element_nbr = 1
- for(var/X in dropship.equipments)
- var/obj/structure/dropship_equipment/E = X
- equipment_data += list(list("name"= sanitize(copytext(E.name,1,MAX_MESSAGE_LEN)), "eqp_tag" = element_nbr, "is_weapon" = E.is_weapon, "is_interactable" = E.is_interactable))
- element_nbr++
- E.linked_console = src
-
-
- var/selected_eqp_name = ""
- var/selected_eqp_ammo_name = ""
- var/selected_eqp_ammo_amt = 0
- var/selected_eqp_max_ammo_amt = 0
var/screen_mode = 0
- var/fm_length = 0
- var/fm_offset = 0
- var/fm_direction = ""
- var/fm_step_text = ""
- var/firemission_signal
- var/firemission_stat = 0
- if(selected_equipment)
- selected_eqp_name = sanitize(copytext(selected_equipment.name,1,MAX_MESSAGE_LEN))
- if(selected_equipment.ammo_equipped)
- selected_eqp_ammo_name = sanitize(copytext(selected_equipment.ammo_equipped.name,1,MAX_MESSAGE_LEN))
- selected_eqp_ammo_amt = selected_equipment.ammo_equipped.ammo_count
- selected_eqp_max_ammo_amt = selected_equipment.ammo_equipped.max_ammo_count
- screen_mode = selected_equipment.screen_mode
-
- var/firemission_id = 1
- var/found_selected = FALSE
if(firemission_envelope)
- firemission_stat = firemission_envelope.stat
- fm_step_text = firemission_envelope.firemission_status_message()
- for(var/datum/cas_fire_mission/X in firemission_envelope.missions)
- if(!istype(X))
- continue //the fuck
- var/error_code = X.check(src)
-
- var/selected = X == selected_firemission
- if(error_code != FIRE_MISSION_ALL_GOOD && selected)
- selected = FALSE
- selected_firemission = null
- var/can_edit = error_code != FIRE_MISSION_CODE_ERROR && !selected
-
- if(selected)
- found_selected = TRUE
- var/can_interact = firemission_envelope.stat == FIRE_MISSION_STATE_IDLE && error_code == FIRE_MISSION_ALL_GOOD
- firemission_data += list(list("name"= sanitize(copytext(X.name,1,MAX_MESSAGE_LEN)), "mission_tag" = firemission_id, "can_edit" = can_edit, "can_interact" = can_interact, "selected" = selected))
- firemission_id++
-
if(!istype(editing_firemission))
editing_firemission = null
- //the fuck
if(editing_firemission)
var/error_code = editing_firemission.check(src)
var/can_edit = error_code != FIRE_MISSION_CODE_ERROR
- if(error_code != FIRE_MISSION_ALL_GOOD)
- current_mission_error = editing_firemission.error_message(error_code)
- else
- current_mission_error = null
if(!can_edit)
editing_firemission = null
//abort
- else
- screen_mode = 2
- for(var/datum/cas_fire_mission_record/firerec in editing_firemission.records)
- var/gimbal = firerec.get_offsets()
- var/ammo = firerec.get_ammo()
- var/offsets = new /list(firerec.offsets.len)
- for(var/idx = 1; idx < firerec.offsets.len; idx++)
- offsets[idx] = firerec.offsets[idx] == null ? "-" : firerec.offsets[idx]
- firemission_edit_data += list(list("name" = sanitize(copytext(firerec.weapon.name, 1, 50)), "ammo" = ammo, "gimbal" = gimbal, "offsets" = firerec.offsets))
-
- if(!found_selected)
- selected_firemission = null
-
- if(editing_firemission)
- fm_length = editing_firemission.mission_length
if((screen_mode != 0 && in_firemission_mode) || !selected_firemission)
in_firemission_mode = FALSE
@@ -196,490 +123,662 @@
selected_firemission = null
if(selected_firemission && in_firemission_mode)
screen_mode = 3
- fm_offset = firemission_envelope.recorded_offset
- fm_direction = dir2text(firemission_envelope.recorded_dir)
if(firemission_envelope.recorded_loc && (!firemission_envelope.recorded_loc.signal_loc || !firemission_envelope.recorded_loc.signal_loc:loc))
firemission_envelope.recorded_loc = null
- firemission_signal = firemission_envelope.recorded_loc?firemission_envelope.recorded_loc.get_name() : "NOT SELECTED"
- if(!fm_direction)
- fm_direction = "NOT SELECTED"
-
- if(screen_mode != 3 || !selected_firemission || shuttle_state != "in_transit")
- update_location(null)
- // /if(firemission_envelope)
-
- data = list(
- "shuttle_state" = shuttle_state,
- "fire_mission_enabled" = dropship.in_flyby,
- "equipment_data" = equipment_data,
- "targets_data" = targets_data,
- "selected_eqp" = selected_eqp_name,
- "selected_eqp_ammo_name" = selected_eqp_ammo_name,
- "selected_eqp_ammo_amt" = selected_eqp_ammo_amt,
- "selected_eqp_max_ammo_amt" = selected_eqp_max_ammo_amt,
- "screen_mode" = screen_mode,
- "firemission_data" = firemission_data,
- "editing_firemission" = editing_firemission,
- "editing_firemission_length" = fm_length,
- "firemission_edit_data" = firemission_edit_data,
- "current_mission_error" = current_mission_error,
- "firemission_edit_timeslices" = firemission_edit_timeslices,
- "has_firemission" = !!firemission_envelope,
- "can_firemission" = !!selected_firemission && shuttle_state == "in_transit",
- "can_launch_firemission" = !!selected_firemission && shuttle_state == "in_transit" && firemission_stat != FIRE_MISSION_STATE_IDLE,
- //firemission related stuff
- "firemission_name" = (selected_firemission ? selected_firemission.name : ""),
- "firemission_selected_laser" = firemission_signal,
- "firemission_offset" = fm_offset,
- "firemission_direction" = fm_direction,
- "firemission_message" = fm_step_text,
- "firemission_step" = firemission_stat,
- )
+ if(screen_mode != 3 || !selected_firemission || dropship.mode != SHUTTLE_CALL)
+ update_location(user, null)
- ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ ui_data(user)
+ if(!tacmap.map_holder)
+ var/level = SSmapping.levels_by_trait(tacmap.targeted_ztrait)
+ tacmap.map_holder = SSminimaps.fetch_tacmap_datum(level[1], tacmap.allowed_flags)
+ user.client.register_map_obj(tacmap.map_holder.map)
+ tgui_interact(user)
+
+/obj/structure/machinery/computer/dropship_weapons/tgui_interact(mob/user, datum/tgui/ui)
+ if(!registered)
+ var/obj/docking_port/mobile/marine_dropship/dropship = SSshuttle.getShuttle(shuttle_tag)
+ RegisterSignal(dropship, COMSIG_DROPSHIP_ADD_EQUIPMENT, PROC_REF(equipment_update))
+ RegisterSignal(dropship, COMSIG_DROPSHIP_REMOVE_EQUIPMENT, PROC_REF(equipment_update))
+ registered=TRUE
+ ui = SStgui.try_update_ui(user, src, ui)
if (!ui)
- ui = new(user, src, ui_key, "dropship_weapons_console.tmpl", "Weapons Control", 800, 600)
- ui.set_initial_data(data)
+ SEND_SIGNAL(src, COMSIG_CAMERA_REGISTER_UI, user)
+ ui = new(user, src, "DropshipWeaponsConsole", "Weapons Console")
ui.open()
- ui.set_auto_update(1)
-/obj/structure/machinery/computer/dropship_weapons/Topic(href, href_list)
- if(..())
- return
+/obj/structure/machinery/computer/dropship_weapons/ui_close(mob/user)
+ . = ..()
+ SEND_SIGNAL(src, COMSIG_CAMERA_UNREGISTER_UI, user)
+ simulation.stop_watching(user)
- add_fingerprint(usr)
+/obj/structure/machinery/computer/dropship_weapons/ui_status(mob/user, datum/ui_state/state)
+ . = ..()
+ if(inoperable())
+ return UI_CLOSE
+ if(!faction)
+ return UI_CLOSE
+
+ var/datum/cas_iff_group/cas_group = GLOB.cas_groups[faction]
+ if(!cas_group)
+ return UI_CLOSE
+
+/obj/structure/machinery/computer/dropship_weapons/ui_state(mob/user)
+ return GLOB.not_incapacitated_and_adjacent_strict_state
+/obj/structure/machinery/computer/dropship_weapons/ui_static_data(mob/user)
+ . = list()
+ .["tactical_map_ref"] = tacmap.map_holder.map_ref
+ .["camera_map_ref"] = camera_map_name
+
+/obj/structure/machinery/computer/dropship_weapons/ui_data(mob/user)
+ . = list()
var/obj/docking_port/mobile/marine_dropship/dropship = SSshuttle.getShuttle(shuttle_tag)
if (!istype(dropship))
return
- if(href_list["equip_interact"])
- var/base_tag = text2num(href_list["equip_interact"])
- var/obj/structure/dropship_equipment/E = shuttle_equipments[base_tag]
- E.linked_console = src
- E.equipment_interact(usr)
-
- if(href_list["open_fire"])
- var/targ_id = text2num(href_list["open_fire"])
- var/mob/M = usr
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(!H.allow_gun_usage)
- to_chat(H, SPAN_WARNING("Your programming prevents you from operating dropship weaponry!"))
- return
- var/obj/structure/dropship_equipment/weapon/DEW = selected_equipment
- if(!selected_equipment || !selected_equipment.is_weapon)
- to_chat(usr, SPAN_WARNING("No weapon selected."))
- return
- if(!skillcheck(M, SKILL_PILOT, DEW.skill_required)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("You don't have the training to fire this weapon!"))
- return
+ var/datum/cas_signal/sig = get_cas_signal(camera_target_id)
+ if(camera_target_id && !sig)
+ set_camera_target(null)
- if(!faction)
- return //no faction, no weapons
-
- var/datum/cas_iff_group/cas_group = cas_groups[faction]
-
- if(!cas_group)
- return //broken group. No fighting
-
- for(var/X in cas_group.cas_signals)
- var/datum/cas_signal/LT = X
- if(LT.target_id == targ_id && LT.valid_signal())
- if(dropship.mode != SHUTTLE_CALL)
- to_chat(usr, SPAN_WARNING("Dropship can only fire while in flight."))
- return
- if(dropship.door_override)
- return
- if(!selected_equipment || !selected_equipment.is_weapon)
- to_chat(usr, SPAN_WARNING("No weapon selected."))
- return
- DEW = selected_equipment // for if the weapon somehow changes
- if(!skillcheck(M, SKILL_PILOT, DEW.skill_required)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("You don't have the training to fire this weapon!"))
- return
- if(!dropship.in_flyby && DEW.fire_mission_only)
- to_chat(usr, SPAN_WARNING("[DEW] requires a fire mission flight type to be fired."))
- return
-
- if(!DEW.ammo_equipped || DEW.ammo_equipped.ammo_count <= 0)
- to_chat(usr, SPAN_WARNING("[DEW] has no ammo."))
- return
- if(DEW.last_fired > world.time - DEW.firing_delay)
- to_chat(usr, SPAN_WARNING("[DEW] just fired, wait for it to cool down."))
- return
- if(!LT.signal_loc)
- return
- var/turf/TU = get_turf(LT.signal_loc)
- var/area/targ_area = get_area(LT.signal_loc)
- var/is_outside = FALSE
- if(is_ground_level(TU.z))
- switch(targ_area.ceiling)
- if(CEILING_NONE)
- is_outside = TRUE
- if(CEILING_GLASS)
- is_outside = TRUE
- if(!is_outside && !cavebreaker) //cavebreaker doesn't care
- to_chat(usr, SPAN_WARNING("INVALID TARGET: target must be visible from high altitude."))
- return
- if (protected_by_pylon(TURF_PROTECTION_CAS, TU))
- to_chat(usr, SPAN_WARNING("INVALID TARGET: biological-pattern interference with signal."))
- return
- if(!DEW.ammo_equipped.can_fire_at(TU, usr))
- return
-
- DEW.open_fire(LT.signal_loc)
- break
-
- if(href_list["deselect"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- selected_equipment = null
+ .["screen_mode"] = get_screen_mode()
- if(href_list["create_mission"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- if(firemission_envelope.max_mission_len <= firemission_envelope.missions.len)
- to_chat(usr, SPAN_WARNING("Cannot store more than [firemission_envelope.max_mission_len] Fire Missions."))
- return
- var/fm_name = stripped_input(usr, "", "Enter Fire Mission Name", "Fire Mission [firemission_envelope.missions.len+1]", 50)
- if(!fm_name || length(fm_name) < 5)
- to_chat(usr, SPAN_WARNING("Name too short (at least 5 symbols)."))
- return
- var/fm_length = stripped_input(usr, "Enter length of the Fire Mission. Has to be less than [firemission_envelope.fire_length]. Use something that divides [firemission_envelope.fire_length] for optimal performance.", "Fire Mission Length (in tiles)", "[firemission_envelope.fire_length]", 5)
- var/fm_length_n = text2num(fm_length)
- if(!fm_length_n)
- to_chat(usr, SPAN_WARNING("Incorrect input format."))
- return
- if(fm_length_n > firemission_envelope.fire_length)
- to_chat(usr, SPAN_WARNING("Fire Mission is longer than allowed by this vehicle."))
- return
- if(firemission_envelope.stat != FIRE_MISSION_STATE_IDLE)
- to_chat(usr, SPAN_WARNING("Vehicle has to be idle to allow Fire Mission editing and creation."))
- return
- //everything seems to be fine now
- firemission_envelope.generate_mission(fm_name, fm_length_n)
-
- if(href_list["mission_tag_delete"])
- var/ref = text2num(href_list["mission_tag_delete"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- if(ref>firemission_envelope.missions.len)
- to_chat(usr, SPAN_WARNING("Fire Mission ID corrupted or already deleted."))
- return
- if(selected_firemission == firemission_envelope.missions[ref])
- to_chat(usr, SPAN_WARNING("Can't delete selected Fire Mission."))
- return
- var/result = firemission_envelope.delete_firemission(ref)
- if(result != 1)
- to_chat(usr, SPAN_WARNING("Unable to delete Fire Mission while in combat."))
- return
+ // dropship info
+ .["shuttle_state"] = dropship.mode
+ .["fire_mission_enabled"] = dropship.in_flyby
- if(href_list["mission_tag"])
- var/ref = text2num(href_list["mission_tag"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- if(ref>firemission_envelope.missions.len)
- to_chat(usr, SPAN_WARNING("Fire Mission ID corrupted or deleted."))
- return
- if(firemission_envelope.stat > FIRE_MISSION_STATE_IN_TRANSIT && firemission_envelope.stat < FIRE_MISSION_STATE_COOLDOWN)
- to_chat(usr, SPAN_WARNING("Fire Mission already underway."))
- return
- if(selected_firemission == firemission_envelope.missions[ref])
- selected_firemission = null
- else
- selected_firemission = firemission_envelope.missions[ref]
+ // equipment info
+ .["equipment_data"] = get_sanitised_equipment(user, dropship)
- if(href_list["mission_tag_edit"])
- var/ref = text2num(href_list["mission_tag_edit"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- if(ref>firemission_envelope.missions.len)
- to_chat(usr, SPAN_WARNING("Fire Mission ID corrupted or deleted."))
- return
- if(selected_firemission == firemission_envelope.missions[ref])
- to_chat(usr, SPAN_WARNING("Can't edit selected Fire Mission."))
- return
- if(firemission_envelope.stat > FIRE_MISSION_STATE_IN_TRANSIT && firemission_envelope.stat < FIRE_MISSION_STATE_COOLDOWN)
- to_chat(usr, SPAN_WARNING("Fire Mission already underway."))
- return
- editing_firemission = firemission_envelope.missions[ref]
+ // medevac targets
+ .["medevac_targets"] = list()
+ for(var/obj/structure/dropship_equipment/equipment as anything in dropship.equipments)
+ if (istype(equipment, /obj/structure/dropship_equipment/medevac_system))
+ var/obj/structure/dropship_equipment/medevac_system/medevac = equipment
+ .["medevac_targets"] += medevac.ui_data(user)
+ // fultons
- if(href_list["leave_firemission_editing"])
- editing_firemission = null
+ .["fulton_targets"] = list()
+ for(var/obj/structure/dropship_equipment/equipment as anything in dropship.equipments)
+ if (istype(equipment, /obj/structure/dropship_equipment/fulton_system))
+ var/obj/structure/dropship_equipment/fulton_system/fult = equipment
+ .["fulton_targets"] += fult.ui_data(user)
- if(href_list["switch_to_firemission"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- in_firemission_mode = TRUE
+ .["targets_data"] = get_targets()
+ .["camera_target"] = camera_target_id
- if(href_list["switch_to_simulation"])
- if(!selected_firemission)
- to_chat(usr, SPAN_WARNING("Select a firemission before attempting to run the simulation"))
- return
+ if(selected_equipment)
+ .["selected_eqp"] = selected_equipment.ship_base.attach_id
+ if(selected_equipment.ammo_equipped)
+ var/obj/structure/ship_ammo/ammo_equipped = selected_equipment.ammo_equipped
+ .["selected_eqp_ammo_name"] = sanitize(copytext(ammo_equipped.name, 1, MAX_MESSAGE_LEN))
+ .["selected_eqp_ammo_amt"] = ammo_equipped.ammo_count
+ .["selected_eqp_max_ammo_amt"] = ammo_equipped.max_ammo_count
+
+ // firemission info
+ .["has_firemission"] = !!firemission_envelope
+ .["can_firemission"] = !!selected_firemission && dropship.mode == SHUTTLE_CALL
+ if(editing_firemission)
+ .["editing_firemission"] = editing_firemission
+ .["editing_firemission_length"] = editing_firemission ? editing_firemission.mission_length : 0
+ var/error_code = editing_firemission.check(src)
+ .["current_mission_error"] = error_code != FIRE_MISSION_ALL_GOOD ? editing_firemission.error_message(error_code) : null
+ .["firemission_edit_data"] = get_edit_firemission_data()
- configuration = selected_firemission
+ if(firemission_envelope)
+ .["can_launch_firemission"] = !!selected_firemission && dropship.mode == SHUTTLE_CALL && firemission_envelope.stat != FIRE_MISSION_STATE_IDLE
+ .["firemission_data"] = get_firemission_data(user)
+ .["firemission_state"] = firemission_envelope.stat
+ .["firemission_offset"] = firemission_envelope.recorded_offset
+ .["firemission_message"] = firemission_envelope.firemission_status_message()
+ .["firemission_name"] = selected_firemission ? selected_firemission.name : ""
+ .["firemission_step"] = firemission_envelope.stat
+ .["firemission_selected_laser"] = firemission_envelope.recorded_loc ? firemission_envelope.recorded_loc.get_name() : "NOT SELECTED"
+
+ .["configuration"] = configuration
+ .["dummy_mode"] = simulation.dummy_mode
+ .["worldtime"] = world.time
+ .["nextdetonationtime"] = simulation.detonation_cooldown
+ .["detonation_cooldown"] = simulation.detonation_cooldown_time
- // simulation mode
- tgui_interact(usr)
+/obj/structure/machinery/computer/dropship_weapons/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+ var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(shuttle_tag)
+ if(shuttle.is_hijacked)
+ return
- if(href_list["leave_firemission_execution"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- firemission_envelope.remove_user_from_tracking(usr)
- in_firemission_mode = FALSE
+ var/mob/user = ui.user
+ switch(action)
+ if("button_push")
+ playsound(src, get_sfx("terminal_button"), 25, FALSE)
+ return TRUE
- if(href_list["change_direction"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- var/list/directions = list(dir2text(NORTH), dir2text(SOUTH), dir2text(EAST), dir2text(WEST))
- var/chosen = tgui_input_list(usr, "Select new Direction for the strafing run", "Select Direction", directions)
+ if("select_equipment")
+ var/base_tag = params["equipment_id"]
+ ui_equip_interact(user, base_tag)
+ return TRUE
- var/chosen_dir = text2dir(chosen)
- if(!chosen_dir)
- to_chat(usr, SPAN_WARNING("Error with direction detected."))
- return
+ if("start_watching")
+ simulation.start_watching(user)
+ . = TRUE
- update_direction(chosen_dir)
+ if("stop_watching")
+ simulation.stop_watching(user)
+ . = TRUE
- if(href_list["change_offset"])
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
+ if("execute_simulated_firemission")
+ if(!configuration)
+ to_chat(user, SPAN_WARNING("No configured firemission"))
+ return
+ simulate_firemission(user)
+ . = TRUE
- var/chosen = stripped_input(usr, "Select Fire Mission length, from 0 to [firemission_envelope.max_offset]", "Select Offset", "[firemission_envelope.recorded_offset]", 2)
- var/chosen_offset = text2num(chosen)
+ if("switch_firemission")
+ configuration = tgui_input_list(user, "Select firemission to simulate", "Select firemission", firemission_envelope.missions, 30 SECONDS)
+ if(!selected_firemission)
+ to_chat(user, SPAN_WARNING("No configured firemission"))
+ return
+ if(!configuration)
+ configuration = selected_firemission
+ . = TRUE
- if(chosen_offset == null)
- to_chat(usr, SPAN_WARNING("Error with offset detected."))
- return
+ if("switchmode")
+ simulation.dummy_mode = tgui_input_list(user, "Select target type to simulate", "Target type", simulation.target_types, 30 SECONDS)
+ if(!simulation.dummy_mode)
+ simulation.dummy_mode = CLF_MODE
+ . = TRUE
- update_offset(chosen_offset)
+ if("set-camera")
+ var/target_camera = params["equipment_id"]
+ set_camera_target(target_camera)
+ return TRUE
+
+ if("set-camera-sentry")
+ var/equipment_tag = params["equipment_id"]
+ for(var/obj/structure/dropship_equipment/equipment as anything in shuttle.equipments)
+ var/mount_point = equipment.ship_base.attach_id
+ if(mount_point != equipment_tag)
+ continue
+ if (istype(equipment, /obj/structure/dropship_equipment/sentry_holder))
+ var/obj/structure/dropship_equipment/sentry_holder/sentry = equipment
+ var/obj/structure/machinery/defenses/sentry/defense = sentry.deployed_turret
+ if (defense.has_camera)
+ defense.set_range()
+ var/datum/shape/rectangle/current_bb = defense.range_bounds
+ SEND_SIGNAL(src, COMSIG_CAMERA_SET_AREA, current_bb.center_x, current_bb.center_y, defense.loc.z, current_bb.width, current_bb.height)
+ return TRUE
+
+ if("clear-camera")
+ set_camera_target(null)
+ return TRUE
+
+ if("medevac-target")
+ var/equipment_tag = params["equipment_id"]
+ for(var/obj/structure/dropship_equipment/equipment as anything in shuttle.equipments)
+ var/mount_point = equipment.ship_base.attach_id
+ if(mount_point != equipment_tag)
+ continue
+ if (istype(equipment, /obj/structure/dropship_equipment/medevac_system))
+ var/obj/structure/dropship_equipment/medevac_system/medevac = equipment
+ var/target_ref = params["ref"]
+ medevac.automate_interact(user, target_ref)
+ if(medevac.linked_stretcher)
+ SEND_SIGNAL(src, COMSIG_CAMERA_SET_TARGET, medevac.linked_stretcher, 5, 5)
+ return TRUE
+ if("fulton-target")
+ var/equipment_tag = params["equipment_id"]
+ for(var/obj/structure/dropship_equipment/equipment as anything in shuttle.equipments)
+ var/mount_point = equipment.ship_base.attach_id
+ if(mount_point != equipment_tag)
+ continue
+ if (istype(equipment, /obj/structure/dropship_equipment/fulton_system))
+ var/obj/structure/dropship_equipment/fulton_system/fulton = equipment
+ var/target_ref = params["ref"]
+ fulton.automate_interact(user, target_ref)
+ return TRUE
+ if("fire-weapon")
+ var/weapon_tag = params["eqp_tag"]
+ var/obj/structure/dropship_equipment/weapon/DEW = get_weapon(weapon_tag)
+ if(!DEW)
+ return FALSE
+
+ var/datum/cas_signal/sig = get_cas_signal(camera_target_id)
+
+ if(!sig)
+ return FALSE
+
+ selected_equipment = DEW
+ ui_open_fire(user, shuttle, camera_target_id)
+ return TRUE
+ if("deploy-equipment")
+ var/equipment_tag = params["equipment_id"]
+ for(var/obj/structure/dropship_equipment/equipment as anything in shuttle.equipments)
+ var/mount_point = equipment.ship_base.attach_id
+ if(mount_point != equipment_tag)
+ continue
+ equipment.equipment_interact(user)
+ return TRUE
+
+ if("firemission-create")
+ var/name = params["firemission_name"]
+ var/length = params["firemission_length"]
+ var/length_n = text2num(length)
+ if(!length_n)
+ to_chat(user, SPAN_WARNING("Incorrect input format."))
+ return FALSE
+ ui_create_firemission(user, name, length_n)
+ return TRUE
+
+ if("firemission-delete")
+ var/name = params["firemission_name"]
+ ui_delete_firemission(user, name)
+ return TRUE
+
+ if("firemission-dual-offset-camera")
+ var/target_id = params["target_id"]
+
+ var/x_offset_value = params["x_offset_value"]
+ var/y_offset_value = params["y_offset_value"]
+
+ var/datum/cas_iff_group/cas_group = GLOB.cas_groups[faction]
+ var/datum/cas_signal/cas_sig
+ for(var/X in cas_group.cas_signals)
+ var/datum/cas_signal/LT = X
+ if(LT.target_id == target_id && LT.valid_signal())
+ cas_sig = LT
+ break
+ // we don't want rapid offset changes to trigger admin warnings
+ // and block the user from accessing TGUI
+ // we change the minute_count
+ user.client.reduce_minute_count()
+ if(!cas_sig)
+ return TRUE
+
+ // find position of cas_sig with offset dir and value applied
+ var/dx = text2num(x_offset_value)
+ var/dy = text2num(y_offset_value)
+
+ var/obj/current = cas_sig.signal_loc
+ var/obj/new_target = locate(
+ current.x + dx,
+ current.y + dy,
+ current.z)
+
+ firemission_envelope.change_current_loc(new_target)
+
+ return TRUE
+ if("nvg-enable")
+ SEND_SIGNAL(src, COMSIG_CAMERA_SET_NVG, 5, "#7aff7a")
+ return TRUE
+ if("nvg-disable")
+ SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR_NVG)
+ return TRUE
+
+ if("firemission-edit")
+ var/fm_tag = text2num(params["tag"])
+ var/weapon_id = text2num(params["weapon_id"])
+ var/offset_id = text2num(params["offset_id"])
+ var/offset_value = text2num(params["offset_value"])
+ return ui_firemission_change_offset(user, fm_tag, weapon_id, offset_id + 1, offset_value)
+
+ if("firemission-execute")
+ var/fm_tag = text2num(params["tag"])
+ var/direction = params["direction"]
+ var/target_id = params["target_id"]
+ var/offset_x_value = params["offset_x_value"]
+ var/offset_y_value = params["offset_y_value"]
+
+ if(!ui_select_firemission(user, fm_tag))
+ playsound(src, 'sound/machines/terminal_error.ogg', 5, 1)
+ return FALSE
+ if(!update_direction(user, text2num(direction)))
+ playsound(src, 'sound/machines/terminal_error.ogg', 5, 1)
+ return FALSE
+ if(!ui_select_laser_firemission(user, shuttle, target_id))
+ playsound(src, 'sound/machines/terminal_error.ogg', 5, 1)
+ return FALSE
+
+ initiate_firemission(user, fm_tag, direction, text2num(offset_x_value), text2num(offset_y_value))
+ return TRUE
+
+/obj/structure/machinery/computer/dropship_weapons/proc/get_weapon(eqp_tag)
+ var/obj/docking_port/mobile/marine_dropship/dropship = SSshuttle.getShuttle(shuttle_tag)
+ for(var/obj/structure/dropship_equipment/equipment in dropship.equipments)
+ if(istype(equipment, /obj/structure/dropship_equipment/weapon))
+ //is weapon
+ if(selected_equipment == equipment)
+ return equipment
+ return
+
+/obj/structure/machinery/computer/dropship_weapons/proc/get_cas_signal(target_ref)
+ if(!target_ref)
+ return
- if(href_list["select_laser_firemission"])
- var/mob/M = usr
- var/targ_id = text2num(href_list["select_laser_firemission"])
- if(!targ_id)
- to_chat(usr, SPAN_WARNING("Bad Target."))
- return
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- if(firemission_envelope.stat > FIRE_MISSION_STATE_IN_TRANSIT && firemission_envelope.stat < FIRE_MISSION_STATE_COOLDOWN)
- to_chat(usr, SPAN_WARNING("Fire Mission already underway."))
- return
- if(dropship.mode != SHUTTLE_CALL)
- to_chat(usr, SPAN_WARNING("Shuttle has to be in orbit."))
- return
- var/datum/cas_iff_group/cas_group = cas_groups[faction]
- var/datum/cas_signal/cas_sig
- for(var/X in cas_group.cas_signals)
- var/datum/cas_signal/LT = X
- if(LT.target_id == targ_id && LT.valid_signal())
- cas_sig = LT
- if(!cas_sig)
- to_chat(usr, SPAN_WARNING("Target lost or obstructed."))
- return
+ var/datum/cas_iff_group/cas_group = GLOB.cas_groups[faction]
+ for(var/datum/cas_signal/sig in cas_group.cas_signals)
+ if(sig.target_id == target_ref)
+ return sig
- update_location(cas_sig)
- if(href_list["execute_firemission"])
- var/mob/M = usr
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(!H.allow_gun_usage)
- to_chat(H, SPAN_WARNING("Your programming prevents you from operating dropship weaponry!"))
- return
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- if(firemission_envelope.stat != FIRE_MISSION_STATE_IDLE)
- to_chat(usr, SPAN_WARNING("Fire Mission already underway."))
- return
- if(dropship.mode != SHUTTLE_CALL)
- to_chat(usr, SPAN_WARNING("Shuttle has to be in orbit."))
- return
- if(!firemission_envelope.recorded_loc)
- to_chat(usr, SPAN_WARNING("Target is not selected or lost."))
- return
+/obj/structure/machinery/computer/dropship_weapons/proc/set_camera_target(target_ref)
+ var/datum/cas_signal/target = get_cas_signal(target_ref)
+ camera_target_id = target_ref
+ if(!target)
+ SEND_SIGNAL(src, COMSIG_CAMERA_CLEAR)
+ return
- initiate_firemission()
+ var/cam_width = camera_width
+ var/cam_height = camera_height
+ if(upgraded == MATRIX_WIDE)
+ cam_width = cam_width * 1.5
+ cam_height = cam_height * 1.5
- if(href_list["fm_weapon_id"])
- var/weap_ref = text2num(href_list["fm_weapon_id"])+1
- var/offset_ref = text2num(href_list["fm_offset_id"])+1
- var/mob/M = usr
- if(!skillcheck(M, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
- to_chat(usr, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
- return
- if(!editing_firemission)
- to_chat(usr, SPAN_WARNING("You are no longer editing Fire Mission."))
- return
- if(!editing_firemission.records || editing_firemission.records.len FIRE_MISSION_STATE_IN_TRANSIT && firemission_envelope.stat < FIRE_MISSION_STATE_COOLDOWN)
- to_chat(usr, SPAN_WARNING("Fire Mission already underway."))
- return
- var/list/gimb = record.get_offsets()
- var/min = gimb["min"]
- var/max = gimb["max"]
- var/offset_value = stripped_input(usr, "Enter offset for the [record.weapon.name]. It has to be between [min] and [max]. Enter '-' to remove fire order on this time stamp.", "Firing offset", "[record.offsets[offset_ref]]", 2)
- if(offset_value == null)
- return
- if(offset_value == "-")
- offset_value = "-"
- else
- offset_value = text2num(offset_value)
- if(offset_value == null)
- to_chat(usr, SPAN_WARNING("Incorrect offset value."))
- return
- var/result = firemission_envelope.update_mission(firemission_envelope.missions.Find(editing_firemission), weap_ref, offset_ref, offset_value, TRUE)
- if(result == 0)
- to_chat(usr, SPAN_WARNING("Update caused an error: [firemission_envelope.mission_error]"))
- if(result == -1)
- to_chat(usr, SPAN_WARNING("System Error. Delete this Fire Mission."))
-
- if(href_list["firemission_camera"])
- if(dropship.mode != SHUTTLE_CALL)
- to_chat(usr, SPAN_WARNING("Shuttle has to be in orbit."))
- return
+ SEND_SIGNAL(src, COMSIG_CAMERA_SET_TARGET, target.linked_cam, cam_width, cam_height)
- if(!firemission_envelope.guidance)
- to_chat(usr, SPAN_WARNING("Guidance is not selected or lost."))
- return
+/obj/structure/machinery/computer/dropship_weapons/proc/get_screen_mode()
+ . = 0
+ if(selected_equipment)
+ . = selected_equipment.screen_mode
+ if(editing_firemission && editing_firemission.check(src) != FIRE_MISSION_CODE_ERROR)
+ . = 2
+ if(selected_firemission && in_firemission_mode)
+ . = 3
+/obj/structure/machinery/computer/dropship_weapons/proc/get_firemission_data(mob/user)
+ . = list()
+ var/firemission_id = 1
+ for(var/datum/cas_fire_mission/firemission in firemission_envelope.missions)
+ var/error_code = firemission.check(src)
- firemission_envelope.add_user_to_tracking(usr)
+ var/selected = firemission == selected_firemission
+ var/can_edit = error_code != FIRE_MISSION_CODE_ERROR && !selected
- to_chat(usr, "You peek through the guidance camera.")
+ var/can_interact = firemission_envelope.stat == FIRE_MISSION_STATE_IDLE && error_code == FIRE_MISSION_ALL_GOOD
+ var/list/fm_data = firemission.ui_data(user)
+ fm_data["mission_tag"] = firemission_id
+ fm_data["can_edit"] = can_edit
+ fm_data["can_interact"] = can_interact
+ fm_data["selected"] = selected
+ . += list(fm_data)
- if(href_list["cas_camera"])
- if(!ishuman(usr))
- to_chat(usr, SPAN_WARNING("You have no idea how to do that!"))
- return
- if(dropship.mode != SHUTTLE_CALL)
- to_chat(usr, SPAN_WARNING("Shuttle has to be in orbit."))
- return
+ firemission_id++
- if(!faction)
- to_chat(usr, SPAN_DANGER("Bug encountered, this console doesn't have a faction set, report this to a coder!"))
- return
+/obj/structure/machinery/computer/dropship_weapons/proc/get_edit_firemission_data()
+ . = list()
+ if(!editing_firemission)
+ return
+ for(var/datum/cas_fire_mission_record/firerec as anything in editing_firemission.records)
+ var/gimbal = firerec.get_offsets()
+ var/ammo = firerec.get_ammo()
+ var/offsets = new /list(firerec.offsets.len)
+ for(var/idx = 1; idx < firerec.offsets.len; idx++)
+ offsets[idx] = firerec.offsets[idx] == null ? "-" : firerec.offsets[idx]
+ . += list(
+ "name" = sanitize(copytext(firerec.weapon.name, 1, 50)),
+ "ammo" = ammo,
+ "gimbal" = gimbal,
+ "offsets" = firerec.offsets
+ )
+
+/obj/structure/machinery/computer/dropship_weapons/proc/get_sanitised_equipment(mob/user, obj/docking_port/mobile/marine_dropship/dropship)
+ . = list()
+ var/element_nbr = 1
+ for(var/obj/structure/dropship_equipment/equipment in dropship.equipments)
+ var/list/data = list(
+ "name"= equipment.name,
+ "shorthand" = equipment.shorthand,
+ "eqp_tag" = element_nbr,
+ "is_weapon" = equipment.is_weapon,
+ "is_interactable" = equipment.is_interactable,
+ "mount_point" = equipment.ship_base.attach_id,
+ "is_missile" = istype(equipment, /obj/structure/dropship_equipment/weapon/rocket_pod),
+ "ammo_name" = equipment.ammo_equipped?.name,
+ "ammo" = equipment.ammo_equipped?.ammo_count,
+ "max_ammo" = equipment.ammo_equipped?.max_ammo_count,
+ "firemission_delay" = equipment.ammo_equipped?.fire_mission_delay,
+ "burst" = equipment.ammo_equipped?.ammo_used_per_firing,
+ "data" = equipment.ui_data(user)
+ )
+
+ . += list(data)
- var/datum/cas_iff_group/cas_group = cas_groups[faction]
- if(!cas_group)
- to_chat(usr, SPAN_DANGER("Bug encountered, no CAS group exists for this console, report this to a coder!"))
- return
+ element_nbr++
+ equipment.linked_console = src
- var/targ_id = text2num(href_list["cas_camera"])
- for(var/datum/cas_signal/LT as anything in cas_group.cas_signals)
- if(LT.target_id == targ_id && LT.valid_signal())
- selected_cas_signal = LT
- break
- if(!selected_cas_signal)
- to_chat(usr, SPAN_WARNING("Target lost or obstructed."))
- return
- if(selected_cas_signal && selected_cas_signal.linked_cam)
- selected_cas_signal.linked_cam.view_directly(usr)
- else
- to_chat(usr, SPAN_WARNING("Error!"))
- return
- give_action(usr, /datum/action/human_action/cancel_view)
- RegisterSignal(usr, COMSIG_MOB_RESET_VIEW, PROC_REF(remove_from_view))
- RegisterSignal(usr, COMSIG_MOB_RESISTED, PROC_REF(remove_from_view))
- firemission_envelope.apply_upgrade(usr)
- to_chat(usr, SPAN_NOTICE("You peek through the guidance camera."))
-
- ui_interact(usr)
-
-/obj/structure/machinery/computer/dropship_weapons/proc/remove_from_view(mob/living/carbon/human/user)
- UnregisterSignal(user, COMSIG_MOB_RESET_VIEW)
- UnregisterSignal(user, COMSIG_MOB_RESISTED)
- if(selected_cas_signal && selected_cas_signal.linked_cam)
- selected_cas_signal.linked_cam.remove_from_view(user)
- firemission_envelope.remove_upgrades(user)
-
-/obj/structure/machinery/computer/dropship_weapons/proc/initiate_firemission()
- set waitfor = 0
- var/obj/docking_port/mobile/marine_dropship/dropship = SSshuttle.getShuttle(shuttle_tag)
- if (!istype(dropship))
- return
- if (dropship.timer && dropship.timeLeft(1) < firemission_envelope.get_total_duration())
- to_chat(usr, "Not enough time to complete the Fire Mission")
- return
- if (!dropship.in_flyby || dropship.mode != SHUTTLE_CALL)
- to_chat(usr, "Has to be in Fly By mode")
- return
+/obj/structure/machinery/computer/dropship_weapons/proc/get_targets()
+ . = list()
+ var/datum/cas_iff_group/cas_group = GLOB.cas_groups[faction]
+ for(var/datum/cas_signal/LT as anything in cas_group.cas_signals)
+ if(!istype(LT) || !LT.valid_signal())
+ continue
+ var/area/laser_area = get_area(LT.signal_loc)
+ . += list(
+ list(
+ "target_name" = "[LT.name] ([laser_area.name])",
+ "target_tag" = LT.target_id
+ )
+ )
+
+/obj/structure/machinery/computer/dropship_weapons/proc/ui_equip_interact(mob/user, base_tag)
+ var/obj/docking_port/mobile/marine_dropship/shuttle = SSshuttle.getShuttle(shuttle_tag)
+ var/obj/structure/dropship_equipment/E = shuttle.equipments[base_tag]
+ E.linked_console = src
+ E.equipment_interact(user)
+
+/obj/structure/machinery/computer/dropship_weapons/proc/ui_open_fire(mob/weapon_operator, obj/docking_port/mobile/marine_dropship/dropship, targ_id)
+ if(ishuman(weapon_operator))
+ var/mob/living/carbon/human/human_operator = weapon_operator
+ if(!human_operator.allow_gun_usage)
+ to_chat(human_operator, SPAN_WARNING("Your programming prevents you from operating dropship weaponry!"))
+ return FALSE
+ var/obj/structure/dropship_equipment/weapon/DEW = selected_equipment
+ if(!selected_equipment || !selected_equipment.is_weapon)
+ to_chat(weapon_operator, SPAN_WARNING("No weapon selected."))
+ return FALSE
+ if(!skillcheck(weapon_operator, SKILL_PILOT, DEW.skill_required)) //only pilots can fire dropship weapons.
+ to_chat(weapon_operator, SPAN_WARNING("You don't have the training to fire this weapon!"))
+ return FALSE
+ if(dropship.mode != SHUTTLE_CALL)
+ to_chat(weapon_operator, SPAN_WARNING("Dropship can only fire while in flight."))
+ return FALSE
+ if(!faction)
+ return FALSE//no faction, no weapons
+ if(!selected_equipment || !selected_equipment.is_weapon)
+ to_chat(weapon_operator, SPAN_WARNING("No weapon selected."))
+ return FALSE
+ if(dropship.door_override)
+ return FALSE
+ if(!skillcheck(weapon_operator, SKILL_PILOT, DEW.skill_required)) //only pilots can fire dropship weapons.
+ to_chat(weapon_operator, SPAN_WARNING("You don't have the training to fire this weapon!"))
+ return FALSE
+ if(!dropship.in_flyby && DEW.fire_mission_only)
+ to_chat(weapon_operator, SPAN_WARNING("[DEW] requires a fire mission flight type to be fired."))
+ return FALSE
+
+ if(!DEW.ammo_equipped || DEW.ammo_equipped.ammo_count <= 0)
+ to_chat(weapon_operator, SPAN_WARNING("[DEW] has no ammo."))
+ return FALSE
+ if(DEW.last_fired > world.time - DEW.firing_delay)
+ to_chat(weapon_operator, SPAN_WARNING("[DEW] just fired, wait for it to cool down."))
+ return FALSE
+
+ var/datum/cas_iff_group/cas_group = GLOB.cas_groups[faction]
- var/fmid = firemission_envelope.missions.Find(selected_firemission)
- if(!fmid)
- to_chat(usr, "No Firemission selected")
- return
+ if(!cas_group)
+ return FALSE//broken group. No fighting
- var/result = firemission_envelope.execute_firemission(firemission_envelope.recorded_loc, firemission_envelope.recorded_offset, firemission_envelope.recorded_dir, fmid)
- if(result<1)
- to_chat(usr, "Screen beeps with an error: "+ firemission_envelope.mission_error)
+ for(var/datum/cas_signal/LT in cas_group.cas_signals)
+ if(LT.target_id != targ_id || !LT.valid_signal())
+ continue
+ if(!LT.signal_loc)
+ return FALSE
+ var/turf/TU = get_turf(LT.signal_loc)
+ var/area/targ_area = get_area(LT.signal_loc)
+ var/is_outside = FALSE
+ if(is_ground_level(TU.z))
+ switch(targ_area.ceiling)
+ if(CEILING_NONE)
+ is_outside = TRUE
+ if(CEILING_GLASS)
+ is_outside = TRUE
+ if(!is_outside && !cavebreaker) //cavebreaker doesn't care
+ to_chat(weapon_operator, SPAN_WARNING("INVALID TARGET: target must be visible from high altitude."))
+ return FALSE
+ if (protected_by_pylon(TURF_PROTECTION_CAS, TU))
+ to_chat(weapon_operator, SPAN_WARNING("INVALID TARGET: biological-pattern interference with signal."))
+ return FALSE
+ if(!DEW.ammo_equipped.can_fire_at(TU, weapon_operator))
+ return FALSE
+
+ DEW.open_fire(LT.signal_loc)
+ return TRUE
+ return FALSE
+
+/obj/structure/machinery/computer/dropship_weapons/proc/ui_create_firemission(mob/weapon_operator, firemission_name, firemission_length)
+ if(!skillcheck(weapon_operator, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
+ to_chat(weapon_operator, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
+ return FALSE
+ // Check name
+ if(!firemission_name || length(firemission_name) < 1)
+ to_chat(weapon_operator, SPAN_WARNING("Name too short (at least 1 symbols)."))
+ return FALSE
+ // Check length
+ if(!firemission_length)
+ to_chat(weapon_operator, SPAN_WARNING("Incorrect input format."))
+ return FALSE
+ if(firemission_length > firemission_envelope.fire_length)
+ to_chat(weapon_operator, SPAN_WARNING("Fire Mission is longer than allowed by this vehicle."))
+ return FALSE
+ if(firemission_envelope.stat != FIRE_MISSION_STATE_IDLE)
+ to_chat(weapon_operator, SPAN_WARNING("Vehicle has to be idle to allow Fire Mission editing and creation."))
+ return FALSE
+
+ for(var/datum/cas_fire_mission/mission in firemission_envelope.missions)
+ if(firemission_name == mission.name)
+ to_chat(weapon_operator, SPAN_WARNING("Fire Mission name must be unique."))
+ return FALSE
+ //everything seems to be fine now
+ firemission_envelope.generate_mission(firemission_name, firemission_length)
+ return TRUE
+
+/obj/structure/machinery/computer/dropship_weapons/proc/ui_delete_firemission(mob/weapon_operator, firemission_tag)
+ if(!skillcheck(weapon_operator, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
+ to_chat(weapon_operator, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
+ return FALSE
+ if(firemission_tag > firemission_envelope.missions.len)
+ to_chat(weapon_operator, SPAN_WARNING("Fire Mission ID corrupted or already deleted."))
+ return FALSE
+ if(selected_firemission == firemission_envelope.missions[firemission_tag])
+ to_chat(weapon_operator, SPAN_WARNING("Can't delete selected Fire Mission."))
+ return FALSE
+ var/result = firemission_envelope.delete_firemission(firemission_tag)
+ if(result != 1)
+ to_chat(weapon_operator, SPAN_WARNING("Unable to delete Fire Mission while in combat."))
+ return FALSE
+ return TRUE
+
+/obj/structure/machinery/computer/dropship_weapons/proc/ui_select_firemission(mob/weapon_operator, firemission_tag)
+ if(!skillcheck(weapon_operator, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
+ to_chat(weapon_operator, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
+ return FALSE
+ if(firemission_envelope.stat > FIRE_MISSION_STATE_IN_TRANSIT && firemission_envelope.stat < FIRE_MISSION_STATE_COOLDOWN)
+ to_chat(weapon_operator, SPAN_WARNING("Fire Mission already underway."))
+ return FALSE
+ if(firemission_tag > firemission_envelope.missions.len)
+ to_chat(weapon_operator, SPAN_WARNING("Fire Mission ID corrupted or deleted."))
+ return FALSE
+ if(selected_firemission == firemission_envelope.missions[firemission_tag])
+ selected_firemission = null
else
- update_trace_loc()
+ selected_firemission = firemission_envelope.missions[firemission_tag]
+ return TRUE
+
+/obj/structure/machinery/computer/dropship_weapons/proc/ui_firemission_change_offset(mob/weapons_operator, fm_tag, weapon_id, offset_id, offset_value)
+ if(!skillcheck(weapons_operator, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
+ to_chat(weapons_operator, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
+ return FALSE
+
+ var/result = firemission_envelope.update_mission(fm_tag, weapon_id, offset_id, offset_value)
+ if(result != FIRE_MISSION_ALL_GOOD)
+ playsound(src, 'sound/machines/terminal_error.ogg', 5, 1)
+ return TRUE
+
+/obj/structure/machinery/computer/dropship_weapons/proc/ui_select_laser_firemission(mob/weapons_operator, obj/docking_port/mobile/marine_dropship/dropship, laser)
+ if(!laser)
+ to_chat(weapons_operator, SPAN_WARNING("Bad Target."))
+ return FALSE
+ if(!skillcheck(weapons_operator, SKILL_PILOT, SKILL_PILOT_TRAINED)) //only pilots can fire dropship weapons.
+ to_chat(weapons_operator, SPAN_WARNING("A screen with graphics and walls of physics and engineering values open, you immediately force it closed."))
+ return FALSE
+ if(firemission_envelope.stat > FIRE_MISSION_STATE_IN_TRANSIT && firemission_envelope.stat < FIRE_MISSION_STATE_COOLDOWN)
+ to_chat(weapons_operator, SPAN_WARNING("Fire Mission already underway."))
+ return FALSE
+ if(dropship.mode != SHUTTLE_CALL)
+ to_chat(weapons_operator, SPAN_WARNING("Shuttle has to be in orbit."))
+ return FALSE
+ var/datum/cas_iff_group/cas_group = GLOB.cas_groups[faction]
+ var/datum/cas_signal/cas_sig
+ for(var/X in cas_group.cas_signals)
+ var/datum/cas_signal/LT = X
+ if(LT.target_id == laser && LT.valid_signal())
+ cas_sig = LT
+ if(!cas_sig)
+ to_chat(weapons_operator, SPAN_WARNING("Target lost or obstructed."))
+ return FALSE
-/obj/structure/machinery/computer/dropship_weapons/proc/update_offset(new_offset)
- var/result = firemission_envelope.change_offset(new_offset)
- if(result<1)
- to_chat(usr, "Screen beeps with an error: "+ firemission_envelope.mission_error)
- else
- update_trace_loc()
+ update_location(weapons_operator, cas_sig)
+ return TRUE
-/obj/structure/machinery/computer/dropship_weapons/proc/update_location(new_location)
+/obj/structure/machinery/computer/dropship_weapons/proc/initiate_firemission(mob/user, fmId, dir, offset_x, offset_y)
+ set waitfor = 0
+ var/obj/docking_port/mobile/marine_dropship/dropship = SSshuttle.getShuttle(shuttle_tag)
+ if (!istype(dropship))
+ return FALSE
+ if (!dropship.in_flyby || dropship.mode != SHUTTLE_CALL)
+ to_chat(user, SPAN_WARNING("Has to be in Fly By mode"))
+ return FALSE
+ if (dropship.timer && dropship.timeLeft(1) < firemission_envelope.get_total_duration())
+ to_chat(user, SPAN_WARNING("Not enough time to complete the Fire Mission"))
+ return FALSE
+ var/datum/cas_signal/recorded_loc = firemission_envelope.recorded_loc
+ var/obj/source = recorded_loc.signal_loc
+ var/turf/target = locate(
+ source.x + offset_x,
+ source.y + offset_y,
+ source.z
+ )
+ var/result = firemission_envelope.execute_firemission(recorded_loc, target, dir, fmId)
+ if(result != FIRE_MISSION_ALL_GOOD)
+ to_chat(user, SPAN_WARNING("Screen beeps with an error: [firemission_envelope.mission_error]"))
+ return TRUE
+
+/obj/structure/machinery/computer/dropship_weapons/proc/update_location(mob/user, new_location)
var/result = firemission_envelope.change_target_loc(new_location)
if(result<1)
- to_chat(usr, "Screen beeps with an error: "+ firemission_envelope.mission_error)
- else
- update_trace_loc()
+ to_chat(user, SPAN_WARNING("Screen beeps with an error: [firemission_envelope.mission_error]"))
+ return FALSE
+ return TRUE
-/obj/structure/machinery/computer/dropship_weapons/proc/update_direction(new_direction)
+/obj/structure/machinery/computer/dropship_weapons/proc/update_direction(mob/user, new_direction)
var/result = firemission_envelope.change_direction(new_direction)
if(result<1)
- to_chat(usr, "Screen beeps with an error: " + firemission_envelope.mission_error)
- else
- update_trace_loc()
+ to_chat(user, SPAN_WARNING("Screen beeps with an error: [firemission_envelope.mission_error]"))
+ return FALSE
+ return TRUE
-/obj/structure/machinery/computer/dropship_weapons/on_unset_interaction(mob/user)
- ..()
- if(firemission_envelope && firemission_envelope.guidance)
- firemission_envelope.remove_user_from_tracking(user)
-
-/obj/structure/machinery/computer/dropship_weapons/proc/update_trace_loc()
+/obj/structure/machinery/computer/dropship_weapons/proc/update_trace_loc(mob/user)
if(!firemission_envelope)
return
if(firemission_envelope.recorded_loc == null || firemission_envelope.recorded_dir == null || firemission_envelope.recorded_offset == null)
return
if(firemission_envelope.recorded_loc.obstructed_signal())
- if(firemission_envelope.user_is_guided(usr))
- to_chat(usr, SPAN_WARNING("Signal Obstructed. You have to go in blind."))
+ if(firemission_envelope.user_is_guided(user))
+ to_chat(user, SPAN_WARNING("Signal Obstructed. You have to go in blind."))
return
var/sx = 0
var/sy = 0
@@ -704,108 +803,29 @@
return
var/area/laser_area = get_area(shootloc)
if(!istype(laser_area) || CEILING_IS_PROTECTED(laser_area.ceiling, CEILING_PROTECTION_TIER_1))
- if(firemission_envelope.user_is_guided(usr))
- to_chat(usr, SPAN_WARNING("Vision Obstructed. You have to go in blind."))
+ if(firemission_envelope.user_is_guided(user))
+ to_chat(user, SPAN_WARNING("Vision Obstructed. You have to go in blind."))
firemission_envelope.change_current_loc()
else
firemission_envelope.change_current_loc(shootloc)
+ return TRUE
/obj/structure/machinery/computer/dropship_weapons/dropship1
name = "\improper 'Alamo' weapons controls"
req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_WY_FLIGHT)
firemission_envelope = new /datum/cas_fire_envelope/uscm_dropship()
-
-/obj/structure/machinery/computer/dropship_weapons/dropship1/New()
- ..()
shuttle_tag = DROPSHIP_ALAMO
/obj/structure/machinery/computer/dropship_weapons/dropship2
name = "\improper 'Normandy' weapons controls"
req_one_access = list(ACCESS_MARINE_LEADER, ACCESS_MARINE_DROPSHIP, ACCESS_WY_FLIGHT)
firemission_envelope = new /datum/cas_fire_envelope/uscm_dropship()
-
-/obj/structure/machinery/computer/dropship_weapons/dropship2/New()
- ..()
shuttle_tag = DROPSHIP_NORMANDY
/obj/structure/machinery/computer/dropship_weapons/Destroy()
. = ..()
-
QDEL_NULL(firemission_envelope)
-
-// CAS TGUI SHIT \\
-
-/obj/structure/machinery/computer/dropship_weapons/tgui_interact(mob/user, datum/tgui/ui)
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "CasSim", "[src.name]")
- ui.open()
-
-/obj/structure/machinery/computer/dropship_weapons/ui_state(mob/user) // we gotta do custom shit here so that it always closes instead of suspending
- return GLOB.not_incapacitated_and_adjacent_strict_state
-
-/obj/structure/machinery/computer/dropship_weapons/ui_status(mob/user, datum/ui_state/state)
- . = ..()
- if(inoperable())
- return UI_CLOSE
-
-/obj/structure/machinery/computer/dropship_weapons/ui_data(mob/user)
- var/list/data = list()
-
- data["configuration"] = configuration
- data["looking"] = simulation.looking_at_simulation
- data["dummy_mode"] = simulation.dummy_mode
-
- data["worldtime"] = world.time
- data["nextdetonationtime"] = simulation.detonation_cooldown
- data["detonation_cooldown"] = simulation.detonation_cooldown_time
-
- return data
-
-/obj/structure/machinery/computer/dropship_weapons/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
- . = ..()
- if(.)
- return
-
- var/user = ui.user
-
- switch(action)
- if("start_watching")
- simulation.start_watching(user)
- . = TRUE
-
- if("stop_watching")
- simulation.stop_watching(user)
- . = TRUE
-
- if("execute_simulated_firemission")
- if(!configuration)
- to_chat(user, SPAN_WARNING("No configured firemission"))
- return
- simulate_firemission(user)
- . = TRUE
-
- if("switch_firemission")
- configuration = tgui_input_list(user, "Select firemission to simulate", "Select firemission", firemission_envelope.missions, 30 SECONDS)
- if(!selected_firemission)
- to_chat(user, SPAN_WARNING("No configured firemission"))
- return
- if(!configuration)
- configuration = selected_firemission
- . = TRUE
-
- if("switchmode")
- simulation.dummy_mode = tgui_input_list(user, "Select target type to simulate", "Target type", simulation.target_types, 30 SECONDS)
- if(!simulation.dummy_mode)
- simulation.dummy_mode = CLF_MODE
- . = TRUE
-
-/obj/structure/machinery/computer/dropship_weapons/ui_close(mob/user)
- . = ..()
- if(simulation.looking_at_simulation)
- simulation.stop_watching(user)
-
-// CAS TGUI SHIT END \\
+ QDEL_NULL(tacmap)
/obj/structure/machinery/computer/dropship_weapons/proc/simulate_firemission(mob/living/user)
diff --git a/code/game/machinery/computer/groundside_operations.dm b/code/game/machinery/computer/groundside_operations.dm
index 9856ae8f970e..7b4c2d5df771 100644
--- a/code/game/machinery/computer/groundside_operations.dm
+++ b/code/game/machinery/computer/groundside_operations.dm
@@ -25,7 +25,11 @@
add_pmcs = FALSE
else if(SSticker.current_state < GAME_STATE_PLAYING)
RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PRESETUP, PROC_REF(disable_pmc))
- tacmap = new(src, minimap_type)
+ if(announcement_faction == FACTION_MARINE)
+ tacmap = new /datum/tacmap/drawing(src, minimap_type)
+ else
+ tacmap = new(src, minimap_type) // Non-drawing version
+
return ..()
/obj/structure/machinery/computer/groundside_operations/Destroy()
@@ -55,7 +59,7 @@
dat += " [is_announcement_active ? "Make An Announcement" : "*Unavailable*"]"
dat += " Tactical Map"
dat += " "
- var/datum/squad/marine/echo/echo_squad = locate() in RoleAuthority.squads
+ var/datum/squad/marine/echo/echo_squad = locate() in GLOB.RoleAuthority.squads
if(!echo_squad.active && faction == FACTION_MARINE)
dat += " Designate Echo Squad"
dat += " "
@@ -247,7 +251,7 @@
if("pick_squad")
var/list/squad_list = list()
- for(var/datum/squad/S in RoleAuthority.squads)
+ for(var/datum/squad/S in GLOB.RoleAuthority.squads)
if(S.active && S.faction == faction)
squad_list += S.name
@@ -276,7 +280,7 @@
usr.UnregisterSignal(cam, COMSIG_PARENT_QDELETING)
cam = null
usr.reset_view(null)
- else if(usr.client.view != world_view_size)
+ else if(usr.client.view != GLOB.world_view_size)
to_chat(usr, SPAN_WARNING("You're too busy peering through binoculars."))
else
if(cam)
@@ -290,7 +294,7 @@
if(!reason)
return
if(alert(usr, "Confirm activation of Echo Squad for [reason]", "Confirm Activation", "Yes", "No") != "Yes") return
- var/datum/squad/marine/echo/echo_squad = locate() in RoleAuthority.squads
+ var/datum/squad/marine/echo/echo_squad = locate() in GLOB.RoleAuthority.squads
if(!echo_squad)
visible_message(SPAN_BOLDNOTICE("ERROR: Unable to locate Echo Squad database."))
return
diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm
index b68ca41d6f09..20aa6925d0b4 100644
--- a/code/game/machinery/computer/medical.dm
+++ b/code/game/machinery/computer/medical.dm
@@ -24,7 +24,7 @@
set name = "Eject ID Card"
set src in oview(1)
- if(!usr || usr.stat || usr.lying) return
+ if(!usr || usr.is_mob_incapacitated()) return
if(scan)
to_chat(usr, "You remove \the [scan] from \the [src].")
@@ -108,7 +108,7 @@
dat += "Back"
dat += " Medical Robots:"
var/bdat = null
- for(var/obj/structure/machinery/bot/medbot/M in machines)
+ for(var/obj/structure/machinery/bot/medbot/M in GLOB.machines)
if(M.z != src.z) continue //only find medibots on the same z-level as the computer
var/turf/bl = get_turf(M)
@@ -123,7 +123,6 @@
else
dat += " [bdat]"
- else
else
dat += text("{Log In}", src)
show_browser(user, dat, "Medical Records", "med_rec")
@@ -365,8 +364,6 @@
for(var/datum/data/record/E in GLOB.data_core.medical)
if ((E.fields["ref"] == R.fields["ref"] || E.fields["id"] == R.fields["id"]))
M = E
- else
- //Foreach continue //goto(2540)
src.active1 = R
src.active2 = M
src.screen = 4
@@ -401,7 +398,7 @@
var/counter = 1
while(src.active2.fields[text("com_[]", counter)])
counter++
- src.active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [game_year] [t1]")
+ src.active2.fields[text("com_[counter]")] = text("Made by [authenticated] ([rank]) on [time2text(world.realtime, "DDD MMM DD hh:mm:ss")], [GLOB.game_year] [t1]")
if (href_list["del_c"])
if ((istype(src.active2, /datum/data/record) && src.active2.fields[text("com_[]", href_list["del_c"])]))
@@ -417,16 +414,12 @@
for(var/datum/data/record/R as anything in GLOB.data_core.medical)
if ((lowertext(R.fields["name"]) == t1 || t1 == lowertext(R.fields["id"])))
src.active2 = R
- else
- //Foreach continue //goto(3229)
if (!active2)
temp = "Could not locate record [t1]."
else
for(var/datum/data/record/E in GLOB.data_core.general)
if ((E.fields["name"] == src.active2.fields["name"] || E.fields["id"] == src.active2.fields["id"]))
src.active1 = E
- else
- //Foreach continue //goto(3334)
src.screen = 4
if (href_list["print_p"])
@@ -457,7 +450,7 @@
else
P.info += "Medical Record Lost! "
P.info += ""
- P.info += text(" This report was printed by [] []. The [MAIN_SHIP_NAME],[]/[], [] \n",last_user_rank,last_user_name,time2text(world.timeofday, "MM/DD"),game_year,worldtime2text())
+ P.info += text(" This report was printed by [] []. The [MAIN_SHIP_NAME],[]/[], [] \n",last_user_rank,last_user_name,time2text(world.timeofday, "MM/DD"),GLOB.game_year,worldtime2text())
src.printing = null
if(href_list["print_bs"])//Prints latest body scan
@@ -480,7 +473,7 @@
break
else
P.info += "No scan on record."
- P.info += text(" This report was printed by [] []. The [MAIN_SHIP_NAME], []/[], [] \n",last_user_rank,last_user_name,time2text(world.timeofday, "MM/DD"),game_year,worldtime2text())
+ P.info += text(" This report was printed by [] []. The [MAIN_SHIP_NAME], []/[], [] \n",last_user_rank,last_user_name,time2text(world.timeofday, "MM/DD"),GLOB.game_year,worldtime2text())
src.printing = null
@@ -490,15 +483,15 @@
return
/obj/structure/machinery/computer/med_data/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
for(var/datum/data/record/R as anything in GLOB.data_core.medical)
if(prob(10/severity))
switch(rand(1,6))
if(1)
- R.fields["name"] = "[pick(pick(first_names_male), pick(first_names_female))] [pick(last_names)]"
+ R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]"
if(2)
R.fields["sex"] = pick("Male", "Female")
if(3)
@@ -516,8 +509,6 @@
qdel(R)
continue
- ..(severity)
-
/obj/structure/machinery/computer/med_data/laptop
name = "Medical Laptop"
diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm
index 3858230a089c..7ec97874bb7f 100644
--- a/code/game/machinery/computer/pod.dm
+++ b/code/game/machinery/computer/pod.dm
@@ -1,159 +1,8 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-
-/obj/structure/machinery/computer/pod
- name = "Pod Launch Control"
- desc = "A control for launching pods. Some people prefer firing Mechas."
+// Legacy SS13 machinery turned into props
+/obj/structure/machinery/computer/pod/old
+ name = "DoorMex Control Computer"
+ desc = "A control for launching pods."
icon_state = "computer_generic"
density = TRUE
- circuit = /obj/item/circuitboard/computer/pod
- var/id = 1
- var/obj/structure/machinery/mass_driver/connected = null
- var/timing = 0
- var/time = 30
- var/title = "Mass Driver Controls"
+ circuit = /obj/item/circuitboard/computer/pod/old
processing = TRUE
-
-
-/obj/structure/machinery/computer/pod/New()
- ..()
- spawn( 5 )
- for(var/obj/structure/machinery/mass_driver/M in machines)
- if(M.id == id)
- connected = M
- else
- return
- return
-
-
-/obj/structure/machinery/computer/pod/proc/alarm()
- if(inoperable())
- return
-
- if(!( connected ))
- to_chat(viewers(null, null), "Cannot locate mass driver connector. Cancelling firing sequence!")
- return
-
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == id)
- M.open()
-
- sleep(20)
-
- for(var/obj/structure/machinery/mass_driver/M in machines)
- if(M.id == id)
- M.power = connected.power
- M.drive()
-
- sleep(50)
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == id)
- M.close()
- return
- return
-
-/obj/structure/machinery/computer/pod/attack_remote(mob/user as mob)
- return attack_hand(user)
-
-/obj/structure/machinery/computer/pod/attack_hand(mob/user as mob)
- if(..())
- return
-
- var/dat = "[title]"
- user.set_interaction(src)
- if(connected)
- var/d2
- if(timing) //door controls do not need timers.
- d2 = "Stop Time Launch"
- else
- d2 = "Initiate Time Launch"
- var/second = time % 60
- var/minute = (time - second) / 60
- dat += "\nTimer System: [d2]\nTime Left: [minute ? "[minute]:" : null][second] --++"
- var/temp = ""
- var/list/L = list( 0.25, 0.5, 1, 2, 4, 8, 16 )
- for(var/t in L)
- if(t == connected.power)
- temp += "[t] "
- else
- temp += "[t] "
- dat += "\nPower Level: [temp] \nFiring Sequence \nTest Fire Driver \nToggle Outer Door "
- else
- dat += " \nToggle Outer Door "
- dat += "
Close"
- show_browser(user, dat, "computer", "size=400x500")
- add_fingerprint(usr)
- return
-
-
-/obj/structure/machinery/computer/pod/process()
- if(!..())
- return
- if(timing)
- if(time > 0)
- time = round(time) - 1
- else
- alarm()
- time = 0
- timing = 0
- updateDialog()
- return
-
-
-/obj/structure/machinery/computer/pod/Topic(href, href_list)
- if(..())
- return
- if((usr.contents.Find(src) || (in_range(src, usr) && istype(loc, /turf))) || (isRemoteControlling(usr)))
- usr.set_interaction(src)
- if(href_list["power"])
- var/t = text2num(href_list["power"])
- t = min(max(0.25, t), 16)
- if(connected)
- connected.power = t
- if(href_list["alarm"])
- alarm()
- if(href_list["drive"])
- for(var/obj/structure/machinery/mass_driver/M in machines)
- if(M.id == id)
- M.power = connected.power
- M.drive()
-
- if(href_list["time"])
- timing = text2num(href_list["time"])
- if(href_list["tp"])
- var/tp = text2num(href_list["tp"])
- time += tp
- time = min(max(round(time), 0), 120)
- if(href_list["door"])
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == id)
- if(M.density)
- M.open()
- else
- M.close()
- updateUsrDialog()
- return
-
-
-
-/obj/structure/machinery/computer/pod/old
- name = "DoorMex Control Computer"
- title = "Door Controls"
-
-/obj/structure/machinery/computer/pod/old/syndicate
- name = "ProComp Executive IIc"
- desc = "The Syndicate operate on a tight budget. Operates external airlocks."
- icon_state = "syndicomp"
- title = "External Airlock Controls"
- req_access = list(ACCESS_ILLEGAL_PIRATE)
-
-/obj/structure/machinery/computer/pod/old/syndicate/attack_hand(mob/user as mob)
- if(!allowed(user))
- to_chat(user, SPAN_DANGER("Access Denied"))
- return
- else
- ..()
-
-/obj/structure/machinery/computer/pod/old/swf
- name = "Magix System IV"
- icon_state = "wizard"
- desc = "An arcane artifact that holds much magic. Running E-Knock 2.2: Sorceror's Edition"
diff --git a/code/game/machinery/computer/research.dm b/code/game/machinery/computer/research.dm
index 2f37d9b2598a..1ba696eeee9c 100644
--- a/code/game/machinery/computer/research.dm
+++ b/code/game/machinery/computer/research.dm
@@ -28,8 +28,8 @@
if(N.note_type == "grant")
if(!N.grant)
return
- chemical_data.update_credits(N.grant)
- visible_message(SPAN_NOTICE("[user] scans the [N.name] on the [src], collecting the [N.grant] research credits."))
+ GLOB.chemical_data.update_credits(N.grant)
+ visible_message(SPAN_NOTICE("[user] scans the [N.name] on [src], collecting the [N.grant] research credits."))
N.grant = 0
qdel(N)
return
@@ -42,7 +42,7 @@
response = alert(usr,"Use existing or new category?","[src]","Existing","New")
if(response == "Existing")
var/list/pool = list()
- for(var/category in chemical_data.research_documents)
+ for(var/category in GLOB.chemical_data.research_documents)
pool += category
pool = sortAssoc(pool)
response = tgui_input_list(usr,"Select a category:", "Categories", pool)
@@ -51,7 +51,7 @@
if(!response)
response = "Misc."
var/obj/item/paper/research_report/CR = P.convert_to_chem_report()
- chemical_data.save_document(CR, response, CR.name)
+ GLOB.chemical_data.save_document(CR, response, CR.name)
return
//Clearance Updating
if(!istype(B, /obj/item/card/id))
@@ -60,8 +60,8 @@
if(!istype(card))
visible_message(SPAN_NOTICE("[user] swipes their ID card on \the [src], but it is refused."))
return
- if(card.clearance_access <= chemical_data.clearance_level || (card.clearance_access == 6 && chemical_data.clearance_level >= 5 && chemical_data.clearance_x_access))
- visible_message(SPAN_NOTICE("[user] swipes the clearance card on the [src], but nothing happens."))
+ if(card.clearance_access <= GLOB.chemical_data.clearance_level || (card.clearance_access == 6 && GLOB.chemical_data.clearance_level >= 5 && GLOB.chemical_data.clearance_x_access))
+ visible_message(SPAN_NOTICE("[user] swipes the clearance card on [src], but nothing happens."))
return
if(user.real_name != card.registered_name)
visible_message(SPAN_WARNING("WARNING: ILLEGAL CLEARANCE USER DETECTED. CARD DATA HAS BEEN WIPED."))
@@ -76,10 +76,10 @@
else
give_level = card.clearance_access
- chemical_data.clearance_level = give_level
+ GLOB.chemical_data.clearance_level = give_level
if(give_x)
- chemical_data.clearance_x_access = TRUE
- chemical_data.reached_x_access = TRUE
+ GLOB.chemical_data.clearance_x_access = TRUE
+ GLOB.chemical_data.reached_x_access = TRUE
visible_message(SPAN_NOTICE("[user] swipes their ID card on \the [src], updating the clearance to level [give_level][give_x ? "X" : ""]."))
msg_admin_niche("[key_name(user)] has updated the research clearance to level [give_level][give_x ? "X" : ""].")
@@ -103,12 +103,12 @@
/obj/structure/machinery/computer/research/ui_data(mob/user)
var/list/data = list(
- "rsc_credits" = chemical_data.rsc_credits,
- "clearance_level" = chemical_data.clearance_level,
- "broker_cost" = max(RESEARCH_LEVEL_INCREASE_MULTIPLIER*(chemical_data.clearance_level + 1), 1),
- "research_documents" = chemical_data.research_documents,
- "published_documents" = chemical_data.research_publications,
- "clearance_x_access" = chemical_data.clearance_x_access,
+ "rsc_credits" = GLOB.chemical_data.rsc_credits,
+ "clearance_level" = GLOB.chemical_data.clearance_level,
+ "broker_cost" = max(RESEARCH_LEVEL_INCREASE_MULTIPLIER*(GLOB.chemical_data.clearance_level + 1), 1),
+ "research_documents" = GLOB.chemical_data.research_documents,
+ "published_documents" = GLOB.chemical_data.research_publications,
+ "clearance_x_access" = GLOB.chemical_data.clearance_x_access,
"photocopier_error" = !photocopier,
"printer_toner" = photocopier?.toner
)
@@ -133,7 +133,7 @@
if ("read_document")
var/print_type = params["print_type"]
var/print_title = params["print_title"]
- var/obj/item/paper/research_report/report = chemical_data.get_report(print_type, print_title)
+ var/obj/item/paper/research_report/report = GLOB.chemical_data.get_report(print_type, print_title)
if(report)
report.read_paper(user)
return
@@ -145,7 +145,7 @@
var/print_title = params["print_title"]
photocopier.toner = max(0, photocopier.toner - 1)
var/obj/item/paper/research_report/printing = new /obj/item/paper/research_report/(photocopier.loc)
- var/obj/item/paper/research_report/report = chemical_data.get_report(print_type, print_title)
+ var/obj/item/paper/research_report/report = GLOB.chemical_data.get_report(print_type, print_title)
if(report)
printing.name = report.name
printing.info = report.info
@@ -154,16 +154,16 @@
if("broker_clearance")
if(!photocopier)
return
- if(chemical_data.clearance_level < 5)
- var/cost = max(RESEARCH_LEVEL_INCREASE_MULTIPLIER*(chemical_data.clearance_level + 1), 1)
- if(cost <= chemical_data.rsc_credits)
- chemical_data.update_credits(cost * -1)
- chemical_data.clearance_level++
- visible_message(SPAN_NOTICE("Clearance access increased to level [chemical_data.clearance_level] for [cost] credits."))
- msg_admin_niche("[key_name(user)] traded research credits to upgrade the clearance to level [chemical_data.clearance_level].")
- if(max_clearance < chemical_data.clearance_level)
- chemical_data.update_income(1) //Bonus income and a paper for buying clearance instead of swiping it up
- switch(chemical_data.clearance_level)
+ if(GLOB.chemical_data.clearance_level < 5)
+ var/cost = max(RESEARCH_LEVEL_INCREASE_MULTIPLIER*(GLOB.chemical_data.clearance_level + 1), 1)
+ if(cost <= GLOB.chemical_data.rsc_credits)
+ GLOB.chemical_data.update_credits(cost * -1)
+ GLOB.chemical_data.clearance_level++
+ visible_message(SPAN_NOTICE("Clearance access increased to level [GLOB.chemical_data.clearance_level] for [cost] credits."))
+ msg_admin_niche("[key_name(user)] traded research credits to upgrade the clearance to level [GLOB.chemical_data.clearance_level].")
+ if(max_clearance < GLOB.chemical_data.clearance_level)
+ GLOB.chemical_data.update_income(1) //Bonus income and a paper for buying clearance instead of swiping it up
+ switch(GLOB.chemical_data.clearance_level)
if(2)
new /obj/item/paper/research_notes/unique/tier_two/(photocopier.loc)
max_clearance = 2
@@ -182,11 +182,11 @@
var/purchase_tier = FLOOR(text2num(params["purchase_document"]), 1)
if(purchase_tier <= 0 || purchase_tier > 5)
return
- if(purchase_tier > chemical_data.clearance_level)
+ if(purchase_tier > GLOB.chemical_data.clearance_level)
return
var/purchase_cost = base_purchase_cost + purchase_tier * 2
- if(purchase_cost <= chemical_data.rsc_credits)
- chemical_data.update_credits(purchase_cost * -1)
+ if(purchase_cost <= GLOB.chemical_data.rsc_credits)
+ GLOB.chemical_data.update_credits(purchase_cost * -1)
var/obj/item/paper/research_notes/unique/N
switch(purchase_tier)
if(1)
@@ -203,21 +203,20 @@
if("publish_document")
var/print_type = params["print_type"]
var/print_title = params["print_title"]
- var/obj/item/paper/research_report/report = chemical_data.get_report(print_type, print_title)
+ var/obj/item/paper/research_report/report = GLOB.chemical_data.get_report(print_type, print_title)
if(!report)
to_chat(usr, SPAN_WARNING("Report data corrupted. Unable to transmit."))
return
- chemical_data.publish_document(report, print_type, print_title)
+ GLOB.chemical_data.publish_document(report, print_type, print_title)
if("unpublish_document")
var/print_title = params["print_title"]
var/print_type = params["print_type"]
- chemical_data.unpublish_document(print_type, print_title)
+ GLOB.chemical_data.unpublish_document(print_type, print_title)
if("request_clearance_x_access")
var/purchase_cost = 5
- if(purchase_cost <= chemical_data.rsc_credits)
- chemical_data.clearance_x_access = TRUE
- chemical_data.reached_x_access = TRUE
- chemical_data.update_credits(purchase_cost * -1)
+ if(purchase_cost <= GLOB.chemical_data.rsc_credits)
+ GLOB.chemical_data.clearance_x_access = TRUE
+ GLOB.chemical_data.reached_x_access = TRUE
+ GLOB.chemical_data.update_credits(purchase_cost * -1)
visible_message(SPAN_NOTICE("Clearance Level X Acquired."))
playsound(loc, pick('sound/machines/computer_typing1.ogg','sound/machines/computer_typing2.ogg','sound/machines/computer_typing3.ogg'), 5, 1)
-
diff --git a/code/game/machinery/computer/robot.dm b/code/game/machinery/computer/robot.dm
index 12f4faedc979..19e3ac900af6 100644
--- a/code/game/machinery/computer/robot.dm
+++ b/code/game/machinery/computer/robot.dm
@@ -51,12 +51,11 @@
dat += "[R.name] |"
if(R.stat)
dat += " Not Responding |"
- else if (!R.canmove)
+ else if (HAS_TRAIT_FROM(R, TRAIT_IMMOBILIZED, HACKED_TRAIT))
dat += " Locked Down |"
else
dat += " Operating Normally |"
- if (!R.canmove)
- else if(R.cell)
+ if(R.cell)
dat += " Battery Installed ([R.cell.charge]/[R.cell.maxcharge]) |"
else
dat += " No Cell Installed |"
@@ -71,7 +70,8 @@
if (isRemoteControlling(user))
if((user.mind.original == user))
dat += "(Hack) "
- dat += "([R.canmove ? "Lockdown" : "Release"]) "
+ var/canmove = HAS_TRAIT_FROM(src, TRAIT_IMMOBILIZED, HACKED_TRAIT)
+ dat += "([canmove ? "Lockdown" : "Release"]) "
dat += "(Destroy)"
dat += " "
dat += "(Return to Main Menu) "
@@ -162,20 +162,22 @@
else if (href_list["stopbot"])
if(src.allowed(usr))
var/mob/living/silicon/robot/R = locate(href_list["stopbot"])
+ var/canmove = HAS_TRAIT_FROM(src, TRAIT_IMMOBILIZED, HACKED_TRAIT)
if(R && istype(R)) // Extra sancheck because of input var references
- var/choice = tgui_input_list(usr, "Are you certain you wish to [R.canmove ? "lock down" : "release"] [R.name]?", "Hack machine", list("Confirm", "Abort"))
+ var/choice = tgui_input_list(usr, "Are you certain you wish to [canmove ? "lock down" : "release"] [R.name]?", "Hack machine", list("Confirm", "Abort"))
if(choice == "Confirm")
if(R && istype(R))
- message_admins("[key_name_admin(usr)] [R.canmove ? "locked down" : "released"] [R.name]!")
- log_game("[key_name(usr)] [R.canmove ? "locked down" : "released"] [R.name]!")
- R.canmove = !R.canmove
+ message_admins("[key_name_admin(usr)] [canmove ? "locked down" : "released"] [R.name]!")
+ log_game("[key_name(usr)] [canmove ? "locked down" : "released"] [R.name]!")
+ if(canmove)
+ ADD_TRAIT(src, TRAIT_IMMOBILIZED, HACKED_TRAIT)
+ else
+ REMOVE_TRAIT(src, TRAIT_IMMOBILIZED, HACKED_TRAIT)
if (R.lockcharge)
- // R.cell.charge = R.lockcharge
R.lockcharge = !R.lockcharge
to_chat(R, "Your lockdown has been lifted!")
else
R.lockcharge = !R.lockcharge
- // R.cell.charge = 0
to_chat(R, "You have been locked down!")
else
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index 857118937910..e7626938549a 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -95,7 +95,7 @@
if("Released")
background = "'background-color:#2981b3;'"
if("Suspect")
- background = "'background-color:#008743;'"
+ background = "'background-color:#686A6C;'"
if("NJP")
background = "'background-color:#faa20a;'"
if("None")
@@ -187,7 +187,7 @@
if("Released")
background = "'background-color:#3BB9FF;'"
if("Suspect")
- background = "'background-color:#1AAFFF;'"
+ background = "'background-color:#686A6C;'"
if("NJP")
background = "'background-color:#faa20a;'"
if("None")
@@ -363,7 +363,7 @@ What a mess.*/
var/t1 = copytext(trim(strip_html(input("Your name and time will be added to this new comment.", "Add a comment", null, null) as message)),1,MAX_MESSAGE_LEN)
if((!t1 || usr.stat || usr.is_mob_restrained() || (!in_range(src, usr) && (!ishighersilicon(usr))) || active2 != a2))
return
- var/created_at = text("[] [] []", time2text(world.realtime, "MMM DD"), time2text(world.time, "[worldtime2text()]:ss"), game_year)
+ var/created_at = text("[] [] []", time2text(world.realtime, "MMM DD"), time2text(world.time, "[worldtime2text()]:ss"), GLOB.game_year)
var/new_comment = list("entry" = t1, "created_by" = list("name" = "", "rank" = ""), "deleted_by" = null, "deleted_at" = null, "created_at" = created_at)
if(istype(usr,/mob/living/carbon/human))
var/mob/living/carbon/human/U = usr
@@ -391,7 +391,7 @@ What a mess.*/
var/mob/living/silicon/robot/U = usr
deleter = "[U.name] ([U.modtype] [U.braintype])"
updated_comments[href_list["del_c"]]["deleted_by"] = deleter
- updated_comments[href_list["del_c"]]["deleted_at"] = text("[] [] []", time2text(world.realtime, "MMM DD"), time2text(world.time, "[worldtime2text()]:ss"), game_year)
+ updated_comments[href_list["del_c"]]["deleted_at"] = text("[] [] []", time2text(world.realtime, "MMM DD"), time2text(world.time, "[worldtime2text()]:ss"), GLOB.game_year)
active2.fields["comments"] = updated_comments
to_chat(usr, text("You have deleted a comment from the Security Record of [].", active2.fields["name"]))
//RECORD CREATE
@@ -524,15 +524,15 @@ What a mess.*/
return selection.fields["img"]
/obj/structure/machinery/computer/secure_data/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
for(var/datum/data/record/R in GLOB.data_core.security)
if(prob(10/severity))
switch(rand(1,6))
if(1)
- R.fields["name"] = "[pick(pick(first_names_male), pick(first_names_female))] [pick(last_names)]"
+ R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]"
if(2)
R.fields["sex"] = pick("Male", "Female")
if(3)
@@ -550,8 +550,6 @@ What a mess.*/
qdel(R)
continue
- ..(severity)
-
/obj/structure/machinery/computer/secure_data/detective_computer
icon = 'icons/obj/structures/machinery/computer.dmi'
icon_state = "messyfiles"
diff --git a/code/game/machinery/computer/sentencing.dm b/code/game/machinery/computer/sentencing.dm
index 52a4159a2a90..3aa9b5a032a8 100644
--- a/code/game/machinery/computer/sentencing.dm
+++ b/code/game/machinery/computer/sentencing.dm
@@ -78,6 +78,7 @@
data["laws"] += list(create_law_data("Major Laws", SSlaw_init.major_law))
data["laws"] += list(create_law_data("Capital Laws", SSlaw_init.capital_law))
data["laws"] += list(create_law_data("Optional Laws", SSlaw_init.optional_law))
+ data["laws"] += list(create_law_data("Precautionary Laws", SSlaw_init.precautionary_law))
return data
diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm
index f891d46bc36b..6e35d147ff38 100644
--- a/code/game/machinery/computer/skills.dm
+++ b/code/game/machinery/computer/skills.dm
@@ -43,16 +43,16 @@
var/dat
if (temp)
- dat = text("[]
"
dat += ""
- dat += text(" Return to index.", src)
- else
+ dat += " Return to index."
else
- dat += text("{Log In}", src)
+ dat += "{Log In}"
show_browser(user, dat, "Employment Records", "secure_rec", "size=600x400")
onclose(user, "secure_rec")
return
@@ -342,7 +338,6 @@ What a mess.*/
if ((R.fields["name"] == active1.fields["name"] || R.fields["id"] == active1.fields["id"]))
GLOB.data_core.medical -= R
qdel(R)
- else
QDEL_NULL(active1)
else
temp = "This function does not appear to be working at the moment. Our apologies."
@@ -352,15 +347,15 @@ What a mess.*/
return
/obj/structure/machinery/computer/skills/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
for(var/datum/data/record/R in GLOB.data_core.security)
if(prob(10/severity))
switch(rand(1,6))
if(1)
- R.fields["name"] = "[pick(pick(first_names_male), pick(first_names_female))] [pick(last_names)]"
+ R.fields["name"] = "[pick(pick(GLOB.first_names_male), pick(GLOB.first_names_female))] [pick(GLOB.last_names)]"
if(2)
R.fields["sex"] = pick("Male", "Female")
if(3)
@@ -378,4 +373,3 @@ What a mess.*/
qdel(R)
continue
- ..(severity)
diff --git a/code/game/machinery/cryopod.dm b/code/game/machinery/cryopod.dm
index eb9aed4f71e4..69c2c897e276 100644
--- a/code/game/machinery/cryopod.dm
+++ b/code/game/machinery/cryopod.dm
@@ -192,7 +192,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
//Lifted from Unity stasis.dm and refactored. ~Zuhayr
/obj/structure/machinery/cryopod/process()
- if(occupant && !(WEAKREF(occupant) in GLOB.freed_mob_list)) //ignore freed mobs
+ if(occupant && !(occupant in GLOB.freed_mob_list)) //ignore freed mobs
//if occupant ghosted, time till despawn is severely shorter
if(!occupant.key && time_till_despawn == 10 MINUTES)
time_till_despawn -= 8 MINUTES
@@ -321,13 +321,13 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
dept_console += A
A.moveToNullspace()
+ var/datum/job/job = GET_MAPPED_ROLE(occupant.job)
if(ishuman(occupant))
var/mob/living/carbon/human/H = occupant
if(H.assigned_squad)
var/datum/squad/S = H.assigned_squad
S.forget_marine_in_squad(H)
- var/datum/job/J = GET_MAPPED_ROLE(H.job)
- if(istype(J, /datum/job/marine/specialist))
+ if(istype(job, /datum/job/marine/specialist))
//we make the set this specialist took if any available again
if(H.skills)
var/set_name
@@ -343,13 +343,14 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
if(SKILL_SPEC_SNIPER)
set_name = "Sniper Set"
- if(set_name && !available_specialist_sets.Find(set_name))
- available_specialist_sets += set_name
+ if(set_name && !GLOB.available_specialist_sets.Find(set_name))
+ GLOB.available_specialist_sets += set_name
- SSticker.mode.latejoin_tally-- //Cryoing someone out removes someone from the Marines, blocking further larva spawns until accounted for
+ //Cryoing someone out removes someone from the Marines, blocking further larva spawns until accounted for
+ SSticker.mode.latejoin_update(job, -1)
//Handle job slot/tater cleanup.
- RoleAuthority.free_role(GET_MAPPED_ROLE(occupant.job), TRUE)
+ GLOB.RoleAuthority.free_role(GET_MAPPED_ROLE(occupant.job), TRUE)
var/occupant_ref = WEAKREF(occupant)
//Delete them from datacore.
@@ -385,34 +386,35 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
stop_processing()
/obj/structure/machinery/cryopod/attackby(obj/item/W, mob/living/user)
-
+ if(isxeno(user))
+ return FALSE
if(istype(W, /obj/item/grab))
- if(isxeno(user)) return
var/obj/item/grab/G = W
if(occupant)
to_chat(user, SPAN_WARNING("[src] is occupied."))
- return
+ return FALSE
if(!isliving(G.grabbed_thing))
- return
+ return FALSE
- var/willing = null //We don't want to allow people to be forced into despawning.
+ var/willing = FALSE //We don't want to allow people to be forced into despawning.
var/mob/living/M = G.grabbed_thing
if(M.stat == DEAD) //This mob is dead
to_chat(user, SPAN_WARNING("[src] immediately rejects [M]. \He passed away!"))
- return
+ return FALSE
if(isxeno(M))
to_chat(user, SPAN_WARNING("There is no way [src] will accept [M]!"))
- return
+ return FALSE
if(M.client)
if(alert(M,"Would you like to enter cryosleep?", , "Yes", "No") == "Yes")
- if(!M || !G || !G.grabbed_thing) return
- willing = 1
+ if(!M || !G || !G.grabbed_thing)
+ return FALSE
+ willing = TRUE
else
- willing = 1
+ willing = TRUE
if(willing)
@@ -423,7 +425,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
if(!M || !G || !G.grabbed_thing) return
if(occupant)
to_chat(user, SPAN_WARNING("[src] is occupied."))
- return
+ return FALSE
go_in_cryopod(M)
@@ -433,6 +435,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
//Despawning occurs when process() is called with an occupant without a client.
add_fingerprint(user)
+ return TRUE
/obj/structure/machinery/cryopod/relaymove(mob/user)
if(user.is_mob_incapacitated(TRUE))
@@ -516,7 +519,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
if(mob.client)
to_chat(mob, SPAN_NOTICE("You feel cool air surround you. You go numb as your senses turn inward."))
to_chat(mob, SPAN_BOLDNOTICE("If you log out or close your client now, your character will permanently removed from the round in 10 minutes. If you ghost, timer will be decreased to 2 minutes."))
- if(!is_admin_level(src.z)) // Set their queue time now because the client has to actually leave to despawn and at that point the client is lost
+ if(!should_block_game_interaction(src)) // Set their queue time now because the client has to actually leave to despawn and at that point the client is lost
mob.client.player_details.larva_queue_time = max(mob.client.player_details.larva_queue_time, world.time)
var/area/location = get_area(src)
if(mob.job != GET_MAPPED_ROLE(JOB_SQUAD_MARINE))
@@ -533,6 +536,7 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
icon_state = "body_scanner_open"
set_light(0)
playsound(src, 'sound/machines/pod_open.ogg', 30)
+ SEND_SIGNAL(src, COMSIG_CRYOPOD_GO_OUT)
#ifdef OBJECTS_PROXY_SPEECH
// Transfers speech to occupant
@@ -551,3 +555,40 @@ GLOBAL_LIST_INIT(frozen_items, list(SQUAD_MARINE_1 = list(), SQUAD_MARINE_2 = li
return
move_inside(target)
+
+
+/obj/structure/machinery/cryopod/tutorial
+ silent_exit = TRUE
+
+/obj/structure/machinery/cryopod/tutorial/process()
+ return
+
+/obj/structure/machinery/cryopod/tutorial/go_in_cryopod(mob/mob, silent = FALSE, del_them = TRUE)
+ if(occupant)
+ return
+ mob.forceMove(src)
+ occupant = mob
+ icon_state = "body_scanner_closed"
+ set_light(2)
+ time_entered = world.time
+ if(del_them)
+ despawn_occupant()
+
+/obj/structure/machinery/cryopod/tutorial/despawn_occupant()
+ SSminimaps.remove_marker(occupant)
+
+ if(ishuman(occupant))
+ var/mob/living/carbon/human/man = occupant
+ man.species.handle_cryo(man)
+
+ icon_state = "body_scanner_open"
+ set_light(0)
+
+
+ var/mob/new_player/new_player = new
+
+ if(!occupant.mind)
+ occupant.mind_initialize()
+
+ occupant.mind.transfer_to(new_player)
+ SEND_SIGNAL(occupant, COMSIG_MOB_END_TUTORIAL)
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index e6df92d258c0..687882d9d7ae 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -54,7 +54,6 @@
src.health -= W.force * 0.75
if("brute")
src.health -= W.force * 0.5
- else
if (src.health <= 0)
src.explode()
..()
@@ -66,6 +65,7 @@
return
/obj/structure/machinery/deployable/barrier/emp_act(severity)
+ . = ..()
if(inoperable())
return
if(prob(50/severity))
diff --git a/code/game/machinery/door_control.dm b/code/game/machinery/door_control.dm
index 8be8609d6008..545d4c35bb5a 100644
--- a/code/game/machinery/door_control.dm
+++ b/code/game/machinery/door_control.dm
@@ -64,7 +64,7 @@
if(is_mainship_level(z)) // on the almayer
return
- shuttle.control_doors("lock", "all", force=FALSE)
+ shuttle.control_doors("force-lock", "all", force=FALSE)
/obj/structure/machinery/door_control/proc/handle_door()
for(var/obj/structure/machinery/door/airlock/D in range(range))
@@ -95,7 +95,7 @@
D.safe = 1
/obj/structure/machinery/door_control/proc/handle_pod()
- for(var/obj/structure/machinery/door/poddoor/M in machines)
+ for(var/obj/structure/machinery/door/poddoor/M in GLOB.machines)
if(M.id == id)
if(M.density)
INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/door, open))
@@ -150,47 +150,6 @@
else
icon_state = initial(icon_state) + "0"
-/obj/structure/machinery/driver_button/attack_remote(mob/user as mob)
- return src.attack_hand(user)
-
-/obj/structure/machinery/driver_button/attackby(obj/item/W, mob/user as mob)
- return src.attack_hand(user)
-
-/obj/structure/machinery/driver_button/attack_hand(mob/user as mob)
-
- src.add_fingerprint(usr)
- if(inoperable())
- return
- if(active)
- return
- add_fingerprint(user)
-
- use_power(5)
-
- active = 1
- icon_state = "launcheract"
-
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == src.id)
- INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/door, open))
-
- sleep(20)
-
- for(var/obj/structure/machinery/mass_driver/M in machines)
- if(M.id == src.id)
- M.drive()
-
- sleep(50)
-
- for(var/obj/structure/machinery/door/poddoor/M in machines)
- if(M.id == src.id)
- INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/door, close))
-
- icon_state = "launcherbtt"
- active = 0
-
- return
-
// Controls elevator railings
/obj/structure/machinery/door_control/railings
name = "railing controls"
@@ -228,7 +187,7 @@
add_fingerprint(user)
var/effective = 0
- for(var/obj/structure/machinery/door/poddoor/M in machines)
+ for(var/obj/structure/machinery/door/poddoor/M in GLOB.machines)
if(M.id == id)
effective = 1
spawn()
@@ -275,3 +234,31 @@
desiredstate = !desiredstate
+/obj/structure/machinery/door_control/cl
+ req_access_txt = "200"
+// seperating quarter and office because we might want to allow more access to the office than quarter in the future.
+/obj/structure/machinery/door_control/cl/office
+/obj/structure/machinery/door_control/cl/office/door
+ name = "Office Door Shutter"
+ id = "cl_office_door"
+/obj/structure/machinery/door_control/cl/office/window
+ name = "Office Windows Shutters"
+ id = "cl_office_windows"
+/obj/structure/machinery/door_control/cl/office/divider
+ name = "Room Divider"
+ id = "RoomDivider"
+//special button that unlock the cl lock on is evac pod door bypassing general lockdown.
+/obj/structure/machinery/door_control/cl/office/evac
+ name = "Evac Pod Door Control"
+ id = "cl_evac"
+ normaldoorcontrol = 1
+/obj/structure/machinery/door_control/cl/quarter
+/obj/structure/machinery/door_control/cl/quarter/officedoor
+ name = "Quarter Door Shutter"
+ id = "cl_quarter_door"
+/obj/structure/machinery/door_control/cl/quarter/backdoor
+ name = "Maintenance Door Shutter"
+ id = "cl_quarter_maintenance"
+/obj/structure/machinery/door_control/cl/quarter/windows
+ name = "Quarter Windows Shutters"
+ id = "cl_quarter_windows"
diff --git a/code/game/machinery/door_display/door_display.dm b/code/game/machinery/door_display/door_display.dm
index 7462b1f1b74d..3f0c53ada18e 100644
--- a/code/game/machinery/door_display/door_display.dm
+++ b/code/game/machinery/door_display/door_display.dm
@@ -31,7 +31,7 @@
get_targets()
/obj/structure/machinery/door_display/proc/get_targets()
- for(var/obj/structure/machinery/door/D in machines)
+ for(var/obj/structure/machinery/door/D in GLOB.machines)
if (D.id == id)
targets += D
@@ -199,7 +199,7 @@
/obj/structure/machinery/door_display/research_cell/get_targets()
..()
- for(var/obj/structure/machinery/flasher/F in machines)
+ for(var/obj/structure/machinery/flasher/F in GLOB.machines)
if(F.id == id)
targets += F
if(has_wall_divider)
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index dc28cdca6f5c..332d9b96bd44 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -91,7 +91,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
else if(user.hallucination > 50 && prob(10) && operating == 0)
to_chat(user, SPAN_DANGER("You feel a powerful shock course through your body!"))
user.halloss += 10
- user.stunned += 10
+ user.apply_effect(10, STUN)
return
..(user)
@@ -550,14 +550,14 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
add_fingerprint(usr)
update_icon()
-/obj/structure/machinery/door/airlock/attackby(obj/item/C, mob/user)
- if(SEND_SIGNAL(C, COMSIG_ITEM_ATTACK_AIRLOCK, src, user) & COMPONENT_CANCEL_AIRLOCK_ATTACK)
+/obj/structure/machinery/door/airlock/attackby(obj/item/attacking_item, mob/user)
+ if(SEND_SIGNAL(attacking_item, COMSIG_ITEM_ATTACK_AIRLOCK, src, user) & COMPONENT_CANCEL_AIRLOCK_ATTACK)
return
- if(istype(C, /obj/item/clothing/mask/cigarette))
+ if(istype(attacking_item, /obj/item/clothing/mask/cigarette))
if(isElectrified())
- var/obj/item/clothing/mask/cigarette/L = C
- L.light(SPAN_NOTICE("[user] lights their [L] on an electrical arc from the [src]"))
+ var/obj/item/clothing/mask/cigarette/L = attacking_item
+ L.light(SPAN_NOTICE("[user] lights their [L] on an electrical arc from [src]"))
return
if(!isRemoteControlling(user))
@@ -567,8 +567,8 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
add_fingerprint(user)
- if(istype(C, /obj/item/weapon/zombie_claws) && (welded || locked))
- user.visible_message(SPAN_NOTICE("[user] starts tearing into the door on the [src]!"), \
+ if(istype(attacking_item, /obj/item/weapon/zombie_claws) && (welded || locked))
+ user.visible_message(SPAN_NOTICE("[user] starts tearing into the door on [src]!"), \
SPAN_NOTICE("You start prying your hand into the gaps of the door with your fingers... This will take about 30 seconds."), \
SPAN_NOTICE("You hear tearing noises!"))
@@ -584,8 +584,8 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
return
- if((iswelder(C) && !operating && density))
- var/obj/item/tool/weldingtool/W = C
+ if((iswelder(attacking_item) && !operating && density))
+ var/obj/item/tool/weldingtool/W = attacking_item
var/weldtime = 50
if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH))
weldtime = 70
@@ -609,7 +609,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
update_icon()
return
- else if(HAS_TRAIT(C, TRAIT_TOOL_SCREWDRIVER))
+ else if(HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER))
if(no_panel)
to_chat(user, SPAN_WARNING("\The [src] has no panel to open!"))
return
@@ -619,17 +619,17 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
update_icon()
return
- else if(HAS_TRAIT(C, TRAIT_TOOL_WIRECUTTERS))
+ else if(HAS_TRAIT(attacking_item, TRAIT_TOOL_WIRECUTTERS))
return attack_hand(user)
- else if(HAS_TRAIT(C, TRAIT_TOOL_MULTITOOL))
+ else if(HAS_TRAIT(attacking_item, TRAIT_TOOL_MULTITOOL))
return attack_hand(user)
- else if(isgun(C))
- var/obj/item/weapon/gun/G = C
- for(var/slot in G.attachments)
- if(istype(G.attachments[slot], /obj/item/attachable/bayonet))
- var/obj/item/attachable/bayonet/a_bayonet = G.attachments[slot]
+ else if(isgun(attacking_item))
+ var/obj/item/weapon/gun/gun_item = attacking_item
+ for(var/slot in gun_item.attachments)
+ if(istype(gun_item.attachments[slot], /obj/item/attachable/bayonet))
+ var/obj/item/attachable/bayonet/a_bayonet = gun_item.attachments[slot]
if(arePowerSystemsOn())
to_chat(user, SPAN_WARNING("The airlock's motors resist your efforts to force it."))
else if(locked)
@@ -647,50 +647,48 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
if(do_after(user, a_bayonet.pry_delay, INTERRUPT_ALL, BUSY_ICON_FRIENDLY))
close(1)
- else if(C.pry_capable)
- if(C.pry_capable == IS_PRY_CAPABLE_CROWBAR && panel_open && welded)
+ else if(attacking_item.pry_capable)
+ if(attacking_item.pry_capable == IS_PRY_CAPABLE_CROWBAR && panel_open && welded)
if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
to_chat(user, SPAN_WARNING("You don't seem to know how to deconstruct machines."))
return
- if(width > 1)
- to_chat(user, SPAN_WARNING("Large doors seem impossible to disassemble."))
- return
playsound(loc, 'sound/items/Crowbar.ogg', 25, 1)
user.visible_message("[user] starts removing the electronics from the airlock assembly.", "You start removing electronics from the airlock assembly.")
if(do_after(user, 40, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
to_chat(user, SPAN_NOTICE(" You removed the airlock electronics!"))
- var/obj/structure/airlock_assembly/da = new assembly_type(loc)
- if(istype(da, /obj/structure/airlock_assembly/multi_tile))
- da.setDir(dir)
+ var/obj/structure/airlock_assembly/doors_assembly = new assembly_type(loc)
+ if(istype(doors_assembly, /obj/structure/airlock_assembly/multi_tile))
+ doors_assembly.setDir(dir)
+ doors_assembly.update_collision_box()
- da.anchored = TRUE
+ doors_assembly.anchored = TRUE
if(mineral)
- da.glass = mineral
+ doors_assembly.glass = mineral
//else if(glass)
- else if(glass && !da.glass)
- da.glass = 1
- da.state = 0
- da.created_name = name
- da.update_icon()
+ else if(glass && !doors_assembly.glass)
+ doors_assembly.glass = TRUE
+ doors_assembly.state = 0
+ doors_assembly.created_name = name
+ doors_assembly.update_icon()
- var/obj/item/circuitboard/airlock/ae
+ var/obj/item/circuitboard/airlock/airlock_electronics
if(!electronics)
- ae = new/obj/item/circuitboard/airlock( loc )
+ airlock_electronics = new/obj/item/circuitboard/airlock(loc)
if(!req_access || !req_one_access)
check_access()
if(req_access.len)
- ae.conf_access = req_access
+ airlock_electronics.conf_access = req_access
else if(req_one_access.len)
- ae.conf_access = req_one_access
- ae.one_access = 1
+ airlock_electronics.conf_access = req_one_access
+ airlock_electronics.one_access = TRUE
else
- ae = electronics
+ airlock_electronics = electronics
electronics = null
- ae.forceMove(loc)
+ airlock_electronics.forceMove(loc)
if(operating == -1)
- ae.fried = TRUE
- ae.update_icon()
+ airlock_electronics.fried = TRUE
+ airlock_electronics.update_icon()
operating = 0
msg_admin_niche("[key_name(user)] deconstructed [src] in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z])")
@@ -698,7 +696,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
deconstruct()
return
- else if(arePowerSystemsOn() && C.pry_capable != IS_PRY_CAPABLE_FORCE)
+ else if(arePowerSystemsOn() && attacking_item.pry_capable != IS_PRY_CAPABLE_FORCE)
to_chat(user, SPAN_WARNING("The airlock's motors resist your efforts to force it."))
else if(locked)
@@ -707,7 +705,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
else if(welded)
to_chat(user, SPAN_WARNING("The airlock is welded shut."))
- else if(C.pry_capable == IS_PRY_CAPABLE_FORCE)
+ else if(attacking_item.pry_capable == IS_PRY_CAPABLE_FORCE)
return FALSE //handled by the item's afterattack
else if(!operating)
@@ -719,7 +717,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
return TRUE //no afterattack call
- if(istype(C, /obj/item/large_shrapnel))
+ if(istype(attacking_item, /obj/item/large_shrapnel))
return FALSE //trigger afterattack call
else
return ..()
@@ -819,7 +817,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
/obj/structure/machinery/door/airlock/LateInitialize()
. = ..()
if(closeOtherId != null)
- for(var/obj/structure/machinery/door/airlock/A in machines)
+ for(var/obj/structure/machinery/door/airlock/A in GLOB.machines)
if(A.closeOtherId == closeOtherId && A != src)
closeOther = A
break
@@ -835,7 +833,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
return
/obj/structure/machinery/door/airlock/allowed(mob/M)
- if(isWireCut(AIRLOCK_WIRE_IDSCAN) || (maint_all_access && check_access_list(list(ACCESS_MARINE_MAINT))))
+ if(isWireCut(AIRLOCK_WIRE_IDSCAN) || (GLOB.maint_all_access && check_access_list(list(ACCESS_MARINE_MAINT))))
return TRUE
return ..(M)
@@ -847,7 +845,7 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
for(var/i in resin_door_shmushereds)
if(istype(x,i)) //I would like to just use a if(locate() in ) here but Im not gonna add every child to GLOB.resin_door_shmushereds so it works
playsound(loc, "alien_resin_break", 25)
- visible_message(SPAN_WARNING("The [src.name] closes on the [x], shmushing it!"))
+ visible_message(SPAN_WARNING("The [src.name] closes on [x], shmushing it!"))
if(isturf(x))
var/turf/closed/wall/resin_wall_to_destroy = x
resin_wall_to_destroy.dismantle_wall()
@@ -860,7 +858,8 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
var/datum/effect_system/spark_spread/sparks = new /datum/effect_system/spark_spread
sparks.set_up(5, 1, src)
sparks.start()
- xeno.apply_effect(1, WEAKEN)
+ xeno.KnockDown(1)
+ xeno.Stun(1)
playsound(src, 'sound/effects/metalhit.ogg', 50, TRUE)
xeno.visible_message(SPAN_XENOWARNING("\The [xeno] strikes \the [src] with its tail!"), SPAN_XENOWARNING("You strike \the [src] with your tail!"))
@@ -868,3 +867,8 @@ GLOBAL_LIST_INIT(airlock_wire_descriptions, list(
var/damage = xeno.melee_damage_upper * TAILSTAB_AIRLOCK_DAMAGE_MULTIPLIER
take_damage(damage, xeno)
return TAILSTAB_COOLDOWN_NORMAL
+
+/obj/structure/machinery/door/airlock/autoclose()
+ if(locked)
+ return
+ ..()
diff --git a/code/game/machinery/doors/airlock_types.dm b/code/game/machinery/doors/airlock_types.dm
index f4d09796194c..feb699fd245e 100644
--- a/code/game/machinery/doors/airlock_types.dm
+++ b/code/game/machinery/doors/airlock_types.dm
@@ -138,7 +138,6 @@
opacity = 0
assembly_type = /obj/structure/airlock_assembly/airlock_assembly_research
glass = 1
- heat_proof = 1
req_one_access = list(ACCESS_CIVILIAN_RESEARCH, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL)
/obj/structure/machinery/door/airlock/glass_mining/colony
diff --git a/code/game/machinery/doors/brig_system.dm b/code/game/machinery/doors/brig_system.dm
index 58c3282abed4..e7437aa9ca2b 100644
--- a/code/game/machinery/doors/brig_system.dm
+++ b/code/game/machinery/doors/brig_system.dm
@@ -290,15 +290,15 @@
addtimer(CALLBACK(src, PROC_REF(search_for_components)), 20)
/obj/structure/machinery/brig_cell/proc/search_for_components()
- for(var/obj/structure/machinery/door/window/brigdoor/M in machines)
+ for(var/obj/structure/machinery/door/window/brigdoor/M in GLOB.machines)
if(M.id == id)
targets += M
- for(var/obj/structure/machinery/flasher/F in machines)
+ for(var/obj/structure/machinery/flasher/F in GLOB.machines)
if(F.id == id)
targets += F
- for(var/obj/structure/machinery/door/poddoor/almayer/locked/P in machines)
+ for(var/obj/structure/machinery/door/poddoor/almayer/locked/P in GLOB.machines)
if(P.id == id)
targets += P
@@ -390,6 +390,14 @@
name = "Cell 4"
id = "Cell 4"
+/obj/structure/machinery/brig_cell/cell_5
+ name = "Cell 5"
+ id = "Cell 5"
+
+/obj/structure/machinery/brig_cell/cell_6
+ name = "Cell 6"
+ id = "Cell 6"
+
/obj/structure/machinery/brig_cell/perma_1
name = "Perma 1"
id = "Perma 1"
diff --git a/code/game/machinery/doors/door.dm b/code/game/machinery/doors/door.dm
index 578ef368f5d9..021cb60769f9 100644
--- a/code/game/machinery/doors/door.dm
+++ b/code/game/machinery/doors/door.dm
@@ -1,4 +1,3 @@
-
/obj/structure/machinery/door
name = "\improper Door"
desc = "It opens and closes."
@@ -7,50 +6,43 @@
anchored = TRUE
opacity = TRUE
density = TRUE
- throwpass = 0
+ throwpass = FALSE
layer = DOOR_OPEN_LAYER
minimap_color = MINIMAP_DOOR
var/open_layer = DOOR_OPEN_LAYER
var/closed_layer = DOOR_CLOSED_LAYER
var/id = ""
+ var/width = 1
var/secondsElectrified = 0
- var/visible = 1
+ var/visible = TRUE
var/panel_open = FALSE
- var/operating = 0
- var/autoclose = 0
- var/glass = 0
- var/normalspeed = 1
- 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/heat_proof = 0 // For glass airlocks/opacity firedoors
- var/air_properties_vary_with_direction = 0
- var/turf/filler //Fixes double door opacity issue
+ var/operating = FALSE
+ var/autoclose = FALSE
+ var/glass = FALSE
+ /// If FALSE it speeds up the autoclosing timing.
+ var/normalspeed = TRUE
+ /// Time to open/close airlock, default is 1 second.
+ var/openspeed = 1 SECONDS
+ /// Fixes multi_tile doors opacity issues.
+ var/list/filler_turfs = list() //Previously this was just var, because no one had forseen someone creating doors more than 2 tiles wide
/// Stops it being forced open through normal means (Hunters/Zombies/Aliens).
var/heavy = FALSE
/// Resistance to masterkey
var/masterkey_resist = FALSE
var/masterkey_mod = 0.1
-
-
- //Multi-tile doors
- dir = EAST
- var/width = 1
+ dir = EAST //So multitile doors are directioned properly
/obj/structure/machinery/door/Initialize(mapload, ...)
. = ..()
- if(density)
- layer = closed_layer
- update_flags_heat_protection(get_turf(src))
- else
- layer = open_layer
-
+ layer = density ? closed_layer : open_layer
handle_multidoor()
/obj/structure/machinery/door/Destroy()
. = ..()
- if(filler && width > 1)
- filler.set_opacity(0)// Ehh... let's hope there are no walls there. Must fix this
- filler = null
+ if(length(filler_turfs) && width > 1)
+ change_filler_opacity(0) // It still doesn't check for walls, might want to add checking that in the future
+ filler_turfs = null
density = FALSE
/obj/structure/machinery/door/initialize_pass_flags(datum/pass_flags_container/PF)
@@ -58,21 +50,41 @@
if (PF)
PF.flags_can_pass_all = NONE
+/// Also refreshes filler_turfs list.
+/obj/structure/machinery/door/proc/change_filler_opacity(new_opacity)
+ // I have no idea why do we null opacity first before... changing it
+ for(var/turf/filler_turf as anything in filler_turfs)
+ filler_turf.set_opacity(null)
+
+ filler_turfs = list()
+ for(var/turf/filler as anything in locate_filler_turfs())
+ filler.set_opacity(new_opacity)
+ filler_turfs += filler
+
+/// Updates collision box and opacity of multi_tile airlocks.
/obj/structure/machinery/door/proc/handle_multidoor()
if(width > 1)
if(dir in list(EAST, WEST))
bound_width = width * world.icon_size
bound_height = world.icon_size
- filler = get_step(src,EAST)
- filler.set_opacity(opacity)
else
bound_width = world.icon_size
bound_height = width * world.icon_size
- filler = get_step(src,NORTH)
- filler.set_opacity(opacity)
+ change_filler_opacity(opacity)
+
+/// Finds turfs which should be filler ones.
+/obj/structure/machinery/door/proc/locate_filler_turfs()
+ var/turf/filler_temp
+ var/list/located_turfs = list()
-//process()
- //return
+ for(var/i in 1 to width - 1)
+ if (dir in list(EAST, WEST))
+ filler_temp = locate(x + i, y, z)
+ else
+ filler_temp = locate(x, y + i, z)
+ if (filler_temp)
+ located_turfs += filler_temp
+ return located_turfs
/obj/structure/machinery/door/proc/borders_space()
for(var/turf/target in range(1, src))
@@ -81,7 +93,8 @@
return FALSE
/obj/structure/machinery/door/Collided(atom/movable/AM)
- if(panel_open || operating) return
+ if(panel_open || operating)
+ return
if(ismob(AM))
var/mob/M = AM
if(world.time - M.last_bumped <= openspeed) return //Can bump-open one airlock per second. This is to prevent shock spam.
@@ -89,12 +102,10 @@
if(!M.is_mob_restrained() && M.mob_size > MOB_SIZE_SMALL)
bumpopen(M)
return
-
if(istype(AM, /obj))
var/obj/O = AM
if(O.buckled_mob)
Collided(O.buckled_mob)
-
if(istype(AM, /obj/structure/machinery/bot))
var/obj/structure/machinery/bot/bot = AM
if(src.check_access(bot.botcard))
@@ -102,16 +113,17 @@
open()
return
-
/obj/structure/machinery/door/proc/bumpopen(mob/user as mob)
- if(operating) return
- src.add_fingerprint(user)
- if(!src.requiresID())
+ if(operating)
+ return
+ add_fingerprint(user)
+ if(!requiresID())
user = null
-
if(density)
- if(allowed(user)) open()
- else flick("door_deny", src)
+ if(allowed(user))
+ open()
+ else
+ flick("door_deny", src)
return
/obj/structure/machinery/door/attack_remote(mob/user)
@@ -124,9 +136,7 @@
add_fingerprint(user)
if(operating)
return
- if(!Adjacent(user))
- user = null //so allowed(user) always succeeds
- if(!requiresID())
+ if(!Adjacent(user) || !requiresID())
user = null //so allowed(user) always succeeds
if(allowed(user))
if(density)
@@ -137,64 +147,56 @@
if(density)
flick("door_deny", src)
-
/obj/structure/machinery/door/attackby(obj/item/I, mob/user)
if(!(I.flags_item & NOBLUDGEON))
try_to_activate_door(user)
- return 1
+ return TRUE
/obj/structure/machinery/door/emp_act(severity)
- if(prob(20/severity) && (istype(src,/obj/structure/machinery/door/airlock) || istype(src,/obj/structure/machinery/door/window)) )
+ . = ..()
+ if(prob(20/severity) && use_power)
open()
if(prob(40/severity))
if(secondsElectrified == 0)
secondsElectrified = -1
spawn(30 SECONDS)
secondsElectrified = 0
- ..()
-
/obj/structure/machinery/door/ex_act(severity)
- if(unacidable) return
+ if(unacidable)
+ return
if(density)
switch(severity)
if(0 to EXPLOSION_THRESHOLD_LOW)
if(prob(80))
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(2, 1, src)
- s.start()
+ var/datum/effect_system/spark_spread/spark = new /datum/effect_system/spark_spread
+ spark.set_up(2, 1, src)
+ spark.start()
if(EXPLOSION_THRESHOLD_LOW to INFINITY)
qdel(src)
else
switch(severity)
if(0 to EXPLOSION_THRESHOLD_MEDIUM)
if(prob(80))
- var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
- s.set_up(2, 1, src)
- s.start()
+ var/datum/effect_system/spark_spread/spark = new /datum/effect_system/spark_spread
+ spark.set_up(2, 1, src)
+ spark.start()
else
qdel(src)
return
-
/obj/structure/machinery/door/get_explosion_resistance()
if(density)
if(unacidable)
- return 1000000
+ return 1000000 //Used for negation of explosions, should probably be made into define in the future
else
return EXPLOSION_THRESHOLD_LOW //this should exactly match the amount of damage needed to destroy the door
else
return 0
-
/obj/structure/machinery/door/update_icon()
- if(density)
- icon_state = "door1"
- else
- icon_state = "door0"
- return
-
+ icon_state = density ? "door1" : "door0"
/obj/structure/machinery/door/proc/do_animate(animation)
switch(animation)
@@ -212,7 +214,6 @@
flick("door_deny", src)
return
-
/obj/structure/machinery/door/proc/open(forced=0)
if(!density)
return TRUE
@@ -223,8 +224,8 @@
do_animate("opening")
icon_state = "door0"
set_opacity(FALSE)
- if(filler)
- filler.set_opacity(opacity)
+ if(length(filler_turfs))
+ change_filler_opacity(opacity)
addtimer(CALLBACK(src, PROC_REF(finish_open)), openspeed)
return TRUE
@@ -235,11 +236,9 @@
if(operating)
operating = FALSE
-
if(autoclose)
addtimer(CALLBACK(src, PROC_REF(autoclose)), normalspeed ? 150 + openspeed : 5)
-
/obj/structure/machinery/door/proc/close()
if(density)
return TRUE
@@ -256,22 +255,19 @@
update_icon()
if(visible && !glass)
set_opacity(TRUE)
- if(filler)
- filler.set_opacity(opacity)
+ if(length(filler_turfs))
+ change_filler_opacity(opacity)
operating = FALSE
/obj/structure/machinery/door/proc/requiresID()
return TRUE
-
-/obj/structure/machinery/door/proc/update_flags_heat_protection(turf/source)
-
-
+/// Used for overriding in airlocks
/obj/structure/machinery/door/proc/autoclose()
- var/obj/structure/machinery/door/airlock/A = src
- if(!A.density && !A.operating && !A.locked && !A.welded && A.autoclose)
+ if(!autoclose)
+ return
+ if(!density && !operating)
close()
- return
/obj/structure/machinery/door/Move(new_loc, new_dir)
. = ..()
@@ -279,16 +275,15 @@
if(dir in list(EAST, WEST))
bound_width = width * world.icon_size
bound_height = world.icon_size
- filler.set_opacity(0)
- filler = (get_step(src,EAST)) //Find new turf
- filler.set_opacity(opacity)
else
bound_width = world.icon_size
bound_height = width * world.icon_size
- filler.set_opacity(0)
- filler = (get_step(src,NORTH)) //Find new turf
- filler.set_opacity(opacity)
+ change_filler_opacity(opacity)
+/obj/structure/machinery/door/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation)
+ . = ..()
+ // Yes, for a split second after departure you can see through rear dropship airlocks, but it's the simplest solution I could've think of
+ handle_multidoor()
/obj/structure/machinery/door/morgue
icon = 'icons/obj/structures/doors/doormorgue.dmi'
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index 065816567ca1..cddd67c7e2b2 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -1,7 +1,4 @@
// Door open and close constants
-/var/const
- CLOSED = 2
-
#define FIREDOOR_MAX_PRESSURE_DIFF 25 // kPa
#define FIREDOOR_MAX_TEMP 50 // °C
#define FIREDOOR_MIN_TEMP 0
@@ -57,7 +54,7 @@
A.all_doors.Add(src)
areas_added = list(A)
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
A = get_area(get_step(src,direction))
if(istype(A) && !(A in areas_added))
A.all_doors.Add(src)
@@ -135,7 +132,7 @@
"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." : ""]",\
"\The [src]", list("Yes", "No")) != "Yes")
return
- if(user.is_mob_incapacitated() || (!user.canmove && !isRemoteControlling(user)) || (get_dist(src, user) > 1 && !isRemoteControlling(user)))
+ if(user.is_mob_incapacitated() || (get_dist(src, user) > 1 && !isRemoteControlling(user)))
to_chat(user, "Sorry, you must remain able bodied and close to \the [src] in order to use it.")
return
if(density && (inoperable())) //can still close without power
@@ -277,7 +274,7 @@
overlays += "palert"
if(dir_alerts)
for(var/d=1;d<=4;d++)
- var/cdir = cardinal[d]
+ var/cdir = GLOB.cardinals[d]
for(var/i=1;i<=ALERT_STATES.len;i++)
if(dir_alerts[d] & (1<<(i-1)))
overlays += new/icon(icon,"alert_[ALERT_STATES[i]]", dir=cdir)
diff --git a/code/game/machinery/doors/multi_tile.dm b/code/game/machinery/doors/multi_tile.dm
index 6123d56b8f23..0a179af27803 100644
--- a/code/game/machinery/doors/multi_tile.dm
+++ b/code/game/machinery/doors/multi_tile.dm
@@ -2,19 +2,24 @@
/obj/structure/machinery/door/airlock/multi_tile
width = 2
damage_cap = 650 // Bigger = more endurable
+ assembly_type = /obj/structure/airlock_assembly/multi_tile
/obj/structure/machinery/door/airlock/multi_tile/close() //Nasty as hell O(n^2) code but unfortunately necessary
- for(var/turf/T in locs)
- for(var/obj/vehicle/multitile/M in T)
- if(M) return 0
+ for(var/turf/turf_tile in locs)
+ for(var/obj/vehicle/multitile/vehicle_tile in turf_tile)
+ if(vehicle_tile) return 0
return ..()
+/obj/structure/machinery/door/airlock/multi_tile/Initialize()
+ . = ..()
+ update_icon()
+
/obj/structure/machinery/door/airlock/multi_tile/glass
name = "Glass Airlock"
icon = 'icons/obj/structures/doors/Door2x1glass.dmi'
opacity = FALSE
- glass = 1
+ glass = TRUE
assembly_type = /obj/structure/airlock_assembly/multi_tile
/obj/structure/machinery/door/airlock/multi_tile/glass/colony
@@ -25,7 +30,7 @@
name = "Security Airlock"
icon = 'icons/obj/structures/doors/Door2x1security.dmi'
opacity = FALSE
- glass = 1
+ glass = TRUE
/obj/structure/machinery/door/airlock/multi_tile/security/colony
req_access = null
@@ -35,7 +40,7 @@
name = "Command Airlock"
icon = 'icons/obj/structures/doors/Door2x1command.dmi'
opacity = FALSE
- glass = 1
+ glass = TRUE
/obj/structure/machinery/door/airlock/multi_tile/command/colony
req_access = null
@@ -45,7 +50,7 @@
name = "Medical Airlock"
icon = 'icons/obj/structures/doors/Door2x1medbay.dmi'
opacity = FALSE
- glass = 1
+ glass = TRUE
/obj/structure/machinery/door/airlock/multi_tile/medical/colony
req_access = null
@@ -55,7 +60,7 @@
name = "Engineering Airlock"
icon = 'icons/obj/structures/doors/Door2x1engine.dmi'
opacity = FALSE
- glass = 1
+ glass = TRUE
/obj/structure/machinery/door/airlock/multi_tile/engineering/colony
req_access = null
@@ -65,7 +70,7 @@
name = "Research Airlock"
icon = 'icons/obj/structures/doors/Door2x1research.dmi'
opacity = FALSE
- glass = 1
+ glass = TRUE
req_one_access = list(ACCESS_MARINE_RESEARCH, ACCESS_WY_RESEARCH, ACCESS_WY_EXEC)
/obj/structure/machinery/door/airlock/multi_tile/research/colony
@@ -103,7 +108,7 @@
name = "Secure Airlock"
icon = 'icons/obj/structures/doors/Door2x1_secure2_glass.dmi'
opacity = FALSE
- glass = 1
+ glass = TRUE
openspeed = 31
req_access = null
@@ -131,7 +136,6 @@
/obj/structure/window/framed/almayer,
/obj/structure/machinery/door/airlock,
)
- var/multi_filler = list()
/obj/structure/machinery/door/airlock/multi_tile/almayer/Initialize()
. = ..()
@@ -141,10 +145,10 @@
. = ..()
relativewall_neighbours()
-/obj/structure/machinery/door/airlock/multi_tile/almayer/take_damage(dam, mob/M)
- var/damage_check = max(0, damage + dam)
- if(damage_check >= damage_cap && M && is_mainship_level(z))
- SSclues.create_print(get_turf(M), M, "The fingerprint contains bits of wire and metal specks.")
+/obj/structure/machinery/door/airlock/multi_tile/almayer/take_damage(taken_damage, mob/damaging_mob)
+ var/damage_check = max(0, damage + taken_damage)
+ if(damage_check >= damage_cap && damaging_mob && is_mainship_level(z))
+ SSclues.create_print(get_turf(damaging_mob), damaging_mob, "The fingerprint contains bits of wire and metal specks.")
..()
/obj/structure/machinery/door/airlock/multi_tile/almayer/generic
@@ -156,6 +160,11 @@
/obj/structure/machinery/door/airlock/multi_tile/almayer/generic/autoname
autoname = TRUE
+/obj/structure/machinery/door/airlock/multi_tile/almayer/generic/solid
+ icon = 'icons/obj/structures/doors/2x1generic_solid.dmi'
+ opacity = TRUE
+ glass = FALSE
+
/obj/structure/machinery/door/airlock/multi_tile/almayer/medidoor
name = "\improper Medical Airlock"
icon = 'icons/obj/structures/doors/2x1medidoor.dmi'
@@ -222,47 +231,6 @@
req_access = null
req_one_access = list(ACCESS_CIVILIAN_BRIG, ACCESS_CIVILIAN_COMMAND, ACCESS_WY_COLONIAL)
-/obj/structure/machinery/door/airlock/multi_tile/almayer/handle_multidoor()
- if(!(width > 1)) return //Bubblewrap
-
- update_filler_turfs()
- if(dir in list(NORTH, SOUTH))
- bound_height = world.icon_size * width
- bound_width = world.icon_size
- else if(dir in list(EAST, WEST))
- bound_width = world.icon_size * width
- bound_height = world.icon_size
-
-//We have to find these again since these doors are used on shuttles a lot so the turfs changes
-/obj/structure/machinery/door/airlock/multi_tile/almayer/proc/update_filler_turfs()
- for(var/turf/T in multi_filler)
- T.set_opacity(null)
-
- multi_filler = list()
- for(var/turf/T in get_filler_turfs())
- T.set_opacity(opacity)
- multi_filler += list(T)
-
-/obj/structure/machinery/door/airlock/multi_tile/proc/get_filler_turfs()
- . = list()
- for(var/i = 1, i < width, i++)
- if(dir in list(NORTH, SOUTH))
- var/turf/T = locate(x, y + i, z)
- if(T)
- . += list(T)
- else if(dir in list(EAST, WEST))
- var/turf/T = locate(x + i, y, z)
- if(T)
- . += list(T)
-
-/obj/structure/machinery/door/airlock/multi_tile/almayer/open()
- . = ..()
- update_filler_turfs()
-
-/obj/structure/machinery/door/airlock/multi_tile/almayer/close()
- . = ..()
- update_filler_turfs()
-
//------Dropship Cargo Doors -----//
/obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear
@@ -307,6 +275,17 @@
name = "\improper Normandy cargo door"
icon = 'icons/obj/structures/doors/dropship2_cargo.dmi'
+/obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/dropshipside
+ width = 2
+
+/obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/dropshipside/ds1
+ name = "\improper Alamo crew hatch"
+ icon = 'icons/obj/structures/doors/dropship1_side2.dmi'
+
+/obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/dropshipside/ds2
+ name = "\improper Normandy crew hatch"
+ icon = 'icons/obj/structures/doors/dropship2_side2.dmi'
+
/obj/structure/machinery/door/airlock/multi_tile/almayer/dropshiprear/blastdoor
name = "bulkhead blast door"
icon = 'icons/obj/structures/doors/almayerblastdoor.dmi'
@@ -427,7 +406,7 @@
/obj/structure/machinery/door/airlock/multi_tile/elevator/access
icon = 'icons/obj/structures/doors/4x1_elevator_access.dmi'
opacity = FALSE
- glass = 1
+ glass = TRUE
/obj/structure/machinery/door/airlock/multi_tile/elevator/access/research
name = "\improper Research Elevator Hatch"
@@ -547,7 +526,7 @@
icon = 'icons/obj/structures/doors/prepdoor.dmi'
req_one_access = list(ACCESS_MARINE_PREP, ACCESS_MARINE_DATABASE, ACCESS_MARINE_CARGO, ACCESS_MARINE_ALPHA, ACCESS_MARINE_BRAVO, ACCESS_MARINE_CHARLIE, ACCESS_MARINE_DELTA)
opacity = FALSE
- glass = 1
+ glass = TRUE
/obj/structure/machinery/door/airlock/multi_tile/almayer/marine/shared/alpha_bravo
name = "\improper Alpha-Bravo Squads Preparations"
diff --git a/code/game/machinery/doors/poddoor.dm b/code/game/machinery/doors/poddoor.dm
index b2d836ee476f..0a3b873ce385 100644
--- a/code/game/machinery/doors/poddoor.dm
+++ b/code/game/machinery/doors/poddoor.dm
@@ -240,6 +240,7 @@
/obj/structure/machinery/door/poddoor/filler_object
name = ""
+ icon = null
icon_state = ""
unslashable = TRUE
unacidable = TRUE
diff --git a/code/game/machinery/doors/runed_sandstone.dm b/code/game/machinery/doors/runed_sandstone.dm
index 4bf66dfdc8d8..a6de7348dd7f 100644
--- a/code/game/machinery/doors/runed_sandstone.dm
+++ b/code/game/machinery/doors/runed_sandstone.dm
@@ -110,8 +110,8 @@
density = FALSE
update_icon()
set_opacity(0)
- if(filler)
- filler.set_opacity(opacity)
+ if(length(filler_turfs))
+ change_filler_opacity(opacity)
if(operating)
operating = FALSE
diff --git a/code/game/machinery/doors/shutters.dm b/code/game/machinery/doors/shutters.dm
index da904f255c40..f91f1f48cade 100644
--- a/code/game/machinery/doors/shutters.dm
+++ b/code/game/machinery/doors/shutters.dm
@@ -155,3 +155,44 @@
if(HAS_TRAIT(attacking_item, TRAIT_TOOL_CROWBAR))
return
..()
+
+/obj/structure/machinery/door/poddoor/shutters/almayer/uniform_vendors/antitheft
+ name = "Anti-Theft Shutters"
+ desc = "Secure Storage shutters, they're reinforced against entry attempts."
+ var/req_level = SEC_LEVEL_RED
+
+/obj/structure/machinery/door/poddoor/shutters/almayer/uniform_vendors/antitheft/Initialize()
+ . = ..()
+ if(is_mainship_level(z))
+ RegisterSignal(SSdcs, COMSIG_GLOB_SECURITY_LEVEL_CHANGED, PROC_REF(sec_changed))
+
+/obj/structure/machinery/door/poddoor/shutters/almayer/uniform_vendors/antitheft/proc/sec_changed(datum/source, new_sec)
+ SIGNAL_HANDLER
+ if(new_sec < req_level)
+ if(density)
+ return
+ close()
+ else
+ if(!density)
+ return
+ open()
+
+//make a subtype for CL office so it as a proper name.
+/obj/structure/machinery/door/poddoor/shutters/almayer/cl
+ name = "\improper Corporate Liaison Privacy Shutters"
+//adding a subtype for CL office to use to secure access to cl office.
+/obj/structure/machinery/door/poddoor/shutters/almayer/cl/office
+/obj/structure/machinery/door/poddoor/shutters/almayer/cl/office/door
+ id = "cl_office_door"
+/obj/structure/machinery/door/poddoor/shutters/almayer/cl/office/window
+ id = "cl_office_windows"
+//adding a subtype for CL quarter to use to secure access to cl quarter.(including seperation with the office)
+/obj/structure/machinery/door/poddoor/shutters/almayer/cl/quarter
+/obj/structure/machinery/door/poddoor/shutters/almayer/cl/quarter/backdoor
+ id = "cl_quarter_maintenance"
+ dir = 4
+/obj/structure/machinery/door/poddoor/shutters/almayer/cl/quarter/door
+ id = "cl_quarter_door"
+ dir = 4
+/obj/structure/machinery/door/poddoor/shutters/almayer/cl/quarter/window
+ id = "cl_quarter_windows"
diff --git a/code/game/machinery/doors/windowdoor.dm b/code/game/machinery/doors/windowdoor.dm
index 2b57fbd0a44d..76a370061a2f 100644
--- a/code/game/machinery/doors/windowdoor.dm
+++ b/code/game/machinery/doors/windowdoor.dm
@@ -11,7 +11,6 @@
flags_atom = ON_BORDER
opacity = FALSE
var/obj/item/circuitboard/airlock/electronics = null
- air_properties_vary_with_direction = 1
/obj/structure/machinery/door/window/Initialize()
. = ..()
@@ -296,12 +295,12 @@
/obj/structure/machinery/door/window/ultra/Initialize(mapload, ...)
. = ..()
- GLOB.hijack_deletable_windows += src
-
-/obj/structure/machinery/door/window/ultra/Destroy()
- GLOB.hijack_deletable_windows -= src
- return ..()
+ if(is_mainship_level(z))
+ RegisterSignal(SSdcs, COMSIG_GLOB_HIJACK_IMPACTED, PROC_REF(impact))
// No damage taken.
/obj/structure/machinery/door/window/ultra/attackby(obj/item/I, mob/user)
return try_to_activate_door(user)
+
+/obj/structure/machinery/door/window/ultra/proc/impact()
+ qdel(src)
diff --git a/code/game/machinery/fax_machine.dm b/code/game/machinery/fax_machine.dm
index ff26ce802b08..4a5c62b1f9a0 100644
--- a/code/game/machinery/fax_machine.dm
+++ b/code/game/machinery/fax_machine.dm
@@ -1,11 +1,12 @@
-var/list/obj/structure/machinery/faxmachine/allfaxes = list()
-var/list/alldepartments = list()
+GLOBAL_LIST_INIT_TYPED(allfaxes, /obj/structure/machinery/faxmachine, list())
+GLOBAL_LIST_EMPTY(alldepartments)
#define DEPARTMENT_WY "Weyland-Yutani"
#define DEPARTMENT_HC "USCM High Command"
#define DEPARTMENT_CMB "CMB Incident Command Center, Local Operations"
#define DEPARTMENT_PROVOST "USCM Provost Office"
#define DEPARTMENT_PRESS "Various Press Organizations"
+#define HIGHCOM_DEPARTMENTS list(DEPARTMENT_WY, DEPARTMENT_HC, DEPARTMENT_CMB, DEPARTMENT_PROVOST, DEPARTMENT_PRESS)
/obj/structure/machinery/faxmachine // why not fax_machine?
name = "\improper General Purpose Fax Machine"
@@ -44,11 +45,11 @@ var/list/alldepartments = list()
/obj/structure/machinery/faxmachine/Initialize(mapload, ...)
. = ..()
- allfaxes += src
+ GLOB.allfaxes += src
update_departments()
/obj/structure/machinery/faxmachine/Destroy()
- allfaxes -= src
+ GLOB.allfaxes -= src
. = ..()
/obj/structure/machinery/faxmachine/initialize_pass_flags(datum/pass_flags_container/PF)
@@ -109,7 +110,8 @@ var/list/alldepartments = list()
set category = "Object"
set name = "Eject ID Card"
set src in view(1)
- if(!usr || usr.stat || usr.lying) return
+ if(usr.is_mob_incapacitated())
+ return
if(ishuman(usr) && scan)
to_chat(usr, "You remove \the [scan] from \the [src].")
@@ -124,18 +126,18 @@ var/list/alldepartments = list()
return
/obj/structure/machinery/faxmachine/proc/update_departments()
- if( !("[department]" in alldepartments) ) //Initialize departments. This will work with multiple fax machines.
- alldepartments += department
- if(!(DEPARTMENT_WY in alldepartments))
- alldepartments += DEPARTMENT_WY
- if(!(DEPARTMENT_HC in alldepartments))
- alldepartments += DEPARTMENT_HC
- if(!(DEPARTMENT_PROVOST in alldepartments))
- alldepartments += DEPARTMENT_PROVOST
- if(!(DEPARTMENT_CMB in alldepartments))
- alldepartments += DEPARTMENT_CMB
- if(!(DEPARTMENT_PRESS in alldepartments))
- alldepartments += DEPARTMENT_PRESS
+ if( !("[department]" in GLOB.alldepartments) ) //Initialize departments. This will work with multiple fax machines.
+ GLOB.alldepartments += department
+ if(!(DEPARTMENT_WY in GLOB.alldepartments))
+ GLOB.alldepartments += DEPARTMENT_WY
+ if(!(DEPARTMENT_HC in GLOB.alldepartments))
+ GLOB.alldepartments += DEPARTMENT_HC
+ if(!(DEPARTMENT_PROVOST in GLOB.alldepartments))
+ GLOB.alldepartments += DEPARTMENT_PROVOST
+ if(!(DEPARTMENT_CMB in GLOB.alldepartments))
+ GLOB.alldepartments += DEPARTMENT_CMB
+ if(!(DEPARTMENT_PRESS in GLOB.alldepartments))
+ GLOB.alldepartments += DEPARTMENT_PRESS
// TGUI SHIT \\
/obj/structure/machinery/faxmachine/tgui_interact(mob/user, datum/tgui/ui)
@@ -254,7 +256,7 @@ var/list/alldepartments = list()
if("select")
var/last_target_department = target_department
- target_department = tgui_input_list(ui.user, "Which department?", "Choose a department", alldepartments)
+ target_department = tgui_input_list(ui.user, "Which department?", "Choose a department", GLOB.alldepartments)
if(!target_department) target_department = last_target_department
. = TRUE
@@ -319,27 +321,31 @@ var/list/alldepartments = list()
GLOB.fax_contents += faxcontents
+ var/scan_department = target_department
+ if(department in HIGHCOM_DEPARTMENTS)
+ scan_department = department
+
var/msg_admin = SPAN_STAFF_IC("[target_department]: [key_name(user, 1)] ")
msg_admin += "[CC_MARK(user)] [ADMIN_PP(user)] [ADMIN_VV(user)] [ADMIN_SM(user)] [ADMIN_JMP_USER(user)] "
- switch(target_department)
+ switch(scan_department)
if(DEPARTMENT_HC)
- GLOB.USCMFaxes.Add("\[view message at [world.timeofday]\]REPLY")
+ GLOB.USCMFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\]REPLY")
msg_admin += "(RPLY): "
if(DEPARTMENT_PROVOST)
- GLOB.ProvostFaxes.Add("\[view message at [world.timeofday]\]REPLY")
+ GLOB.ProvostFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\]REPLY")
msg_admin += "(RPLY): "
if(DEPARTMENT_CMB)
- GLOB.CMBFaxes.Add("\[view message at [world.timeofday]\]REPLY")
+ GLOB.CMBFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\]REPLY")
msg_admin += "(RPLY): "
if(DEPARTMENT_WY)
- GLOB.WYFaxes.Add("\[view message at [world.timeofday]\]REPLY")
+ GLOB.WYFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\]REPLY")
msg_admin += "(RPLY): "
if(DEPARTMENT_PRESS)
- GLOB.PressFaxes.Add("\[view message at [world.timeofday]\]REPLY")
+ GLOB.PressFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\]REPLY")
msg_admin += "(RPLY): "
else
- GLOB.GeneralFaxes.Add("\[view message at [world.timeofday]\]REPLY")
+ GLOB.GeneralFaxes.Add("\['[original_fax.name]' from [key_name(usr)], [scan] at [time2text(world.timeofday, "hh:mm:ss")]\]REPLY")
msg_admin += "(RPLY): "
msg_admin += SPAN_STAFF_IC("Receiving fax via secure connection ... view message")
@@ -374,7 +380,7 @@ var/list/alldepartments = list()
/obj/structure/machinery/faxmachine/proc/send_fax(datum/fax/faxcontents)
- for(var/obj/structure/machinery/faxmachine/F in allfaxes)
+ for(var/obj/structure/machinery/faxmachine/F in GLOB.allfaxes)
if(F != src && F.department == target_department)
if(!faxcontents)
return
diff --git a/code/game/machinery/fire_alarm.dm b/code/game/machinery/fire_alarm.dm
index fe1f80646c4f..55aef1323c4d 100644
--- a/code/game/machinery/fire_alarm.dm
+++ b/code/game/machinery/fire_alarm.dm
@@ -47,7 +47,7 @@ FIRE ALARM
if(stat & BROKEN)
icon_state = "firex"
- else if(stat & NOPOWER & (security_level != SEC_LEVEL_RED))
+ else if(stat & NOPOWER & (GLOB.security_level != SEC_LEVEL_RED))
icon_state = "firep"
/obj/structure/machinery/firealarm/fire_act(temperature, volume)
@@ -63,8 +63,9 @@ FIRE ALARM
return src.alarm()
/obj/structure/machinery/firealarm/emp_act(severity)
- if(prob(50/severity)) alarm()
- ..()
+ . = ..()
+ if(prob(50/severity))
+ alarm()
/obj/structure/machinery/firealarm/attackby(obj/item/held_object as obj, mob/user as mob)
src.add_fingerprint(user)
@@ -182,7 +183,7 @@ FIRE ALARM
pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
if(!is_mainship_level(z))
- if(security_level)
+ if(GLOB.security_level)
src.overlays += image('icons/obj/structures/machinery/monitors.dmi', "overlay_[get_security_level()]")
else
src.overlays += image('icons/obj/structures/machinery/monitors.dmi', "overlay_green")
diff --git a/code/game/machinery/flasher.dm b/code/game/machinery/flasher.dm
index 75d0de56dec0..437ef7b067ea 100644
--- a/code/game/machinery/flasher.dm
+++ b/code/game/machinery/flasher.dm
@@ -60,7 +60,7 @@
src.last_flash = world.time
use_power(1500)
- for (var/mob/O in viewers(src, null))
+ for (var/mob/living/O in viewers(src, null))
if (get_dist(src, O) > src.range)
continue
@@ -72,7 +72,9 @@
if (istype(O, /mob/living/carbon/xenomorph))//So aliens don't get flashed (they have no external eyes)/N
continue
- O.apply_effect(strength, WEAKEN)
+ O.KnockDown(strength)
+ O.Stun(strength)
+
if (istype(O, /mob/living/carbon/human))
var/mob/living/carbon/human/H = O
var/datum/internal_organ/eyes/E = H.internal_organs_by_name["eyes"]
@@ -84,12 +86,11 @@
/obj/structure/machinery/flasher/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
if(prob(75/severity))
flash()
- ..(severity)
/obj/structure/machinery/flasher/portable/HasProximity(atom/movable/AM as mob|obj)
if ((src.disable) || (src.last_flash && world.time < src.last_flash + 150))
@@ -134,7 +135,7 @@
active = 1
icon_state = "launcheract"
- for(var/obj/structure/machinery/flasher/M in machines)
+ for(var/obj/structure/machinery/flasher/M in GLOB.machines)
if(M.id == src.id)
INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/flasher, flash))
diff --git a/code/game/machinery/floodlight.dm b/code/game/machinery/floodlight.dm
index 5f6cd02a4bf8..580fea644eec 100644
--- a/code/game/machinery/floodlight.dm
+++ b/code/game/machinery/floodlight.dm
@@ -1,30 +1,28 @@
-//these are probably broken
-
/obj/structure/machinery/floodlight
- name = "Emergency Floodlight"
+ name = "emergency floodlight"
+ desc = "A powerful light usually stationed near landing zones to provide better visibility."
icon = 'icons/obj/structures/machinery/floodlight.dmi'
icon_state = "flood00"
density = TRUE
anchored = TRUE
- var/obj/item/cell/cell = null
- var/use = 0
- var/unlocked = 0
- var/open = 0
light_power = 2
- unslashable = TRUE
- unacidable = TRUE
+ wrenchable = TRUE
+ use_power = USE_POWER_IDLE
+ idle_power_usage = 0
+ active_power_usage = 100
var/on_light_range = 6
+ ///Whether or not the floodlight can be toggled on or off
+ var/toggleable = TRUE
+
+ ///Whether or not the floodlight is turned on, disconnected from whether it has power or is lit
+ var/turned_on = FALSE
+
/obj/structure/machinery/floodlight/Initialize(mapload, ...)
. = ..()
- cell = new /obj/item/cell(src)
- if(light_on)
- set_light(on_light_range)
-/obj/structure/machinery/floodlight/Destroy()
- QDEL_NULL(cell)
- return ..()
+ turn_light(toggle_on = (operable() && turned_on))
/obj/structure/machinery/floodlight/turn_light(mob/user, toggle_on)
. = ..()
@@ -36,100 +34,51 @@
else
set_light(0)
+ update_icon()
-/obj/structure/machinery/floodlight/proc/updateicon()
- icon_state = "flood[open ? "o" : ""][open && cell ? "b" : ""]0[light_on]"
-
-/obj/structure/machinery/floodlight/attack_hand(mob/user as mob)
- if(open && cell)
- if(ishuman(user))
- if(!user.get_active_hand())
- user.put_in_hands(cell)
- cell.forceMove(user.loc)
- else
- cell.forceMove(loc)
+/obj/structure/machinery/floodlight/attack_hand(mob/living/user)
+ if(!toggleable)
+ to_chat(user, SPAN_NOTICE("[src] doesn't seem to have a switch to toggle the light."))
+ return
- cell.add_fingerprint(user)
- cell.update_icon()
+ if(user.is_mob_incapacitated())
+ return
- src.cell = null
- to_chat(user, "You remove the power cell.")
- updateicon()
+ if(!is_valid_user(user))
+ to_chat(user, SPAN_NOTICE("You don't have the dexterity to do this."))
return
- if(light_on)
- to_chat(user, SPAN_NOTICE("You turn off the light."))
- turn_light(user, toggle_on = FALSE)
- unslashable = TRUE
- unacidable = TRUE
- else
- if(!cell)
- return
- if(cell.charge <= 0)
- return
- to_chat(user, SPAN_NOTICE("You turn on the light."))
- turn_light(user, toggle_on = TRUE)
- unacidable = FALSE
+ turned_on = !turned_on
- updateicon()
+ if(inoperable())
+ to_chat(user, SPAN_NOTICE("You turn [turned_on ? "on" : "off"] the floodlight. It seems to be inoperable."))
+ return
+ to_chat(user, SPAN_NOTICE("You turn [turned_on ? "on" : "off"] the light."))
+ turn_light(user, toggle_on = turned_on)
+ update_use_power(turned_on ? USE_POWER_ACTIVE : USE_POWER_IDLE)
-/obj/structure/machinery/floodlight/attackby(obj/item/W as obj, mob/user as mob)
- if(!ishuman(user))
- return
+/obj/structure/machinery/floodlight/update_icon()
+ . = ..()
+ icon_state = "flood0[light_on]"
+
+/obj/structure/machinery/floodlight/power_change(area/master_area = null)
+ . = ..()
- if (HAS_TRAIT(W, TRAIT_TOOL_WRENCH))
- if (!anchored)
- anchored = TRUE
- to_chat(user, "You anchor the [src] in place.")
- else
- anchored = FALSE
- to_chat(user, "You remove the bolts from the [src].")
-
- if (HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER))
- if (!open)
- if(unlocked)
- unlocked = 0
- to_chat(user, "You screw the battery panel in place.")
- else
- unlocked = 1
- to_chat(user, "You unscrew the battery panel.")
-
- if (HAS_TRAIT(W, TRAIT_TOOL_CROWBAR))
- if(unlocked)
- if(open)
- open = 0
- overlays = null
- to_chat(user, "You crowbar the battery panel in place.")
- else
- if(unlocked)
- open = 1
- to_chat(user, "You remove the battery panel.")
-
- if (istype(W, /obj/item/cell))
- if(open)
- if(cell)
- to_chat(user, "There is a power cell already installed.")
- else
- if(user.drop_inv_item_to_loc(W, src))
- cell = W
- to_chat(user, "You insert the power cell.")
- updateicon()
+ turn_light(toggle_on = (!(stat & NOPOWER) && turned_on))
//Magical floodlight that cannot be destroyed or interacted with.
/obj/structure/machinery/floodlight/landing
- name = "Landing Light"
- desc = "A powerful light stationed near landing zones to provide better visibility."
+ name = "landing light"
+ desc = "A powerful light usually stationed near landing zones to provide better visibility. This one seems to have been bolted down and is unable to be moved."
icon_state = "flood01"
- light_on = TRUE
- in_use = 1
use_power = USE_POWER_NONE
-
-/obj/structure/machinery/floodlight/landing/attack_hand()
- return
-
-/obj/structure/machinery/floodlight/landing/attackby()
- return
+ needs_power = FALSE
+ unslashable = TRUE
+ unacidable = TRUE
+ wrenchable = FALSE
+ toggleable = FALSE
+ turned_on = TRUE
/obj/structure/machinery/floodlight/landing/floor
icon_state = "floor_flood01"
diff --git a/code/game/machinery/fusion_engine.dm b/code/game/machinery/fusion_engine.dm
index 4158727e3745..0e5f8142c2be 100644
--- a/code/game/machinery/fusion_engine.dm
+++ b/code/game/machinery/fusion_engine.dm
@@ -15,6 +15,7 @@
unacidable = TRUE //NOPE.jpg
anchored = TRUE
density = TRUE
+ power_machine = TRUE
var/power_gen_percent = 0 //50,000W at full capacity
var/buildstate = 0 //What state of building it are we on, 0-3, 1 is "broken", the default
@@ -24,7 +25,8 @@
var/obj/item/fuelCell/fusion_cell = new //Starts with a fuel cell loaded in. Maybe replace with the plasma tanks in the future and have it consume plasma? Possibly remove this later if it's irrelevent...
var/fuel_rate = 0 //Rate at which fuel is used. Based mostly on how long the generator has been running.
- power_machine = TRUE
+ /// If the generator is overloaded. Only possible during hijack once fuel is at 100%.
+ var/overloaded = FALSE
/obj/structure/machinery/power/fusion_engine/Initialize(mapload, ...)
. = ..()
@@ -35,11 +37,25 @@
/obj/structure/machinery/power/fusion_engine/Destroy()
QDEL_NULL(fusion_cell)
- . = ..()
+ return ..()
+/obj/structure/machinery/power/fusion_engine/attack_alien(mob/living/carbon/xenomorph/xeno)
+ if(!overloaded)
+ to_chat(xeno, SPAN_WARNING("You see no reason to attack [src]."))
+ return XENO_NO_DELAY_ACTION
+
+ xeno.animation_attack_on(src)
+ playsound(src, 'sound/effects/metalhit.ogg', 25, 1)
+ xeno.visible_message(SPAN_DANGER("[xeno] [xeno.slashes_verb] [src], stopping its overload process!"), \
+ SPAN_DANGER("You [xeno.slash_verb] [src], stopping its overload process!"), null, 5, CHAT_TYPE_XENO_COMBAT)
+ set_overloading(FALSE)
+ return XENO_ATTACK_ACTION
/obj/structure/machinery/power/fusion_engine/power_change()
- return
+ . = ..()
+ if(overloaded)
+ set_overloading(FALSE)
+ visible_message("[icon2html(src, viewers(src))] [src]'s overload suddenly ceases as primary power is lost.")
/obj/structure/machinery/power/fusion_engine/process()
if(!is_on || buildstate || !anchored || !powernet || !fusion_cell) //Default logic checking
@@ -60,9 +76,18 @@
stop_processing()
return FALSE
- if(!check_failure())
+ if(overloaded && prob(1)) // up to 18 generators at 1% every 3.5 seconds means that every ~21 seconds or so, one generator will make noise assuming all are overloaded
+ switch(rand(1, 2))
+ if(1)
+ visible_message("[icon2html(src, viewers(src))] [SPAN_NOTICE("[src] loudly hums.")]")
+ playsound(src, 'sound/machines/resource_node/node_idle.ogg', 60, TRUE)
+ if(2)
+ visible_message("[icon2html(src, viewers(src))] [SPAN_NOTICE("[src] makes a worrying hiss.")]")
+ playsound(src, 'sound/machines/hiss.ogg', 60, TRUE)
- if(power_gen_percent < 100) power_gen_percent++
+ if(!check_failure())
+ if(power_gen_percent < 100)
+ power_gen_percent++
switch(power_gen_percent) //Flavor text!
if(10)
@@ -96,6 +121,10 @@
to_chat(user, SPAN_NOTICE("Use a wrench to repair it."))
return FALSE
if(is_on)
+ if(overloaded)
+ to_chat(user, SPAN_WARNING("You can't shut off [src] while it's overloaded!"))
+ return
+
visible_message("[icon2html(src, viewers(src))] [SPAN_WARNING("[src] beeps softly and the humming stops as [usr] shuts off the generator.")]")
is_on = 0
power_gen_percent = 0
@@ -127,13 +156,13 @@
/obj/structure/machinery/power/fusion_engine/attackby(obj/item/O, mob/user)
if(istype(O, /obj/item/fuelCell))
if(is_on)
- to_chat(user, SPAN_WARNING("The [src] needs to be turned off first."))
+ to_chat(user, SPAN_WARNING("[src] needs to be turned off first."))
return TRUE
if(!fusion_cell)
if(user.drop_inv_item_to_loc(O, src))
fusion_cell = O
update_icon()
- to_chat(user, SPAN_NOTICE("You load the [src] with the [O]."))
+ to_chat(user, SPAN_NOTICE("You load [src] with [O]."))
return TRUE
else
to_chat(user, SPAN_WARNING("You need to remove the fuel cell from [src] first."))
@@ -208,11 +237,18 @@
if(buildstate)
to_chat(user, SPAN_WARNING("You must repair the generator before working with its fuel cell."))
return
+
+ if(overloaded)
+ to_chat(user, SPAN_WARNING("You must restore the safeties on the generator before working with its fuel cell."))
+ return
+
if(is_on)
to_chat(user, SPAN_WARNING("You must turn off the generator before working with its fuel cell."))
return
+
if(!fusion_cell)
to_chat(user, SPAN_WARNING("There is no cell to remove."))
+
else
if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
user.visible_message(SPAN_WARNING("[user] fumbles around figuring out [src]'s fuel receptacle."),
@@ -232,23 +268,73 @@
fusion_cell = null
update_icon()
return TRUE
+
+ else if(HAS_TRAIT(O, TRAIT_TOOL_MULTITOOL))
+ if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
+ to_chat(user, SPAN_WARNING("You have no idea what to do with [src]."))
+ return
+
+ if(!overloaded)
+ if(!SShijack.sd_unlocked)
+ to_chat(user, SPAN_WARNING("You consider overloading [src]'s safeties, but you decide against it."))
+ return
+
+ if(inoperable())
+ to_chat(user, SPAN_WARNING("[src] needs to be working and have external power in order to overload it!"))
+ return
+
+ to_chat(user, SPAN_WARNING("You start overloading the safeties on [src]..."))
+ if(!do_after(user, 1.5 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
+ return
+
+ if(inoperable())
+ return
+
+ to_chat(user, SPAN_WARNING("You finish overloading the safeties on [src]."))
+ set_overloading(TRUE)
+ log_game("[key_name(user)] has overloaded a generator.")
+
+ else
+ to_chat(user, SPAN_WARNING("You start restoring the safeties on [src]..."))
+ if(!do_after(user, 1.5 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
+ return
+
+ if(inoperable())
+ return
+
+ to_chat(user, SPAN_WARNING("You finish restoring the safeties on [src]."))
+ log_game("[key_name(user)] has restored the safeties of a generator.")
+ set_overloading(FALSE)
+
+ return TRUE
+
else
return ..()
/obj/structure/machinery/power/fusion_engine/get_examine_text(mob/user)
. = ..()
- if(ishuman(user))
+ if(isxeno(user))
+ if(overloaded)
+ . += SPAN_INFO("You could attack this to stop the overload process.")
+
+ else if(ishuman(user))
if(buildstate)
. += SPAN_INFO("It's broken.")
switch(buildstate)
if(1)
- . += SPAN_INFO("Use a blowtorch, then wirecutters, then wrench to repair it.")
+ . += SPAN_INFO("Use a blowtorch, then wirecutters, then wrench to repair it.")
if(2)
- . += SPAN_INFO("Use a wirecutters, then wrench to repair it.")
+ . += SPAN_INFO("Use a wirecutters, then wrench to repair it.")
if(3)
- . += SPAN_INFO("Use a wrench to repair it.")
+ . += SPAN_INFO("Use a wrench to repair it.")
return FALSE
+ if(SShijack.sd_unlocked && skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
+ if(!overloaded)
+ . += SPAN_INFO("You could overload this with a multitool.")
+ else
+ . += SPAN_INFO("You could restore its safeties with a multitool.")
+
if(!is_on)
. += SPAN_INFO("It looks offline.")
else
@@ -270,22 +356,30 @@
else
. += SPAN_INFO("There is no fuel cell in the receptacle.")
+/obj/structure/machinery/power/fusion_engine/ex_act(severity)
+ if(overloaded && severity >= EXPLOSION_THRESHOLD_MLOW)
+ set_overloading(FALSE)
+ return
+
/obj/structure/machinery/power/fusion_engine/update_icon()
switch(buildstate)
if(0)
if(fusion_cell)
- var/pstatus = is_on ? "on" : "off"
- switch(fusion_cell.get_fuel_percent())
- if(0 to 10)
- icon_state = "[pstatus]-10"
- if(10 to 25)
- icon_state = "[pstatus]-25"
- if(25 to 50)
- icon_state = "[pstatus]-50"
- if(50 to 75)
- icon_state = "[pstatus]-75"
- if(75 to INFINITY)
- icon_state = "[pstatus]-100"
+ if(overloaded)
+ icon_state = "overloaded"
+ else
+ var/pstatus = is_on ? "on" : "off"
+ switch(fusion_cell.get_fuel_percent())
+ if(0 to 10)
+ icon_state = "[pstatus]-10"
+ if(10 to 25)
+ icon_state = "[pstatus]-25"
+ if(25 to 50)
+ icon_state = "[pstatus]-50"
+ if(50 to 75)
+ icon_state = "[pstatus]-75"
+ if(75 to INFINITY)
+ icon_state = "[pstatus]-100"
else
icon_state = "off"
@@ -317,9 +411,13 @@
else
return 0
+/obj/structure/machinery/power/fusion_engine/proc/set_overloading(new_overloading)
+ if(overloaded == new_overloading)
+ return
-
-
+ overloaded = new_overloading
+ SEND_GLOBAL_SIGNAL(COMSIG_GLOB_GENERATOR_SET_OVERLOADING, overloaded)
+ update_icon()
diff --git a/code/game/machinery/groundmap_geothermal.dm b/code/game/machinery/groundmap_geothermal.dm
index 808c717e8891..087facdbf5ee 100644
--- a/code/game/machinery/groundmap_geothermal.dm
+++ b/code/game/machinery/groundmap_geothermal.dm
@@ -223,7 +223,7 @@
/obj/structure/machinery/colony_floodlight_switch/LateInitialize()
. = ..()
- for(var/obj/structure/machinery/colony_floodlight/F in machines)
+ for(var/obj/structure/machinery/colony_floodlight/F in GLOB.machines)
floodlist += F
F.fswitch = src
start_processing()
diff --git a/code/game/machinery/hologram.dm b/code/game/machinery/hologram.dm
index 2f8f113ddd23..9ce3cb89bf79 100644
--- a/code/game/machinery/hologram.dm
+++ b/code/game/machinery/hologram.dm
@@ -59,12 +59,6 @@ Possible to do for anyone motivated enough:
Itegrate EMP effect to disable the unit.
*/
-
-// HOLOPAD MODE
-// 0 = RANGE BASED
-// 1 = AREA BASED
-var/const/HOLOPAD_MODE = 0
-
/obj/structure/machinery/hologram/holopad
name = "\improper AI holopad"
desc = "It's a floor-mounted device for projecting holographic images. It is activated remotely."
@@ -167,17 +161,9 @@ For the other part of the code, check silicon say.dm. Particularly robot talk.*/
if(hologram)//If there is a hologram.
if(master && !master.stat && master.client && master.eyeobj)//If there is an AI attached, it's not incapacitated, it has a client, and the client eye is centered on the projector.
if(!(stat & NOPOWER))//If the machine has power.
- if((HOLOPAD_MODE == 0 && (get_dist(master.eyeobj, src) <= holo_range)))
+ if(get_dist(master.eyeobj, src) <= holo_range)
return 1
- else if (HOLOPAD_MODE == 1)
-
- var/area/holo_area = get_area(src)
- var/area/eye_area = get_area(master.eyeobj)
-
- if(eye_area == holo_area)
- return 1
-
clear_holo()//If not, we want to get rid of the hologram.
return 1
diff --git a/code/game/machinery/holosign.dm b/code/game/machinery/holosign.dm
index 2d4182772cf3..41c63d465918 100644
--- a/code/game/machinery/holosign.dm
+++ b/code/game/machinery/holosign.dm
@@ -63,7 +63,7 @@
else
icon_state = "light0"
- for(var/obj/structure/machinery/holosign/M in machines)
+ for(var/obj/structure/machinery/holosign/M in GLOB.machines)
if (M.id == src.id)
INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/holosign, toggle))
diff --git a/code/game/machinery/igniter.dm b/code/game/machinery/igniter.dm
index 33f75c50e341..6109833004d6 100644
--- a/code/game/machinery/igniter.dm
+++ b/code/game/machinery/igniter.dm
@@ -105,11 +105,10 @@
return 1
/obj/structure/machinery/sparker/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
ignite()
- ..(severity)
/obj/structure/machinery/ignition_switch/attack_remote(mob/user as mob)
return attack_hand(user)
@@ -125,11 +124,11 @@
active = 1
icon_state = "launcheract"
- for(var/obj/structure/machinery/sparker/M in machines)
+ for(var/obj/structure/machinery/sparker/M in GLOB.machines)
if (M.id == src.id)
INVOKE_ASYNC(M, TYPE_PROC_REF(/obj/structure/machinery/sparker, ignite))
- for(var/obj/structure/machinery/igniter/M in machines)
+ for(var/obj/structure/machinery/igniter/M in GLOB.machines)
if(M.id == src.id)
use_power(50)
M.on = !( M.on )
diff --git a/code/game/machinery/iv_drip.dm b/code/game/machinery/iv_drip.dm
index ef6c74a052cd..e16d2cacf63b 100644
--- a/code/game/machinery/iv_drip.dm
+++ b/code/game/machinery/iv_drip.dm
@@ -57,7 +57,7 @@
if(ishuman(usr))
var/mob/living/carbon/human/user = usr
- if(user.stat || get_dist(user, src) > 1 || user.blinded || user.lying)
+ if(user.is_mob_incapacitated() || get_dist(user, src) > 1 || user.blinded)
return
if(!skillcheck(user, SKILL_SURGERY, SKILL_SURGERY_NOVICE))
@@ -101,7 +101,7 @@
for(var/datum/reagent/chem in beaker.reagents.reagent_list)
reagentnames += ";[chem.name]"
- log_admin("[key_name(user)] put a [beaker] into [src], containing [reagentnames] at ([src.loc.x],[src.loc.y],[src.loc.z]).")
+ log_admin("[key_name(user)] put \a [beaker] into [src], containing [reagentnames] at ([src.loc.x],[src.loc.y],[src.loc.z]).")
to_chat(user, "You attach \the [container] to \the [src].")
update_beam()
@@ -179,7 +179,7 @@
if(!istype(usr, /mob/living))
return
- if(usr.stat || usr.lying)
+ if(usr.stat || usr.is_mob_incapacitated())
return
mode = !mode
diff --git a/code/game/machinery/kitchen/gibber.dm b/code/game/machinery/kitchen/gibber.dm
index 08a3d5c4dfee..3fa96ca0bc3a 100644
--- a/code/game/machinery/kitchen/gibber.dm
+++ b/code/game/machinery/kitchen/gibber.dm
@@ -27,7 +27,7 @@
/obj/structure/machinery/gibber/autogibber/New()
..()
spawn(5)
- for(var/i in cardinal)
+ for(var/i in GLOB.cardinals)
var/obj/structure/machinery/mineral/input/input_obj = locate( /obj/structure/machinery/mineral/input, get_step(loc, i) )
if(input_obj)
if(isturf(input_obj.loc))
diff --git a/code/game/machinery/kitchen/microwave.dm b/code/game/machinery/kitchen/microwave.dm
index f4611b9042db..220772e98b17 100644
--- a/code/game/machinery/kitchen/microwave.dm
+++ b/code/game/machinery/kitchen/microwave.dm
@@ -139,7 +139,6 @@
if (!(R.id in acceptable_reagents))
to_chat(user, SPAN_DANGER("Your [O] contains components unsuitable for cookery."))
return 1
- //G.reagents.trans_to(src,G.amount_per_transfer_from_this)
else if(istype(O,/obj/item/grab))
return 1
else
@@ -152,74 +151,78 @@
/obj/structure/machinery/microwave/attack_hand(mob/user as mob)
user.set_interaction(src)
- interact(user)
+ tgui_interact(user)
+
+/obj/structure/machinery/microwave/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if (!ui)
+ ui = new(user, src, "Microwave", "Microwave Controls")
+ ui.open()
//*******************
//* Microwave Menu
//********************/
-
-/obj/structure/machinery/microwave/interact(mob/user as mob) // The microwave Menu
- var/dat = ""
- if(src.broken > 0)
- dat = {"Bzzzzttttt"}
- else if(src.operating)
- dat = {"Microwaving in progress! Please wait...!"}
- else if(src.dirty==100)
- dat = {"This microwave is dirty! Please clean it before use!"}
- else
- var/list/items_counts = new
- var/list/items_measures = new
- var/list/items_measures_p = new
- for (var/obj/O in contents)
- var/display_name = O.name
- if (istype(O,/obj/item/reagent_container/food/snacks/egg))
- items_measures[display_name] = "egg"
- items_measures_p[display_name] = "eggs"
- if (istype(O,/obj/item/reagent_container/food/snacks/tofu))
- items_measures[display_name] = "tofu chunk"
- items_measures_p[display_name] = "tofu chunks"
- if (istype(O,/obj/item/reagent_container/food/snacks/meat)) //any meat
- items_measures[display_name] = "slab of meat"
- items_measures_p[display_name] = "slabs of meat"
- if (istype(O,/obj/item/reagent_container/food/snacks/donkpocket))
- display_name = "Turnovers"
- items_measures[display_name] = "turnover"
- items_measures_p[display_name] = "turnovers"
- if (istype(O,/obj/item/reagent_container/food/snacks/carpmeat))
- items_measures[display_name] = "fillet of meat"
- items_measures_p[display_name] = "fillets of meat"
- items_counts[display_name]++
- for (var/O in items_counts)
- var/N = items_counts[O]
- if (!(O in items_measures))
- dat += {"[capitalize(O)]: [N] [lowertext(O)]\s "}
- else
- if (N==1)
- dat += {"[capitalize(O)]: [N] [items_measures[O]] "}
- else
- dat += {"[capitalize(O)]: [N] [items_measures_p[O]] "}
-
- for (var/datum/reagent/R in reagents.reagent_list)
- var/display_name = R.name
- if (R.id == "hotsauce")
- display_name = "Hotsauce"
- if (R.id == "frostoil")
- display_name = "Coldsauce"
- dat += {"[display_name]: [R.volume] unit\s "}
-
- if (items_counts.len==0 && reagents.reagent_list.len==0)
- dat = {"The microwave is empty "}
+/obj/structure/machinery/microwave/ui_data(mob/user)
+ var/list/data = list()
+
+ data["operating"] = operating
+ data["broken"] = (broken > 0)
+ data["dirty"] = (dirty == 100)
+
+ var/list/ingredients = list()
+ var/list/items_counts = list()
+ var/list/items_measures = list()
+ var/list/items_measures_p = list()
+
+ for (var/obj/contents_item as anything in contents)
+ var/display_name = contents_item.name
+
+ if (istype(contents_item, /obj/item/reagent_container/food/snacks/tofu))
+ items_measures[display_name] = "tofu chunk"
+ items_measures_p[display_name] = "tofu chunks"
+ if (istype(contents_item, /obj/item/reagent_container/food/snacks/meat)) //any meat
+ items_measures[display_name] = "slab of meat"
+ items_measures_p[display_name] = "slabs of meat"
+ if (istype(contents_item, /obj/item/reagent_container/food/snacks/donkpocket))
+ display_name = "Turnovers"
+ items_measures[display_name] = "turnover"
+ items_measures_p[display_name] = "turnovers"
+ if (istype(contents_item, /obj/item/reagent_container/food/snacks/carpmeat))
+ items_measures[display_name] = "fillet of meat"
+ items_measures_p[display_name] = "fillets of meat"
+ items_counts[display_name]++
+
+ for (var/contents_item in items_counts)
+ var/list/item = list()
+
+ item["name"] = capitalize(contents_item)
+ item["count"] = items_counts[contents_item]
+
+ if (!(contents_item in items_measures))
+ item["measure"] = "[lowertext(contents_item)][items_counts[contents_item] > 1 ? "s" : ""]" // Adds 's' for plurals.
+ else if (items_counts[contents_item] == 1)
+ item["measure"] = items_measures[contents_item]
else
- dat = {"Ingredients: [dat]"}
- dat += {" \
-Turn on! \
-Eject ingredients! \
-"}
+ item["measure"] = items_measures_p[contents_item]
+
+ ingredients += list(item)
+
+ for (var/datum/reagent/contents_reagent as anything in reagents.reagent_list)
+ var/list/reagent = list()
- show_browser(user, dat, "Microwave Controls", "microwave")
- return
+ reagent["count"] = contents_reagent.volume
+ reagent["measure"] = contents_reagent.volume > 1 ? "units" : "unit"
+ reagent["name"] = contents_reagent.name
+ if (contents_reagent.id == "hotsauce")
+ reagent["name"] = "Hotsauce"
+ if (contents_reagent.id == "frostoil")
+ reagent["name"] = "Coldsauce"
+ ingredients += list(reagent)
+
+ data["ingredients"] = ingredients
+ return data
//***********************************
//* Microwave Menu Handling/Cooking
@@ -322,7 +325,7 @@
if (src.reagents.total_volume)
src.dirty++
src.reagents.clear_reagents()
- to_chat(usr, SPAN_NOTICE(" You dispose of the microwave contents."))
+ to_chat(usr, SPAN_NOTICE("You dispose of the microwave contents."))
src.updateUsrDialog()
/obj/structure/machinery/microwave/proc/muck_start()
@@ -365,19 +368,16 @@
ffuu.reagents.add_reagent("toxin", amount/10)
return ffuu
-/obj/structure/machinery/microwave/Topic(href, href_list)
- if(..())
- return
-
- usr.set_interaction(src)
- if(src.operating)
- src.updateUsrDialog()
+/obj/structure/machinery/microwave/ui_act(action, params)
+ . = ..()
+ if(.)
return
- switch(href_list["action"])
+ switch (action)
if ("cook")
cook(usr.get_skill_duration_multiplier(SKILL_DOMESTIC)) // picking the right microwave setting for the right food. when's the last time you used the special setting on the microwave? i bet you just slam the 30 second increment. Do you know how much programming went into putting the Pizza setting into a microwave emitter?
- if ("dispose")
+ if ("eject_all")
dispose()
- return
+
+ return TRUE
diff --git a/code/game/machinery/kitchen/processor.dm b/code/game/machinery/kitchen/processor.dm
index 0c4b8a973e83..a18f5db8af43 100644
--- a/code/game/machinery/kitchen/processor.dm
+++ b/code/game/machinery/kitchen/processor.dm
@@ -89,7 +89,7 @@
to_chat(user, SPAN_DANGER("That probably won't blend."))
return 1
user.visible_message("[user] put [what] into [src].", \
- "You put the [what] into [src].")
+ "You put [what] into [src].")
user.drop_held_item()
what.forceMove(src)
@@ -118,4 +118,3 @@
src.processing = 0
src.visible_message(SPAN_NOTICE("\the [src] finished processing."), \
"You hear the food processor stopping/")
-
diff --git a/code/game/machinery/kitchen/smartfridge.dm b/code/game/machinery/kitchen/smartfridge.dm
index f52350aa8db3..6d3e18933457 100644
--- a/code/game/machinery/kitchen/smartfridge.dm
+++ b/code/game/machinery/kitchen/smartfridge.dm
@@ -23,7 +23,7 @@
var/icon_on = "smartfridge"
var/icon_off = "smartfridge-off"
var/icon_panel = "smartfridge-panel"
- var/item_quants = list()
+ var/list/item_quants = list() //! Assoc list of names -> list(items)
var/ispowered = TRUE //starts powered
var/is_secure_fridge = FALSE
var/shoot_inventory = FALSE
@@ -40,6 +40,24 @@
GLOB.vending_products[/obj/item/reagent_container/glass/bottle] = 1
GLOB.vending_products[/obj/item/storage/pill_bottle] = 1
+/obj/structure/machinery/smartfridge/Destroy(force)
+ if(is_in_network()) // Delete all contents from networked storage index
+ for(var/atom/movable/item as anything in contents)
+ delete_contents(item)
+ item_quants.Cut()
+ return ..() // parent will delete contents if we're not networked
+
+/// Deletes given object in contents of the smartfridge
+/obj/structure/machinery/smartfridge/proc/delete_contents(obj/item/item)
+ if(item.loc != src)
+ return
+ contents -= item
+ if(item_quants[item.name])
+ item_quants[item.name] -= item
+ if(is_in_network() && GLOB.chemical_data.shared_item_storage[item.name])
+ GLOB.chemical_data.shared_item_storage[item.name] -= item
+ qdel(item)
+
/obj/structure/machinery/smartfridge/proc/accept_check(obj/item/O as obj)
if(istype(O,/obj/item/reagent_container/food/snacks/grown/) || istype(O,/obj/item/seeds/))
return 1
@@ -76,7 +94,7 @@
overlays.Cut()
if(panel_open)
overlays += image(icon, icon_panel)
- nanomanager.update_uis(src)
+ SSnano.nanomanager.update_uis(src)
return
if(HAS_TRAIT(O, TRAIT_TOOL_MULTITOOL)||HAS_TRAIT(O, TRAIT_TOOL_WIRECUTTERS))
@@ -139,7 +157,7 @@
/obj/structure/machinery/smartfridge/proc/add_network_item(obj/item/O)
if(is_in_network())
- add_item(chemical_data.shared_item_storage, O)
+ add_item(GLOB.chemical_data.shared_item_storage, O)
return TRUE
return FALSE
@@ -214,9 +232,9 @@
var/list/networked_items = list()
if(is_in_network())
- for (var/i=1 to length(chemical_data.shared_item_storage))
- var/item_index = chemical_data.shared_item_storage[i]
- var/list/item_list = chemical_data.shared_item_storage[item_index]
+ for (var/i=1 to length(GLOB.chemical_data.shared_item_storage))
+ var/item_index = GLOB.chemical_data.shared_item_storage[i]
+ var/list/item_list = GLOB.chemical_data.shared_item_storage[item_index]
var/count = length(item_list)
if(count < 1)
continue
@@ -277,7 +295,7 @@
var/list/target_list = item_quants
if(params["isLocal"] == 0)
- target_list = chemical_data.shared_item_storage
+ target_list = GLOB.chemical_data.shared_item_storage
var/item_index = target_list[index]
var/list/item_list = target_list[item_index]
@@ -310,9 +328,9 @@
var/amount=params["amount"]
var/source = item_quants
- var/target = chemical_data.shared_item_storage
+ var/target = GLOB.chemical_data.shared_item_storage
if(params["isLocal"] == 0)
- source = chemical_data.shared_item_storage
+ source = GLOB.chemical_data.shared_item_storage
target = item_quants
var/item_index = source[index]
diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm
index 66eb0386713f..de61830c2501 100644
--- a/code/game/machinery/lightswitch.dm
+++ b/code/game/machinery/lightswitch.dm
@@ -62,8 +62,7 @@
updateicon()
/obj/structure/machinery/light_switch/emp_act(severity)
+ . = ..()
if(inoperable())
- ..(severity)
return
power_change()
- ..(severity)
diff --git a/code/game/machinery/line_nexter.dm b/code/game/machinery/line_nexter.dm
index d736df44664a..ae1896ad8138 100644
--- a/code/game/machinery/line_nexter.dm
+++ b/code/game/machinery/line_nexter.dm
@@ -62,7 +62,7 @@
icon_state = "doorctrl1"
add_fingerprint(user)
- for(var/obj/structure/machinery/line_nexter/L in machines)
+ for(var/obj/structure/machinery/line_nexter/L in GLOB.machines)
if(id == L.id)
L.next()
diff --git a/code/game/machinery/machinery.dm b/code/game/machinery/machinery.dm
index f4ad7a63ba77..c5eaa14e05b5 100644
--- a/code/game/machinery/machinery.dm
+++ b/code/game/machinery/machinery.dm
@@ -105,7 +105,7 @@ Class Procs:
var/list/component_parts //list of all the parts used to build it, if made from certain kinds of frames.
var/manual = 0
layer = OBJ_LAYER
- var/machine_processing = 0 // whether the machine is busy and requires process() calls in scheduler.
+ var/machine_processing = 0 // whether the machine is busy and requires process() calls in scheduler. // Please replace this by DF_ISPROCESSING in another refactor --fira
throwpass = 1
projectile_coverage = PROJECTILE_COVERAGE_MEDIUM
var/power_machine = FALSE //Whether the machine should process on power, or normal processor
@@ -128,15 +128,15 @@ Class Procs:
/obj/structure/machinery/Initialize(mapload, ...)
. = ..()
- machines += src
+ GLOB.machines += src
var/area/A = get_area(src)
if(A)
A.add_machine(src) //takes care of adding machine's power usage
/obj/structure/machinery/Destroy()
- machines -= src
- processing_machines -= src
- power_machines -= src
+ GLOB.machines -= src
+ GLOB.processing_machines -= src
+ GLOB.power_machines -= src
var/area/A = get_area(src)
if(A)
A.remove_machine(src) //takes care of removing machine from power usage
@@ -151,15 +151,15 @@ Class Procs:
if(!machine_processing)
machine_processing = 1
if(power_machine)
- addToListNoDupe(power_machines, src)
+ addToListNoDupe(GLOB.power_machines, src)
else
- addToListNoDupe(processing_machines, src)
+ addToListNoDupe(GLOB.processing_machines, src)
/obj/structure/machinery/proc/stop_processing()
if(machine_processing)
machine_processing = 0
- processing_machines -= src
- power_machines -= src
+ GLOB.processing_machines -= src
+ GLOB.power_machines -= src
/obj/structure/machinery/process()//If you dont use process or power why are you here
return PROCESS_KILL
@@ -175,10 +175,10 @@ Class Procs:
. += SPAN_WARNING("[msg]")
/obj/structure/machinery/emp_act(severity)
+ . = ..()
if(use_power && stat == 0)
use_power(7500/severity)
new /obj/effect/overlay/temp/emp_sparks (loc)
- ..()
/obj/structure/machinery/ex_act(severity)
@@ -229,7 +229,11 @@ Class Procs:
return TRUE
if(inoperable())
return 1
- if(usr.is_mob_restrained() || usr.lying || usr.stat)
+ if(isliving(usr))
+ var/mob/living/living = usr
+ if(living.body_position == LYING_DOWN) // legacy. if you too find it doesn't make sense, consider removing it
+ return TRUE
+ if(usr.is_mob_restrained())
return 1
if(!is_valid_user(usr))
to_chat(usr, SPAN_DANGER("You don't have the dexterity to do this!"))
@@ -251,10 +255,10 @@ Class Procs:
else
return src.attack_hand(user)
-/obj/structure/machinery/attack_hand(mob/user as mob)
+/obj/structure/machinery/attack_hand(mob/living/user as mob)
if(inoperable(MAINT))
return TRUE
- if(user.lying || user.stat)
+ if(user.is_mob_incapacitated())
return TRUE
if(!is_valid_user(user))
to_chat(usr, SPAN_DANGER("You don't have the dexterity to do this!"))
diff --git a/code/game/machinery/magnet.dm b/code/game/machinery/magnet.dm
deleted file mode 100644
index 591cec1f5baa..000000000000
--- a/code/game/machinery/magnet.dm
+++ /dev/null
@@ -1,421 +0,0 @@
-// Magnetic attractor, creates variable magnetic fields and attraction.
-// Can also be used to emit electron/proton beams to create a center of magnetism on another tile
-
-// tl;dr: it's magnets lol
-// This was created for firing ranges, but I suppose this could have other applications - Doohl
-
-/obj/structure/machinery/magnetic_module
-
- icon = 'icons/obj/objects.dmi'
- icon_state = "floor_magnet-f"
- name = "Electromagnetic Generator"
- desc = "A device that uses station power to create points of magnetic energy."
- level = 1 // underfloor
- layer = UNDERFLOOR_OBJ_LAYER
- anchored = TRUE
- use_power = USE_POWER_IDLE
- idle_power_usage = 50
-
- var/freq = 1449 // radio frequency
- var/electricity_level = 1 // intensity of the magnetic pull
- var/magnetic_field = 1 // the range of magnetic attraction
- var/code = 0 // frequency code, they should be different unless you have a group of magnets working together or something
- var/turf/center // the center of magnetic attraction
- var/on = 0
- var/pulling = 0
-
- // x, y modifiers to the center turf; (0, 0) is centered on the magnet, whereas (1, -1) is one tile right, one tile down
- var/center_x = 0
- var/center_y = 0
- var/max_dist = 20 // absolute value of center_x,y cannot exceed this integer
-
-/obj/structure/machinery/magnetic_module/Initialize(mapload, ...)
- . = ..()
-
- var/turf/T = loc
- hide(T.intact_tile)
- center = T
-
- SSradio.add_object(src, freq, RADIO_MAGNETS)
-
- INVOKE_ASYNC(src, PROC_REF(magnetic_process))
-
-/obj/structure/machinery/magnetic_module/Destroy()
- center = null
- SSradio.remove_object(src, freq)
- . = ..()
-
-
- // update the invisibility and icon
-/obj/structure/machinery/magnetic_module/hide(intact)
- invisibility = intact ? 101 : 0
- updateicon()
-
- // update the icon_state
-/obj/structure/machinery/magnetic_module/proc/updateicon()
- var/state="floor_magnet"
- var/onstate=""
- if(!on)
- onstate="0"
-
- if(invisibility)
- icon_state = "[state][onstate]-f" // if invisible, set icon to faded version
- // in case of being revealed by T-scanner
- else
- icon_state = "[state][onstate]"
-
-/obj/structure/machinery/magnetic_module/receive_signal(datum/signal/signal)
-
- var/command = signal.data["command"]
- var/modifier = signal.data["modifier"]
- var/signal_code = signal.data["code"]
- if(command && (signal_code == code))
-
- Cmd(command, modifier)
-
-
-
-/obj/structure/machinery/magnetic_module/proc/Cmd(command, modifier)
-
- if(command)
- switch(command)
- if("set-electriclevel")
- if(modifier) electricity_level = modifier
- if("set-magneticfield")
- if(modifier) magnetic_field = modifier
-
- if("add-elec")
- electricity_level++
- if(electricity_level > 12)
- electricity_level = 12
- if("sub-elec")
- electricity_level--
- if(electricity_level <= 0)
- electricity_level = 1
- if("add-mag")
- magnetic_field++
- if(magnetic_field > 4)
- magnetic_field = 4
- if("sub-mag")
- magnetic_field--
- if(magnetic_field <= 0)
- magnetic_field = 1
-
- if("set-x")
- if(modifier) center_x = modifier
- if("set-y")
- if(modifier) center_y = modifier
-
- if("N") // NORTH
- center_y++
- if("S") // SOUTH
- center_y--
- if("E") // EAST
- center_x++
- if("W") // WEST
- center_x--
- if("C") // CENTER
- center_x = 0
- center_y = 0
- if("R") // RANDOM
- center_x = rand(-max_dist, max_dist)
- center_y = rand(-max_dist, max_dist)
-
- if("set-code")
- if(modifier) code = modifier
- if("toggle-power")
- on = !on
-
- if(on)
- INVOKE_ASYNC(src, PROC_REF(magnetic_process))
-
-
-/obj/structure/machinery/magnetic_module/process()
- if(stat & NOPOWER)
- on = 0
-
- // Sanity checks:
- if(electricity_level <= 0)
- electricity_level = 1
- if(magnetic_field <= 0)
- magnetic_field = 1
-
-
- // Limitations:
- if(abs(center_x) > max_dist)
- center_x = max_dist
- if(abs(center_y) > max_dist)
- center_y = max_dist
- if(magnetic_field > 4)
- magnetic_field = 4
- if(electricity_level > 12)
- electricity_level = 12
-
- // Update power usage:
- if(on)
- use_power = USE_POWER_ACTIVE
- active_power_usage = electricity_level*15
- else
- use_power = USE_POWER_NONE
-
-
- // Overload conditions:
- /* // Eeeehhh kinda stupid
- if(on)
- if(electricity_level > 11)
- if(prob(electricity_level))
- explosion(loc, 0, 1, 2, 3) // ooo dat shit EXPLODES son
- spawn(2)
- qdel(src)
- */
-
- updateicon()
-
-
-/obj/structure/machinery/magnetic_module/proc/magnetic_process() // proc that actually does the pulling
- if(pulling) return
- while(on)
-
- pulling = 1
- center = locate(x+center_x, y+center_y, z)
- if(center)
- for(var/obj/M in orange(magnetic_field, center))
- if(!M.anchored && (M.flags_atom & CONDUCT))
- step_towards(M, center)
-
- for(var/mob/living/silicon/S in orange(magnetic_field, center))
- if(isAI(S)) continue
- step_towards(S, center)
-
- use_power(electricity_level * 5)
- sleep(13 - electricity_level)
-
- pulling = 0
-
-/obj/structure/machinery/magnetic_controller
- name = "Magnetic Control Console"
- icon = 'icons/obj/structures/machinery/airlock_machines.dmi' // uses an airlock machine icon, THINK GREEN HELP THE ENVIRONMENT - RECYCLING!
- icon_state = "airlock_control_standby"
- density = TRUE
- anchored = TRUE
- use_power = USE_POWER_IDLE
- idle_power_usage = 45
- var/frequency = 1449
- var/code = 0
- var/list/magnets = list()
- var/title = "Magnetic Control Console"
- var/autolink = 0 // if set to 1, can't probe for other magnets!
-
- var/pathpos = 1 // position in the path
- var/path = "NULL" // text path of the magnet
- var/speed = 1 // lowest = 1, highest = 10
- var/list/rpath = list() // real path of the magnet, used in iterator
-
- var/moving = 0 // 1 if scheduled to loop
- var/looping = 0 // 1 if looping
-
- var/datum/radio_frequency/radio_connection
-
-/obj/structure/machinery/magnetic_controller/Initialize(mapload, ...)
- . = ..()
- if(autolink)
- for(var/obj/structure/machinery/magnetic_module/M in machines)
- if(M.freq == frequency && M.code == code)
- magnets.Add(M)
-
- SSradio.add_object(src, frequency, RADIO_MAGNETS)
-
- if(path) // check for default path
- filter_path() // renders rpath
-
-/obj/structure/machinery/magnetic_controller/Destroy()
- QDEL_NULL_LIST(magnets)
- SSradio.remove_object(src, frequency)
- . = ..()
-
-
-/obj/structure/machinery/magnetic_controller/process()
- if(magnets.len == 0 && autolink)
- for(var/obj/structure/machinery/magnetic_module/M in machines)
- if(M.freq == frequency && M.code == code)
- magnets.Add(M)
-
-/obj/structure/machinery/magnetic_controller/attack_remote(mob/user as mob)
- return src.attack_hand(user)
-
-/obj/structure/machinery/magnetic_controller/attack_hand(mob/user as mob)
- if(inoperable())
- return
- user.set_interaction(src)
- var/dat = "Magnetic Control Console
"
- if(!autolink)
- dat += {"
- Frequency: [frequency]
- Code: [code]
- Probe Generators
- "}
-
- if(magnets.len >= 1)
-
- dat += "Magnets confirmed: "
- var/i = 0
- for(var/obj/structure/machinery/magnetic_module/M in magnets)
- i++
- dat += " < \[[i]\] ([M.on ? "On":"Off"])|Electricity level: - [M.electricity_level] +; Magnetic field: - [M.magnetic_field] + "
-
- dat += " Speed: - [speed] + "
- dat += "Path: {[path]} "
- dat += "Moving: [moving ? "Enabled":"Disabled"]"
-
-
- show_browser(user, dat, name, "magnet", "size=400x500")
-
-/obj/structure/machinery/magnetic_controller/Topic(href, href_list)
- . = ..()
- if(.)
- return
- if(inoperable())
- return
- usr.set_interaction(src)
- src.add_fingerprint(usr)
-
- if(href_list["radio-op"])
-
- // Prepare signal beforehand, because this is a radio operation
- var/datum/signal/signal = new
- signal.transmission_method = 1 // radio transmission
- signal.source = src
- signal.frequency = frequency
- signal.data["code"] = code
-
- // Apply any necessary commands
- switch(href_list["radio-op"])
- if("togglepower")
- signal.data["command"] = "toggle-power"
-
- if("minuselec")
- signal.data["command"] = "sub-elec"
- if("pluselec")
- signal.data["command"] = "add-elec"
-
- if("minusmag")
- signal.data["command"] = "sub-mag"
- if("plusmag")
- signal.data["command"] = "add-mag"
-
-
- // Broadcast the signal
-
- radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS)
-
- addtimer(CALLBACK(src, PROC_REF(updateUsrDialog)), 1)
-
- if(href_list["operation"])
- switch(href_list["operation"])
- if("plusspeed")
- speed ++
- if(speed > 10)
- speed = 10
- if("minusspeed")
- speed --
- if(speed <= 0)
- speed = 1
- if("setpath")
- var/newpath = copytext(sanitize(input(usr, "Please define a new path!",,path) as text|null),1,MAX_MESSAGE_LEN)
- if(newpath && newpath != "")
- moving = 0 // stop moving
- path = newpath
- pathpos = 1 // reset position
- filter_path() // renders rpath
-
- if("togglemoving")
- moving = !moving
- if(moving)
- INVOKE_ASYNC(src, PROC_REF(MagnetMove))
-
-
- updateUsrDialog()
-
-/obj/structure/machinery/magnetic_controller/proc/MagnetMove()
- if(looping) return
-
- while(moving && rpath.len >= 1)
-
- if(inoperable())
- break
-
- looping = 1
-
- // Prepare the radio signal
- var/datum/signal/signal = new
- signal.transmission_method = 1 // radio transmission
- signal.source = src
- signal.frequency = frequency
- signal.data["code"] = code
-
- if(pathpos > rpath.len) // if the position is greater than the length, we just loop through the list!
- pathpos = 1
-
- var/nextmove = uppertext(rpath[pathpos]) // makes it un-case-sensitive
-
- if(!(nextmove in list("N","S","E","W","C","R")))
- // N, S, E, W are directional
- // C is center
- // R is random (in magnetic field's bounds)
- qdel(signal)
- break // break the loop if the character located is invalid
-
- signal.data["command"] = nextmove
-
-
- pathpos++ // increase iterator
-
- // Broadcast the signal
- spawn()
- radio_connection.post_signal(src, signal, filter = RADIO_MAGNETS)
-
- if(speed == 10)
- sleep(1)
- else
- sleep(12-speed)
-
- looping = 0
-
-
-/obj/structure/machinery/magnetic_controller/proc/filter_path()
- // Generates the rpath variable using the path string, think of this as "string2list"
- // Doesn't use params2list() because of the akward way it stacks entities
- rpath = list() // clear rpath
- var/maximum_character = min( 50, length(path) ) // chooses the maximum length of the iterator. 50 max length
-
- for(var/i=1, i<=maximum_character, i++) // iterates through all characters in path
-
- var/nextchar = copytext(path, i, i+1) // find next character
-
- if(!(nextchar in list(";", "&", "*", " "))) // if char is a separator, ignore
- rpath += copytext(path, i, i+1) // else, add to list
-
- // there doesn't HAVE to be separators but it makes paths syntatically visible
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/code/game/machinery/mass_driver.dm b/code/game/machinery/mass_driver.dm
index d1e2fecce20f..f1b0081e3a39 100644
--- a/code/game/machinery/mass_driver.dm
+++ b/code/game/machinery/mass_driver.dm
@@ -1,5 +1,4 @@
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-
+// Legacy SS13 machinery turned into a prop
/obj/structure/machinery/mass_driver
name = "mass driver"
desc = "Shoots things into space."
@@ -9,32 +8,3 @@
use_power = USE_POWER_IDLE
idle_power_usage = 2
active_power_usage = 50
-
- var/power = 1
- var/code = 1
- var/id = 1
- var/drive_range = 50 //this is mostly irrelevant since current mass drivers throw into space, but you could make a lower-range mass driver for interstation transport or something I guess.
-
-
-/obj/structure/machinery/mass_driver/proc/drive(amount)
- if(inoperable())
- return
- use_power(500)
- var/O_limit
- var/atom/target = get_edge_target_turf(src, dir)
- for(var/atom/movable/O in loc)
- if(!O.anchored)
- if(O_limit >= 20)
- for(var/mob/M in hearers(src, null))
- to_chat(M, SPAN_NOTICE(" The mass driver lets out a screech, it mustn't be able to handle any more items."))
- break
- use_power(500)
- INVOKE_ASYNC(O, TYPE_PROC_REF(/atom/movable, throw_atom), target, drive_range * power, 100/power)
- flick("mass_driver1", src)
- return
-
-/obj/structure/machinery/mass_driver/emp_act(severity)
- if(inoperable())
- return
- drive()
- ..(severity)
diff --git a/code/game/machinery/medical_pod/bodyscanner.dm b/code/game/machinery/medical_pod/bodyscanner.dm
index 4756121e50ae..732ff1ba97b9 100644
--- a/code/game/machinery/medical_pod/bodyscanner.dm
+++ b/code/game/machinery/medical_pod/bodyscanner.dm
@@ -62,8 +62,6 @@
if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY)
deconstruct(FALSE)
return
- else
- return
#ifdef OBJECTS_PROXY_SPEECH
// Transfers speech to occupant
@@ -124,8 +122,6 @@
if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY)
deconstruct(FALSE)
return
- else
- return
/obj/structure/machinery/body_scanconsole/power_change()
..()
@@ -208,7 +204,7 @@
"toxloss" = H.getToxLoss(),
"cloneloss" = H.getCloneLoss(),
"brainloss" = H.getBrainLoss(),
- "knocked_out" = H.knocked_out,
+ "knocked_out" = H.GetKnockOutDuration(),
"bodytemp" = H.bodytemperature,
"inaprovaline_amount" = H.reagents.get_reagent_amount("inaprovaline"),
"dexalin_amount" = H.reagents.get_reagent_amount("dexalin"),
@@ -267,7 +263,7 @@
s_class = occ["brainloss"] < 1 ? INTERFACE_GOOD : INTERFACE_BAD
dat += "[SET_CLASS("  Approx. Brain Damage:", INTERFACE_PINK)] [SET_CLASS("[occ["brainloss"]]%", s_class)]
"
- dat += "[SET_CLASS("Knocked Out Summary:", "#40628a")] [occ["knocked_out"]]% ([round(occ["knocked_out"] / 4)] seconds left!) "
+ dat += "[SET_CLASS("Knocked Out Summary:", "#40628a")] [occ["knocked_out"]]% (approximately [round(occ["knocked_out"] * GLOBAL_STATUS_MULTIPLIER / (1 SECONDS))] seconds left!) "
dat += "[SET_CLASS("Body Temperature:", "#40628a")] [occ["bodytemp"]-T0C]°C ([occ["bodytemp"]*1.8-459.67]°F) "
s_class = occ["blood_amount"] > 448 ? INTERFACE_OKAY : INTERFACE_BAD
diff --git a/code/game/machinery/medical_pod/medical_pod.dm b/code/game/machinery/medical_pod/medical_pod.dm
index b284d71ad4a7..62c8eef1f72c 100644
--- a/code/game/machinery/medical_pod/medical_pod.dm
+++ b/code/game/machinery/medical_pod/medical_pod.dm
@@ -155,7 +155,6 @@
if(exit_stun)
occupant.apply_effect(exit_stun, STUN) //Action delay when going out
- occupant.update_canmove() //Force the delay to go in action immediately
occupant.visible_message(SPAN_WARNING("[occupant] pops out of \the [src]!"),
SPAN_WARNING("You get out of \the [src] and get your bearings!"))
diff --git a/code/game/machinery/medical_pod/sleeper.dm b/code/game/machinery/medical_pod/sleeper.dm
index 805fedb29257..84ef2f579ba1 100644
--- a/code/game/machinery/medical_pod/sleeper.dm
+++ b/code/game/machinery/medical_pod/sleeper.dm
@@ -164,7 +164,7 @@
var/chemicals[0]
for(var/re in connected.available_chemicals)
- var/datum/reagent/temp = chemical_reagents_list[re]
+ var/datum/reagent/temp = GLOB.chemical_reagents_list[re]
if(temp)
var/reagent_amount = 0
var/pretty_amount
@@ -332,14 +332,13 @@
/obj/structure/machinery/medical_pod/sleeper/emp_act(severity)
+ . = ..()
if(filtering)
toggle_filter()
if(inoperable())
- ..(severity)
return
if(occupant)
go_out()
- ..()
/obj/structure/machinery/medical_pod/sleeper/proc/toggle_filter()
if(!occupant)
@@ -366,7 +365,7 @@
if(occupant && occupant.reagents)
if(occupant.reagents.get_reagent_amount(chemical) + amount <= max_chem)
occupant.reagents.add_reagent(chemical, amount, , , user)
- var/datum/reagent/temp = chemical_reagents_list[chemical]
+ var/datum/reagent/temp = GLOB.chemical_reagents_list[chemical]
to_chat(user, SPAN_NOTICE("[occupant] now has [occupant.reagents.get_reagent_amount(chemical)] units of [temp.name] in \his bloodstream."))
return
to_chat(user, SPAN_WARNING("There's no occupant in the sleeper or the subject has too many chemicals!"))
@@ -385,15 +384,14 @@
t1 = "Unconscious"
if(2)
t1 = "*dead*"
- else
to_chat(user, "[]\t Health %: [] ([])", (occupant.health > 50 ? SPAN_NOTICE("") : SPAN_DANGER("")), occupant.health, t1)
to_chat(user, "[]\t -Core Temperature: []°C ([]°F) ", (occupant.bodytemperature > 50 ? "" : ""), occupant.bodytemperature-T0C, occupant.bodytemperature*1.8-459.67)
to_chat(user, "[]\t -Brute Damage %: []", (occupant.getBruteLoss() < 60 ? SPAN_NOTICE("") : SPAN_DANGER("")), occupant.getBruteLoss())
to_chat(user, "[]\t -Respiratory Damage %: []", (occupant.getOxyLoss() < 60 ? SPAN_NOTICE("") : SPAN_DANGER("")), occupant.getOxyLoss())
to_chat(user, "[]\t -Toxin Content %: []", (occupant.getToxLoss() < 60 ? SPAN_NOTICE("") : SPAN_DANGER("")), occupant.getToxLoss())
to_chat(user, "[]\t -Burn Severity %: []", (occupant.getFireLoss() < 60 ? SPAN_NOTICE("") : SPAN_DANGER("")), occupant.getFireLoss())
- to_chat(user, SPAN_NOTICE(" Expected time till occupant can safely awake: (note: If health is below 20% these times are inaccurate)"))
- to_chat(user, SPAN_NOTICE(" \t [occupant.knocked_out / 5] second\s (if around 1 or 2 the sleeper is keeping them asleep.)"))
+ to_chat(user, SPAN_NOTICE(" Expected time till occupant can safely awake: (note: These times are always inaccurate)"))
+ to_chat(user, SPAN_NOTICE(" \t [occupant.GetKnockOutDuration() * GLOBAL_STATUS_MULTIPLIER / (1 SECONDS)] second\s (if around 1 or 2 the sleeper is keeping them asleep.)"))
else
to_chat(user, SPAN_NOTICE(" There is no one inside!"))
return
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index 89c9e9277f4c..9bd7e5f5e965 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -45,10 +45,9 @@
var/list/datum/feed_channel/network_channels = list()
var/datum/feed_message/wanted_issue
-var/datum/feed_network/news_network = new /datum/feed_network //The global news-network, which is coincidentally a global list.
-
-var/list/obj/structure/machinery/newscaster/allCasters = list() //Global list that will contain reference to all newscasters in existence.
+GLOBAL_DATUM_INIT(news_network, /datum/feed_network, new()) //The global news-network, which is coincidentally a global list.
+GLOBAL_LIST_INIT_TYPED(allCasters, /obj/structure/machinery/newscaster, list()) //Global list that will contain reference to all newscasters in existence.
/obj/structure/machinery/newscaster
name = "newscaster"
@@ -101,15 +100,15 @@ var/list/obj/structure/machinery/newscaster/allCasters = list() //Global list th
securityCaster = 1
/obj/structure/machinery/newscaster/security_unit/New() //Constructor, ho~
- allCasters += src
+ GLOB.allCasters += src
src.paper_remaining = 15 // Will probably change this to something better
- for(var/obj/structure/machinery/newscaster/NEWSCASTER in allCasters) // Let's give it an appropriate unit number
+ for(var/obj/structure/machinery/newscaster/NEWSCASTER in GLOB.allCasters) // Let's give it an appropriate unit number
src.unit_no++
src.update_icon() //for any custom ones on the map...
..() //I just realised the newscasters weren't in the global machines list. The superconstructor call will tend to that
/obj/structure/machinery/newscaster/security_unit/Destroy()
- allCasters -= src
+ GLOB.allCasters -= src
return ..()
/obj/structure/machinery/newscaster/update_icon()
@@ -122,7 +121,7 @@ var/list/obj/structure/machinery/newscaster/allCasters = list() //Global list th
src.overlays.Cut() //reset overlays
- if(news_network.wanted_issue) //wanted icon state, there can be no overlays on it as it's a priority message
+ if(GLOB.news_network.wanted_issue) //wanted icon state, there can be no overlays on it as it's a priority message
icon_state = "newscaster_wanted"
return
@@ -184,7 +183,7 @@ var/list/obj/structure/machinery/newscaster/allCasters = list() //Global list th
if(0)
dat += "Welcome to Newscasting Unit #[src.unit_no]. Interface & News networks Operational."
dat += " Property of Weyland-Yutani"
- if(news_network.wanted_issue)
+ if(GLOB.news_network.wanted_issue)
dat+= "Read Wanted Issue"
dat+= " Create Feed Channel"
dat+= " View Feed Channels"
@@ -194,7 +193,7 @@ var/list/obj/structure/machinery/newscaster/allCasters = list() //Global list th
dat+= "
",\
"You ARE aware of the xenomorph threat.",\
"Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons")
- story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?"
+ story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route."
spawn_priority = SPAWN_PRIORITY_LOW
/obj/effect/landmark/survivor_spawner/upp_sapper
@@ -154,7 +159,7 @@
intro_text = list("
You are a member of a UPP recon force!
",\
"You ARE aware of the xenomorph threat.",\
"Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons")
- story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?"
+ story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route."
spawn_priority = SPAWN_PRIORITY_MEDIUM
/obj/effect/landmark/survivor_spawner/upp_medic
@@ -163,7 +168,7 @@
intro_text = list("
You are a member of a UPP recon force!
",\
"You ARE aware of the xenomorph threat.",\
"Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons")
- story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?"
+ story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route."
spawn_priority = SPAWN_PRIORITY_MEDIUM
/obj/effect/landmark/survivor_spawner/upp_specialist
@@ -172,7 +177,7 @@
intro_text = list("
You are a member of a UPP recon force!
",\
"You ARE aware of the xenomorph threat.",\
"Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons")
- story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?"
+ story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route."
spawn_priority = SPAWN_PRIORITY_HIGH
/obj/effect/landmark/survivor_spawner/squad_leader
@@ -181,5 +186,5 @@
intro_text = list("
You are a member of a UPP recon force!
",\
"You ARE aware of the xenomorph threat.",\
"Your primary objective is to survive. You believe a second dropship crashed somewhere to the south east, which was carrying additional weapons")
- story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route, but is the enemy of my enemy truly your friend?"
+ story_text = "Your orders were simple, Recon the site, ascertain if there is a biological weapons program in the area, and if so to secure the colony and retrieve a sample. However your team failed to account for an active anti-air battery near the area. Both your craft and your sister ship crashed. Barely having a chance to catch your breath, you found yourself being assailed by vile xenomorphs! You and your team have barely held your ground, at the cost of four of your own, but more are coming and ammo is low. You believe an American rescue force is en route."
spawn_priority = SPAWN_PRIORITY_VERY_HIGH
diff --git a/code/game/objects/effects/overlays.dm b/code/game/objects/effects/overlays.dm
index 16f30eaf0fd2..ce0fd5506cd7 100644
--- a/code/game/objects/effects/overlays.dm
+++ b/code/game/objects/effects/overlays.dm
@@ -176,17 +176,17 @@
user = _user
if(squad_name)
name = "[squad_name] laser"
- if(user && user.faction && cas_groups[user.faction])
+ if(user && user.faction && GLOB.cas_groups[user.faction])
signal = new(src)
signal.name = name
signal.target_id = tracking_id
signal.linked_cam = new(loc, name)
- cas_groups[user.faction].add_signal(signal)
+ GLOB.cas_groups[user.faction].add_signal(signal)
/obj/effect/overlay/temp/laser_target/Destroy()
if(signal)
- cas_groups[user.faction].remove_signal(signal)
+ GLOB.cas_groups[user.faction].remove_signal(signal)
if(signal.linked_cam)
qdel(signal.linked_cam)
signal.linked_cam = null
@@ -225,7 +225,7 @@
effect_duration = 10
/obj/effect/overlay/temp/emp_sparks/New(loc)
- setDir(pick(cardinal))
+ setDir(pick(GLOB.cardinals))
..()
/obj/effect/overlay/temp/emp_pulse
diff --git a/code/game/objects/effects/spawners/faction_spawners.dm b/code/game/objects/effects/spawners/faction_spawners.dm
new file mode 100644
index 000000000000..2daf6392e5e7
--- /dev/null
+++ b/code/game/objects/effects/spawners/faction_spawners.dm
@@ -0,0 +1,197 @@
+/*
+ * USCM weapons
+ */
+/obj/effect/spawner/random/gun/uscm_primary
+ name = "USCM primary weapon spawner"
+ desc = "spawns USCM primary weapons"
+ mags_max = 2
+ mags_min = 1
+ guns = list(
+ /obj/item/weapon/gun/rifle/m41a = /obj/item/ammo_magazine/rifle,
+ /obj/item/weapon/gun/rifle/m41a/tactical = /obj/item/ammo_magazine/rifle,
+ /obj/item/weapon/gun/smg/m39 = /obj/item/ammo_magazine/smg/m39,
+ /obj/item/weapon/gun/smg/m39 = /obj/item/ammo_magazine/smg/m39,
+ /obj/item/weapon/gun/shotgun/pump = /datum/ammo/bullet/shotgun/buckshot
+ )
+
+/obj/effect/spawner/random/gun/uscm_primary/lowchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_rifle_20"
+
+/obj/effect/spawner/random/gun/uscm_primary/midchance
+ spawn_nothing_percentage = 50
+ icon_state = "loot_rifle_50"
+
+/obj/effect/spawner/random/gun/uscm_primary/highchance
+ spawn_nothing_percentage = 20
+ icon_state = "loot_rifle_80"
+
+/obj/effect/spawner/random/gun/uscm_secondary
+ name = "USCM secondary weapon spawner"
+ desc = "spawns USCM secondary weapons"
+ spawn_nothing_percentage = 0
+ mags_max = 2
+ mags_min = 1
+ guns = list(
+ /obj/item/weapon/gun/pistol/m4a3 = /obj/item/ammo_magazine/pistol,
+ /obj/item/weapon/gun/revolver/m44 = /obj/item/ammo_magazine/handful/revolver/marksman
+ )
+
+/obj/effect/spawner/random/gun/uscm_secondary/lowchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_pistol_20"
+
+/obj/effect/spawner/random/gun/uscm_secondary/midchance
+ spawn_nothing_percentage = 50
+ icon_state = "loot_pistol_50"
+
+/obj/effect/spawner/random/gun/uscm_secondary/highchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_pistol_80"
+
+
+/*
+ * UPP weapons
+ */
+/obj/effect/spawner/random/gun/upp_primary
+ name = "UPP primary weapon spawner"
+ desc = "spawns UPP primary weapons"
+ mags_max = 2
+ mags_min = 1
+ guns = list(
+ /obj/item/weapon/gun/smg/bizon/upp = /obj/item/ammo_magazine/smg/bizon,
+ /obj/item/weapon/gun/rifle/type71 = /obj/item/ammo_magazine/rifle/type71,
+ /obj/item/weapon/gun/rifle/type71/carbine = /obj/item/ammo_magazine/rifle/type71
+ )
+
+/obj/effect/spawner/random/gun/upp_primary/lowchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_rifle_20"
+
+/obj/effect/spawner/random/gun/upp_primary/midchance
+ spawn_nothing_percentage = 50
+ icon_state = "loot_rifle_50"
+
+/obj/effect/spawner/random/gun/upp_primary/highchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_rifle_80"
+
+/obj/effect/spawner/random/gun/upp_secondary
+ name = "UPP secondary weapon spawner"
+ desc = "spawns UPP secondary weapons"
+ mags_max = 2
+ mags_min = 1
+ guns = list(
+ /obj/item/weapon/gun/pistol/t73 = /obj/item/ammo_magazine/pistol/t73,
+ /obj/item/weapon/gun/pistol/np92 = /obj/item/ammo_magazine/pistol/np92,
+ /obj/item/weapon/gun/revolver/upp = /obj/item/ammo_magazine/revolver/upp
+ )
+
+/obj/effect/spawner/random/gun/upp_secondary/lowchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_pistol_20"
+
+/obj/effect/spawner/random/gun/upp_secondary/medchance
+ spawn_nothing_percentage = 50
+ icon_state = "loot_pistol_50"
+
+/obj/effect/spawner/random/gun/upp_secondary/highchance
+ spawn_nothing_percentage = 20
+ icon_state = "loot_pistol_80"
+/*
+ * PMC weapons
+ */
+/obj/effect/spawner/random/gun/pmc_primary
+ name = "PMC primary weapon spawner"
+ desc = "spawns PMC primary weapons"
+ mags_max = 2
+ mags_min = 1
+ guns = list(
+ /obj/item/weapon/gun/rifle/m41a/elite = /obj/item/ammo_magazine/rifle/ap,
+ /obj/item/weapon/gun/rifle/m41a/elite = /obj/item/ammo_magazine/rifle/extended,
+ /obj/item/weapon/gun/smg/m39/elite = /obj/item/ammo_magazine/smg/m39/ap,
+ /obj/item/weapon/gun/smg/m39/elite = /obj/item/ammo_magazine/smg/m39/extended,
+ /obj/item/weapon/gun/rifle/nsg23 = /obj/item/ammo_magazine/rifle/nsg23/ap,
+ /obj/item/weapon/gun/rifle/nsg23 = /obj/item/ammo_magazine/rifle/nsg23/extended
+ )
+
+/obj/effect/spawner/random/gun/pmc_primary/lowchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_rifle_20"
+
+/obj/effect/spawner/random/gun/pmc_primary/midchance
+ spawn_nothing_percentage = 50
+ icon_state = "loot_rifle_50"
+
+/obj/effect/spawner/random/gun/pmc_primary/highchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_rifle_80"
+
+/obj/effect/spawner/random/gun/pmc_secondary
+ name = "PMC secondary weapon spawner"
+ desc = "spawns PMC secondary weapons"
+ mags_max = 2
+ mags_min = 1
+ guns = list(
+ /obj/item/weapon/gun/pistol/vp78 = /obj/item/ammo_magazine/pistol/vp78,
+ /obj/item/weapon/gun/pistol/mod88 = /obj/item/ammo_magazine/pistol/mod88
+ )
+
+/obj/effect/spawner/random/gun/pmc_secondary/lowchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_pistol_20"
+
+/obj/effect/spawner/random/gun/pmc_secondary/medchance
+ spawn_nothing_percentage = 50
+ icon_state = "loot_pistol_50"
+
+/obj/effect/spawner/random/gun/pmc_secondary/highchance
+ spawn_nothing_percentage = 20
+ icon_state = "loot_pistol_80"
+
+/*
+ * CLF weapons
+ */
+/obj/effect/spawner/random/gun/clf_primary
+ name = "CLF primary weapon spawner"
+ desc = "spawns CLF primary weapons"
+ mags_max = 2
+ mags_min = 1
+ guns = list(
+ /obj/item/weapon/gun/rifle/m16 = /obj/item/ammo_magazine/rifle/m16,
+ /obj/item/weapon/gun/rifle/mar40/carbine = /obj/item/ammo_magazine/rifle/mar40
+ )
+
+/obj/effect/spawner/random/gun/clf_primary/lowchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_rifle_20"
+
+/obj/effect/spawner/random/gun/clf_primary/midchance
+ spawn_nothing_percentage = 50
+ icon_state = "loot_rifle_50"
+
+/obj/effect/spawner/random/gun/clf_primary/highchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_rifle_80"
+
+/obj/effect/spawner/random/gun/clf_secondary
+ name = "CLF secondary weapon spawner"
+ desc = "spawns CLF secondary weapons"
+ mags_max = 2
+ mags_min = 1
+ guns = list(
+ /obj/item/weapon/gun/pistol/kt42 = /obj/item/ammo_magazine/pistol/kt42,
+ /obj/item/weapon/gun/pistol/b92fs = /obj/item/ammo_magazine/pistol/b92fs
+ )
+
+/obj/effect/spawner/random/gun/clf_secondary/lowchance
+ spawn_nothing_percentage = 80
+ icon_state = "loot_pistol_20"
+
+/obj/effect/spawner/random/gun/clf_secondary/medchance
+ spawn_nothing_percentage = 50
+ icon_state = "loot_pistol_50"
+
+/obj/effect/spawner/random/gun/clf_secondary/highchance
+ spawn_nothing_percentage = 20
+ icon_state = "loot_pistol_80"
diff --git a/code/game/objects/effects/spawners/gibspawner.dm b/code/game/objects/effects/spawners/gibspawner.dm
index 382b92489baa..77b69f79e86f 100644
--- a/code/game/objects/effects/spawners/gibspawner.dm
+++ b/code/game/objects/effects/spawners/gibspawner.dm
@@ -99,7 +99,7 @@
gibamounts = list(1,1,1)
/obj/effect/spawner/gibspawner/human/Initialize(mapload, list/viruses, mob/living/ml, fleshcolor, bloodcolor)
- gibdirections = list(alldirs, alldirs, list())
+ gibdirections = list(GLOB.alldirs, GLOB.alldirs, list())
. = ..()
/obj/effect/spawner/gibspawner/xeno
@@ -107,7 +107,7 @@
gibamounts = list(1,1,1)
/obj/effect/spawner/gibspawner/xeno/Initialize(mapload, list/viruses, mob/living/ml, fleshcolor, bloodcolor)
- gibdirections = list(alldirs, alldirs, list())
+ gibdirections = list(GLOB.alldirs, GLOB.alldirs, list())
. = ..()
/obj/effect/spawner/gibspawner/robot
@@ -116,6 +116,6 @@
gibamounts = list(1,1,1,1,1,1)
/obj/effect/spawner/gibspawner/robot/Initialize(mapload, list/viruses, mob/living/ml, fleshcolor, bloodcolor)
- gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), alldirs, alldirs)
+ gibdirections = list(list(NORTH, NORTHEAST, NORTHWEST),list(SOUTH, SOUTHEAST, SOUTHWEST),list(WEST, NORTHWEST, SOUTHWEST),list(EAST, NORTHEAST, SOUTHEAST), GLOB.alldirs, GLOB.alldirs)
gibamounts[6] = pick(0,1,2)
. = ..()
diff --git a/code/game/objects/effects/spawners/prop_gun_spawner.dm b/code/game/objects/effects/spawners/prop_gun_spawner.dm
index b04f6cffffe1..5e620994e7fb 100644
--- a/code/game/objects/effects/spawners/prop_gun_spawner.dm
+++ b/code/game/objects/effects/spawners/prop_gun_spawner.dm
@@ -17,7 +17,7 @@
stack_trace("[src] using incorrect typepath, \"[prop_gun_type]\".") //Can't make a prop gun of something not a gun
qdel(src)
return
- if(!spawn_prob)
+ if(!prob(spawn_prob))
qdel(src)
return
if(!mapload)
@@ -71,6 +71,7 @@
pixel_x = source_gun.pixel_x
pixel_y = source_gun.pixel_y
layer = source_gun.layer
+ overlays = source_gun.overlays
/obj/item/prop/prop_gun/attack_self(mob/user) //Mimic wielding of real guns
. = ..()
diff --git a/code/game/objects/effects/spawners/random.dm b/code/game/objects/effects/spawners/random.dm
index 450981377a73..388e9f289cd7 100644
--- a/code/game/objects/effects/spawners/random.dm
+++ b/code/game/objects/effects/spawners/random.dm
@@ -57,10 +57,13 @@
icon_state = "atmos"
/obj/effect/spawner/random/technology_scanner/item_to_spawn()
- return pick(prob(5);/obj/item/device/t_scanner,\
- prob(2);/obj/item/device/radio,\
- prob(5);/obj/item/device/analyzer)
-
+ return pick_weight(list(
+ "none" = 10,
+ /obj/item/device/t_scanner = 10,
+ /obj/item/device/radio = 8,
+ /obj/item/device/analyzer = 10,
+ /obj/item/device/black_market_hacking_device = 2,
+ ))
/obj/effect/spawner/random/powercell
name = "Random Powercell"
@@ -339,38 +342,37 @@
var/gunpath = pick(guns)
var/ammopath
if(istype(gunpath, /obj/item/weapon/gun/shotgun))
- ammopath = pick(shotgun_boxes_12g)
+ ammopath = pick(GLOB.shotgun_boxes_12g)
else if(istype(gunpath, /obj/item/weapon/gun/launcher/grenade))
- ammopath = pick(grenade_packets)
+ ammopath = pick(GLOB.grenade_packets)
else
ammopath = guns[gunpath]
spawn_weapon_on_floor(gunpath, ammopath, rand(mags_min, mags_max))
/obj/effect/spawner/random/gun/proc/spawn_weapon_on_floor(gunpath, ammopath, ammo_amount = 1)
- var/atom/spawnloc = src
- spawnloc = get_turf(spawnloc)
+ var/turf/spawnloc = get_turf(src)
var/obj/gun
var/obj/ammo
if(gunpath)
gun = new gunpath(spawnloc)
if(scatter)
- var/direction = pick(alldirs)
- var/turf/T = get_step(gun, direction)
- if(!T || T.density)
+ var/direction = pick(GLOB.alldirs)
+ var/turf/turf = get_step(gun, direction)
+ if(!turf || turf.density)
return
- gun.loc = T
+ gun.forceMove(turf)
if(ammopath)
for(var/i in 0 to ammo_amount-1)
ammo = new ammopath(spawnloc)
if(scatter)
for(i=0, i\The [src] have been [pick(W.attack_verb)] with \the [W][(user ? "by [user]." : ".")]"))
else
visible_message(SPAN_DANGER("\The [src] have been attacked with \the [W][(user ? "by [user]." : ".")]"))
diff --git a/code/game/objects/effects/step_triggers.dm b/code/game/objects/effects/step_triggers.dm
index 2499810cbd3f..ab3c248c797f 100644
--- a/code/game/objects/effects/step_triggers.dm
+++ b/code/game/objects/effects/step_triggers.dm
@@ -50,7 +50,7 @@
if(ismob(AM))
var/mob/M = AM
if(immobilize)
- M.canmove = 0
+ ADD_TRAIT(M, TRAIT_IMMOBILIZED, STEP_TRIGGER_TRAIT)
affecting.Add(AM)
while(AM && !stopthrow)
@@ -87,7 +87,7 @@
if(ismob(AM))
var/mob/M = AM
if(immobilize)
- M.canmove = 1
+ REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, STEP_TRIGGER_TRAIT)
/* Stops things thrown by a thrower, doesn't do anything */
diff --git a/code/game/objects/explosion_recursive.dm b/code/game/objects/explosion_recursive.dm
index 1f52901c21a6..2ec61b0cc1f1 100644
--- a/code/game/objects/explosion_recursive.dm
+++ b/code/game/objects/explosion_recursive.dm
@@ -139,7 +139,7 @@ explosion resistance exactly as much as their health
//spread in each ordinal direction
var/direction_angle = dir2angle(direction)
- for(var/spread_direction in alldirs)
+ for(var/spread_direction in GLOB.alldirs)
var/spread_power = power
if(direction) //false if, for example, this turf was the explosion source
@@ -149,7 +149,7 @@ explosion resistance exactly as much as their health
switch(angle) //this reduces power when the explosion is going around corners
if (0)
- //no change
+ pass()
if (45)
if(spread_power >= 0)
spread_power *= 0.75
@@ -325,7 +325,7 @@ explosion resistance exactly as much as their health
return
if(!direction)
- direction = pick(alldirs)
+ direction = pick(GLOB.alldirs)
var/range = min(round(severity/src.w_class * 0.2, 1), 14)
if(!direction)
range = round( range/2 ,1)
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 077c0a463aaa..7cb2781b253b 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -156,6 +156,11 @@
var/list/inherent_traits
+ /// How much to offset the item randomly either way alongside X visually
+ var/ground_offset_x = 0
+ /// How much to offset the item randomly either way alongside Y visually
+ var/ground_offset_y = 0
+
/obj/item/Initialize(mapload, ...)
. = ..()
@@ -175,6 +180,8 @@
if(flags_item & MOB_LOCK_ON_EQUIP)
AddComponent(/datum/component/id_lock)
+ scatter_item()
+
/obj/item/Destroy()
flags_item &= ~DELONDROP //to avoid infinite loop of unequip, delete, unequip, delete.
flags_item &= ~NODROP //so the item is properly unequipped if on a mob.
@@ -268,7 +275,6 @@ cases. Override_icon_state should be a list.*/
size = "huge"
if(SIZE_MASSIVE)
size = "massive"
- else
. += "This is a [blood_color ? blood_color != "#030303" ? "bloody " : "oil-stained " : ""][icon2html(src, user)][src.name]. It is a [size] item."
if(desc)
. += desc
@@ -358,6 +364,7 @@ cases. Override_icon_state should be a list.*/
qdel(src)
SEND_SIGNAL(src, COMSIG_ITEM_DROPPED, user)
+ SEND_SIGNAL(user, COMSIG_MOB_ITEM_DROPPED, src)
if(drop_sound && (src.loc?.z))
playsound(src, drop_sound, dropvol, drop_vary)
src.do_drop_animation(user)
@@ -459,27 +466,32 @@ cases. Override_icon_state should be a list.*/
/obj/item/proc/item_action_slot_check(mob/user, slot)
return TRUE
+/obj/item/proc/scatter_item()
+ if(!pixel_x && !pixel_y)
+ pixel_x = rand(-ground_offset_x, ground_offset_x)
+ pixel_y = rand(-ground_offset_y, ground_offset_y)
+
// The mob M is attempting to equip this item into the slot passed through as 'slot'. return TRUE if it can do this and 0 if it can't.
// If you are making custom procs but would like to retain partial or complete functionality of this one, include a 'return ..()' to where you want this to happen.
// Set disable_warning to TRUE if you wish it to not give you outputs.
// warning_text is used in the case that you want to provide a specific warning for why the item cannot be equipped.
-/obj/item/proc/mob_can_equip(mob/M, slot, disable_warning = FALSE)
+/obj/item/proc/mob_can_equip(mob/equipping_mob, slot, disable_warning = FALSE)
if(!slot)
return FALSE
- if(!M)
+ if(!equipping_mob)
return FALSE
- if(SEND_SIGNAL(src, COMSIG_ITEM_ATTEMPTING_EQUIP, M) & COMPONENT_CANCEL_EQUIP)
+ if(SEND_SIGNAL(src, COMSIG_ITEM_ATTEMPTING_EQUIP, equipping_mob, slot) & COMPONENT_CANCEL_EQUIP)
return FALSE
- if(ishuman(M))
+ if(ishuman(equipping_mob))
//START HUMAN
- var/mob/living/carbon/human/H = M
+ var/mob/living/carbon/human/human = equipping_mob
var/list/mob_equip = list()
- if(H.hud_used && H.hud_used.equip_slots)
- mob_equip = H.hud_used.equip_slots
+ if(human.hud_used && human.hud_used.equip_slots)
+ mob_equip = human.hud_used.equip_slots
- if(H.species && !(slot in mob_equip))
+ if(human.species && !(slot in mob_equip))
return FALSE
if(uniform_restricted)
@@ -490,136 +502,136 @@ cases. Override_icon_state should be a list.*/
required_clothing += initial(restriction_type.name)
// You can't replace this with a switch(), flags_equip_slot is a bitfield
if(valid_equip_slots & SLOT_ICLOTHING)
- if(istype(H.w_uniform, restriction_type))
+ if(istype(human.w_uniform, restriction_type))
restriction_satisfied = TRUE
break
if(valid_equip_slots & SLOT_OCLOTHING)
- if(istype(H.wear_suit, restriction_type))
+ if(istype(human.wear_suit, restriction_type))
restriction_satisfied = TRUE
break
if(!restriction_satisfied)
if(!disable_warning)
- to_chat(H, SPAN_WARNING("You cannot wear this without wearing one of the following; [required_clothing.Join(", ")]."))
+ to_chat(human, SPAN_WARNING("You cannot wear this without wearing one of the following; [required_clothing.Join(", ")]."))
return FALSE
switch(slot)
if(WEAR_L_HAND)
- if(H.l_hand)
+ if(human.l_hand)
return FALSE
- if(H.lying)
- to_chat(H, SPAN_WARNING("You can't equip that while lying down."))
+ if(human.body_position == LYING_DOWN)
+ to_chat(human, SPAN_WARNING("You can't equip that while lying down."))
return
return TRUE
if(WEAR_R_HAND)
- if(H.r_hand)
+ if(human.r_hand)
return FALSE
- if(H.lying)
- to_chat(H, SPAN_WARNING("You can't equip that while lying down."))
+ if(human.body_position == LYING_DOWN)
+ to_chat(human, SPAN_WARNING("You can't equip that while lying down."))
return
return TRUE
if(WEAR_FACE)
- if(H.wear_mask)
+ if(human.wear_mask)
return FALSE
if(!(flags_equip_slot & SLOT_FACE))
return FALSE
return TRUE
if(WEAR_BACK)
- if(H.back)
+ if(human.back)
return FALSE
if(!(flags_equip_slot & SLOT_BACK))
return FALSE
return TRUE
if(WEAR_JACKET)
- if(H.wear_suit)
+ if(human.wear_suit)
return FALSE
if(!(flags_equip_slot & SLOT_OCLOTHING))
return FALSE
return TRUE
if(WEAR_HANDS)
- if(H.gloves)
+ if(human.gloves)
return FALSE
if(!(flags_equip_slot & SLOT_HANDS))
return FALSE
return TRUE
if(WEAR_FEET)
- if(H.shoes)
+ if(human.shoes)
return FALSE
if(!(flags_equip_slot & SLOT_FEET))
return FALSE
return TRUE
if(WEAR_WAIST)
- if(H.belt)
+ if(human.belt)
return FALSE
- if(!H.w_uniform && (WEAR_BODY in mob_equip))
+ if(!human.w_uniform && (WEAR_BODY in mob_equip))
if(!disable_warning)
- to_chat(H, SPAN_WARNING("You need a jumpsuit before you can attach this [name]."))
+ to_chat(human, SPAN_WARNING("You need a jumpsuit before you can attach this [name]."))
return FALSE
if(!(flags_equip_slot & SLOT_WAIST))
return
return TRUE
if(WEAR_EYES)
- if(H.glasses)
+ if(human.glasses)
return FALSE
if(!(flags_equip_slot & SLOT_EYES))
return FALSE
return TRUE
if(WEAR_HEAD)
- if(H.head)
+ if(human.head)
return FALSE
if(!(flags_equip_slot & SLOT_HEAD))
return FALSE
return TRUE
if(WEAR_L_EAR)
- if(H.wear_l_ear)
+ if(human.wear_l_ear)
return FALSE
if(HAS_TRAIT(src, TRAIT_ITEM_EAR_EXCLUSIVE))
- if(H.wear_r_ear && HAS_TRAIT(H.wear_r_ear, TRAIT_ITEM_EAR_EXCLUSIVE))
+ if(human.wear_r_ear && HAS_TRAIT(human.wear_r_ear, TRAIT_ITEM_EAR_EXCLUSIVE))
if(!disable_warning)
- to_chat(H, SPAN_WARNING("You can't wear [src] while you have [H.wear_r_ear] in your right ear!"))
+ to_chat(human, SPAN_WARNING("You can't wear [src] while you have [human.wear_r_ear] in your right ear!"))
return FALSE
if(!(flags_equip_slot & SLOT_EAR))
return FALSE
return TRUE
if(WEAR_R_EAR)
- if(H.wear_r_ear)
+ if(human.wear_r_ear)
return FALSE
if(HAS_TRAIT(src, TRAIT_ITEM_EAR_EXCLUSIVE))
- if(H.wear_l_ear && HAS_TRAIT(H.wear_l_ear, TRAIT_ITEM_EAR_EXCLUSIVE))
+ if(human.wear_l_ear && HAS_TRAIT(human.wear_l_ear, TRAIT_ITEM_EAR_EXCLUSIVE))
if(!disable_warning)
- to_chat(H, SPAN_WARNING("You can't wear [src] while you have [H.wear_l_ear] in your left ear!"))
+ to_chat(human, SPAN_WARNING("You can't wear [src] while you have [human.wear_l_ear] in your left ear!"))
return FALSE
if(!(flags_equip_slot & SLOT_EAR))
return FALSE
return TRUE
if(WEAR_BODY)
- if(H.w_uniform)
+ if(human.w_uniform)
return FALSE
if(!(flags_equip_slot & SLOT_ICLOTHING))
return FALSE
return TRUE
if(WEAR_ID)
- if(H.wear_id)
+ if(human.wear_id)
return FALSE
if(!(flags_equip_slot & SLOT_ID))
return FALSE
return TRUE
if(WEAR_L_STORE)
- if(H.l_store)
+ if(human.l_store)
return FALSE
- if(!H.w_uniform && (WEAR_BODY in mob_equip))
+ if(!human.w_uniform && (WEAR_BODY in mob_equip))
if(!disable_warning)
- to_chat(H, SPAN_WARNING("You need a jumpsuit before you can attach this [name]."))
+ to_chat(human, SPAN_WARNING("You need a jumpsuit before you can attach this [name]."))
return FALSE
if(flags_equip_slot & SLOT_NO_STORE)
return FALSE
if(w_class <= SIZE_SMALL || (flags_equip_slot & SLOT_STORE))
return TRUE
if(WEAR_R_STORE)
- if(H.r_store)
+ if(human.r_store)
return FALSE
- if(!H.w_uniform && (WEAR_BODY in mob_equip))
+ if(!human.w_uniform && (WEAR_BODY in mob_equip))
if(!disable_warning)
- to_chat(H, SPAN_WARNING("You need a jumpsuit before you can attach this [name]."))
+ to_chat(human, SPAN_WARNING("You need a jumpsuit before you can attach this [name]."))
return FALSE
if(flags_equip_slot & SLOT_NO_STORE)
return FALSE
@@ -627,109 +639,107 @@ cases. Override_icon_state should be a list.*/
return TRUE
return FALSE
if(WEAR_ACCESSORY)
- for(var/obj/item/clothing/C in H.contents)
- if(C.can_attach_accessory(src))
+ for(var/obj/item/clothing/clothes in human.contents)
+ if(clothes.can_attach_accessory(src))
return TRUE
return FALSE
if(WEAR_J_STORE)
- if(H.s_store)
+ if(human.s_store)
return FALSE
if(flags_equip_slot & SLOT_SUIT_STORE)
return TRUE
if(flags_equip_slot & SLOT_BLOCK_SUIT_STORE)
return FALSE
- if(!H.wear_suit && (WEAR_JACKET in mob_equip))
+ if(!human.wear_suit && (WEAR_JACKET in mob_equip))
if(!disable_warning)
- to_chat(H, SPAN_WARNING("You need a suit before you can attach this [name]."))
+ to_chat(human, SPAN_WARNING("You need a suit before you can attach this [name]."))
return FALSE
- if(H.wear_suit && !H.wear_suit.allowed)
+ if(human.wear_suit && !human.wear_suit.allowed)
if(!disable_warning)
to_chat(usr, "You somehow have a suit with no defined allowed items for suit storage, stop that.")
return FALSE
- if(H.wear_suit && is_type_in_list(src, H.wear_suit.allowed))
+ if(human.wear_suit && is_type_in_list(src, human.wear_suit.allowed))
return TRUE
return FALSE
if(WEAR_HANDCUFFS)
- if(H.handcuffed)
+ if(human.handcuffed)
return FALSE
if(!istype(src, /obj/item/handcuffs))
return FALSE
return TRUE
if(WEAR_LEGCUFFS)
- if(H.legcuffed)
+ if(human.legcuffed)
return FALSE
if(!istype(src, /obj/item/legcuffs))
return FALSE
return TRUE
if(WEAR_IN_ACCESSORY)
- if(H.w_uniform)
- for(var/A in H.w_uniform.accessories)
- if(istype(A, /obj/item/clothing/accessory/storage))
- var/obj/item/clothing/accessory/storage/S = A
- if(S.hold.can_be_inserted(src, M, TRUE))
+ if(human.w_uniform)
+ for(var/accessory in human.w_uniform.accessories)
+ if(istype(accessory, /obj/item/clothing/accessory/storage))
+ var/obj/item/clothing/accessory/storage/holster = accessory
+ if(holster.hold.can_be_inserted(src, human, TRUE))
return TRUE
- else if(istype(A, /obj/item/storage/internal/accessory/holster))
- var/obj/item/storage/internal/accessory/holster/AH = A
- if(!(AH.current_gun) && AH.can_be_inserted(src, M))
+ else if(istype(accessory, /obj/item/storage/internal/accessory/holster))
+ var/obj/item/storage/internal/accessory/holster/internal_storage = accessory
+ if(!(internal_storage.current_gun) && internal_storage.can_be_inserted(src, human))
return TRUE
return FALSE
if(WEAR_IN_JACKET)
- if(H.wear_suit)
- var/obj/item/clothing/suit/storage/S = H.wear_suit
- if(istype(S) && S.pockets)//not all suits have pockits
- var/obj/item/storage/internal/I = S.pockets
- if(I.can_be_inserted(src, M, TRUE))
+ if(human.wear_suit)
+ var/obj/item/clothing/suit/storage/storage = human.wear_suit
+ if(istype(storage) && storage.pockets)//not all suits have pockits
+ var/obj/item/storage/internal/internal_storage = storage.pockets
+ if(internal_storage.can_be_inserted(src, human, TRUE))
return TRUE
return FALSE
if(WEAR_IN_HELMET)
- if(H.head)
- var/obj/item/clothing/head/helmet/marine/HM = H.head
- if(istype(HM) && HM.pockets)//not all helmuts have pockits
- var/obj/item/storage/internal/I = HM.pockets
- if(I.can_be_inserted(src, M, TRUE))
+ if(human.head)
+ var/obj/item/clothing/head/helmet/marine/helmet = human.head
+ if(istype(helmet) && helmet.pockets)//not all helmuts have pockits
+ var/obj/item/storage/internal/internal_storage = helmet.pockets
+ if(internal_storage.can_be_inserted(src, human, TRUE))
return TRUE
if(WEAR_IN_BACK)
- if (H.back && isstorage(H.back))
- var/obj/item/storage/B = H.back
- if(B.can_be_inserted(src, M, TRUE))
+ if (human.back && isstorage(human.back))
+ var/obj/item/storage/backpack = human.back
+ if(backpack.can_be_inserted(src, human, TRUE))
return TRUE
return FALSE
if(WEAR_IN_SHOES)
- if(H.shoes && istype(H.shoes, /obj/item/clothing/shoes))
- var/obj/item/clothing/shoes/S = H.shoes
- if(!S.stored_item && S.items_allowed && S.items_allowed.len)
- for (var/i in S.items_allowed)
- if(istype(src, i))
- return TRUE
+ if(human.shoes && istype(human.shoes, /obj/item/clothing/shoes))
+ var/obj/item/clothing/shoes/shoes = human.shoes
+ if(shoes.can_be_inserted(src))
+ return TRUE
return FALSE
if(WEAR_IN_SCABBARD)
- if(H.back && istype(H.back, /obj/item/storage/large_holster))
- var/obj/item/storage/large_holster/B = H.back
- if(B.can_be_inserted(src, M, TRUE))
+ if(human.back && istype(human.back, /obj/item/storage/large_holster))
+ var/obj/item/storage/large_holster/backpack = human.back
+ if(backpack.can_be_inserted(src, human, TRUE))
return TRUE
return FALSE
if(WEAR_IN_BELT)
- if(H.belt && isstorage(H.belt))
- var/obj/item/storage/B = H.belt
- if(B.can_be_inserted(src, M, TRUE))
+ if(human.belt && isstorage(human.belt))
+ var/obj/item/storage/belt = human.belt
+ if(belt.can_be_inserted(src, human, TRUE))
return TRUE
return FALSE
if(WEAR_IN_J_STORE)
- if(H.s_store && isstorage(H.s_store))
- var/obj/item/storage/B = H.s_store
- if(B.can_be_inserted(src, M, TRUE))
+ if(human.s_store && isstorage(human.s_store))
+ var/obj/item/storage/armor = human.s_store
+ if(armor.can_be_inserted(src, human, TRUE))
return TRUE
return FALSE
if(WEAR_IN_L_STORE)
- if(H.l_store && istype(H.l_store, /obj/item/storage/pouch))
- var/obj/item/storage/pouch/P = H.l_store
- if(P.can_be_inserted(src, M, TRUE))
+ if(human.l_store && istype(human.l_store, /obj/item/storage/pouch))
+ var/obj/item/storage/pouch/pouch = human.l_store
+ if(pouch.can_be_inserted(src, human, TRUE))
return TRUE
return FALSE
if(WEAR_IN_R_STORE)
- if(H.r_store && istype(H.r_store, /obj/item/storage/pouch))
- var/obj/item/storage/pouch/P = H.r_store
- if(P.can_be_inserted(src, M, TRUE))
+ if(human.r_store && istype(human.r_store, /obj/item/storage/pouch))
+ var/obj/item/storage/pouch/pouch = human.r_store
+ if(pouch.can_be_inserted(src, human, TRUE))
return TRUE
return FALSE
return FALSE //Unsupported slot
@@ -786,7 +796,7 @@ cases. Override_icon_state should be a list.*/
/obj/item/proc/showoff(mob/user)
- var/list/viewers = get_mobs_in_view(world_view_size, user)
+ var/list/viewers = get_mobs_in_view(GLOB.world_view_size, user)
user.langchat_speech("holds up [src].", viewers, GLOB.all_languages, skip_language_check = TRUE, animation_style = LANGCHAT_FAST_POP, additional_styles = list("langchat_small", "emote"))
for (var/mob/M in viewers)
M.show_message("[user] holds up [src]. Take a closer look.", SHOW_MESSAGE_VISIBLE)
@@ -824,6 +834,8 @@ cases. Override_icon_state should be a list.*/
unzoom(user)
/obj/item/proc/unzoom(mob/living/user)
+ if(user.interactee == src)
+ user.unset_interaction()
var/zoom_device = zoomdevicename ? "\improper [zoomdevicename] of [src]" : "\improper [src]"
INVOKE_ASYNC(user, TYPE_PROC_REF(/atom, visible_message), SPAN_NOTICE("[user] looks up from [zoom_device]."),
SPAN_NOTICE("You look up from [zoom_device]."))
@@ -839,7 +851,7 @@ cases. Override_icon_state should be a list.*/
UnregisterSignal(user, COMSIG_MOB_MOVE_OR_LOOK)
//General reset in case anything goes wrong, the view will always reset to default unless zooming in.
if(user.client)
- user.client.change_view(world_view_size, src)
+ user.client.change_view(GLOB.world_view_size, src)
user.client.pixel_x = 0
user.client.pixel_y = 0
@@ -909,9 +921,10 @@ cases. Override_icon_state should be a list.*/
mob_state += GLOB.slot_to_contained_sprite_shorthand[slot]
return mob_state
-/obj/item/proc/drop_to_floor(mob/wearer)
+/obj/item/proc/drop_to_floor(mob/wearer, body_position)
SIGNAL_HANDLER
- wearer.drop_inv_item_on_ground(src)
+ if(body_position == LYING_DOWN)
+ wearer.drop_inv_item_on_ground(src)
// item animatzionen
diff --git a/code/game/objects/items/XMAS.dm b/code/game/objects/items/XMAS.dm
index 4b7bca2fb319..b10ea2035d96 100644
--- a/code/game/objects/items/XMAS.dm
+++ b/code/game/objects/items/XMAS.dm
@@ -66,7 +66,7 @@
gift_type = pick(
/obj/item/weapon/gun/revolver/mateba,
/obj/item/weapon/gun/pistol/heavy,
- /obj/item/weapon/claymore,
+ /obj/item/weapon/sword,
/obj/item/weapon/energy/sword/green,
/obj/item/weapon/energy/sword/red,
/obj/item/attachable/heavy_barrel,
diff --git a/code/game/objects/items/books/manuals.dm b/code/game/objects/items/books/manuals.dm
index ba2a30c35c7d..0854d2ec1b06 100644
--- a/code/game/objects/items/books/manuals.dm
+++ b/code/game/objects/items/books/manuals.dm
@@ -1302,9 +1302,9 @@
/obj/item/book/manual/orbital_cannon_manual/New()
. = ..()
- LAZYADD(objects_of_interest, src)
+ LAZYADD(GLOB.objects_of_interest, src)
/obj/item/book/manual/orbital_cannon_manual/Destroy()
. = ..()
- LAZYREMOVE(objects_of_interest, src)
+ LAZYREMOVE(GLOB.objects_of_interest, src)
diff --git a/code/game/objects/items/cards_ids.dm b/code/game/objects/items/cards_ids.dm
index a5e0eafe2f91..5f58a3b1d292 100644
--- a/code/game/objects/items/cards_ids.dm
+++ b/code/game/objects/items/cards_ids.dm
@@ -80,7 +80,7 @@
/// actual job
var/rank = null
/// Marine's paygrade
- var/paygrade = "ME1"
+ var/paygrade = PAY_SHORT_CIV
/// For medics and engineers to 'claim' a locker
var/claimedgear = 1
@@ -97,6 +97,21 @@
. = ..()
screen_loc = null
+/obj/item/card/id/proc/GetJobName() //Used in secHUD icon generation
+
+ var/job_icons = get_all_job_icons()
+ var/centcom = get_all_centcom_jobs()
+
+ if(assignment in job_icons)
+ return assignment//Check if the job has a hud icon
+ if(rank in job_icons)
+ return rank
+ if(assignment in centcom)
+ return "Centcom"//Return with the NT logo if it is a Centcom job
+ if(rank in centcom)
+ return "Centcom"
+ return "Unknown" //Return unknown if none of the above apply
+
/obj/item/card/id/attack_self(mob/user as mob)
..()
user.visible_message("[user] shows you: [icon2html(src, viewers(user))] [name]: assignment: [assignment]")
@@ -129,6 +144,12 @@
to_chat(usr, "[icon2html(src, usr)] [name]: The current assignment on the card is [assignment]")
to_chat(usr, "The blood type on the card is [blood_type].")
+/obj/item/card/id/proc/check_biometrics(mob/living/carbon/human/target)
+ if(registered_ref && (registered_ref != WEAKREF(target)))
+ return FALSE
+ if(target.real_name != registered_name)
+ return FALSE
+ return TRUE
/obj/item/card/id/data
name = "identification holo-badge"
diff --git a/code/game/objects/items/circuitboards/computer.dm b/code/game/objects/items/circuitboards/computer.dm
index db19b79ac0fd..08dcfc6964a6 100644
--- a/code/game/objects/items/circuitboards/computer.dm
+++ b/code/game/objects/items/circuitboards/computer.dm
@@ -96,9 +96,9 @@
/obj/item/circuitboard/computer/atmos_alert
name = "Circuit board (Atmospheric Alert)"
build_path = /obj/structure/machinery/computer/atmos_alert
-/obj/item/circuitboard/computer/pod
- name = "Circuit board (Massdriver control)"
- build_path = /obj/structure/machinery/computer/pod
+/obj/item/circuitboard/computer/pod/old
+ name = "Circuit board (DoorMex)"
+ build_path = /obj/structure/machinery/computer/pod/old
/obj/item/circuitboard/computer/robotics
name = "Circuit board (Robotics Control)"
build_path = /obj/structure/machinery/computer/robotics
@@ -117,15 +117,6 @@
/obj/item/circuitboard/computer/powermonitor
name = "Circuit board (Power Monitor)"
build_path = /obj/structure/machinery/power/monitor
-/obj/item/circuitboard/computer/olddoor
- name = "Circuit board (DoorMex)"
- build_path = /obj/structure/machinery/computer/pod/old
-/obj/item/circuitboard/computer/syndicatedoor
- name = "Circuit board (ProComp Executive)"
- build_path = /obj/structure/machinery/computer/pod/old/syndicate
-/obj/item/circuitboard/computer/swfdoor
- name = "Circuit board (Magix)"
- build_path = /obj/structure/machinery/computer/pod/old/swf
/obj/item/circuitboard/computer/prisoner
name = "Circuit board (Prisoner Management)"
build_path = /obj/structure/machinery/computer/prisoner
@@ -177,7 +168,11 @@
/obj/item/circuitboard/computer/supplycomp/attackby(obj/item/tool, mob/user)
if(HAS_TRAIT(tool, TRAIT_TOOL_MULTITOOL))
- to_chat(user, SPAN_WARNING("You start messing around with the electronics of \the [src]..."))
+ to_chat(user, SPAN_WARNING("You try to pulse the circuit board, but nothing happens. Maybe you need something more specialized?"))
+ return
+
+ else if(HAS_TRAIT(tool, TRAIT_TOOL_BLACKMARKET_HACKER))
+ to_chat(user, SPAN_WARNING("You start messing around with the electronics of [src]..."))
if(do_after(user, 8 SECONDS, INTERRUPT_ALL, BUSY_ICON_FRIENDLY))
if(!skillcheck(user, SKILL_ENGINEER, SKILL_ENGINEER_ENGI))
to_chat(user, SPAN_WARNING("You have no idea what you're doing."))
@@ -191,8 +186,7 @@
to_chat(user, SPAN_WARNING("You weaken the broadcasting function with \the [tool], and the red light stops blinking, turning off. It's probably good now."))
contraband_enabled = FALSE
- if(HAS_TRAIT(tool, TRAIT_TOOL_TRADEBAND))
-
+ else if(HAS_TRAIT(tool, TRAIT_TOOL_TRADEBAND))
if(!skillcheck(user, SKILL_POLICE, SKILL_POLICE_SKILLED))
to_chat(user, SPAN_NOTICE("You do not know how to use [tool]"))
return
@@ -284,7 +278,7 @@
to_chat(usr, "No input found please hang up and try your call again.")
return
var/list/tempnetwork = splittext(input, ",")
- tempnetwork = difflist(tempnetwork,RESTRICTED_CAMERA_NETWORKS,1)
+ tempnetwork = difflist(tempnetwork,GLOB.RESTRICTED_CAMERA_NETWORKS,1)
if(tempnetwork.len < 1)
to_chat(usr, "No network found please hang up and try your call again.")
return
@@ -293,14 +287,12 @@
/obj/item/circuitboard/computer/rdconsole/attackby(obj/item/I as obj, mob/user as mob)
if(HAS_TRAIT(I, TRAIT_TOOL_SCREWDRIVER))
- user.visible_message(SPAN_NOTICE("\the [user] adjusts the jumper on the [src]'s access protocol pins."), SPAN_NOTICE("You adjust the jumper on the access protocol pins."))
+ user.visible_message(SPAN_NOTICE("[user] adjusts the jumper on [src]'s access protocol pins."), SPAN_NOTICE("You adjust the jumper on the access protocol pins."))
if(src.build_path == /obj/structure/machinery/computer/rdconsole/core)
src.name = "Circuit Board (RD Console - Robotics)"
src.build_path = /obj/structure/machinery/computer/rdconsole/robotics
- to_chat(user, SPAN_NOTICE(" Access protocols set to robotics."))
+ to_chat(user, SPAN_NOTICE("Access protocols set to robotics."))
else
src.name = "Circuit Board (RD Console)"
src.build_path = /obj/structure/machinery/computer/rdconsole/core
- to_chat(user, SPAN_NOTICE(" Access protocols set to default."))
-
-
+ to_chat(user, SPAN_NOTICE("Access protocols set to default."))
diff --git a/code/game/objects/items/circuitboards/machine.dm b/code/game/objects/items/circuitboards/machine.dm
index ad4c31cb11e9..248d0d5c8885 100644
--- a/code/game/objects/items/circuitboards/machine.dm
+++ b/code/game/objects/items/circuitboards/machine.dm
@@ -141,7 +141,7 @@ to destroy them and players will be able to make replacements.
if(HAS_TRAIT(I, TRAIT_TOOL_SCREWDRIVER))
machine_dir = turn(machine_dir, 90)
init_dirs = machine_dir
- user.visible_message(SPAN_NOTICE("\The [user] adjusts the jumper on the [src]'s port configuration pins."), SPAN_NOTICE("You adjust the jumper on the port configuration pins. Now set to [dir2text(machine_dir)]."))
+ user.visible_message(SPAN_NOTICE("[user] adjusts the jumper on [src]'s port configuration pins."), SPAN_NOTICE("You adjust the jumper on the port configuration pins. Now set to [dir2text(machine_dir)]."))
return
/obj/item/circuitboard/machine/unary_atmos/get_examine_text(mob/user)
@@ -300,5 +300,3 @@ to destroy them and players will be able to make replacements.
// Board itself is high tech. Coils have to be ordered from cargo or salvaged from existing SMESs.
frame_desc = "Requires 1 superconducting magnetic coil and 30 wires."
req_components = list(/obj/item/stock_parts/smes_coil = 1, /obj/item/stack/cable_coil = 30)
-
-
diff --git a/code/game/objects/items/circuitboards/robot_modules.dm b/code/game/objects/items/circuitboards/robot_modules.dm
index 2e5185353852..04fcff10fa2b 100644
--- a/code/game/objects/items/circuitboards/robot_modules.dm
+++ b/code/game/objects/items/circuitboards/robot_modules.dm
@@ -9,13 +9,12 @@
var/list/stacktypes
/obj/item/circuitboard/robot_module/emp_act(severity)
+ . = ..()
if(modules)
for(var/obj/O in modules)
O.emp_act(severity)
if(emag)
emag.emp_act(severity)
- ..()
- return
/obj/item/circuitboard/robot_module/Initialize()
diff --git a/code/game/objects/items/devices/autopsy_scanner.dm b/code/game/objects/items/devices/autopsy_scanner.dm
index c4c7ec665e23..6703ead88147 100644
--- a/code/game/objects/items/devices/autopsy_scanner.dm
+++ b/code/game/objects/items/devices/autopsy_scanner.dm
@@ -17,12 +17,12 @@
/obj/item/device/autopsy_scanner/Initialize()
. = ..()
- LAZYADD(objects_of_interest, src)
+ LAZYADD(GLOB.objects_of_interest, src)
/obj/item/device/autopsy_scanner/Destroy()
. = ..()
- LAZYREMOVE(objects_of_interest, src)
+ LAZYREMOVE(GLOB.objects_of_interest, src)
/datum/autopsy_data_scanner
var/weapon = null // this is the DEFINITE weapon type that was used
@@ -90,7 +90,7 @@
var/scan_data = ""
if(timeofdeath)
- scan_data += "Time of death: [worldtime2text("hh:mm", timeofdeath)] [time2text(timeofdeath, "DDD MMM DD [game_year]")]
"
var/n = 1
for(var/wdata_idx in wdata)
@@ -139,7 +139,7 @@
if(damaging_weapon)
scan_data += "Severity: [damage_desc] "
scan_data += "Hits by weapon: [total_hits] "
- scan_data += "Approximate time of wound infliction: [worldtime2text("hh:mm", age)] [time2text(age, "DDD MMM DD [game_year]")] "
+ scan_data += "Approximate time of wound infliction: [worldtime2text("hh:mm", age)] [time2text(age, "DDD MMM DD [GLOB.game_year]")] "
scan_data += "Affected limbs: [D.organ_names] "
scan_data += "Possible weapons: "
for(var/weapon_name in weapon_chances)
@@ -174,7 +174,7 @@
M.update_inv_r_hand()
/obj/item/device/autopsy_scanner/attack(mob/living/carbon/human/M as mob, mob/living/carbon/user as mob)
- if(!istype(M) || !M.lying)
+ if(!istype(M) || !M.is_mob_incapacitated())
return
var/table
diff --git a/code/game/objects/items/devices/binoculars.dm b/code/game/objects/items/devices/binoculars.dm
index a4589fb1dd78..a9b7706bcfb7 100644
--- a/code/game/objects/items/devices/binoculars.dm
+++ b/code/game/objects/items/devices/binoculars.dm
@@ -38,10 +38,14 @@
/obj/item/device/binoculars/on_set_interaction(mob/user)
flags_atom |= RELAY_CLICK
-
+ RegisterSignal(user, COMSIG_HUMAN_MOVEMENT_CANCEL_INTERACTION, PROC_REF(interaction_handler))
/obj/item/device/binoculars/on_unset_interaction(mob/user)
flags_atom &= ~RELAY_CLICK
+ UnregisterSignal(user, COMSIG_HUMAN_MOVEMENT_CANCEL_INTERACTION)
+
+/obj/item/device/binoculars/proc/interaction_handler()
+ return COMPONENT_HUMAN_MOVEMENT_KEEP_USING
/obj/item/device/binoculars/civ
desc = "A pair of binoculars."
@@ -211,7 +215,7 @@
/obj/item/device/binoculars/range/designator/Initialize()
. = ..()
- tracking_id = ++cas_tracking_id_increment
+ tracking_id = ++GLOB.cas_tracking_id_increment
/obj/item/device/binoculars/range/designator/Destroy()
QDEL_NULL(laser)
@@ -418,7 +422,7 @@
if(!(GLOB.character_traits[/datum/character_trait/skills/spotter] in human.traits))
to_chat(human, SPAN_WARNING("You have no idea how to use this!"))
return FALSE
- if(istype(human) && !human.is_mob_incapacitated() && !human.lying && (holder_item == human.r_hand || holder_item || human.l_hand))
+ if(istype(human) && !human.is_mob_incapacitated() && (holder_item == human.r_hand || holder_item || human.l_hand))
return TRUE
/datum/action/item_action/specialist/spotter_target/proc/use_ability(atom/targeted_atom)
diff --git a/code/game/objects/items/devices/camera_bug.dm b/code/game/objects/items/devices/camera_bug.dm
index 80a0d603282f..1549fbd3739b 100644
--- a/code/game/objects/items/devices/camera_bug.dm
+++ b/code/game/objects/items/devices/camera_bug.dm
@@ -10,7 +10,7 @@
..()
var/list/cameras = new/list()
- for (var/obj/structure/machinery/camera/C in cameranet.cameras)
+ for (var/obj/structure/machinery/camera/C in GLOB.cameranet.cameras)
if (C.bugged && C.status)
cameras.Add(C)
if (length(cameras) == 0)
diff --git a/code/game/objects/items/devices/cictablet.dm b/code/game/objects/items/devices/cictablet.dm
index fc9bb015ece0..3f87b2bfbea2 100644
--- a/code/game/objects/items/devices/cictablet.dm
+++ b/code/game/objects/items/devices/cictablet.dm
@@ -24,7 +24,10 @@
COOLDOWN_DECLARE(distress_cooldown)
/obj/item/device/cotablet/Initialize()
- tacmap = new(src, minimap_type)
+ if(announcement_faction == FACTION_MARINE)
+ tacmap = new /datum/tacmap/drawing(src, minimap_type)
+ else
+ tacmap = new(src, minimap_type) // Non-drawing version
if(SSticker.mode && MODE_HAS_FLAG(MODE_FACTION_CLASH))
add_pmcs = FALSE
else if(SSticker.current_state < GAME_STATE_PLAYING)
@@ -60,8 +63,8 @@
/obj/item/device/cotablet/ui_data(mob/user)
var/list/data = list()
- data["alert_level"] = security_level
- data["evac_status"] = EvacuationAuthority.evac_status
+ data["alert_level"] = GLOB.security_level
+ data["evac_status"] = SShijack.evac_status
data["endtime"] = announcement_cooldown
data["distresstime"] = distress_cooldown
data["worldtime"] = world.time
@@ -131,29 +134,28 @@
if(announcement_faction != FACTION_MARINE)
return
- if(security_level < SEC_LEVEL_RED)
+ if(GLOB.security_level < SEC_LEVEL_RED)
to_chat(usr, SPAN_WARNING("The ship must be under red alert in order to enact evacuation procedures."))
return FALSE
- if(EvacuationAuthority.flags_scuttle & FLAGS_EVACUATION_DENY)
+ if(SShijack.evac_admin_denied)
to_chat(usr, SPAN_WARNING("The USCM has placed a lock on deploying the evacuation pods."))
return FALSE
- if(!EvacuationAuthority.initiate_evacuation())
+ if(!SShijack.initiate_evacuation())
to_chat(usr, SPAN_WARNING("You are unable to initiate an evacuation procedure right now!"))
return FALSE
log_game("[key_name(usr)] has called for an emergency evacuation.")
message_admins("[key_name_admin(usr)] has called for an emergency evacuation.")
- var/datum/ares_link/link = GLOB.ares_link
- link.log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.")
+ log_ares_security("Initiate Evacuation", "[usr] has called for an emergency evacuation.")
. = TRUE
if("distress")
if(!SSticker.mode)
return FALSE //Not a game mode?
- if(security_level == SEC_LEVEL_DELTA)
+ if(GLOB.security_level == SEC_LEVEL_DELTA)
to_chat(usr, SPAN_WARNING("The ship is already undergoing self destruct procedures!"))
return FALSE
diff --git a/code/game/objects/items/devices/cloaking.dm b/code/game/objects/items/devices/cloaking.dm
index 05e7786744e2..b0c5ed799977 100644
--- a/code/game/objects/items/devices/cloaking.dm
+++ b/code/game/objects/items/devices/cloaking.dm
@@ -47,12 +47,12 @@
src.add_fingerprint(user)
if(chameleon_on)
user.alpha = 25
- to_chat(user, SPAN_NOTICE("You activate the [src]."))
+ to_chat(user, SPAN_NOTICE("You activate [src]."))
spark_system.start()
src.icon_state = "shield1"
else
user.alpha = initial(user.alpha)
- to_chat(user, SPAN_NOTICE("You deactivate the [src]."))
+ to_chat(user, SPAN_NOTICE("You deactivate [src]."))
src.icon_state = "shield0"
spark_system.start()
diff --git a/code/game/objects/items/devices/coins.dm b/code/game/objects/items/devices/coins.dm
index 6ab79e3216d4..6c00364642da 100644
--- a/code/game/objects/items/devices/coins.dm
+++ b/code/game/objects/items/devices/coins.dm
@@ -11,11 +11,8 @@
black_market_value = 10
var/string_attached
var/sides = 2
-
-/obj/item/coin/Initialize()
- . = ..()
- pixel_x = rand(0,16)-8
- pixel_y = rand(0,8)-8
+ ground_offset_x = 8
+ ground_offset_y = 4
/obj/item/coin/gold
name = "gold coin"
@@ -29,6 +26,11 @@
icon_state = "coin_silver"
black_market_value = 25
+//CO coin
+/obj/item/coin/silver/falcon
+ name = "falling falcons challenge coin"
+ desc = "A small coin, bearing the falling falcons insignia."
+
/obj/item/coin/copper
name = "copper coin"
desc = "A familiar, but cheap form of currency."
@@ -65,12 +67,6 @@
icon_state = "coin_platinum"
black_market_value = 35
-/obj/item/coin/marine/synth
- name = "synthetic experimental tool redemption token"
- desc = "Insert this into a synthetic experimental tools vendor in order to access a variety of experimental support tools."
- icon_state = "coin_synth"
- black_market_value = 0
-
/obj/item/coin/chitin
name = "chitin coin"
desc = "Durable alien chitin pressed into a coin. There are much better uses for chitin..."
@@ -119,3 +115,33 @@
comment = "heads"
user.visible_message(SPAN_NOTICE("[user] has thrown \the [src]. It lands on [comment]! "), \
SPAN_NOTICE("You throw \the [src]. It lands on [comment]! "))
+
+
+/obj/item/coin/marine
+ name = "marine equipment token"
+ desc = "I wonder what it does?"
+ icon_state = "coin_copper"
+ black_market_value = 0
+ /// What is the token for?
+ var/token_type = VEND_TOKEN_VOID
+
+/obj/item/coin/marine/attackby(obj/item/W as obj, mob/user as mob) //To remove attaching a string functionality
+ return
+
+/obj/item/coin/marine/engineer
+ name = "marine engineer support token"
+ desc = "Insert this into an engineer vendor in order to access a support weapon."
+ icon_state = "coin_gold"
+ token_type = VEND_TOKEN_ENGINEER
+
+/obj/item/coin/marine/specialist
+ name = "marine specialist weapon token"
+ desc = "Insert this into a USCM equipment vendor in order to access a single highly dangerous weapon."
+ icon_state = "coin_diamond"
+ token_type = VEND_TOKEN_SPEC
+
+/obj/item/coin/marine/synth
+ name = "synthetic experimental tool redemption token"
+ desc = "Insert this into a synthetic experimental tools vendor in order to access a variety of experimental support tools."
+ icon_state = "coin_synth"
+ token_type = VEND_TOKEN_SYNTH
diff --git a/code/game/objects/items/devices/device.dm b/code/game/objects/items/devices/device.dm
index d3058960233c..23fe7b86bb3a 100644
--- a/code/game/objects/items/devices/device.dm
+++ b/code/game/objects/items/devices/device.dm
@@ -7,7 +7,7 @@
/obj/item/device/Initialize(mapload, ...)
. = ..()
- serial_number = "[rand(0,9)][pick(alphabet_uppercase)][rand(0,9)][rand(0,9)][rand(0,9)][rand(0,9)][pick(alphabet_uppercase)]"
+ serial_number = "[rand(0,9)][pick(GLOB.alphabet_uppercase)][rand(0,9)][rand(0,9)][rand(0,9)][rand(0,9)][pick(GLOB.alphabet_uppercase)]"
/obj/item/device/get_examine_text(mob/user)
. = ..()
diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm
index 0a7709aa6101..33a93ed18db5 100644
--- a/code/game/objects/items/devices/flash.dm
+++ b/code/game/objects/items/devices/flash.dm
@@ -155,6 +155,7 @@
do_flash(user = user, aoe = TRUE)
/obj/item/device/flash/emp_act(severity)
+ . = ..()
if(broken) return
switch(flashes_stored)
if(0 to 5)
@@ -168,7 +169,6 @@
if(M.flash_eyes())
M.apply_effect(10, WEAKEN)
M.visible_message(SPAN_DISARM("[M] is blinded by \the [src]!"))
- ..()
/obj/item/device/flash/synthetic
name = "synthetic flash"
diff --git a/code/game/objects/items/devices/flashlight.dm b/code/game/objects/items/devices/flashlight.dm
index e795f4e28de4..58e86998f39a 100644
--- a/code/game/objects/items/devices/flashlight.dm
+++ b/code/game/objects/items/devices/flashlight.dm
@@ -12,6 +12,8 @@
light_range = 5
light_power = 1
+ ground_offset_x = 2
+ ground_offset_y = 6
actions_types = list(/datum/action/item_action)
var/on = FALSE
@@ -33,6 +35,11 @@
else
icon_state = initial(icon_state)
+/obj/item/device/flashlight/animation_spin(speed = 5, loop_amount = -1, clockwise = TRUE, sections = 3, angular_offset = 0, pixel_fuzz = 0)
+ clockwise = pick(TRUE, FALSE)
+ angular_offset = rand(360)
+ return ..()
+
/obj/item/device/flashlight/proc/update_brightness(mob/user = null)
if(on)
set_light_range(light_range)
@@ -296,8 +303,6 @@
// Causes flares to stop with a rotation offset for visual purposes
/obj/item/device/flashlight/flare/animation_spin(speed = 5, loop_amount = -1, clockwise = TRUE, sections = 3, angular_offset = 0, pixel_fuzz = 0)
- clockwise = pick(TRUE, FALSE)
- angular_offset = rand(360)
pixel_fuzz = 16
return ..()
/obj/item/device/flashlight/flare/pickup()
@@ -482,13 +487,13 @@
/obj/item/device/flashlight/flare/signal/activate_signal(mob/living/carbon/human/user)
..()
- if(faction && cas_groups[faction])
+ if(faction && GLOB.cas_groups[faction])
signal = new(src)
- signal.target_id = ++cas_tracking_id_increment
+ signal.target_id = ++GLOB.cas_tracking_id_increment
name = "[user.assigned_squad ? user.assigned_squad.name : "X"]-[signal.target_id] flare"
signal.name = name
signal.linked_cam = new(loc, name)
- cas_groups[user.faction].add_signal(signal)
+ GLOB.cas_groups[user.faction].add_signal(signal)
anchored = TRUE
if(activate_message)
visible_message(SPAN_DANGER("[src]'s flame reaches full strength. It's fully active now."), null, 5)
@@ -508,14 +513,14 @@
/obj/item/device/flashlight/flare/signal/Destroy()
STOP_PROCESSING(SSobj, src)
if(signal)
- cas_groups[faction].remove_signal(signal)
+ GLOB.cas_groups[faction].remove_signal(signal)
QDEL_NULL(signal)
return ..()
/obj/item/device/flashlight/flare/signal/turn_off()
anchored = FALSE
if(signal)
- cas_groups[faction].remove_signal(signal)
+ GLOB.cas_groups[faction].remove_signal(signal)
qdel(signal)
..()
@@ -544,9 +549,9 @@
turn_on()
faction = FACTION_MARINE
signal = new(src)
- signal.target_id = ++cas_tracking_id_increment
+ signal.target_id = ++GLOB.cas_tracking_id_increment
name += " [rand(100, 999)]"
signal.name = name
signal.linked_cam = new(loc, name)
- cas_groups[FACTION_MARINE].add_signal(signal)
+ GLOB.cas_groups[FACTION_MARINE].add_signal(signal)
anchored = TRUE
diff --git a/code/game/objects/items/devices/helmet_visors.dm b/code/game/objects/items/devices/helmet_visors.dm
index dd913daf7620..05d75a9fefd6 100644
--- a/code/game/objects/items/devices/helmet_visors.dm
+++ b/code/game/objects/items/devices/helmet_visors.dm
@@ -14,31 +14,65 @@
///The sound when toggling off the visor
var/toggle_off_sound = 'sound/handling/hud_off.ogg'
- ///The icon name for our helmet's action
+ ///The icon name for our helmet's action, in 'icons/obj/items/clothing/helmet_visors.dmi'
var/action_icon_string = "hud_sight_down"
- ///The overlay name for when our visor is active
+ ///The overlay name for when our visor is active, in 'icons/mob/humans/onmob/helmet_garb.dmi'
var/helmet_overlay = "hud_sight_right"
+/obj/item/device/helmet_visor/Destroy(force)
+ if(!istype(loc, /obj/item/clothing/head/helmet/marine))
+ return ..()
+
+ if(!istype(loc?.loc, /mob/living/carbon/human))
+ return ..()
+
+ var/obj/item/clothing/head/helmet/marine/attached_helmet = loc
+ var/mob/living/carbon/human/user = loc.loc
+ deactivate_visor(attached_helmet, user)
+ . = ..()
+
/// Called to see if the user can even use this visor
/obj/item/device/helmet_visor/proc/can_toggle(mob/living/carbon/human/user)
return TRUE
/// Called to see if this visor is a special non-HUD visor
-/obj/item/device/helmet_visor/proc/visor_function(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user, silent = FALSE)
+/obj/item/device/helmet_visor/proc/toggle_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user, silent = FALSE)
if(attached_helmet == user.head && attached_helmet.active_visor == src)
- var/datum/mob_hud/current_mob_hud = huds[hud_type]
- current_mob_hud.add_hud_to(user, attached_helmet)
+
+ if(!can_toggle(user))
+ return FALSE
+
+ activate_visor(attached_helmet, user)
+
if(!silent)
to_chat(user, SPAN_NOTICE("You activate [src] on [attached_helmet]."))
+ playsound_client(user.client, toggle_on_sound, null, 75)
+
return TRUE
- var/datum/mob_hud/current_mob_hud = huds[hud_type]
- current_mob_hud.remove_hud_from(user, attached_helmet)
+ deactivate_visor(attached_helmet, user)
+
if(!silent)
to_chat(user, SPAN_NOTICE("You deactivate [src] on [attached_helmet]."))
+ playsound_client(user.client, toggle_off_sound, null, 75)
+
return TRUE
+/// Called by toggle_visor() to activate the visor's effects
+/obj/item/device/helmet_visor/proc/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ var/datum/mob_hud/current_mob_hud = GLOB.huds[hud_type]
+ current_mob_hud.add_hud_to(user, attached_helmet)
+
+/// Called by toggle_visor() to deactivate the visor's effects
+/obj/item/device/helmet_visor/proc/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ var/datum/mob_hud/current_mob_hud = GLOB.huds[hud_type]
+ current_mob_hud.remove_hud_from(user, attached_helmet)
+
+/// Called by /obj/item/clothing/head/helmet/marine/get_examine_text(mob/user) to get extra examine text for this visor
+/obj/item/device/helmet_visor/proc/get_helmet_examine_text()
+ return SPAN_NOTICE("\A [name] is flipped down.")
+
/obj/item/device/helmet_visor/medical
name = "basic medical optic"
icon_state = "med_sight"
@@ -50,13 +84,75 @@
name = "advanced medical optic"
helmet_overlay = "med_sight_left"
+/obj/item/device/helmet_visor/medical/advanced/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ . = ..()
+
+ var/datum/action/item_action/view_publications/helmet_visor/publication_action = new(attached_helmet)
+ publication_action.give_to(user)
+
+/obj/item/device/helmet_visor/medical/advanced/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ . = ..()
+
+ var/datum/action/item_action/view_publications/helmet_visor/publication_action = locate() in attached_helmet.actions
+ qdel(publication_action)
+
/obj/item/device/helmet_visor/medical/advanced/can_toggle(mob/living/carbon/human/user)
+ . = ..()
+ if(!.)
+ return
+
if(!skillcheck(user, SKILL_MEDICAL, SKILL_MEDICAL_MEDIC))
to_chat(user, SPAN_NOTICE("You are not skilled enough to use [src]."))
return FALSE
return TRUE
+/obj/item/device/helmet_visor/medical/advanced/ui_state(mob/user)
+ return GLOB.not_incapacitated_and_adjacent_strict_state
+
+/obj/item/device/helmet_visor/medical/advanced/ui_data(mob/user)
+ var/list/data = list(
+ "published_documents" = GLOB.chemical_data.research_publications,
+ "terminal_view" = FALSE
+ )
+ return data
+
+/obj/item/device/helmet_visor/medical/advanced/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if (!ui)
+ ui = new(user, src, "PublishedDocsHud", name)
+ ui.open()
+
+/obj/item/device/helmet_visor/medical/advanced/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state)
+ . = ..()
+ if(.)
+ return
+
+ if(!ishuman(ui.user))
+ return
+
+ var/mob/living/carbon/human/user = ui.user
+
+ if(user.stat || user.is_mob_restrained() || !in_range(src, user))
+ return
+
+ switch(action)
+ if ("read_document")
+ var/print_type = params["print_type"]
+ var/print_title = params["print_title"]
+ var/obj/item/paper/research_report/report = GLOB.chemical_data.get_report(print_type, print_title)
+ if(report)
+ report.read_paper(user)
+ return
+
+/datum/action/item_action/view_publications/helmet_visor/action_activate()
+ var/obj/item/device/helmet_visor/medical/advanced/medical_visor = locate() in holder_item
+
+ if(!medical_visor)
+ return
+
+ medical_visor.tgui_interact(owner)
+
/obj/item/device/helmet_visor/security
name = "security optic"
icon_state = "sec_sight"
@@ -71,28 +167,159 @@
action_icon_string = "blank_hud_sight_down"
helmet_overlay = "weld_visor"
-/obj/item/device/helmet_visor/welding_visor/visor_function(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user, silent = FALSE)
- if(attached_helmet == user.head && attached_helmet.active_visor == src)
- attached_helmet.vision_impair = VISION_IMPAIR_MAX
- attached_helmet.flags_inventory |= COVEREYES|COVERMOUTH
- attached_helmet.flags_inv_hide |= HIDEEYES|HIDEFACE
- attached_helmet.eye_protection = EYE_PROTECTION_WELDING
- user.update_tint()
- if(!silent)
- to_chat(user, SPAN_NOTICE("You activate [src] on [attached_helmet]."))
- return TRUE
+/obj/item/device/helmet_visor/welding_visor/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ attached_helmet.vision_impair = VISION_IMPAIR_MAX
+ attached_helmet.flags_inventory |= COVEREYES|COVERMOUTH
+ attached_helmet.flags_inv_hide |= HIDEEYES|HIDEFACE
+ attached_helmet.eye_protection = EYE_PROTECTION_WELDING
+ user.update_tint()
+/obj/item/device/helmet_visor/welding_visor/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
attached_helmet.vision_impair = VISION_IMPAIR_NONE
attached_helmet.flags_inventory &= ~(COVEREYES|COVERMOUTH)
attached_helmet.flags_inv_hide &= ~(HIDEEYES|HIDEFACE)
attached_helmet.eye_protection = EYE_PROTECTION_NONE
- if(!silent)
- to_chat(user, SPAN_NOTICE("You deactivate [src] on [attached_helmet]."))
user.update_tint()
- return TRUE
/obj/item/device/helmet_visor/welding_visor/mercenary
helmet_overlay = ""
/obj/item/device/helmet_visor/welding_visor/tanker
helmet_overlay = "tanker_weld_visor"
+
+#define NVG_VISOR_USAGE(delta_time) (power_cell.use(power_use * (delta_time ? delta_time : 1)))
+
+/obj/item/device/helmet_visor/night_vision
+ name = "night vision optic"
+ desc = "An insertable visor HUD into a standard USCM helmet. This type gives a form of night vision and is standard issue in units with regular funding."
+ icon_state = "nvg_sight"
+ hud_type = null
+ action_icon_string = "nvg_sight_down"
+ helmet_overlay = "nvg_sight_right"
+ toggle_on_sound = 'sound/handling/toggle_nv1.ogg'
+ toggle_off_sound = 'sound/handling/toggle_nv2.ogg'
+
+ /// The internal battery for the visor
+ var/obj/item/cell/high/power_cell
+
+ /// About 5 minutes active use charge (hypothetically)
+ var/power_use = 33
+
+ /// The alpha of darkness we set to for the mob while the visor is on, not completely fullbright but see-able
+ var/lighting_alpha = 100
+
+ /// A slight glowing green light while the NVG is activated, is initialized as in the attached_helmet's contents
+ var/atom/movable/nvg_light/on_light
+
+ /// Whether or not the sight uses on_light and produces light
+ var/visor_glows = TRUE
+
+/obj/item/device/helmet_visor/night_vision/Initialize(mapload, ...)
+ . = ..()
+ power_cell = new(src)
+
+/obj/item/device/helmet_visor/night_vision/Destroy()
+ power_cell = null
+ . = ..()
+
+/obj/item/device/helmet_visor/night_vision/get_examine_text(mob/user)
+ . = ..()
+
+ . += SPAN_NOTICE("It is currently at [round((power_cell.charge / power_cell.maxcharge) * 100)]% charge.")
+
+/obj/item/device/helmet_visor/night_vision/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ RegisterSignal(user, COMSIG_HUMAN_POST_UPDATE_SIGHT, PROC_REF(on_update_sight))
+
+ user.add_client_color_matrix("nvg_visor", 99, color_matrix_multiply(color_matrix_saturation(0), color_matrix_from_string("#7aff7a")))
+ user.overlay_fullscreen("nvg_visor", /atom/movable/screen/fullscreen/flash/noise/nvg)
+ user.overlay_fullscreen("nvg_visor_blur", /atom/movable/screen/fullscreen/brute/nvg, 3)
+ user.update_sight()
+ if(visor_glows)
+ on_light = new(attached_helmet)
+ on_light.set_light_on(TRUE)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/device/helmet_visor/night_vision/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ user.remove_client_color_matrix("nvg_visor", 1 SECONDS)
+ user.clear_fullscreen("nvg_visor", 0.5 SECONDS)
+ user.clear_fullscreen("nvg_visor_blur", 0.5 SECONDS)
+
+ if(visor_glows)
+ qdel(on_light)
+ UnregisterSignal(user, COMSIG_HUMAN_POST_UPDATE_SIGHT)
+
+ user.update_sight()
+ STOP_PROCESSING(SSobj, src)
+
+/obj/item/device/helmet_visor/night_vision/process(delta_time)
+ if(!NVG_VISOR_USAGE(delta_time))
+
+ if(!istype(loc, /obj/item/clothing/head/helmet/marine))
+ return PROCESS_KILL
+
+ if(!istype(loc?.loc, /mob/living/carbon/human))
+ return PROCESS_KILL
+
+ var/obj/item/clothing/head/helmet/marine/attached_helmet = loc
+ var/mob/living/carbon/human/user = loc.loc
+ to_chat(user, SPAN_NOTICE("[src] deactivates as the battery goes out."))
+ deactivate_visor(attached_helmet, user)
+ return PROCESS_KILL
+
+/obj/item/device/helmet_visor/night_vision/can_toggle(mob/living/carbon/human/user)
+ . = ..()
+ if(!.)
+ return
+
+ if(!NVG_VISOR_USAGE(FALSE))
+ to_chat(user, SPAN_NOTICE("Your [src] is out of power! You'll need to recharge it."))
+ return FALSE
+
+ return TRUE
+
+/obj/item/device/helmet_visor/night_vision/get_helmet_examine_text()
+ . = ..()
+
+ . += SPAN_NOTICE(" It is currently at [round((power_cell.charge / power_cell.maxcharge) * 100)]% charge.")
+
+/obj/item/device/helmet_visor/night_vision/proc/on_update_sight(mob/user)
+ SIGNAL_HANDLER
+
+ if(lighting_alpha < 255)
+ user.see_in_dark = 12
+ user.lighting_alpha = lighting_alpha
+ user.sync_lighting_plane_alpha()
+
+#undef NVG_VISOR_USAGE
+
+/atom/movable/nvg_light
+ light_power = 0.5
+ light_range = 1
+ light_color = COLOR_LIGHT_GREEN
+ light_system = MOVABLE_LIGHT
+ light_flags = LIGHT_ATTACHED
+
+/obj/item/device/helmet_visor/night_vision/marine_raider
+ name = "advanced night vision optic"
+ desc = "An insertable visor HUD into a standard USCM helmet. This type gives a form of night vision and is standard issue in special forces units."
+ hud_type = list(MOB_HUD_FACTION_USCM, MOB_HUD_MEDICAL_ADVANCED)
+ helmet_overlay = "nvg_sight_right_raider"
+ power_use = 0
+ visor_glows = FALSE
+
+/obj/item/device/helmet_visor/night_vision/marine_raider/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ . = ..()
+
+ for(var/type in hud_type)
+ var/datum/mob_hud/current_mob_hud = GLOB.huds[type]
+ current_mob_hud.add_hud_to(user, attached_helmet)
+
+/obj/item/device/helmet_visor/night_vision/marine_raider/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
+ . = ..()
+
+ for(var/type in hud_type)
+ var/datum/mob_hud/current_mob_hud = GLOB.huds[type]
+ current_mob_hud.remove_hud_from(user, attached_helmet)
+
+/obj/item/device/helmet_visor/night_vision/marine_raider/process(delta_time)
+ return PROCESS_KILL
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 40ef8792aedb..3f285b358fb2 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -121,7 +121,7 @@
if(target.status != LIGHT_OK)
if(CanUse(U))
if(!Use(U)) return
- to_chat(U, SPAN_NOTICE("You replace the [target.fitting] with the [src]."))
+ to_chat(U, SPAN_NOTICE("You replace the [target.fitting] with [src]."))
if(target.status != LIGHT_EMPTY)
diff --git a/code/game/objects/items/devices/megaphone.dm b/code/game/objects/items/devices/megaphone.dm
index c6da7d354054..114ed48b1819 100644
--- a/code/game/objects/items/devices/megaphone.dm
+++ b/code/game/objects/items/devices/megaphone.dm
@@ -30,9 +30,8 @@
return
// we know user is a human now, so adjust user for this check
var/mob/living/carbon/human/humanoid = user
- if(humanoid.speech_problem_flag)
- var/list/new_message = humanoid.handle_speech_problems(message)
- message = new_message[1]
+ var/list/new_message = humanoid.handle_speech_problems(message)
+ message = new_message[1]
message = capitalize(message)
log_admin("[key_name(user)] used a megaphone to say: >[message]<")
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index 273ced980b44..a92135b9d7ed 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -53,8 +53,8 @@
var/area/A = get_area(src)
var/APC = A? A.get_apc() : null
if(APC)
- to_chat(user, SPAN_NOTICE("The local APC is located at [SPAN_BOLD("[get_dist(src, APC)] units [dir2text(get_dir(src, APC))]")]."))
- user.balloon_alert(user, "[get_dist(src, APC)] units [dir2text(get_dir(src, APC))]")
+ to_chat(user, SPAN_NOTICE("The local APC is located at [SPAN_BOLD("[get_dist(src, APC)] units [dir2text(Get_Compass_Dir(src, APC))]")]."))
+ user.balloon_alert(user, "[get_dist(src, APC)] units [dir2text(Get_Compass_Dir(src, APC))]")
else
to_chat(user, SPAN_WARNING("ERROR: Could not locate local APC."))
user.balloon_alert(user, "could not locate!")
diff --git a/code/game/objects/items/devices/personal_data_transmitter.dm b/code/game/objects/items/devices/personal_data_transmitter.dm
index 6e8aa001cad3..98f8c60452ea 100644
--- a/code/game/objects/items/devices/personal_data_transmitter.dm
+++ b/code/game/objects/items/devices/personal_data_transmitter.dm
@@ -122,7 +122,7 @@
return
var/dist = get_dist(self_turf, bracelet_turf)
- var/direction = dir2text_short(get_dir(self_turf, bracelet_turf))
+ var/direction = dir2text_short(Get_Compass_Dir(self_turf, bracelet_turf))
if(dist > 1)
to_chat(user, SPAN_BOLDNOTICE("The display on \the [src] lights up: [dist]-[direction]"))
else
diff --git a/code/game/objects/items/devices/pinpointer.dm b/code/game/objects/items/devices/pinpointer.dm
index 7ec3118ef96b..2f5d9ffe9d5f 100644
--- a/code/game/objects/items/devices/pinpointer.dm
+++ b/code/game/objects/items/devices/pinpointer.dm
@@ -31,7 +31,7 @@
if(!the_disk)
icon_state = "pinonnull"
return
- setDir(get_dir(src,the_disk))
+ setDir(Get_Compass_Dir(src,the_disk))
switch(get_dist(src,the_disk))
if(0)
icon_state = "pinondirect"
@@ -45,7 +45,7 @@
/obj/item/device/pinpointer/get_examine_text(mob/user)
. = ..()
- for(var/obj/structure/machinery/nuclearbomb/bomb in machines)
+ for(var/obj/structure/machinery/nuclearbomb/bomb in GLOB.machines)
if(bomb.timing)
. += "Extreme danger. Arming signal detected. Time remaining: [bomb.timeleft]"
@@ -80,7 +80,7 @@
if(!location)
icon_state = "pinonnull"
return
- setDir(get_dir(src,location))
+ setDir(Get_Compass_Dir(src,location))
switch(get_dist(src,location))
if(0)
icon_state = "pinondirect"
@@ -99,7 +99,7 @@
if(!target)
icon_state = "pinonnull"
return
- setDir(get_dir(src,target))
+ setDir(Get_Compass_Dir(src,target))
switch(get_dist(src,target))
if(0)
icon_state = "pinondirect"
diff --git a/code/game/objects/items/devices/pipe_painter.dm b/code/game/objects/items/devices/pipe_painter.dm
index 840098cbc492..a69fe64c2565 100644
--- a/code/game/objects/items/devices/pipe_painter.dm
+++ b/code/game/objects/items/devices/pipe_painter.dm
@@ -9,7 +9,7 @@
/obj/item/device/pipe_painter/New()
..()
modes = new()
- for(var/C in pipe_colors)
+ for(var/C in GLOB.pipe_colors)
modes += "[C]"
mode = pick(modes)
@@ -26,7 +26,7 @@
to_chat(user, SPAN_DANGER("You must remove the plating first."))
return
- P.change_color(pipe_colors[mode])
+ P.change_color(GLOB.pipe_colors[mode])
/obj/item/device/pipe_painter/attack_self(mob/user)
..()
diff --git a/code/game/objects/items/devices/portable_vendor.dm b/code/game/objects/items/devices/portable_vendor.dm
index 65e2128a02c0..465ba0666828 100644
--- a/code/game/objects/items/devices/portable_vendor.dm
+++ b/code/game/objects/items/devices/portable_vendor.dm
@@ -21,10 +21,12 @@
var/use_points = TRUE
var/fabricating = FALSE
var/broken = FALSE
+ var/contraband = FALSE
var/list/purchase_log = list()
var/list/listed_products = list()
+ var/list/contraband_products = list()
/// needs to be a time define
var/special_prod_time_lock
@@ -44,7 +46,7 @@
if(!ishuman(user))
return
- var/mob/living/carbon/human/H = user
+ var/mob/living/carbon/human/human_user = user
src.add_fingerprint(usr)
@@ -56,17 +58,17 @@
to_chat(user, SPAN_WARNING("Access denied."))
return
- var/obj/item/card/id/I = H.wear_id
- if(!istype(I)) //not wearing an ID
- to_chat(H, SPAN_WARNING("Access denied. No ID card detected"))
+ var/obj/item/card/id/idcard = human_user.wear_id
+ if(!istype(idcard)) //not wearing an ID
+ to_chat(human_user, SPAN_WARNING("Access denied. No ID card detected"))
return
- if(I.registered_name != H.real_name)
- to_chat(H, SPAN_WARNING("Wrong ID card owner detected."))
+ if(!idcard.check_biometrics(human_user))
+ to_chat(human_user, SPAN_WARNING("Wrong ID card owner detected."))
return
- if(req_role && I.rank != req_role)
- to_chat(H, SPAN_WARNING("This device isn't for you."))
+ if(req_role && idcard.rank != req_role)
+ to_chat(human_user, SPAN_WARNING("This device isn't for you."))
return
@@ -97,6 +99,22 @@
var/available = points >= product[2] || !use_points
available_items += list(list("index" = index, "name" = name, "cost" = cost, "available" = available, "color" = color, "description" = description))
+ if(contraband)
+ var/non_contraband_product_count = length(listed_products)
+ for(var/index in 1 to length(contraband_products))
+ var/product = contraband_products[index]
+
+ var/name = product[1]
+ var/cost = product[2]
+ var/color = product[4]
+ var/description = product[5]
+
+ if(cost > 0)
+ name += " ([cost] points)"
+
+ var/available = points >= product[2] || !use_points
+ available_items += list(list("index" = index + non_contraband_product_count, "name" = name, "cost" = cost, "available" = available, "color" = color, "description" = description))
+
.["vendor_name"] = name
.["show_points"] = use_points
.["current_points"] = round(points)
@@ -139,7 +157,13 @@
if(req_role && req_role != id.rank)
to_chat(human_user, SPAN_WARNING("This device isn't for you."))
- var/list/product = listed_products[choice]
+ var/list/product
+ var/non_contraband_product_count = length(listed_products)
+ if(choice > non_contraband_product_count)
+ choice -= non_contraband_product_count
+ product = contraband_products[choice]
+ else
+ product = listed_products[choice]
var/cost = product[2]
@@ -210,6 +234,7 @@
s.start()
/obj/item/device/portable_vendor/emp_act(severity)
+ . = ..()
if (broken)
return
if (prob(40*severity))
@@ -273,4 +298,20 @@
list("AMMO", 0, null, null, null),
list("ES-4 stun magazine", 10, /obj/item/ammo_magazine/pistol/es4, "white", "Holds 19 rounds of specialized Conductive 9mm."),
+
+ list("RADIO KEYS", 0, null, null, null),
+ list("Alpha Squad", 15, /obj/item/device/encryptionkey/alpha, "white", "Radio Key for USCM Alpha Squad."),
+ list("Bravo Squad", 15, /obj/item/device/encryptionkey/bravo, "white", "Radio Key for USCM Bravo Squad."),
+ list("Charlie Squad", 15, /obj/item/device/encryptionkey/charlie, "white", "Radio Key for USCM Charlie Squad."),
+ list("Delta Squad", 15, /obj/item/device/encryptionkey/delta, "white", "Radio Key for USCM Delta Squad."),
+ list("Echo Squad", 15, /obj/item/device/encryptionkey/echo, "white", "Radio Key for USCM Echo Squad."),
+ list("Colony", 20, /obj/item/device/encryptionkey/colony, "white", "Pre-tuned Radio Key for local colony comms."),
+ )
+
+ contraband_products = list(
+ list("CONTRABAND", 0, null, null, null),
+ list("W-Y PMC", 20, /obj/item/device/encryptionkey/pmc, "white", "Radio Key for Weyland-Yutani PMC Combat Comms."),
+ list("CONTRABAND: Colonial Marshals", 40, /obj/item/device/encryptionkey/cmb, "white", "Radio Key for the CMB."),
+ list("CONTRABAND: Colonial Liberation Front", 40, /obj/item/device/encryptionkey/clf, "white", "Radio Key for known local CLF frequencies."),
+ list("CONTRABAND: Union of Progressive Peoples", 40, /obj/item/device/encryptionkey/upp, "white", "Radio Key for known UPP listening frequencies."),
)
diff --git a/code/game/objects/items/devices/radio/beacon.dm b/code/game/objects/items/devices/radio/beacon.dm
index 0b8cbc303c06..bc97cf04fdfb 100644
--- a/code/game/objects/items/devices/radio/beacon.dm
+++ b/code/game/objects/items/devices/radio/beacon.dm
@@ -27,7 +27,7 @@
set category = "Object"
set src in usr
- if ((usr.canmove && !( usr.is_mob_restrained() )))
+ if (usr.is_mob_incapacitated())
src.code = t
if (!( src.code ))
src.code = "beacon"
diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm
index 21aa96e971a1..e5c717e699f0 100644
--- a/code/game/objects/items/devices/radio/headset.dm
+++ b/code/game/objects/items/devices/radio/headset.dm
@@ -59,8 +59,8 @@
verbs += /obj/item/device/radio/headset/proc/switch_tracker_target
if(frequency)
- for(var/cycled_channel in radiochannels)
- if(radiochannels[cycled_channel] == frequency)
+ for(var/cycled_channel in GLOB.radiochannels)
+ if(GLOB.radiochannels[cycled_channel] == frequency)
default_freq = cycled_channel
/obj/item/device/radio/headset/Destroy()
@@ -183,7 +183,7 @@
/obj/item/device/radio/headset/proc/recalculateChannels()
for(var/ch_name in channels)
- SSradio.remove_object(src, radiochannels[ch_name])
+ SSradio.remove_object(src, GLOB.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
channels = list()
translate_apollo = FALSE
@@ -214,14 +214,14 @@
locate_setting = initial(locate_setting)
for (var/ch_name in channels)
- secure_radio_connections[ch_name] = SSradio.add_object(src, radiochannels[ch_name], RADIO_CHAT)
+ secure_radio_connections[ch_name] = SSradio.add_object(src, GLOB.radiochannels[ch_name], RADIO_CHAT)
SStgui.update_uis(src)
/obj/item/device/radio/headset/set_frequency(new_frequency)
..()
if(frequency)
- for(var/cycled_channel in radiochannels)
- if(radiochannels[cycled_channel] == frequency)
+ for(var/cycled_channel in GLOB.radiochannels)
+ if(GLOB.radiochannels[cycled_channel] == frequency)
default_freq = cycled_channel
/obj/item/device/radio/headset/equipped(mob/living/carbon/human/user, slot)
@@ -237,7 +237,7 @@
RegisterSignal(user, COMSIG_MOB_DEATH, PROC_REF(update_minimap_icon))
RegisterSignal(user, COMSIG_HUMAN_SET_UNDEFIBBABLE, PROC_REF(update_minimap_icon))
if(headset_hud_on)
- var/datum/mob_hud/H = huds[hud_type]
+ var/datum/mob_hud/H = GLOB.huds[hud_type]
H.add_hud_to(user, src)
//squad leader locator is no longer invisible on our player HUD.
if(user.mind && (user.assigned_squad || misc_tracking) && user.hud_used && user.hud_used.locate_leader)
@@ -256,7 +256,7 @@
COMSIG_MOB_STAT_SET_ALIVE
))
if(istype(user) && user.has_item_in_ears(src)) //dropped() is called before the inventory reference is update.
- var/datum/mob_hud/H = huds[hud_type]
+ var/datum/mob_hud/H = GLOB.huds[hud_type]
H.remove_hud_from(user, src)
//squad leader locator is invisible again
if(user.hud_used && user.hud_used.locate_leader)
@@ -288,7 +288,7 @@
if(ishuman(usr))
var/mob/living/carbon/human/user = usr
if(user.has_item_in_ears(src)) //worn
- var/datum/mob_hud/H = huds[hud_type]
+ var/datum/mob_hud/H = GLOB.huds[hud_type]
if(headset_hud_on)
H.add_hud_to(usr, src)
if(user.mind && (misc_tracking || user.assigned_squad) && user.hud_used?.locate_leader)
@@ -520,6 +520,7 @@
name = "corporate liaison radio headset"
desc = "Used by the CL to convince people to sign NDAs. Channels are as follows: :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad, :n - engineering, :m - medbay, :u - requisitions, :j - JTAC, :t - intel, :y for WY."
icon_state = "wy_headset"
+ maximum_keys = 5
initial_keys = list(/obj/item/device/encryptionkey/mcom/cl)
/obj/item/device/radio/headset/almayer/reporter
@@ -808,7 +809,7 @@
set_frequency(frequency)
for(var/ch_name in channels)
- secure_radio_connections[ch_name] = SSradio.add_object(src, radiochannels[ch_name], RADIO_CHAT)
+ secure_radio_connections[ch_name] = SSradio.add_object(src, GLOB.radiochannels[ch_name], RADIO_CHAT)
recalculateChannels()
if(H.mind && H.hud_used && H.hud_used.locate_leader) //make SL tracker visible
H.hud_used.locate_leader.alpha = 255
@@ -849,6 +850,14 @@
"Corporate Liaison" = TRACKER_CL
)
+/obj/item/device/radio/headset/distress/cbrn
+ name = "\improper CBRN headset"
+ desc = "A headset given to CBRN marines. Channels are as follows: :g - public, :v - marine command, :a - alpha squad, :b - bravo squad, :c - charlie squad, :d - delta squad, :n - engineering, :m - medbay, :u - requisitions, :j - JTAC, :t - intel"
+ frequency = CBRN_FREQ
+ initial_keys = list(/obj/item/device/encryptionkey/public, /obj/item/device/encryptionkey/mcom)
+ ignore_z = TRUE
+ has_hud = TRUE
+
/obj/item/device/radio/headset/distress/pmc/hvh
desc = "A special headset used by corporate personnel. Channels are as follows: :o - colony."
initial_keys = list(/obj/item/device/encryptionkey/colony, /obj/item/device/encryptionkey/WY)
diff --git a/code/game/objects/items/devices/radio/listening_bugs.dm b/code/game/objects/items/devices/radio/listening_bugs.dm
new file mode 100644
index 000000000000..67a91de1bd56
--- /dev/null
+++ b/code/game/objects/items/devices/radio/listening_bugs.dm
@@ -0,0 +1,276 @@
+#define DISGUISE_REMOVE "remove disguise"
+#define DISGUISE_RADIO "radio"
+#define DISGUISE_PEN "pen"
+#define DISGUISE_FOUNTAIN_PEN "fountain pen"
+#define DISGUISE_ACCESS_TUNER "access tuner"
+#define DISGUISE_WHISTLE "whistle"
+#define DISGUISE_MASS_SPEC "mass-spectrometer"
+#define DISGUISE_CAMERA "camera"
+#define DISGUISE_ZIPPO "zippo lighter"
+#define DISGUISE_TAPE_RECORDER "tape recorder"
+
+/obj/item/device/radio/listening_bug
+ name = "listening device"
+ desc = "A small, and disguisable, listening device."
+
+ icon = 'icons/obj/items/devices.dmi'
+ icon_state = "voice0"
+ item_state = "analyzer"
+
+ w_class = SIZE_TINY
+ volume = RADIO_VOLUME_RAISED
+
+ broadcasting = FALSE
+ listening = FALSE
+ frequency = BUG_A_FREQ
+ canhear_range = 2
+ freqlock = TRUE
+ /// If the bug is disguised or not.
+ var/ready_to_disguise = FALSE
+ var/disguised = FALSE
+ /// Whether or not the bug can be used to listen to its own channel.
+ var/prevent_snooping = FALSE
+ /// The ID tag of the device, for identification.
+ var/nametag = "Device"
+
+/obj/item/device/radio/listening_bug/ui_data(mob/user)
+ var/list/data = list()
+
+ data["broadcasting"] = broadcasting
+ data["listening"] = listening
+ data["frequency"] = frequency
+ data["freqlock"] = freqlock
+
+ var/list/radio_channels = list()
+
+ for(var/channel in channels)
+ var/channel_key = channel_to_prefix(channel)
+ radio_channels += list(list(
+ "name" = channel,
+ "status" = channels[channel] & FREQ_LISTENING,
+ "hotkey" = channel_key))
+
+ data["channels"] = radio_channels
+
+ data["command"] = volume
+ data["useCommand"] = use_volume
+ data["subspace"] = subspace_transmission
+ data["subspaceSwitchable"] = subspace_switchable
+ data["headset"] = FALSE
+
+ return data
+
+/obj/item/device/radio/listening_bug/ui_act(action, params, datum/tgui/ui, datum/ui_state/state)
+ switch(action)
+ if("listen")
+ if(prevent_snooping)
+ to_chat(usr, SPAN_WARNING("This device cannot receive transmissions!"))
+ return
+ listening = !listening
+ return
+ if("subspace")
+ if(!ishuman(usr))
+ return
+ var/mob/living/carbon/human/user = usr
+ if(!check_access(user.wear_id) && !check_access(user.get_active_hand()))
+ to_chat(user, SPAN_WARNING("You need an authenticated ID card to change this function!"))
+ return
+ if(subspace_switchable)
+ subspace_transmission = !subspace_transmission
+ var/initial_prevent = initial(prevent_snooping)
+ if(initial_prevent)
+ prevent_snooping = TRUE
+ if(!subspace_transmission)
+ prevent_snooping = FALSE
+ channels = list()
+ return
+ ..()
+
+/obj/item/device/radio/listening_bug/hear_talk(mob/M as mob, msg, verb = "says", datum/language/speaking = null)
+ var/processed_verb = "[SPAN_RED("\[LSTN [nametag]\]")] [verb]"
+ if(broadcasting)
+ if(get_dist(src, M) <= 7)
+ talk_into(M, msg, null, processed_verb, speaking, listening_device = TRUE)
+
+/obj/item/device/radio/listening_bug/afterattack(atom/target_atom, mob/user as mob, proximity)
+ if(!ready_to_disguise)
+ return ..()
+
+ var/obj/item/target_item = target_atom
+ if(!istype(target_item) || target_item.anchored || target_item.w_class >= SIZE_LARGE)
+ to_chat(user, SPAN_WARNING("You cannot disguise the listening device as this object."))
+ return FALSE
+
+ var/confirm = tgui_alert(user, "Are you sure you wish to disguise the listening device as '[target_item]'?", "Confirm Choice", list("Yes","No"), 20 SECONDS)
+ if(confirm != "Yes")
+ return FALSE
+
+ icon = target_item.icon
+ name = target_item.name
+ desc = target_item.desc
+ icon_state = target_item.icon_state
+ item_state = target_item.item_state
+ flags_equip_slot = target_item.flags_equip_slot
+ w_class = target_item.w_class
+ ready_to_disguise = FALSE
+ disguised = TRUE
+
+/obj/item/device/radio/listening_bug/get_examine_text(mob/user)
+ if(disguised)
+ . = list()
+ var/size
+ switch(w_class)
+ if(SIZE_TINY)
+ size = "tiny"
+ if(SIZE_SMALL)
+ size = "small"
+ if(SIZE_MEDIUM)
+ size = "normal-sized"
+ . += "This is a [blood_color ? blood_color != "#030303" ? "bloody " : "oil-stained " : ""][icon2html(src, user)][src.name]. It is a [size] item."
+ if(desc)
+ . += desc
+ if(desc_lore)
+ . += SPAN_NOTICE("This has an extended lore description.")
+ else
+ . = ..()
+ . += SPAN_INFO("[src] is set to frequency [get_bug_letter()].")
+ if(nametag != initial(nametag))
+ . += SPAN_INFO("[src]'s nametag is set to '[nametag]'")
+
+/obj/item/device/radio/listening_bug/verb/change_disguise()
+ set name = "Change Disguise"
+ set category = "Object"
+ set src in usr
+
+ if(usr.is_mob_incapacitated())
+ to_chat(usr, SPAN_WARNING("You cannot do this while incapacitated!"))
+ return FALSE
+
+ var/check = tgui_alert(usr, "Do you wish to change the disguise of this listening bug?", "Change Disguise?", list("Yes", "No"))
+ if(check != "Yes")
+ return FALSE
+ if(disguised)
+ var/remove_check = tgui_alert(usr, "Do you wish to remove the current disguise?", "Remove Disguise?", list("Yes","No"))
+ if(remove_check == "Yes")
+ icon = initial(icon)
+ name = initial(name)
+ desc = initial(desc)
+ icon_state = initial(icon_state)
+ item_state = initial(item_state)
+ flags_equip_slot = initial(flags_equip_slot)
+ w_class = initial(w_class)
+ disguised = FALSE
+ return TRUE
+
+ to_chat(usr, SPAN_HELPFUL("You can now change the disguise of the device by selecting a normal, or smaller, sized object."))
+ ready_to_disguise = TRUE
+ return TRUE
+
+/obj/item/device/radio/listening_bug/proc/get_bug_letter()
+ switch(frequency)
+ if(BUG_A_FREQ)
+ return "A"
+ if(BUG_B_FREQ)
+ return "B"
+ if(SEC_FREQ)
+ return "MP"
+ if(PVST_FREQ)
+ return "PVST"
+ if(HC_FREQ)
+ return "HC"
+ if(WY_FREQ, PMC_CCT_FREQ)
+ return "WY"
+ if(PMC_CMD_FREQ)
+ return "WYC"
+ if(UPP_CCT_FREQ, UPP_KDO_FREQ)
+ return "UPP"
+ else
+ return "X"
+
+#define OPTION_REMOVE "Remove Tag"
+#define OPTION_NEW "New Tag"
+
+/obj/item/device/radio/listening_bug/verb/set_nametag()
+ set name = "Set Nametag"
+ set category = "Object"
+ set src in usr
+
+ if(usr.is_mob_incapacitated())
+ to_chat(usr, SPAN_WARNING("You cannot do this while incapacitated!"))
+ return FALSE
+
+ var/check = tgui_alert(usr, "Do you wish to change the name tag of this listening bug?", "Change Name tag?", list("Yes", "No"))
+ if(check != "Yes")
+ return FALSE
+
+
+ var/new_nametag
+ var/remove
+ if(nametag != initial(nametag))
+ remove = tgui_alert(usr, "Do you wish to remove the current nametag?", "Remove Nametag", list("Yes", "No"))
+ if(remove == "Yes")
+ new_nametag = initial(nametag)
+ else
+ new_nametag = tgui_input_text(usr, "What new name tag do you wish to use?", "New Name", initial(nametag), 6)
+
+ if(!new_nametag || (new_nametag == nametag))
+ return FALSE
+
+ nametag = new_nametag
+ log_game("[key_name(usr)] set a listening device nametag to [new_nametag].")
+ return TRUE
+
+#undef OPTION_REMOVE
+#undef OPTION_NEW
+
+/obj/item/device/radio/listening_bug/freq_a
+ frequency = BUG_A_FREQ
+
+/obj/item/device/radio/listening_bug/freq_b
+ frequency = BUG_B_FREQ
+
+/obj/item/device/radio/listening_bug/radio_linked
+ prevent_snooping = TRUE
+ subspace_transmission = TRUE
+ subspace_switchable = TRUE
+
+/obj/item/device/radio/listening_bug/radio_linked/mp
+ frequency = SEC_FREQ
+ req_one_access = list(ACCESS_MARINE_BRIG)
+
+/obj/item/device/radio/listening_bug/radio_linked/hc
+ frequency = HC_FREQ
+ req_one_access = list(ACCESS_MARINE_CO)
+/obj/item/device/radio/listening_bug/radio_linked/hc/pvst
+ frequency = PVST_FREQ
+
+/obj/item/device/radio/listening_bug/radio_linked/wy
+ frequency = WY_FREQ
+ req_one_access = list(ACCESS_WY_EXEC, ACCESS_WY_SECURITY)
+
+/obj/item/device/radio/listening_bug/radio_linked/wy/pmc
+ frequency = PMC_CCT_FREQ
+ req_one_access = list(ACCESS_WY_EXEC, ACCESS_WY_SECURITY)
+
+/obj/item/device/radio/listening_bug/radio_linked/upp
+ frequency = UPP_CCT_FREQ
+ req_one_access = list(ACCESS_UPP_COMMANDO, ACCESS_UPP_SECURITY)
+
+/obj/item/device/radio/listening_bug/radio_linked/upp/commando
+ frequency = UPP_KDO_FREQ
+ req_one_access = list(ACCESS_UPP_COMMANDO)
+
+
+// ENCRYPTION KEYS FOR LISTENING IN!
+//REQURIES SUBSPACE ACTIVATION ON THE BUGS FIRST!
+/obj/item/device/encryptionkey/listening_bug
+ desc = "A small encryption key for listening to a secret broadcasting device! Unlikely to work if the device is not using subspace communications!"
+ icon_state = "stripped_key"
+
+/obj/item/device/encryptionkey/listening_bug/freq_a
+ name = "Listening Bug Encryption Key (A)"
+ channels = list(RADIO_CHANNEL_BUG_A = TRUE)
+
+/obj/item/device/encryptionkey/listening_bug/freq_b
+ name = "Listening Bug Encryption Key (B)"
+ channels = list(RADIO_CHANNEL_BUG_B = TRUE)
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index 2092ffa108c6..43eb1810d700 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -73,7 +73,7 @@
set_frequency(frequency)
for (var/ch_name in channels)
- secure_radio_connections[ch_name] = SSradio.add_object(src, radiochannels[ch_name], RADIO_CHAT)
+ secure_radio_connections[ch_name] = SSradio.add_object(src, GLOB.radiochannels[ch_name], RADIO_CHAT)
flags_atom |= USES_HEARING
@@ -206,7 +206,7 @@
// If we were to send to a channel we don't have, drop it.
return null
-/obj/item/device/radio/talk_into(mob/living/M as mob, message, channel, verb = "says", datum/language/speaking = null)
+/obj/item/device/radio/talk_into(mob/living/M as mob, message, channel, verb = "says", datum/language/speaking = null, listening_device = FALSE)
if(!on) return // the device has to be on
// Fix for permacell radios, but kinda eh about actually fixing them.
if(!M || !message) return
@@ -297,11 +297,11 @@
if(use_volume)
Broadcast_Message(connection, M, voicemask, pick(M.speak_emote),
src, message, displayname, jobname, real_name, M.voice_name,
- filter_type, 0, target_zs, connection.frequency, verb, speaking, volume)
+ filter_type, 0, target_zs, connection.frequency, verb, speaking, volume, listening_device)
else
Broadcast_Message(connection, M, voicemask, pick(M.speak_emote),
src, message, displayname, jobname, real_name, M.voice_name,
- filter_type, 0, target_zs, connection.frequency, verb, speaking, RADIO_VOLUME_QUIET)
+ filter_type, 0, target_zs, connection.frequency, verb, speaking, RADIO_VOLUME_QUIET, listening_device)
/obj/item/device/radio/proc/get_target_zs(frequency)
var/turf/position = get_turf(src)
@@ -425,11 +425,11 @@
else return
/obj/item/device/radio/emp_act(severity)
+ . = ..()
broadcasting = FALSE
listening = FALSE
for (var/ch_name in channels)
channels[ch_name] = 0
- ..()
///////////////////////////////
//////////Borg Radios//////////
@@ -461,7 +461,7 @@
for(var/ch_name in channels)
- SSradio.remove_object(src, radiochannels[ch_name])
+ SSradio.remove_object(src, GLOB.radiochannels[ch_name])
secure_radio_connections[ch_name] = null
@@ -509,7 +509,7 @@
src.channels[ch_name] += keyslot.channels[ch_name]
for (var/ch_name in src.channels)
- secure_radio_connections[ch_name] = SSradio.add_object(src, radiochannels[ch_name], RADIO_CHAT)
+ secure_radio_connections[ch_name] = SSradio.add_object(src, GLOB.radiochannels[ch_name], RADIO_CHAT)
SStgui.update_uis(src)
@@ -563,11 +563,11 @@
/obj/item/device/radio/proc/config(op)
for (var/ch_name in channels)
- SSradio.remove_object(src, radiochannels[ch_name])
+ SSradio.remove_object(src, GLOB.radiochannels[ch_name])
secure_radio_connections = new
channels = op
for (var/ch_name in op)
- secure_radio_connections[ch_name] = SSradio.add_object(src, radiochannels[ch_name], RADIO_CHAT)
+ secure_radio_connections[ch_name] = SSradio.add_object(src, GLOB.radiochannels[ch_name], RADIO_CHAT)
/obj/item/device/radio/off
listening = 0
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index 38ff8859ef97..512ca8baad9b 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -457,6 +457,16 @@ FORENSIC SCANNER
playsound(user, 'sound/machines/twobeep.ogg', 15, TRUE)
to_chat(user, SPAN_NOTICE("You scan [hit_atom] and notice a reading on [src]'s pad, it says: ITEM HAS [market_value] VALUE "))
+/obj/item/device/black_market_hacking_device
+ name = "modified security access tuner"
+ desc = "A security access tuner with wires and electrical pins sticking out at odd angles. A handwritten label on the bottom says something about the ASRS system."
+ icon_state = "bm_hacker"
+ item_state = "analyzer"
+ w_class = SIZE_SMALL
+ flags_atom = FPRINT
+ flags_equip_slot = SLOT_WAIST
+ inherent_traits = list(TRAIT_TOOL_BLACKMARKET_HACKER)
+
/obj/item/device/cmb_black_market_tradeband
name = "\improper CMB Tradeband Compliance Device"
desc = "A device used to reset any tampering done to trading devices' signal range. Occasionally used to fix any signal chips damaged in an accident, but often for malpractice in trading. Use this with caution, as it will also reset any evidence of potential illicit trade. Created to fulfill a joint-organization requirement for CMB-ICC teams on the frontier, where tampered machinery was difficult to move and refurbish. Smugglers beware."
diff --git a/code/game/objects/items/devices/suit_cooling.dm b/code/game/objects/items/devices/suit_cooling.dm
index d388e06b9fa7..e0f65a4b31ec 100644
--- a/code/game/objects/items/devices/suit_cooling.dm
+++ b/code/game/objects/items/devices/suit_cooling.dm
@@ -110,7 +110,7 @@
cell.add_fingerprint(user)
cell.update_icon()
- to_chat(user, "You remove the [src.cell].")
+ to_chat(user, "You remove [cell].")
src.cell = null
updateicon()
return
@@ -121,7 +121,7 @@
else
turn_on()
if (on)
- to_chat(user, "You switch on the [src].")
+ to_chat(user, "You switch on [src].")
/obj/item/device/suit_cooling_unit/attackby(obj/item/W as obj, mob/user as mob)
if (HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER))
@@ -137,12 +137,12 @@
if (istype(W, /obj/item/cell))
if(cover_open)
if(cell)
- to_chat(user, "There is a [cell] already installed here.")
+ to_chat(user, "There is \a [cell] already installed here.")
else
if(user.drop_held_item())
W.forceMove(src)
cell = W
- to_chat(user, "You insert the [cell].")
+ to_chat(user, "You insert [cell].")
updateicon()
return
@@ -169,7 +169,7 @@
if (cover_open)
if(cell)
- . += "The panel is open, exposing the [cell]."
+ . += "The panel is open, exposing [cell]."
else
. += "The panel is open."
diff --git a/code/game/objects/items/devices/taperecorder.dm b/code/game/objects/items/devices/taperecorder.dm
index 01567084d5c7..9fe3521d858b 100644
--- a/code/game/objects/items/devices/taperecorder.dm
+++ b/code/game/objects/items/devices/taperecorder.dm
@@ -168,7 +168,7 @@
mytape.timestamp += mytape.used_capacity
var/language_known = (M.universal_speak || (speaking && (speaking.name in known_languages)))
var/mob_name = language_known ? M.GetVoice() : "Unknown"
- var/message = language_known ? msg : speaking.scramble(msg)
+ var/message = (!speaking || language_known) ? msg : speaking.scramble(msg)
mytape.storedinfo += "\[[time2text(mytape.used_capacity,"mm:ss")]\] [mob_name] [verb], \"[italics ? "" : null][message][italics ? "" : null]\""
@@ -261,7 +261,7 @@
audible_message(SPAN_MAROON("[icon2html(src, usr)] End of recording."))
break
- var/list/heard = get_mobs_in_view(world_view_size, src)
+ var/list/heard = get_mobs_in_view(GLOB.world_view_size, src)
langchat_speech(mytape.storedinfo[i], heard, GLOB.all_languages, skip_language_check = TRUE, additional_styles = list("langchat_small"))
audible_message(SPAN_MAROON("[icon2html(src, usr)] [mytape.storedinfo[i]]"))//We want to display this properly, don't double encode
diff --git a/code/game/objects/items/devices/teleportation.dm b/code/game/objects/items/devices/teleportation.dm
index 72a5c970b18f..8dea3b872cd1 100644
--- a/code/game/objects/items/devices/teleportation.dm
+++ b/code/game/objects/items/devices/teleportation.dm
@@ -48,8 +48,8 @@
if (usr.stat || usr.is_mob_restrained())
return
var/turf/current_location = get_turf(usr)//What turf is the user on?
- if(!current_location || is_admin_level(current_location.z))//If turf was not found or they're on z level 2.
- to_chat(usr, "The [src] is malfunctioning.")
+ if(!current_location || should_block_game_interaction(current_location))//If turf was not found or they're on z level 2.
+ to_chat(usr, "[src] is malfunctioning.")
return
if ((usr.contents.Find(src) || (in_range(src, usr) && istype(src.loc, /turf))))
usr.set_interaction(src)
@@ -140,11 +140,11 @@
..()
var/turf/current_location = get_turf(user)//What turf is the user on?
- if(!current_location || is_admin_level(current_location.z))//If turf was not found or they're on z level 2
+ if(!current_location || should_block_game_interaction(current_location))//If turf was not found or they're on z level 2
to_chat(user, SPAN_NOTICE("\The [src] is malfunctioning."))
return
var/list/L = list( )
- for(var/obj/structure/machinery/teleport/hub/R in machines)
+ for(var/obj/structure/machinery/teleport/hub/R in GLOB.machines)
var/obj/structure/machinery/computer/teleporter/com = locate(/obj/structure/machinery/computer/teleporter, locate(R.x - 2, R.y, R.z))
if (istype(com, /obj/structure/machinery/computer/teleporter) && com.locked && !com.one_time_use)
if(R.icon_state == "tele1")
@@ -177,4 +177,3 @@
P.creator = src
src.add_fingerprint(user)
return
-
diff --git a/code/game/objects/items/devices/transfer_valve.dm b/code/game/objects/items/devices/transfer_valve.dm
index b3d433727946..6fc526936809 100644
--- a/code/game/objects/items/devices/transfer_valve.dm
+++ b/code/game/objects/items/devices/transfer_valve.dm
@@ -47,7 +47,7 @@
user.temp_drop_inv_item(A)
attached_device = A
A.forceMove(src)
- to_chat(user, SPAN_NOTICE("You attach the [item] to the valve controls and secure it."))
+ to_chat(user, SPAN_NOTICE("You attach [item] to the valve controls and secure it."))
A.holder = src
A.toggle_secure() //this calls update_icon(), which calls update_icon() on the holder (i.e. the bomb).
diff --git a/code/game/objects/items/explosives/explosive.dm b/code/game/objects/items/explosives/explosive.dm
index 0c482e8db9e7..4483372c9b85 100644
--- a/code/game/objects/items/explosives/explosive.dm
+++ b/code/game/objects/items/explosives/explosive.dm
@@ -262,8 +262,8 @@
if(falloff_mode == EXPLOSION_FALLOFF_SHAPE_LINEAR)
falloff_mode = EXPLOSION_FALLOFF_SHAPE_EXPONENTIAL
- to_chat(usr, SPAN_NOTICE("You enable the [src]'s blast wave dampener, limiting the blast radius."))
+ to_chat(usr, SPAN_NOTICE("You enable [src]'s blast wave dampener, limiting the blast radius."))
else
falloff_mode = EXPLOSION_FALLOFF_SHAPE_LINEAR
- to_chat(usr, SPAN_NOTICE("You disable the [src]'s blast wave dampener, restoring the blast radius to full."))
+ to_chat(usr, SPAN_NOTICE("You disable [src]'s blast wave dampener, restoring the blast radius to full."))
playsound(loc, 'sound/items/Screwdriver2.ogg', 25, 0, 6)
diff --git a/code/game/objects/items/explosives/grenades/chem_grenade.dm b/code/game/objects/items/explosives/grenades/chem_grenade.dm
index e975603d45d8..48430aacecc9 100644
--- a/code/game/objects/items/explosives/grenades/chem_grenade.dm
+++ b/code/game/objects/items/explosives/grenades/chem_grenade.dm
@@ -1,5 +1,5 @@
/obj/item/explosive/grenade/custom
- name = "Custom grenade"
+ name = "custom grenade"
icon_state = "grenade_custom"
desc = "A custom chemical grenade with an M40 casing. This one is made to fit into underslung grenade launchers, but can also be thrown by hand."
w_class = SIZE_SMALL
@@ -17,7 +17,7 @@
..()
/obj/item/explosive/grenade/custom/large
- name = "Large Custom Grenade"
+ name = "large custom grenade"
desc = "A custom chemical grenade with an M15 casing. This casing has a higher explosive capacity than the M40 variant."
icon_state = "large_grenade_custom"
allowed_containers = list(/obj/item/reagent_container/glass)
@@ -33,7 +33,7 @@
/obj/item/explosive/grenade/custom/metal_foam
- name = "Metal-Foam Grenade"
+ name = "metal-foam grenade"
desc = "Used for emergency sealing of air breaches."
assembly_stage = ASSEMBLY_LOCKED
harmful = FALSE
@@ -56,7 +56,7 @@
update_icon()
/obj/item/explosive/grenade/custom/incendiary
- name = "Incendiary Grenade"
+ name = "incendiary grenade"
desc = "Used for clearing rooms of living things."
assembly_stage = ASSEMBLY_LOCKED
has_blast_wave_dampener = FALSE
@@ -79,7 +79,7 @@
update_icon()
/obj/item/explosive/grenade/custom/flare
- name = "M40-F flare grenade"
+ name = "\improper M40-F flare grenade"
desc = "Chemical flare in a grenade form, designed for compatibility with most standard issue launchers."
assembly_stage = ASSEMBLY_LOCKED
has_blast_wave_dampener = FALSE
@@ -103,7 +103,7 @@
update_icon()
/obj/item/explosive/grenade/custom/large/flare
- name = "M15-F flare grenade"
+ name = "\improper M15-F flare grenade"
desc = "Chemical flare in a grenade form, expanded variant. The casing is too large to fit most launchers."
assembly_stage = ASSEMBLY_LOCKED
has_blast_wave_dampener = FALSE
diff --git a/code/game/objects/items/explosives/grenades/flashbang.dm b/code/game/objects/items/explosives/grenades/flashbang.dm
index 365dfe26df89..50cb34668ae3 100644
--- a/code/game/objects/items/explosives/grenades/flashbang.dm
+++ b/code/game/objects/items/explosives/grenades/flashbang.dm
@@ -256,6 +256,7 @@
//decide how banged mob is
var/bang_effect = 0
+ var/lying = H.body_position == LYING_DOWN
//flashbang effect depends on eye protection only, so we will process this case first
//A bit dumb, but headsets don't have ear protection and even earmuffs are a fluff now
@@ -264,7 +265,7 @@
if((get_dist(H, T) <= 1 || src.loc == H.loc || src.loc == H))
H.apply_damage(5, BRUTE)
H.apply_damage(5, BURN)
- if(H.lying)
+ if(lying)
bang_effect = 1
else
bang_effect = 2
@@ -277,13 +278,13 @@
H.apply_damage(5, BRUTE)
H.apply_damage(5, BURN)
- if(H.lying)
+ if(lying)
bang_effect = 4
else
bang_effect = 5
else if(get_dist(H, T) <= 5)
- if(H.lying)
+ if(lying)
bang_effect = 3
else
bang_effect = 4
diff --git a/code/game/objects/items/explosives/grenades/grenade.dm b/code/game/objects/items/explosives/grenades/grenade.dm
index 7e98e9819931..6b793233678d 100644
--- a/code/game/objects/items/explosives/grenades/grenade.dm
+++ b/code/game/objects/items/explosives/grenades/grenade.dm
@@ -20,12 +20,12 @@
var/hand_throwable = TRUE
harmful = TRUE //Is it harmful? Are they banned for synths?
antigrief_protection = TRUE //Should it be checked by antigrief?
+ ground_offset_x = 7
+ ground_offset_y = 6
/obj/item/explosive/grenade/Initialize()
. = ..()
det_time = max(0, rand(det_time - 5, det_time + 5))
- pixel_y = rand(-6, 6)
- pixel_x = rand(-7, 7)
/obj/item/explosive/grenade/proc/can_use_grenade(mob/living/carbon/human/user)
if(!hand_throwable)
diff --git a/code/game/objects/items/explosives/mine.dm b/code/game/objects/items/explosives/mine.dm
index 742a5f314c4a..768a32c003fa 100644
--- a/code/game/objects/items/explosives/mine.dm
+++ b/code/game/objects/items/explosives/mine.dm
@@ -42,6 +42,7 @@
prime() //We don't care about how strong the explosion was.
/obj/item/explosive/mine/emp_act()
+ . = ..()
prime() //Same here. Don't care about the effect strength.
@@ -122,7 +123,7 @@
if(prob(75))
triggered = TRUE
if(tripwire)
- var/direction = reverse_dir[src.dir]
+ var/direction = GLOB.reverse_dir[src.dir]
var/step_direction = get_step(src, direction)
tripwire.forceMove(step_direction)
prime()
@@ -240,7 +241,7 @@
//We move the tripwire randomly in either of the four cardinal directions
triggered = TRUE
if(tripwire)
- var/direction = pick(cardinal)
+ var/direction = pick(GLOB.cardinals)
var/step_direction = get_step(src, direction)
tripwire.forceMove(step_direction)
prime()
@@ -308,7 +309,7 @@
map_deployed = TRUE
/obj/item/explosive/mine/custom
- name = "Custom mine"
+ name = "custom mine"
desc = "A custom chemical mine built from an M20 casing."
icon_state = "m20_custom"
customizable = TRUE
diff --git a/code/game/objects/items/explosives/plastic.dm b/code/game/objects/items/explosives/plastic.dm
index 830df9659070..071ff3458a91 100644
--- a/code/game/objects/items/explosives/plastic.dm
+++ b/code/game/objects/items/explosives/plastic.dm
@@ -26,7 +26,7 @@
/obj/item/explosive/plastic/Destroy()
disarm()
- . = ..()
+ return ..()
/obj/item/explosive/plastic/explosion_throw(severity, direction, scatter_multiplier)
if(active)
@@ -156,7 +156,9 @@
plant_target.overlays -= overlay
qdel(overlay)
plant_target.contents -= src
- forceMove(get_turf(plant_target))
+ var/turf/plant_turf = get_turf(plant_target)
+ if(plant_turf)
+ forceMove(plant_turf)
plant_target = null
if(customizable)
if(active) //deactivate
@@ -182,7 +184,7 @@
//vehicle interior stuff checks
if(SSinterior.in_interior(target))
- to_chat(user, SPAN_WARNING("It's too cramped in here to deploy \the [src]."))
+ to_chat(user, SPAN_WARNING("It's too cramped in here to deploy [src]."))
return FALSE
if(istype(target, /obj/effect) || istype(target, /obj/structure/machinery))
@@ -193,7 +195,7 @@
if(istype(target, /turf/closed/wall))
var/turf/closed/wall/W = target
if(W.hull)
- to_chat(user, SPAN_WARNING("You are unable to stick \the [src] to the [W]!"))
+ to_chat(user, SPAN_WARNING("You are unable to stick [src] to [W]!"))
return FALSE
if(istype(target, /obj/structure/window))
@@ -299,7 +301,7 @@
prime(TRUE)
/obj/item/explosive/plastic/custom
- name = "Custom plastic explosive"
+ name = "custom plastic explosive"
desc = "A custom plastic explosive."
icon_state = "custom_plastic_explosive"
overlay_image = "custom_plastic_explosive_sensing"
diff --git a/code/game/objects/items/explosives/warhead.dm b/code/game/objects/items/explosives/warhead.dm
index 5dfdf2a41eac..9825d7483193 100644
--- a/code/game/objects/items/explosives/warhead.dm
+++ b/code/game/objects/items/explosives/warhead.dm
@@ -2,11 +2,8 @@
icon = 'icons/obj/items/weapons/grenade.dmi'
customizable = TRUE
allowed_sensors = list() //We only need a detonator
-
-/obj/item/explosive/warhead/Initialize(mapload, ...)
- . = ..()
- pixel_y = rand(-6, 6)
- pixel_x = rand(-7, 7)
+ ground_offset_x = 7
+ ground_offset_y = 6
/obj/item/explosive/warhead/rocket
name = "84mm rocket warhead"
diff --git a/code/game/objects/items/frames/alarms.dm b/code/game/objects/items/frames/alarms.dm
index f34b18d6825c..d665df65fc83 100644
--- a/code/game/objects/items/frames/alarms.dm
+++ b/code/game/objects/items/frames/alarms.dm
@@ -24,7 +24,7 @@ Code shamelessly copied from apc_frame
return
var/ndir = get_dir(on_wall,usr)
- if (!(ndir in cardinal))
+ if (!(ndir in GLOB.cardinals))
return
var/turf/loc = get_turf(usr)
@@ -67,7 +67,7 @@ Code shamelessly copied from apc_frame
return
var/ndir = get_dir(on_wall,usr)
- if (!(ndir in cardinal))
+ if (!(ndir in GLOB.cardinals))
return
var/turf/loc = get_turf(usr)
diff --git a/code/game/objects/items/frames/camera.dm b/code/game/objects/items/frames/camera.dm
index e367e64e641d..efe697c3944b 100644
--- a/code/game/objects/items/frames/camera.dm
+++ b/code/game/objects/items/frames/camera.dm
@@ -105,9 +105,9 @@
C.auto_turn()
C.network = uniquelist(tempnetwork)
- tempnetwork = difflist(C.network,RESTRICTED_CAMERA_NETWORKS)
+ tempnetwork = difflist(C.network,GLOB.RESTRICTED_CAMERA_NETWORKS)
if(!tempnetwork.len)//Camera isn't on any open network - remove its chunk from AI visibility.
- cameranet.removeCamera(C)
+ GLOB.cameranet.removeCamera(C)
C.c_tag = input
@@ -167,7 +167,7 @@
to_chat(user, SPAN_WARNING("\The [WT] needs to be on!"))
return 0
- to_chat(user, SPAN_NOTICE("You start to weld the [src].."))
+ to_chat(user, SPAN_NOTICE("You start to weld [src].."))
playsound(src.loc, 'sound/items/Welder.ogg', 25, 1)
WT.eyecheck(user)
if(do_after(user, 20, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
diff --git a/code/game/objects/items/frames/frame.dm b/code/game/objects/items/frames/frame.dm
index 9c039821cb75..06b1c14e46c8 100644
--- a/code/game/objects/items/frames/frame.dm
+++ b/code/game/objects/items/frames/frame.dm
@@ -23,7 +23,7 @@
if (get_dist(on_wall,usr)>1)
return
var/ndir = get_dir(usr,on_wall)
- if (!(ndir in cardinal))
+ if (!(ndir in GLOB.cardinals))
return
var/turf/loc = get_turf(usr)
var/area/A = get_area(loc)
diff --git a/code/game/objects/items/frames/light_fixtures.dm b/code/game/objects/items/frames/light_fixtures.dm
index 35f800f28fac..b52e19492cab 100644
--- a/code/game/objects/items/frames/light_fixtures.dm
+++ b/code/game/objects/items/frames/light_fixtures.dm
@@ -21,7 +21,7 @@
if (get_dist(on_wall,usr)>1)
return
var/ndir = get_dir(usr,on_wall)
- if (!(ndir in cardinal))
+ if (!(ndir in GLOB.cardinals))
return
var/turf/loc = get_turf(usr)
if (!istype(loc, /turf/open/floor))
diff --git a/code/game/objects/items/fulton.dm b/code/game/objects/items/fulton.dm
index 98987d1cd2b3..788613cf4c6e 100644
--- a/code/game/objects/items/fulton.dm
+++ b/code/game/objects/items/fulton.dm
@@ -1,7 +1,7 @@
// Fulton baloon deployment devices, used to gather and send crates, dead things, and other objective-based items into space for collection.
/// A list of fultons currently airborne.
-var/global/list/deployed_fultons = list()
+GLOBAL_LIST_EMPTY(deployed_fultons)
/obj/item/stack/fulton
name = "fulton recovery device"
@@ -36,7 +36,7 @@ var/global/list/deployed_fultons = list()
attached_atom = null
if(original_location)
original_location = null
- deployed_fultons -= src
+ GLOB.deployed_fultons -= src
. = ..()
/obj/item/stack/fulton/update_icon()
@@ -90,7 +90,7 @@ var/global/list/deployed_fultons = list()
var/mob/living/carbon/human/H = target_atom
if(isyautja(H) && H.stat == DEAD)
can_attach = TRUE
- else if((H.stat != DEAD || H.mind && H.check_tod() && H.is_revivable()))
+ else if((H.stat != DEAD || H.check_tod() && H.is_revivable()))
to_chat(user, SPAN_WARNING("You can't attach [src] to [target_atom], they still have a chance!"))
return
else
@@ -154,7 +154,7 @@ var/global/list/deployed_fultons = list()
attached_atom.forceMove(space_tile)
forceMove(attached_atom)
- deployed_fultons += src
+ GLOB.deployed_fultons += src
attached_atom.overlays -= I
addtimer(CALLBACK(src, PROC_REF(return_fulton), original_location), 150 SECONDS)
@@ -169,11 +169,11 @@ var/global/list/deployed_fultons = list()
attached_atom.anchored = FALSE
playsound(attached_atom.loc,'sound/effects/bamf.ogg', 50, 1)
- if(intel_system)
+ if(GLOB.intel_system)
if (!LAZYISIN(GLOB.failed_fultons, attached_atom))
//Giving marines an objective to retrieve that fulton (so they'd know what they lost and where)
var/datum/cm_objective/retrieve_item/fulton/objective = new /datum/cm_objective/retrieve_item/fulton(attached_atom)
- intel_system.store_single_objective(objective)
+ GLOB.intel_system.store_single_objective(objective)
qdel(reservation)
qdel(src)
diff --git a/code/game/objects/items/handcuffs.dm b/code/game/objects/items/handcuffs.dm
index 71fb02cf3f07..2137b41d86bf 100644
--- a/code/game/objects/items/handcuffs.dm
+++ b/code/game/objects/items/handcuffs.dm
@@ -29,20 +29,6 @@
if(!C.handcuffed)
place_handcuffs(C, user)
-/obj/item/handcuffs/obj/structure/MouseDrop(mob/living/carbon/human/H)
- var/mob/living/carbon/human/user = usr
- if (!istype(user))
- return
- if (user.stat || get_dist(user, src) > 1 || get_dist(user, H) > 1 || H.lying)
- return
- if (!istype(H))
- return
-
- if(!do_after(user, cuff_delay, INTERRUPT_ALL, BUSY_ICON_HOSTILE, H, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
- return
-
- // TODO: apply handcuffs
-
/obj/item/handcuffs/get_mob_overlay(mob/user_mob, slot)
var/image/ret = ..()
diff --git a/code/game/objects/items/handheld_distress_beacon.dm b/code/game/objects/items/handheld_distress_beacon.dm
index d3f99134cd23..c11a7a57c350 100644
--- a/code/game/objects/items/handheld_distress_beacon.dm
+++ b/code/game/objects/items/handheld_distress_beacon.dm
@@ -1,12 +1,21 @@
///handheld distress beacons used by goon chem retrieval team to call for PMC back up
/obj/item/handheld_distress_beacon
- name = "handheld distress beacon"
+ name = "\improper PMC handheld distress beacon"
desc = "A standard handheld distress beacon. Generally used by teams who may be out of regular communications range but must signal for assistance. This one is branded with a Weyland Yutani symbol and sold en masse to colonies across the Neroid Sector."
icon = 'icons/obj/items/handheld_distress_beacon.dmi'
icon_state = "beacon_inactive"
w_class = SIZE_SMALL
+ ///The beacons faction that will be sent in message_admins
+ var/beacon_type = "PMC beacon"
+ ///Tells the user who the beacon will be sent to IC
+ var/recipient = "the USCSS Royce"
+ ///The name of the ERT that will be passed to get_specific_call
+ var/list/ert_full_name = list("Weyland-Yutani PMC (Chemical Investigation Squad)")
+ ///The clickable version that will be sent in message_admins
+ var/list/ert_short_name = list("SEND PMCs")
+ ///Whether beacon can be used, or has already been used
var/active = FALSE
/obj/item/handheld_distress_beacon/get_examine_text(mob/user)
@@ -20,8 +29,8 @@
if(active)
icon_state = "beacon_active"
- else
- icon_state = initial(icon_state)
+ return
+ icon_state = initial(icon_state)
/obj/item/handheld_distress_beacon/attack_self(mob/user)
. = ..()
@@ -29,12 +38,29 @@
if(active)
to_chat(user, "[src] is already active!")
return
-
- for(var/client/C in GLOB.admins)
- if((R_ADMIN|R_MOD) & C.admin_holder.rights)
- playsound_client(C,'sound/effects/sos-morse-code.ogg',10)
- message_admins("[key_name(user)] has requested a PMC Distress Beacon! [CC_MARK(user)] (SEND) (DENY) [ADMIN_JMP_USER(user)] [CC_REPLY(user)]")
- to_chat(user, SPAN_NOTICE("A distress beacon request has been sent to the USCSS Royce."))
-
active = TRUE
update_icon()
+
+ if(!ert_full_name || !ert_short_name || (length(ert_full_name) != length(ert_short_name))) //Make sure they are greater than 0, and both are same length
+ to_chat(user, SPAN_BOLDWARNING("[src] is broken!"))
+ CRASH("[src] was improperly set, and has been disabled.") //For the runtime logs
+
+ var/beacon_call_buttons
+ for(var/current_ert_num in 1 to length(ert_full_name))
+ beacon_call_buttons += "([ert_short_name[current_ert_num]]) "
+
+ for(var/client/admin_client in GLOB.admins)
+ if((R_ADMIN|R_MOD) & admin_client.admin_holder.rights)
+ playsound_client(admin_client,'sound/effects/sos-morse-code.ogg',10)
+ message_admins("[key_name(user)] has used a [beacon_type]! [CC_MARK(user)] [beacon_call_buttons](DENY) [ADMIN_JMP_USER(user)] [CC_REPLY(user)]")
+ to_chat(user, SPAN_NOTICE("A distress beacon request has been sent to [recipient]."))
+
+/// CMB distress beacon held by CMB Marshal for signalling distress to Anchorpoint Station
+/obj/item/handheld_distress_beacon/cmb
+ name = "\improper CMB handheld distress beacon"
+ desc = "An emergency beacon. This one is branded with a Colonial Marshal Bureau star and 'ANCHORPOINT STATION' is etched in stencil on the side. This device is issued to CMB Marshals and features an extended relay antenna."
+
+ beacon_type = "CMB beacon"
+ recipient = "Anchorpoint Station"
+ ert_full_name = list("CMB - Patrol Team - Marshals in Distress (Friendly)", "CMB - Anchorpoint Station Colonial Marine QRF (Friendly)")
+ ert_short_name = list("SEND CMB", "SEND QRF")
diff --git a/code/game/objects/items/hoverpack.dm b/code/game/objects/items/hoverpack.dm
index c2bfacd3c3ad..027b9d77f581 100644
--- a/code/game/objects/items/hoverpack.dm
+++ b/code/game/objects/items/hoverpack.dm
@@ -184,7 +184,7 @@
warning.forceMove(path[max_distance])
/obj/item/hoverpack/proc/can_use_hoverpack(mob/living/carbon/human/user)
- if(user.is_mob_incapacitated() || user.lying)
+ if(user.is_mob_incapacitated())
to_chat(user, SPAN_WARNING("You're a bit too incapacitated for that."))
return FALSE
@@ -204,7 +204,7 @@
/datum/action/item_action/hover/can_use_action()
var/mob/living/carbon/human/H = owner
- if(!H.is_mob_incapacitated() && !H.lying && holder_item == H.back)
+ if(!H.is_mob_incapacitated() && holder_item == H.back)
return TRUE
/datum/action/item_action/hover/action_activate()
diff --git a/code/game/objects/items/implants/implant.dm b/code/game/objects/items/implants/implant.dm
index d39b7e675452..e7ebe0391fae 100644
--- a/code/game/objects/items/implants/implant.dm
+++ b/code/game/objects/items/implants/implant.dm
@@ -82,6 +82,7 @@ Implant Specifics: "}
return dat
/obj/item/implant/tracking/emp_act(severity)
+ . = ..()
if (malfunction) //no, dawg, you can't malfunction while you are malfunctioning
return
malfunction = MALFUNCTION_TEMPORARY
@@ -216,6 +217,7 @@ Implant Specifics: "}
return 1
/obj/item/implant/explosive/emp_act(severity)
+ . = ..()
if (malfunction)
return
malfunction = MALFUNCTION_TEMPORARY
@@ -307,6 +309,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
return
/obj/item/implant/chem/emp_act(severity)
+ . = ..()
if (malfunction)
return
malfunction = MALFUNCTION_TEMPORARY
@@ -432,6 +435,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
STOP_PROCESSING(SSobj, src)
/obj/item/implant/death_alarm/emp_act(severity) //for some reason alarms stop going off in case they are emp'd, even without this
+ . = ..()
if (malfunction) //so I'm just going to add a meltdown chance here
return
malfunction = MALFUNCTION_TEMPORARY
diff --git a/code/game/objects/items/implants/implantneurostim.dm b/code/game/objects/items/implants/implantneurostim.dm
index a46cc31a2ca4..21ee2542649b 100644
--- a/code/game/objects/items/implants/implantneurostim.dm
+++ b/code/game/objects/items/implants/implantneurostim.dm
@@ -63,7 +63,7 @@
var/mob_pain_msg = "Excruciating pain shoots through [part ? "your [part.display_name]" : "you"]!"
M.visible_message(SPAN_DANGER("[M] convulses in pain!"), SPAN_DANGER(mob_pain_msg))
M.flash_eyes(1, TRUE)
- M.stunned += 10
+ M.apply_effect(10, STUN)
M.apply_effect(10, WEAKEN)
M.apply_damage(100, HALLOSS, part)
M.apply_damage(5, BURN, part, 0, 0, src)
@@ -105,6 +105,7 @@
/obj/item/implant/neurostim/emp_act(severity)
+ . = ..()
if (malfunction)
return
if (prob(80))
diff --git a/code/game/objects/items/lightstick.dm b/code/game/objects/items/lightstick.dm
index 70418049994b..05f5a96c5b16 100644
--- a/code/game/objects/items/lightstick.dm
+++ b/code/game/objects/items/lightstick.dm
@@ -8,7 +8,7 @@
icon = 'icons/obj/items/lighting.dmi'
icon_state = "lightstick_blue0"
light_range = 2
- light_color = COLOUR_BLUE
+ light_color = COLOR_BLUE
var/s_color = "blue"
var/trample_chance = 30
var/can_trample = TRUE
@@ -22,7 +22,7 @@
/obj/item/lightstick/Crossed(mob/living/O)
if(anchored && prob(trample_chance) && can_trample)
if(!istype(O,/mob/living/carbon/xenomorph/larva))
- visible_message(SPAN_DANGER("[O] tramples the [src]!"))
+ visible_message(SPAN_DANGER("[O] tramples [src]!"))
playsound(src, 'sound/weapons/Genhit.ogg', 25, 1)
if(istype(O,/mob/living/carbon/xenomorph))
if(prob(40))
@@ -46,17 +46,17 @@
if(!anchored)//If planted
return
- to_chat(user, "You start pulling out \the [src].")
- if(!do_after(user,20, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
+ to_chat(user, "You start pulling out [src].")
+ if(!do_after(user, 2 SECONDS, INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
return
anchored = FALSE
- user.visible_message("[user.name] removes \the [src] from the ground.","You remove the [src] from the ground.")
+ user.visible_message("[user.name] removes [src] from the ground.", "You remove [src] from the ground.")
icon_state = "lightstick_[s_color][anchored]"
set_light(0)
pixel_x = 0
pixel_y = 0
- playsound(user, 'sound/weapons/Genhit.ogg', 25, 1)
+ playsound(user, 'sound/weapons/Genhit.ogg', 25, TRUE)
//Red
/obj/item/lightstick/planted
@@ -68,7 +68,7 @@
name = "red lightstick"
icon_state = "lightstick_red0"
s_color = "red"
- light_color = COLOUR_RED
+ light_color = COLOR_RED
/obj/item/lightstick/red/planted
icon_state = "lightstick_red1"
diff --git a/code/game/objects/items/misc.dm b/code/game/objects/items/misc.dm
index abd8404d6e25..1699cb24ef39 100644
--- a/code/game/objects/items/misc.dm
+++ b/code/game/objects/items/misc.dm
@@ -134,20 +134,20 @@
return
stored_item = object
mobber.drop_inv_item_to_loc(object, src)
- to_chat(mobber, SPAN_NOTICE("You slide the [object] into [src]."))
+ to_chat(mobber, SPAN_NOTICE("You slide [object] into [src]."))
playsound(mobber, 'sound/weapons/gun_shotgun_shell_insert.ogg', 15, TRUE)
update_icon()
break
. = ..()
/obj/item/weapon/pole/fancy_cane/this_is_a_knife/machete
- stored_item = new /obj/item/weapon/claymore/mercsword/machete
+ stored_item = new /obj/item/weapon/sword/machete
/obj/item/weapon/pole/fancy_cane/this_is_a_knife/ceremonial_sword
- stored_item = new /obj/item/weapon/claymore/mercsword/ceremonial
+ stored_item = new /obj/item/weapon/sword/ceremonial
/obj/item/weapon/pole/fancy_cane/this_is_a_knife/katana
- stored_item = new /obj/item/weapon/katana
+ stored_item = new /obj/item/weapon/sword/katana
// IN SHOTGUNS.DM!!
diff --git a/code/game/objects/items/paint.dm b/code/game/objects/items/paint.dm
index 9089dd228ed0..c538cbf3944f 100644
--- a/code/game/objects/items/paint.dm
+++ b/code/game/objects/items/paint.dm
@@ -1,6 +1,6 @@
//NEVER USE THIS IT SUX -PETETHEGOAT
-var/global/list/cached_icons = list()
+GLOBAL_LIST_EMPTY(cached_icons)
/obj/item/reagent_container/glass/paint
desc = "It's a paint bucket."
diff --git a/code/game/objects/items/pamphlets.dm b/code/game/objects/items/pamphlets.dm
index 682215be67bb..763d78bd6ea6 100644
--- a/code/game/objects/items/pamphlets.dm
+++ b/code/game/objects/items/pamphlets.dm
@@ -84,7 +84,7 @@
if(!istype(ID)) //not wearing an ID
to_chat(user, SPAN_WARNING("You should wear your ID before doing this."))
return FALSE
- if(ID.registered_ref != WEAKREF(user))
+ if(!ID.check_biometrics(user))
to_chat(user, SPAN_WARNING("You should wear your ID before doing this."))
return FALSE
diff --git a/code/game/objects/items/props/helmetgarb.dm b/code/game/objects/items/props/helmetgarb.dm
index 661c8d422316..bdf140ff11c3 100644
--- a/code/game/objects/items/props/helmetgarb.dm
+++ b/code/game/objects/items/props/helmetgarb.dm
@@ -37,6 +37,11 @@
desc = "The more you fire these, the more you're reminded that a fragmentation grenade is probably more effective at fulfilling the same purpose. Say, aren't these supposed to eject from your gun?"
icon_state = "spent_flech"
+/obj/item/prop/helmetgarb/cartridge
+ name = "cartridge"
+ desc = "This is the bullet from a Type 71 Pulse Rifle. It is deformed from impact against an armored surface. It's been reduced to a lucky keepsake now."
+ icon_state = "cartridge"
+
/obj/item/prop/helmetgarb/prescription_bottle
name = "prescription medication"
desc = "Anti-anxiety meds? Amphetamines? The cure for Sudden Sleep Disorder? The label can't be read, leaving the now absent contents forever a mystery. The cap is screwed on tighter than any ID lock."
@@ -94,10 +99,8 @@
var/nvg_maxhealth = 125
var/nvg_health = 125
- var/nvg_maxcharge = 2500
- var/nvg_charge = 2500
- var/nvg_drain = 8 // has a 5 minute duration but byond may give it a couple of irl time due to lag
- var/infinite_charge = FALSE
+ /// How much charge the cell should have at most. -1 is infinite
+ var/cell_max_charge = 2500
var/activated = FALSE
var/nightvision = FALSE
@@ -112,6 +115,13 @@
var/mob/living/attached_mob
var/lighting_alpha = 100
+/obj/item/prop/helmetgarb/helmet_nvg/Initialize(mapload, ...)
+ . = ..()
+ if(shape != NVG_SHAPE_COSMETIC)
+ AddComponent(/datum/component/cell, cell_max_charge, TRUE, charge_drain = 8)
+ RegisterSignal(src, COMSIG_CELL_TRY_RECHARGING, PROC_REF(cell_try_recharge))
+ RegisterSignal(src, COMSIG_CELL_OUT_OF_CHARGE, PROC_REF(on_power_out))
+
/obj/item/prop/helmetgarb/helmet_nvg/on_enter_storage(obj/item/storage/internal/S)
..()
@@ -134,42 +144,30 @@
/obj/item/prop/helmetgarb/helmet_nvg/attackby(obj/item/A as obj, mob/user as mob)
- if(istype(A,/obj/item/cell))
- recharge(A, user)
-
if(HAS_TRAIT(A, TRAIT_TOOL_SCREWDRIVER))
repair(user)
else
..()
-/obj/item/prop/helmetgarb/helmet_nvg/proc/recharge(obj/item/cell/C, mob/user as mob)
+/obj/item/prop/helmetgarb/helmet_nvg/proc/cell_try_recharge(datum/source, mob/living/user)
+ SIGNAL_HANDLER
+
if(user.action_busy)
- return
+ return COMPONENT_CELL_NO_RECHARGE
+
if(src != user.get_inactive_hand())
- to_chat(user, SPAN_WARNING("You need to hold \the [src] in hand in order to recharge them."))
- return
+ to_chat(user, SPAN_WARNING("You need to hold [src] in hand in order to recharge them."))
+ return COMPONENT_CELL_NO_RECHARGE
+
if(shape == NVG_SHAPE_COSMETIC)
- to_chat(user, SPAN_WARNING("There is no connector for the power cell inside \the [src]."))
- return
+ to_chat(user, SPAN_WARNING("There is no connector for the power cell inside [src]."))
+ return COMPONENT_CELL_NO_RECHARGE
+
if(shape == NVG_SHAPE_BROKEN)
- to_chat(user, SPAN_WARNING("You need to repair \the [src] first."))
- return
- if(nvg_charge == nvg_maxcharge)
- to_chat(user, SPAN_WARNING("\The [src] are already fully charged."))
- return
+ to_chat(user, SPAN_WARNING("You need to repair [src] first."))
+ return COMPONENT_CELL_NO_RECHARGE
- while(nvg_charge < nvg_maxcharge)
- if(C.charge <= 0)
- to_chat(user, SPAN_WARNING("\The [C] is completely dry."))
- break
- if(!do_after(user, 1 SECONDS, (INTERRUPT_ALL & (~INTERRUPT_MOVED)), BUSY_ICON_BUILD, C, INTERRUPT_DIFF_LOC))
- to_chat(user, SPAN_WARNING("You were interrupted."))
- break
- var/to_transfer = min(400, C.charge, (nvg_maxcharge - nvg_charge))
- if(C.use(to_transfer))
- nvg_charge += to_transfer
- to_chat(user, "You transfer some power between \the [C] and \the [src]. The gauge now reads: [round(100.0*nvg_charge/nvg_maxcharge) ]%.")
/obj/item/prop/helmetgarb/helmet_nvg/proc/repair(mob/user as mob)
if(user.action_busy)
@@ -197,7 +195,6 @@
to_chat(user, "You successfully patch \the [src].")
nvg_maxhealth = 65
nvg_health = 65
- nvg_drain = initial(nvg_drain) * 2
return
else if(nvg_health == nvg_maxhealth)
@@ -207,7 +204,7 @@
to_chat(user, SPAN_WARNING("Nothing to fix."))
else if(shape == NVG_SHAPE_COSMETIC)
- to_chat(user, SPAN_WARNING("it's nothing but a husk of what it used to be."))
+ to_chat(user, SPAN_WARNING("It's nothing but a husk of what it used to be."))
else
to_chat(user, "You begin to repair \the [src].")
@@ -239,9 +236,6 @@
else if(nvg_health_procent >= 0)
. += "They are falling apart."
- if (get_dist(user, src) <= 1 && (shape == NVG_SHAPE_FINE || shape == NVG_SHAPE_PATCHED))
- . += "A small gauge in the corner reads: Power: [round(100.0*nvg_charge/nvg_maxcharge) ]%."
-
/obj/item/prop/helmetgarb/helmet_nvg/on_exit_storage(obj/item/storage/S)
remove_attached_item()
return ..()
@@ -291,7 +285,7 @@
if(attached_mob != user && slot == WEAR_HEAD)
set_attached_mob(user)
- if(slot == WEAR_HEAD && !nightvision && activated && nvg_charge > 0 && shape > NVG_SHAPE_BROKEN)
+ if(slot == WEAR_HEAD && !nightvision && activated && !SEND_SIGNAL(src, COMSIG_CELL_CHECK_CHARGE) && shape > NVG_SHAPE_BROKEN)
enable_nvg(user)
else
remove_nvg()
@@ -314,7 +308,7 @@
attached_item.update_icon()
activation.update_button_icon()
- START_PROCESSING(SSobj, src)
+ SEND_SIGNAL(src, COMSIG_CELL_START_TICK_DRAIN)
/obj/item/prop/helmetgarb/helmet_nvg/proc/update_sight(mob/M)
@@ -348,20 +342,15 @@
attached_mob.update_sight()
- STOP_PROCESSING(SSobj, src)
+ SEND_SIGNAL(src, COMSIG_CELL_STOP_TICK_DRAIN)
/obj/item/prop/helmetgarb/helmet_nvg/process(delta_time)
- if(nvg_charge > 0 && !infinite_charge)
- nvg_charge = max(0, nvg_charge - nvg_drain * delta_time)
-
if(!attached_mob)
return PROCESS_KILL
- if(!activated || !attached_item || nvg_charge <= 0 || attached_mob.is_dead())
- if(activated && !attached_mob.is_dead())
- to_chat(attached_mob, SPAN_WARNING("\The [src] emit a low power warning and immediately shut down!"))
- remove_nvg()
+ if(!activated || !attached_item || attached_mob.is_dead())
+ on_power_out()
return
if(!attached_item.has_garb_overlay())
@@ -370,6 +359,13 @@
return
+/obj/item/prop/helmetgarb/helmet_nvg/proc/on_power_out(datum/source)
+ SIGNAL_HANDLER
+
+ if(activated && !attached_mob.is_dead())
+ to_chat(attached_mob, SPAN_WARNING("[src] emit a low power warning and immediately shut down!"))
+ remove_nvg()
+
/obj/item/prop/helmetgarb/helmet_nvg/ui_action_click(mob/owner, obj/item/holder)
toggle_nods(owner)
@@ -405,7 +401,7 @@
if(activated)
to_chat(user, SPAN_NOTICE("You flip the goggles down."))
icon_state = active_icon_state
- if(nvg_charge > 0 && user.head == attached_item && shape > NVG_SHAPE_BROKEN)
+ if(!SEND_SIGNAL(src, COMSIG_CELL_CHECK_CHARGE) && user.head == attached_item && shape > NVG_SHAPE_BROKEN)
enable_nvg(user)
else
icon_state = active_icon_state
@@ -457,7 +453,7 @@
/obj/item/prop/helmetgarb/helmet_nvg/marsoc //for Marine Raiders
name = "\improper Tactical M3 night vision goggles"
desc = "With an integrated self-recharging battery, nothing can stop you. Put them on your helmet and press the button and it's go-time."
- infinite_charge = TRUE
+ cell_max_charge = -1
#undef NVG_SHAPE_COSMETIC
#undef NVG_SHAPE_BROKEN
@@ -500,14 +496,38 @@
desc = "The USCM had its funding pulled for these when it became apparent that not every deployed enlisted was wearing a helmet 24/7; much to the bafflement of UA High Command."
icon_state = "helmet_gasmask"
+/obj/item/prop/helmetgarb/helmet_gasmask/on_enter_storage(obj/item/storage/internal/helmet_internal_inventory)
+ ..()
+ if(!istype(helmet_internal_inventory))
+ return
+ var/obj/item/clothing/head/helmet/helmet_item = helmet_internal_inventory.master_object
+
+ if(!istype(helmet_item))
+ return
+
+ helmet_item.flags_inventory |= BLOCKGASEFFECT
+ helmet_item.flags_inv_hide |= HIDEFACE
+
+/obj/item/prop/helmetgarb/helmet_gasmask/on_exit_storage(obj/item/storage/internal/helmet_internal_inventory)
+ ..()
+ if(!istype(helmet_internal_inventory))
+ return
+ var/obj/item/clothing/head/helmet/helmet_item = helmet_internal_inventory.master_object
+
+ if(!istype(helmet_item))
+ return
+
+ helmet_item.flags_inventory &= ~(BLOCKGASEFFECT)
+ helmet_item.flags_inv_hide &= ~(HIDEFACE)
+
/obj/item/prop/helmetgarb/trimmed_wire
name = "trimmed barbed wire"
desc = "It is a length of barbed wire that's had most of the sharp points filed down so that it is safe to handle."
icon_state = "trimmed_wire"
/obj/item/prop/helmetgarb/bullet_pipe
- name = "10x99mm XM42B casing pipe"
- desc = "The XM42B was an experimental weapons platform briefly fielded by the USCM and Wey-Yu PMC teams. It was manufactured by ARMAT systems at the Atlas weapons facility. Unfortunately the project had its funding pulled alongside the M5 integrated gasmask program. This spent casing has been converted into a pipe, but there is too much tar in the mouthpiece for it to be useable."
+ name = "10x99mm XM43E1 casing pipe"
+ desc = "The XM43E1 was an experimental weapons platform briefly fielded by the USCM and Wey-Yu PMC teams. It was manufactured by ARMAT systems at the Atlas weapons facility. Unfortunately the project had its funding pulled alongside the M5 integrated gasmask program. This spent casing has been converted into a pipe, but there is too much tar in the mouthpiece for it to be useable."
icon_state = "bullet_pipe"
/obj/item/prop/helmetgarb/chaplain_patch
@@ -515,3 +535,83 @@
desc = "This patch is all that remains of the Chaplaincy of the USS Almayer, along with the Chaplains themselves. Both no longer exist as a result of losses suffered during Operation Tychon Tackle."
icon_state = "chaplain_patch"
flags_obj = OBJ_NO_HELMET_BAND
+
+/obj/item/prop/helmetgarb/family_photo
+ name = "family photo"
+ desc = ""
+ icon = 'icons/obj/items/items.dmi'
+ icon_state = "photo"
+ ///The human who spawns with the photo
+ var/datum/weakref/owner
+ ///The belonging human name
+ var/owner_name
+ ///The belonging human faction
+ var/owner_faction
+ ///Text written on the back
+ var/scribble
+
+/obj/item/prop/helmetgarb/family_photo/pickup(mob/user, silent)
+ . = ..()
+ if(!owner)
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner), override = TRUE)
+
+
+///Sets the owner of the family photo to the human it spawns with, needs var/source for signals
+/obj/item/prop/helmetgarb/family_photo/proc/set_owner(datum/source)
+ SIGNAL_HANDLER
+ UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE)
+ var/mob/living/carbon/human/user = source
+ owner = WEAKREF(user)
+ owner_name = user.name
+ owner_faction = user.faction
+
+/obj/item/prop/helmetgarb/family_photo/get_examine_text(mob/user)
+ . = ..()
+ if(scribble)
+ . += "\"[scribble]\" is written on the back of the photo."
+ if(user.weak_reference == owner)
+ . += "A photo of you and your family."
+ return
+ if(user.faction == owner_faction)
+ . += "A photo of [owner_name] and their family."
+ return
+ . += "A photo of a family you do not know."
+
+/obj/item/prop/helmetgarb/family_photo/attackby(obj/item/attacking_item, mob/user)
+ . = ..()
+ if(HAS_TRAIT(attacking_item, TRAIT_TOOL_PEN) || istype(attacking_item, /obj/item/toy/crayon))
+ if(scribble)
+ to_chat(user, SPAN_NOTICE("[src] has already been written on."))
+ return
+ var/new_text = copytext(strip_html(tgui_input_text(user, "What would you like to write on the back of [src]?", "Photo Writing")), 1, 128)
+
+ if(!loc == user)
+ to_chat(user, SPAN_NOTICE("You need to be holding [src] to write on it."))
+ return
+ if(!user.stat == CONSCIOUS)
+ to_chat(user, SPAN_NOTICE("You cannot write on [src] in this state."))
+ return
+ scribble = new_text
+ playsound(src, "paper_writing", 15, TRUE)
+ return TRUE
+
+/obj/item/prop/helmetgarb/compass
+ name = "compass"
+ desc = "It always faces north. Are you sure it is not broken?"
+ icon = 'icons/obj/items/items.dmi'
+ icon_state = "compass"
+ w_class = SIZE_SMALL
+
+/obj/item/prop/helmetgarb/compass/get_examine_text(mob/user)
+ . = ..()
+ if(is_ground_level(user.z) && !SSmapping.configs[GROUND_MAP].environment_traits[ZTRAIT_IN_SPACE])
+ . += SPAN_NOTICE("It seems you are facing [dir2text(user.dir)].")
+ return
+ . += SPAN_NOTICE("The needle is not moving.")
+
+/obj/item/prop/helmetgarb/bug_spray
+ name = "insect repellent"
+ desc = "A store-brand insect repellent, to keep any variety of pest or mosquito away from you."
+ icon = 'icons/obj/items/spray.dmi'
+ icon_state = "pestspray"
+ w_class = SIZE_SMALL
diff --git a/code/game/objects/items/reagent_containers/autoinjectors.dm b/code/game/objects/items/reagent_containers/autoinjectors.dm
index 46463e628c1d..04a3a15585ab 100644
--- a/code/game/objects/items/reagent_containers/autoinjectors.dm
+++ b/code/game/objects/items/reagent_containers/autoinjectors.dm
@@ -139,6 +139,12 @@
item_state = "emptyskill"
skilllock = SKILL_MEDICAL_DEFAULT
+/obj/item/reagent_container/hypospray/autoinjector/tramadol/skillless/one_use
+ desc = "An EZ autoinjector loaded with 1 use of Tramadol, a weak but effective painkiller for normal wounds. Doesn't require any training to use."
+ volume = 15
+ amount_per_transfer_from_this = 15
+ uses_left = 1
+
/obj/item/reagent_container/hypospray/autoinjector/oxycodone
name = "oxycodone autoinjector (EXTREME PAINKILLER)"
chemname = "oxycodone"
@@ -164,6 +170,12 @@
item_state = "emptyskill"
skilllock = SKILL_MEDICAL_DEFAULT
+/obj/item/reagent_container/hypospray/autoinjector/kelotane/skillless/one_use
+ desc = "An EZ autoinjector loaded with 1 use of Kelotane, a common burn medicine. Doesn't require any training to use."
+ volume = 15
+ amount_per_transfer_from_this = 15
+ uses_left = 1
+
/obj/item/reagent_container/hypospray/autoinjector/bicaridine
name = "bicaridine autoinjector"
chemname = "bicaridine"
@@ -180,6 +192,12 @@
item_state = "emptyskill"
skilllock = SKILL_MEDICAL_DEFAULT
+/obj/item/reagent_container/hypospray/autoinjector/bicaridine/skillless/one_use
+ desc = "An EZ autoinjector loaded with 1 use of Bicaridine, a common brute and circulatory damage medicine. Doesn't require any training to use."
+ volume = 15
+ amount_per_transfer_from_this = 15
+ uses_left = 1
+
/obj/item/reagent_container/hypospray/autoinjector/inaprovaline
name = "inaprovaline autoinjector"
chemname = "inaprovaline"
diff --git a/code/game/objects/items/reagent_containers/blood_pack.dm b/code/game/objects/items/reagent_containers/blood_pack.dm
index 0879dcffdc68..92c68e81c9d2 100644
--- a/code/game/objects/items/reagent_containers/blood_pack.dm
+++ b/code/game/objects/items/reagent_containers/blood_pack.dm
@@ -163,7 +163,7 @@
if(!istype(usr, /mob/living))
return
- if(usr.stat || usr.lying)
+ if(usr.stat || usr.is_mob_incapacitated())
return
mode = !mode
diff --git a/code/game/objects/items/reagent_containers/borghydro.dm b/code/game/objects/items/reagent_containers/borghydro.dm
index 30a9bdbd3c65..4f1f5540988b 100644
--- a/code/game/objects/items/reagent_containers/borghydro.dm
+++ b/code/game/objects/items/reagent_containers/borghydro.dm
@@ -22,7 +22,7 @@
for(var/T in reagent_ids)
reagent_volumes[T] = volume
- var/datum/reagent/R = chemical_reagents_list[T]
+ var/datum/reagent/R = GLOB.chemical_reagents_list[T]
reagent_names += R.name
START_PROCESSING(SSobj, src)
@@ -71,7 +71,7 @@
..()
var/selection = tgui_input_list(usr, "Please select a reagent:", "Reagent", reagent_ids)
if(!selection) return
- var/datum/reagent/R = chemical_reagents_list[selection]
+ var/datum/reagent/R = GLOB.chemical_reagents_list[selection]
to_chat(user, SPAN_NOTICE(" Synthesizer is now producing '[R.name]'."))
mode = reagent_ids.Find(selection)
playsound(src.loc, 'sound/effects/pop.ogg', 15, 0)
@@ -81,6 +81,6 @@
. = ..()
if (user != loc) return
- var/datum/reagent/R = chemical_reagents_list[reagent_ids[mode]]
+ var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_ids[mode]]
. += SPAN_NOTICE("It is currently producing [R.name] and has [reagent_volumes[reagent_ids[mode]]] out of [volume] units left.")
diff --git a/code/game/objects/items/reagent_containers/dropper.dm b/code/game/objects/items/reagent_containers/dropper.dm
index eaf28f66b012..f36145e285cd 100644
--- a/code/game/objects/items/reagent_containers/dropper.dm
+++ b/code/game/objects/items/reagent_containers/dropper.dm
@@ -32,7 +32,7 @@
if(ismob(target))
var/time = 20 //2/3rds the time of a syringe
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(SPAN_DANGER("[user] is trying to squirt something into [target]'s eyes!"), SHOW_MESSAGE_VISIBLE)
if(!do_after(user, time, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, target, INTERRUPT_MOVED, BUSY_ICON_MEDICAL)) return
@@ -56,7 +56,7 @@
safe_thing.create_reagents(100)
trans = src.reagents.trans_to(safe_thing, amount_per_transfer_from_this)
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(SPAN_DANGER("[user] tries to squirt something into [target]'s eyes, but fails!"), SHOW_MESSAGE_VISIBLE)
spawn(5)
src.reagents.reaction(safe_thing, TOUCH)
@@ -67,7 +67,7 @@
icon_state = "dropper[filled]"
return
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(SPAN_DANGER("[user] squirts something into [target]'s eyes!"), SHOW_MESSAGE_VISIBLE)
src.reagents.reaction(target, TOUCH)
diff --git a/code/game/objects/items/reagent_containers/food/condiment.dm b/code/game/objects/items/reagent_containers/food/condiment.dm
index a13489f0af1e..35944e4422c4 100644
--- a/code/game/objects/items/reagent_containers/food/condiment.dm
+++ b/code/game/objects/items/reagent_containers/food/condiment.dm
@@ -23,7 +23,7 @@
return FALSE
if(M == user)
- to_chat(M, SPAN_NOTICE(" You swallow some of contents of the [src]."))
+ to_chat(M, SPAN_NOTICE("You swallow some of contents of [src]."))
else if(istype(M, /mob/living/carbon/human))
user.affected_message(M,
@@ -80,7 +80,7 @@
to_chat(user, SPAN_DANGER("[src] is empty."))
return
if(target.reagents.total_volume >= target.reagents.maximum_volume)
- to_chat(user, SPAN_DANGER("you can't add anymore to [target]."))
+ to_chat(user, SPAN_DANGER("You can't add any more to [target]."))
return
var/trans = src.reagents.trans_to(target, amount_per_transfer_from_this)
to_chat(user, SPAN_NOTICE(" You transfer [trans] units of the condiment to [target]."))
@@ -202,7 +202,7 @@
/obj/item/reagent_container/food/condiment/hotsauce/franks
name = "\improper Frank's Red Hot bottle"
desc = "A bottle of Weyland-Yutani brand Frank's Red Hot hot sauce."
- desc_lore = "Supposedly designed as a middle-ground flavor between ketchup and cayenne, this brand of spicy goodness achieved critical acclaim throughout UA space within both colonies and vessels alike. The sudden and widespread adoption was curiously timed with the near-simultaneous shelving of the original Frank's 'ULTRA' hot sauce."
+ desc_lore = "Supposedly designed as a middle-ground flavor between ketchup and cayenne, this brand of spicy goodness achieved critical acclaim throughout UA space within both colonies and vessels alike. The sudden and widespread adoption was curiously timed with the near-simultaneous shelving of the original Frank's 'ULTRA' hot sauce."
icon_state = "hotsauce_franks"
item_state = "hotsauce_franks"
diff --git a/code/game/objects/items/reagent_containers/food/drinks.dm b/code/game/objects/items/reagent_containers/food/drinks.dm
index 9f88990e5350..db83723bc8df 100644
--- a/code/game/objects/items/reagent_containers/food/drinks.dm
+++ b/code/game/objects/items/reagent_containers/food/drinks.dm
@@ -23,6 +23,10 @@
to_chat(user, SPAN_DANGER("The [src.name] is empty!"))
return FALSE
+ if(HAS_TRAIT(M, TRAIT_CANNOT_EAT))
+ to_chat(user, SPAN_DANGER("[user == M ? "You are" : "[M] is"] unable to drink!"))
+ return FALSE
+
if(M == user)
to_chat(M, SPAN_NOTICE(" You swallow a gulp from \the [src]."))
if(reagents.total_volume)
diff --git a/code/game/objects/items/reagent_containers/food/fortunecookie.dm b/code/game/objects/items/reagent_containers/food/fortunecookie.dm
index a878ff589dc8..6077541acd84 100644
--- a/code/game/objects/items/reagent_containers/food/fortunecookie.dm
+++ b/code/game/objects/items/reagent_containers/food/fortunecookie.dm
@@ -75,7 +75,7 @@
to_chat(user,SPAN_WARNING("[src] is cracked open! How are you gonna slip something in that?"))
else
if(!cookiefortune)
- to_chat(user, SPAN_NOTICE("You slip the paper into the [src]."))
+ to_chat(user, SPAN_NOTICE("You slip the paper into [src]."))
cookiefortune = W
user.drop_inv_item_to_loc(W, src)
else
@@ -93,7 +93,7 @@
user.put_in_hands(cookiefortune)
cookiefortune = null
else
- to_chat(SPAN_WARNING("You break open the fortune cookie, but there's no fortune inside! Oh no!"))
+ to_chat(user, SPAN_WARNING("You break open the fortune cookie, but there's no fortune inside! Oh no!"))
else
. = ..()
@@ -109,7 +109,7 @@
user.put_in_hands(cookiefortune)
cookiefortune = null
else
- to_chat(SPAN_WARNING("You break open the fortune cookie, but there's no fortune inside! Oh no!"))
+ to_chat(user, SPAN_WARNING("You break open the fortune cookie, but there's no fortune inside! Oh no!"))
else
. = ..()
diff --git a/code/game/objects/items/reagent_containers/food/sandwich.dm b/code/game/objects/items/reagent_containers/food/sandwich.dm
index 1b7d61eaddad..511c0c042be1 100644
--- a/code/game/objects/items/reagent_containers/food/sandwich.dm
+++ b/code/game/objects/items/reagent_containers/food/sandwich.dm
@@ -18,7 +18,7 @@
/obj/item/reagent_container/food/snacks/csandwich/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/reagent_container/food/snacks/csandwich))
//No sandwitch inception, it causes some bugs...
- to_chat(user, SPAN_NOTICE(" You can't put a [W] in the [src]."))
+ to_chat(user, SPAN_NOTICE("You can't put \a [W] in [src]."))
return
var/sandwich_limit = 4
diff --git a/code/game/objects/items/reagent_containers/food/snacks.dm b/code/game/objects/items/reagent_containers/food/snacks.dm
index 06a4d785e677..076a4f77cf01 100644
--- a/code/game/objects/items/reagent_containers/food/snacks.dm
+++ b/code/game/objects/items/reagent_containers/food/snacks.dm
@@ -21,6 +21,7 @@
//Placeholder for effect that trigger on eating that aren't tied to reagents.
/obj/item/reagent_container/food/snacks/proc/On_Consume(mob/M)
SEND_SIGNAL(src, COMSIG_SNACK_EATEN, M)
+ SEND_SIGNAL(M, COMSIG_MOB_EATEN_SNACK, src)
if(!usr) return
if(!reagents.total_volume)
@@ -42,7 +43,7 @@
..()
if (world.time <= user.next_move)
- return
+ return FALSE
attack(user, user, "head")//zone does not matter
user.next_move += attack_speed
@@ -51,24 +52,24 @@
to_chat(user, SPAN_DANGER("None of [src] left, oh no!"))
M.drop_inv_item_on_ground(src) //so icons update :[
qdel(src)
- return 0
+ return FALSE
if(package)
to_chat(M, SPAN_WARNING("How do you expect to eat this with the package still on?"))
- return 0
+ return FALSE
if(istype(M, /mob/living/carbon))
var/mob/living/carbon/C = M
var/fullness = M.nutrition + (M.reagents.get_reagent_amount("nutriment") * 25)
if(fullness > NUTRITION_HIGH && world.time < C.overeat_cooldown)
to_chat(user, SPAN_WARNING("[user == M ? "You" : "They"] don't feel like eating more right now."))
- return
+ return FALSE
if(issynth(C))
fullness = 200 //Synths never get full
if(HAS_TRAIT(M, TRAIT_CANNOT_EAT)) //Do not feed the Working Joes
to_chat(user, SPAN_DANGER("[user == M ? "You are" : "[M] is"] unable to eat!"))
- return
+ return FALSE
if(fullness > NUTRITION_HIGH)
C.overeat_cooldown = world.time + OVEREAT_TIME
@@ -120,9 +121,9 @@
reagents.trans_to_ingest(M, reagents.total_volume)
bitecount++
On_Consume(M)
- return 1
+ return TRUE
- return 0
+ return FALSE
/obj/item/reagent_container/food/snacks/afterattack(obj/target, mob/user, proximity)
return ..()
@@ -182,10 +183,9 @@
return 0
var/inaccurate = 0
- if(W.sharp == IS_SHARP_ITEM_ACCURATE)
- else if(W.sharp == IS_SHARP_ITEM_BIG)
+ if(W.sharp == IS_SHARP_ITEM_BIG)
inaccurate = 1
- else
+ else if(W.sharp != IS_SHARP_ITEM_ACCURATE)
return 1
if ( !istype(loc, /obj/structure/surface/table) && \
(!isturf(src.loc) || \
@@ -206,7 +206,7 @@
SPAN_NOTICE("[user] crudely slices \the [src] with [W]!"), \
SPAN_NOTICE("You crudely slice \the [src] with your [W]!") \
)
- slices_lost = rand(1,min(1,round(slices_num/2)))
+ slices_lost = rand(1,max(1,round(slices_num/2)))
var/reagents_per_slice = reagents.total_volume/slices_num
for(var/i=1 to (slices_num-slices_lost))
var/obj/slice = new slice_path (src.loc)
@@ -218,10 +218,10 @@
if(isanimal(M))
if(iscorgi(M))
if(bitecount == 0 || prob(50))
- M.emote("nibbles away at the [src]")
+ M.emote("nibbles away at [src]")
bitecount++
if(bitecount >= 5)
- var/sattisfaction_text = pick("burps from enjoyment", "yaps for more", "woofs twice", "looks at the area where the [src] was")
+ var/sattisfaction_text = pick("burps from enjoyment", "yaps for more", "woofs twice", "looks at the area where [src] was")
if(sattisfaction_text)
M.emote("[sattisfaction_text]")
qdel(src)
@@ -2802,7 +2802,7 @@
if( open && pizza )
user.put_in_hands( pizza )
- to_chat(user, SPAN_DANGER("You take the [src.pizza] out of the [src]."))
+ to_chat(user, SPAN_DANGER("You take the [src.pizza] out of [src]."))
src.pizza = null
update_icon()
return
@@ -2853,11 +2853,11 @@
box.update_icon()
update_icon()
- to_chat(user, SPAN_DANGER("You put the [box] ontop of the [src]!"))
+ to_chat(user, SPAN_DANGER("You put [box] ontop of [src]!"))
else
to_chat(user, SPAN_DANGER("The stack is too high!"))
else
- to_chat(user, SPAN_DANGER("Close the [box] first!"))
+ to_chat(user, SPAN_DANGER("Close [box] first!"))
return
@@ -2869,9 +2869,9 @@
update_icon()
- to_chat(user, SPAN_DANGER("You put the [I] in the [src]!"))
+ to_chat(user, SPAN_DANGER("You put [I] in [src]!"))
else
- to_chat(user, SPAN_DANGER("You try to push the [I] through the lid but it doesn't work!"))
+ to_chat(user, SPAN_DANGER("You try to push [I] through the lid but it doesn't work!"))
return
if( istype(I, /obj/item/tool/pen/) )
@@ -3132,6 +3132,7 @@
icon_state = "packaged-burrito"
bitesize = 2
package = 1
+ flags_obj = OBJ_NO_HELMET_BAND|OBJ_IS_HELMET_GARB
/obj/item/reagent_container/food/snacks/packaged_burrito/Initialize()
. = ..()
@@ -3175,6 +3176,7 @@
name = "Packaged Hotdog"
desc = "A singular squishy, room temperature, hot dog. There's no time given for how long to cook it, so you assume its probably good to go. Packaged by the Weyland-Yutani Corporation."
icon_state = "packaged-hotdog"
+ flags_obj = OBJ_NO_HELMET_BAND|OBJ_IS_HELMET_GARB
bitesize = 2
package = 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 12a5a704f663..32423c121b61 100644
--- a/code/game/objects/items/reagent_containers/food/snacks/grown.dm
+++ b/code/game/objects/items/reagent_containers/food/snacks/grown.dm
@@ -30,7 +30,7 @@
/obj/item/reagent_container/food/snacks/grown/proc/update_from_seed()// Fill the object up with the appropriate reagents.
if(!isnull(plantname))
- var/datum/seed/S = seed_types[plantname]
+ var/datum/seed/S = GLOB.seed_types[plantname]
if(!S)
return
name = S.seed_name //Copies the name from the seed, important for renamed plants
diff --git a/code/game/objects/items/reagent_containers/glass.dm b/code/game/objects/items/reagent_containers/glass.dm
index 240809b7851f..2a7bde748fba 100644
--- a/code/game/objects/items/reagent_containers/glass.dm
+++ b/code/game/objects/items/reagent_containers/glass.dm
@@ -237,7 +237,7 @@
overlays += lid
/obj/item/reagent_container/glass/minitank
- name = "MS-11 Smart Refill Tank"
+ name = "\improper MS-11 Smart Refill Tank"
desc = "A robust little tank capable of refilling autoinjectors that previously required a nanomed system to refill. Using the wonders of microchips, it automatically sorts the correct chemicals into most single reagent autoinjectors. It is unable to partially fill them however. A valve exists on the top to transfer reagents to another container or to flush it entirely."
icon = 'icons/obj/items/tank.dmi'
icon_state = "mini_reagent_tank"
@@ -277,7 +277,7 @@
if(istype(W, /obj/item/reagent_container/hypospray/autoinjector))
var/obj/item/reagent_container/hypospray/autoinjector/A = W
if(A.mixed_chem)
- to_chat(user, SPAN_WARNING("The autoinjector doesn't fit into the [src]'s valve. It's probably not compatible."))
+ to_chat(user, SPAN_WARNING("The autoinjector doesn't fit into [src]'s valve. It's probably not compatible."))
return
if(reagents.has_reagent(A.chemname, A.volume))
reagents.trans_id_to(A, A.chemname, A.volume)
@@ -285,10 +285,10 @@
A.update_icon()
playsound(src.loc, 'sound/effects/refill.ogg', 25, 1, 3)
else
- to_chat(user, SPAN_WARNING("A small LED on \the [src] blinks. The tank can't refill \the [A] - it's either incompatible or out of chemicals to fill it with!"))
+ to_chat(user, SPAN_WARNING("A small LED on [src] blinks. The tank can't refill [A] - it's either incompatible or out of chemicals to fill it with!"))
. = ..()
return
- to_chat(user,SPAN_INFO("You successfully refill \the [W.name] with \the [src]!"))
+ to_chat(user, SPAN_INFO("You successfully refill [A] with [src]!"))
/obj/item/reagent_container/glass/minitank/verb/flush_tank(mob/user)
set category = "Object"
@@ -299,7 +299,7 @@
to_chat(user, SPAN_WARNING("It's already empty!"))
return
playsound(src.loc, 'sound/effects/slosh.ogg', 25, 1, 3)
- to_chat(user, SPAN_WARNING("You work the flush valve and successfully flush \the [src]'s contents!"))
+ to_chat(user, SPAN_WARNING("You work the flush valve and successfully flush [src]'s contents!"))
reagents.clear_reagents()
update_icon() // just to be sure
return
@@ -363,11 +363,8 @@
matter = list()
possible_transfer_amounts = list(5,10,15,25,30)
flags_atom = FPRINT|OPENCONTAINER
-
-/obj/item/reagent_container/glass/beaker/vial/Initialize()
- . = ..()
- pixel_y = rand(-8, 8)
- pixel_x = rand(-9, 9)
+ ground_offset_x = 9
+ ground_offset_y = 8
/obj/item/reagent_container/glass/beaker/vial/tricordrazine
name = "tricordrazine vial"
@@ -392,17 +389,17 @@
. = ..()
var/random_chem
if(tier)
- random_chem = pick(chemical_gen_classes_list[tier])
+ random_chem = pick(GLOB.chemical_gen_classes_list[tier])
else
- random_chem = pick( prob(3);pick(chemical_gen_classes_list["C1"]),\
- prob(5);pick(chemical_gen_classes_list["C2"]),\
- prob(7);pick(chemical_gen_classes_list["C3"]),\
- prob(10);pick(chemical_gen_classes_list["C4"]),\
- prob(15);pick(chemical_gen_classes_list["C5"]),\
- prob(25);pick(chemical_gen_classes_list["T1"]),\
- prob(15);pick(chemical_gen_classes_list["T2"]),\
- prob(10);pick(chemical_gen_classes_list["T3"]),\
- prob(5);pick(chemical_gen_classes_list["T4"]),\
+ random_chem = pick( prob(3);pick(GLOB.chemical_gen_classes_list["C1"]),\
+ prob(5);pick(GLOB.chemical_gen_classes_list["C2"]),\
+ prob(7);pick(GLOB.chemical_gen_classes_list["C3"]),\
+ prob(10);pick(GLOB.chemical_gen_classes_list["C4"]),\
+ prob(15);pick(GLOB.chemical_gen_classes_list["C5"]),\
+ prob(25);pick(GLOB.chemical_gen_classes_list["T1"]),\
+ prob(15);pick(GLOB.chemical_gen_classes_list["T2"]),\
+ prob(10);pick(GLOB.chemical_gen_classes_list["T3"]),\
+ prob(5);pick(GLOB.chemical_gen_classes_list["T4"]),\
prob(15);"")
if(random_chem)
reagents.add_reagent(random_chem, 30)
@@ -675,5 +672,5 @@
if(istype(AM) && (src in user))
user.visible_message("[user] starts to wipe down [AM] with [src]!")
if(do_after(user,30, INTERRUPT_ALL, BUSY_ICON_GENERIC))
- user.visible_message("[user] finishes wiping off the [AM]!")
+ user.visible_message("[user] finishes wiping off [AM]!")
AM.clean_blood()
diff --git a/code/game/objects/items/reagent_containers/glass/bottle.dm b/code/game/objects/items/reagent_containers/glass/bottle.dm
index dd857d391b52..01eb751774e1 100644
--- a/code/game/objects/items/reagent_containers/glass/bottle.dm
+++ b/code/game/objects/items/reagent_containers/glass/bottle.dm
@@ -30,7 +30,7 @@
/obj/item/reagent_container/glass/bottle/Initialize()
. = ..()
if(!icon_state)
- icon_state = "bottle-[rand(1.4)]"
+ icon_state = "bottle-[rand(1,4)]"
/obj/item/reagent_container/glass/bottle/update_icon()
overlays.Cut()
diff --git a/code/game/objects/items/reagent_containers/hypospray.dm b/code/game/objects/items/reagent_containers/hypospray.dm
index fcea8997f0b5..5e268d35a33d 100644
--- a/code/game/objects/items/reagent_containers/hypospray.dm
+++ b/code/game/objects/items/reagent_containers/hypospray.dm
@@ -206,6 +206,7 @@
to_chat(user, SPAN_NOTICE(" You inject [M] with [src]."))
to_chat(M, SPAN_WARNING("You feel a tiny prick!"))
playsound(loc, injectSFX, injectVOL, 1)
+ SEND_SIGNAL(M, COMSIG_LIVING_HYPOSPRAY_INJECTED, src)
reagents.reaction(M, INGEST)
if(M.reagents)
diff --git a/code/game/objects/items/reagent_containers/pill.dm b/code/game/objects/items/reagent_containers/pill.dm
index de86ad07f53a..6c71d8be3c0c 100644
--- a/code/game/objects/items/reagent_containers/pill.dm
+++ b/code/game/objects/items/reagent_containers/pill.dm
@@ -23,6 +23,8 @@
w_class = SIZE_TINY
volume = 60
reagent_desc_override = TRUE //it has a special examining mechanic
+ ground_offset_x = 7
+ ground_offset_y = 7
var/identificable = TRUE //can medically trained people tell what's in it?
var/pill_desc = "An unknown pill." // The real description of the pill, shown when examined by a medically trained person
var/pill_icon_class = "random" // Pills with the same icon class share icons
diff --git a/code/game/objects/items/reagent_containers/reagent_container.dm b/code/game/objects/items/reagent_containers/reagent_container.dm
index eddbf5197a9e..327f6ba1ce1c 100644
--- a/code/game/objects/items/reagent_containers/reagent_container.dm
+++ b/code/game/objects/items/reagent_containers/reagent_container.dm
@@ -14,6 +14,8 @@
var/transparent = FALSE //can we see what's in it?
var/reagent_desc_override = FALSE //does it have a special examining mechanic that should override the normal /reagent_containers examine proc?
actions_types = list(/datum/action/item_action/reagent_container/set_transfer_amount)
+ ground_offset_x = 7
+ ground_offset_y = 7
/obj/item/reagent_container/Initialize()
if(!possible_transfer_amounts)
@@ -65,12 +67,6 @@
if (N)
R.amount_per_transfer_from_this = N
-/obj/item/reagent_container/Initialize()
- . = ..()
- if (!possible_transfer_amounts)
- verbs -= /obj/item/reagent_container/verb/set_APTFT //which objects actually uses it?
- create_reagents(volume)
-
/obj/item/reagent_container/Destroy()
possible_transfer_amounts = null
return ..()
diff --git a/code/game/objects/items/reagent_containers/robodropper.dm b/code/game/objects/items/reagent_containers/robodropper.dm
index 7447681f0566..694194fbef70 100644
--- a/code/game/objects/items/reagent_containers/robodropper.dm
+++ b/code/game/objects/items/reagent_containers/robodropper.dm
@@ -45,7 +45,7 @@
safe_thing.create_reagents(100)
trans = src.reagents.trans_to(safe_thing, amount_per_transfer_from_this)
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(SPAN_DANGER("[user] tries to squirt something into [target]'s eyes, but fails!"), SHOW_MESSAGE_VISIBLE)
spawn(5)
src.reagents.reaction(safe_thing, TOUCH)
@@ -58,7 +58,7 @@
return
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(SPAN_DANGER("[user] squirts something into [target]'s eyes!"), SHOW_MESSAGE_VISIBLE)
src.reagents.reaction(target, TOUCH)
diff --git a/code/game/objects/items/reagent_containers/syringes.dm b/code/game/objects/items/reagent_containers/syringes.dm
index 06cbb559360c..2bb121740cef 100644
--- a/code/game/objects/items/reagent_containers/syringes.dm
+++ b/code/game/objects/items/reagent_containers/syringes.dm
@@ -258,20 +258,20 @@
return
if (target != user && target.getarmor(target_zone, ARMOR_MELEE) > 5 && prob(50))
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(text(SPAN_DANGER("[user] tries to stab [target] in \the [hit_area] with [src.name], but the attack is deflected by armor!")), SHOW_MESSAGE_VISIBLE)
user.temp_drop_inv_item(src)
qdel(src)
return
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(text(SPAN_DANGER("[user] stabs [target] in \the [hit_area] with [src.name]!")), SHOW_MESSAGE_VISIBLE)
if(affecting.take_damage(3))
target:UpdateDamageIcon()
else
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(text(SPAN_DANGER("[user] stabs [target] with [src.name]!")), SHOW_MESSAGE_VISIBLE)
target.take_limb_damage(3)// 7 is the same as crowbar punch
diff --git a/code/game/objects/items/robot/robot_upgrades.dm b/code/game/objects/items/robot/robot_upgrades.dm
index c5fa39fd100c..de2daa9a3009 100644
--- a/code/game/objects/items/robot/robot_upgrades.dm
+++ b/code/game/objects/items/robot/robot_upgrades.dm
@@ -12,7 +12,7 @@
/obj/item/robot/upgrade/proc/action(mob/living/silicon/robot/R)
if(R.stat == DEAD)
- to_chat(usr, SPAN_DANGER("The [src] will not function on a deceased robot."))
+ to_chat(usr, SPAN_DANGER("[src] will not function on a deceased robot."))
return 1
return 0
@@ -68,7 +68,7 @@
for(var/mob/dead/observer/ghost in GLOB.observer_list)
if(ghost.mind && ghost.mind.original == R)
R.key = ghost.key
- if(R.client) R.client.change_view(world_view_size)
+ if(R.client) R.client.change_view(GLOB.world_view_size)
break
R.set_stat(CONSCIOUS)
diff --git a/code/game/objects/items/shards.dm b/code/game/objects/items/shards.dm
index 84c3d5b83427..dab573e6f5a5 100644
--- a/code/game/objects/items/shards.dm
+++ b/code/game/objects/items/shards.dm
@@ -81,7 +81,7 @@
/obj/item/large_shrapnel/proc/on_embedded_movement(mob/living/embedded_mob)
return
-/obj/item/large_shrapnel/proc/on_embed(mob/embedded_mob, obj/limb/target_organ)
+/obj/item/large_shrapnel/proc/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE)
return
/obj/item/large_shrapnel/at_rocket_dud
@@ -180,14 +180,14 @@
cell_explosion(get_turf(target), 200, 150, EXPLOSION_FALLOFF_SHAPE_LINEAR, direction, create_cause_data("[cause] UXO detonation", user))
qdel(src)
-/obj/item/large_shrapnel/at_rocket_dud/on_embed(mob/embedded_mob, obj/limb/target_organ)
+/obj/item/large_shrapnel/at_rocket_dud/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE)
if(!ishuman(embedded_mob))
return
var/mob/living/carbon/human/H = embedded_mob
if(H.species.flags & NO_SHRAPNEL)
return
if(istype(target_organ))
- target_organ.embed(src)
+ target_organ.embed(src, silent)
/obj/item/large_shrapnel/at_rocket_dud/on_embedded_movement(mob/living/embedded_mob)
if(!ishuman(embedded_mob))
@@ -212,14 +212,14 @@
source_sheet_type = null
var/damage_on_move = 0.5
-/obj/item/shard/shrapnel/proc/on_embed(mob/embedded_mob, obj/limb/target_organ)
+/obj/item/shard/shrapnel/proc/on_embed(mob/embedded_mob, obj/limb/target_organ, silent = FALSE)
if(!ishuman(embedded_mob))
return
var/mob/living/carbon/human/H = embedded_mob
if(H.species.flags & NO_SHRAPNEL)
return
if(istype(target_organ))
- target_organ.embed(src)
+ target_organ.embed(src, silent)
/obj/item/shard/shrapnel/proc/on_embedded_movement(mob/living/embedded_mob)
if(!ishuman(embedded_mob))
@@ -228,7 +228,7 @@
if(H.species.flags & NO_SHRAPNEL)
return
var/obj/limb/organ = embedded_organ
- if(istype(organ))
+ if(istype(organ) && damage_on_move)
organ.take_damage(damage_on_move * count, 0, 0, no_limb_loss = TRUE)
embedded_mob.pain.apply_pain(damage_on_move * count)
@@ -261,3 +261,7 @@
name = "alien bone fragments"
icon_state = "alienbonechips"
desc = "Sharp, jagged fragments of alien bone. Looks like the previous owner exploded violently..."
+
+/obj/item/shard/shrapnel/tutorial
+ damage_on_move = 0
+
diff --git a/code/game/objects/items/stacks/cable_coil.dm b/code/game/objects/items/stacks/cable_coil.dm
index 9135c793cd00..e846979c00b4 100644
--- a/code/game/objects/items/stacks/cable_coil.dm
+++ b/code/game/objects/items/stacks/cable_coil.dm
@@ -20,14 +20,14 @@
attack_verb = list("whipped", "lashed", "disciplined", "flogged")
stack_id = "cable coil"
attack_speed = 3
+ ground_offset_x = 2
+ ground_offset_y = 2
/obj/item/stack/cable_coil/Initialize(mapload, length = MAXCOIL, param_color = null)
. = ..()
src.amount = length
if (param_color) // It should be red by default, so only recolor it if parameter was specified.
color = param_color
- pixel_x = rand(-2,2)
- pixel_y = rand(-2,2)
updateicon()
update_wclass()
@@ -276,8 +276,6 @@
/obj/item/stack/cable_coil/cut/Initialize()
. = ..()
src.amount = rand(1,2)
- pixel_x = rand(-2,2)
- pixel_y = rand(-2,2)
updateicon()
update_wclass()
diff --git a/code/game/objects/items/stacks/medical.dm b/code/game/objects/items/stacks/medical.dm
index f96903cfb687..5434aa006137 100644
--- a/code/game/objects/items/stacks/medical.dm
+++ b/code/game/objects/items/stacks/medical.dm
@@ -95,6 +95,9 @@
to_chat(user, SPAN_WARNING("There are no wounds on [possessive] [affecting.display_name]."))
return TRUE
+/obj/item/stack/medical/bruise_pack/two
+ amount = 2
+
/obj/item/stack/medical/ointment
name = "ointment"
desc = "Used to treat burns, infected wounds, and relieve itching in unusual places."
diff --git a/code/game/objects/items/stacks/nanopaste.dm b/code/game/objects/items/stacks/nanopaste.dm
index 32e9a030462e..754a36c6012a 100644
--- a/code/game/objects/items/stacks/nanopaste.dm
+++ b/code/game/objects/items/stacks/nanopaste.dm
@@ -40,7 +40,7 @@
H.pain.recalculate_pain()
H.updatehealth()
use(1)
- var/others_msg = "\The [user] applies some nanite paste at[user != M ? " \the [M]'s" : " \the"] [S.display_name] with \the [src]." // Needs to create vars for these messages because macro doesn't work otherwise
+ var/others_msg = "\The [user] applies some nanite paste at[user != M ? " \the [M]'s" : " the"] [S.display_name] with \the [src]." // Needs to create vars for these messages because macro doesn't work otherwise
var/user_msg = "You apply some nanite paste at [user == M ? "your" : "[M]'s"] [S.display_name]."
user.visible_message(SPAN_NOTICE("[others_msg]"),\
SPAN_NOTICE("[user_msg]"))
diff --git a/code/game/objects/items/stacks/sheets/glass.dm b/code/game/objects/items/stacks/sheets/glass.dm
index 972898e6449b..7c12da0707c7 100644
--- a/code/game/objects/items/stacks/sheets/glass.dm
+++ b/code/game/objects/items/stacks/sheets/glass.dm
@@ -106,7 +106,7 @@
if(AC)
to_chat(usr, SPAN_WARNING("\The [src] cannot be built here!"))
return TRUE
- var/list/directions = new/list(cardinal)
+ var/list/directions = GLOB.cardinals.Copy()
var/i = 0
for (var/obj/structure/window/win in user.loc)
i++
@@ -114,7 +114,7 @@
to_chat(user, SPAN_DANGER("There are too many windows in this location."))
return TRUE
directions-=win.dir
- if(!(win.dir in cardinal))
+ if(!(win.dir in GLOB.cardinals))
to_chat(user, SPAN_DANGER("Can't let you do that."))
return TRUE
@@ -189,6 +189,13 @@
is_reinforced = 1
construction_options = list("One Direction", "Full Window", "Windoor")
+/obj/item/stack/sheet/glass/reinforced/medium_stack
+ amount = 25
+
+/obj/item/stack/sheet/glass/reinforced/large_stack
+ amount = 50
+
+
/obj/item/stack/sheet/glass/reinforced/cyborg
matter = null
diff --git a/code/game/objects/items/stacks/sheets/sheet_types.dm b/code/game/objects/items/stacks/sheets/sheet_types.dm
index 98a7ab036f06..a0814290ca40 100644
--- a/code/game/objects/items/stacks/sheets/sheet_types.dm
+++ b/code/game/objects/items/stacks/sheets/sheet_types.dm
@@ -10,7 +10,7 @@
/*
* Metal
*/
-var/global/list/datum/stack_recipe/metal_recipes = list ( \
+GLOBAL_LIST_INIT_TYPED(metal_recipes, /datum/stack_recipe, list ( \
new/datum/stack_recipe("barbed wire", /obj/item/stack/barbed_wire, 1, 1, 20, time = 1 SECONDS, skill_req = SKILL_CONSTRUCTION, skill_lvl = SKILL_CONSTRUCTION_TRAINED), \
new/datum/stack_recipe("metal barricade", /obj/structure/barricade/metal, 4, time = 2 SECONDS, one_per_turf = ONE_TYPE_PER_BORDER, on_floor = 1, skill_req = SKILL_CONSTRUCTION, skill_lvl = SKILL_CONSTRUCTION_TRAINED, min_time = 1 SECONDS), \
new/datum/stack_recipe("folding metal barricade", /obj/structure/barricade/plasteel/metal, 6, time = 3 SECONDS, one_per_turf = ONE_TYPE_PER_BORDER, on_floor = 1, skill_req = SKILL_CONSTRUCTION, skill_lvl = SKILL_CONSTRUCTION_ENGI, min_time = 1.5 SECONDS), \
@@ -54,7 +54,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \
null, \
new/datum/stack_recipe("metal baseball bat", /obj/item/weapon/baseballbat/metal, 10, time = 20, on_floor = 1), \
null, \
-)
+))
/obj/item/stack/sheet/metal
name = "metal sheets"
@@ -69,6 +69,7 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \
sheettype = "metal"
stack_id = "metal"
+
/obj/item/stack/sheet/metal/small_stack
amount = STACK_10
@@ -87,20 +88,20 @@ var/global/list/datum/stack_recipe/metal_recipes = list ( \
/obj/item/stack/sheet/metal/cyborg
/obj/item/stack/sheet/metal/Initialize(mapload, amount)
- recipes = metal_recipes
+ recipes = GLOB.metal_recipes
return ..()
/*
* Plasteel
*/
-var/global/list/datum/stack_recipe/plasteel_recipes = list ( \
+GLOBAL_LIST_INIT_TYPED(plasteel_recipes, /datum/stack_recipe, list ( \
new/datum/stack_recipe("plasteel barricade", /obj/structure/barricade/plasteel, 8, time = 4 SECONDS, one_per_turf = ONE_TYPE_PER_TURF, on_floor = 1, skill_req = SKILL_CONSTRUCTION, skill_lvl = SKILL_CONSTRUCTION_ENGI, min_time = 2 SECONDS),
null, \
new/datum/stack_recipe("reinforced window frame", /obj/structure/window_frame/colony/reinforced, 5, time = 40, one_per_turf = ONE_TYPE_PER_TURF, on_floor = 1, skill_req = SKILL_CONSTRUCTION, skill_lvl = SKILL_CONSTRUCTION_ENGI),
null, \
new/datum/stack_recipe("plasteel rod", /obj/item/stack/rods/plasteel, 1, 1, 30),
new/datum/stack_recipe("metal crate", /obj/structure/closet/crate, 5, time = 50, one_per_turf = ONE_TYPE_PER_TURF), \
- )
+ ))
/obj/item/stack/sheet/plasteel
name = "plasteel sheet"
@@ -114,9 +115,11 @@ var/global/list/datum/stack_recipe/plasteel_recipes = list ( \
amount_sprites = TRUE
sheettype = "plasteel"
stack_id = "plasteel"
+ ground_offset_x = 4
+ ground_offset_y = 5
/obj/item/stack/sheet/plasteel/New(loc, amount=null)
- recipes = plasteel_recipes
+ recipes = GLOB.plasteel_recipes
return ..()
@@ -138,7 +141,7 @@ var/global/list/datum/stack_recipe/plasteel_recipes = list ( \
/*
* Wood
*/
-var/global/list/datum/stack_recipe/wood_recipes = list ( \
+GLOBAL_LIST_INIT_TYPED(wood_recipes, /datum/stack_recipe, list ( \
new/datum/stack_recipe("pair of wooden sandals", /obj/item/clothing/shoes/sandal, 1), \
new/datum/stack_recipe("wood floor tile", /obj/item/stack/tile/wood, 1, 4, 20), \
/*
@@ -153,7 +156,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
new/datum/stack_recipe("baseball bat", /obj/item/weapon/baseballbat, 10, time = 20, on_floor = 1), \
new/datum/stack_recipe("wooden cross", /obj/structure/prop/wooden_cross, 2, time = 10, one_per_turf = ONE_TYPE_PER_TURF, on_floor = 1), \
new/datum/stack_recipe("wooden pole", /obj/item/weapon/pole, 3, time = 10, one_per_turf = ONE_TYPE_PER_TURF, on_floor = 1) \
- )
+ ))
/obj/item/stack/sheet/wood
name = "wooden plank"
@@ -181,7 +184,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
icon_state = "sheet-wood"
/obj/item/stack/sheet/wood/New(loc, amount=null)
- recipes = wood_recipes
+ recipes = GLOB.wood_recipes
return ..()
/*
@@ -198,7 +201,7 @@ var/global/list/datum/stack_recipe/wood_recipes = list ( \
/*
* Cardboard
*/
-var/global/list/datum/stack_recipe/cardboard_recipes = list ( \
+GLOBAL_LIST_INIT_TYPED(cardboard_recipes, /datum/stack_recipe, list ( \
new/datum/stack_recipe("box", /obj/item/storage/box), \
new/datum/stack_recipe("donut box", /obj/item/storage/donut_box/empty), \
new/datum/stack_recipe("egg box", /obj/item/storage/fancy/egg_box), \
@@ -208,6 +211,7 @@ var/global/list/datum/stack_recipe/cardboard_recipes = list ( \
new/datum/stack_recipe("cardborg suit", /obj/item/clothing/suit/cardborg, 3), \
new/datum/stack_recipe("cardborg helmet", /obj/item/clothing/head/cardborg), \
new/datum/stack_recipe("pizza box", /obj/item/pizzabox), \
+ new/datum/stack_recipe("dartboard", /obj/item/dartboard), \
null, \
new/datum/stack_recipe_list("folders",list( \
new/datum/stack_recipe("blue folder", /obj/item/folder/blue), \
@@ -219,11 +223,13 @@ var/global/list/datum/stack_recipe/cardboard_recipes = list ( \
null, \
new/datum/stack_recipe_list("empty ammo boxes",list( \
new/datum/stack_recipe("empty magazine box (88 Mod 4 AP)", /obj/item/ammo_box/magazine/mod88/empty), \
+ new/datum/stack_recipe("empty magazine box (SU-6)", /obj/item/ammo_box/magazine/su6/empty), \
+ new/datum/stack_recipe("empty magazine box (VP78)", /obj/item/ammo_box/magazine/vp78/empty), \
+ null, \
new/datum/stack_recipe("empty magazine box (M4A3)", /obj/item/ammo_box/magazine/m4a3/empty), \
new/datum/stack_recipe("empty magazine box (M4A3 AP)", /obj/item/ammo_box/magazine/m4a3/ap/empty), \
new/datum/stack_recipe("empty magazine box (M4A3 HP)", /obj/item/ammo_box/magazine/m4a3/hp/empty), \
- new/datum/stack_recipe("empty magazine box (SU-6)", /obj/item/ammo_box/magazine/su6/empty), \
- new/datum/stack_recipe("empty magazine box (VP78)", /obj/item/ammo_box/magazine/vp78/empty), \
+ new/datum/stack_recipe("empty magazine box (M4A3 Incen)", /obj/item/ammo_box/magazine/m4a3/incen/empty), \
null, \
new/datum/stack_recipe("empty speed loader box (M44)", /obj/item/ammo_box/magazine/m44/empty), \
new/datum/stack_recipe("empty speed loader box (M44 Heavy)", /obj/item/ammo_box/magazine/m44/heavy/empty), \
@@ -252,10 +258,27 @@ var/global/list/datum/stack_recipe/cardboard_recipes = list ( \
new/datum/stack_recipe("empty magazine box (M41A Incen)", /obj/item/ammo_box/magazine/incen/empty), \
new/datum/stack_recipe("empty magazine box (M41A LE)", /obj/item/ammo_box/magazine/le/empty), \
null, \
+ new/datum/stack_recipe("empty magazine box (M41A MK1)", /obj/item/ammo_box/magazine/mk1/empty), \
+ new/datum/stack_recipe("empty magazine box (M41A MK1 AP)", /obj/item/ammo_box/magazine/mk1/ap/empty), \
+ null, \
+ new/datum/stack_recipe("empty drum box (M56B)", /obj/item/ammo_box/magazine/m56b/empty), \
+ new/datum/stack_recipe("empty drum box (M56B Irradiated)", /obj/item/ammo_box/magazine/m56b/dirty/empty), \
+ new/datum/stack_recipe("empty drum box (M56D)", /obj/item/ammo_box/magazine/m56d/empty), \
+ null, \
+ new/datum/stack_recipe("empty drum box (M2C)", /obj/item/ammo_box/magazine/m2c/empty), \
+ null, \
+ new/datum/stack_recipe("empty magazine box (M41AE2)", /obj/item/ammo_box/magazine/m41ae2/empty), \
+ new/datum/stack_recipe("empty magazine box (M41AE2 Holo-Target)", /obj/item/ammo_box/magazine/m41ae2/holo/empty), \
+ new/datum/stack_recipe("empty magazine box (M41AE2 HEAP)", /obj/item/ammo_box/magazine/m41ae2/heap/empty), \
+ null, \
+ new/datum/stack_recipe("empty flamer tank box (UT-Napthal)", /obj/item/ammo_box/magazine/flamer/empty), \
+ new/datum/stack_recipe("empty flamer tank box (Napalm B-Gel)", /obj/item/ammo_box/magazine/flamer/bgel/empty), \
+ null, \
new/datum/stack_recipe("empty shotgun shell box (Beanbag)", /obj/item/ammo_box/magazine/shotgun/beanbag/empty), \
new/datum/stack_recipe("empty shotgun shell box (Buckshot)", /obj/item/ammo_box/magazine/shotgun/buckshot/empty), \
new/datum/stack_recipe("empty shotgun shell box (Flechette)", /obj/item/ammo_box/magazine/shotgun/flechette/empty), \
new/datum/stack_recipe("empty shotgun shell box (Incendiary)", /obj/item/ammo_box/magazine/shotgun/incendiary/empty), \
+ new/datum/stack_recipe("empty shotgun shell box (Incendiary Buckshot)", /obj/item/ammo_box/magazine/shotgun/incendiarybuck/empty), \
new/datum/stack_recipe("empty shotgun shell box (Slugs)", /obj/item/ammo_box/magazine/shotgun/empty), \
null, \
new/datum/stack_recipe("empty 45-70 bullets box", /obj/item/ammo_box/magazine/lever_action/empty), \
@@ -275,23 +298,48 @@ var/global/list/datum/stack_recipe/cardboard_recipes = list ( \
new/datum/stack_recipe("empty rifle ammo box (10x24mm Incen)", /obj/item/ammo_box/rounds/incen/empty), \
new/datum/stack_recipe("empty rifle ammo box (10x24mm LE)", /obj/item/ammo_box/rounds/le/empty), \
null, \
+ new/datum/stack_recipe("empty rifle ammo box (9mm)", /obj/item/ammo_box/rounds/pistol/empty), \
+ new/datum/stack_recipe("empty rifle ammo box (9mm AP)", /obj/item/ammo_box/rounds/pistol/ap/empty), \
+ new/datum/stack_recipe("empty rifle ammo box (9mm HP)", /obj/item/ammo_box/rounds/pistol/hp/empty), \
+ new/datum/stack_recipe("empty rifle ammo box (9mm Incen)", /obj/item/ammo_box/rounds/pistol/incen/empty), \
+ null, \
new/datum/stack_recipe("empty box of MREs", /obj/item/ammo_box/magazine/misc/mre/empty), \
new/datum/stack_recipe("empty box of M94 Marking Flare Packs", /obj/item/ammo_box/magazine/misc/flares/empty), \
+ new/datum/stack_recipe("empty box of M89 Signal Flare Packs", /obj/item/ammo_box/magazine/misc/flares/signal/empty), \
new/datum/stack_recipe("empty box of flashlights", /obj/item/ammo_box/magazine/misc/flashlight/empty), \
new/datum/stack_recipe("empty box of High-Capacity Power Cells", /obj/item/ammo_box/magazine/misc/power_cell/empty), \
null, \
+ new/datum/stack_recipe("empty magazine box (Desert Eagle)", /obj/item/ammo_box/magazine/deagle/empty), \
+ new/datum/stack_recipe("empty magazine box (Desert Eagle Heavy)", /obj/item/ammo_box/magazine/deagle/super/empty), \
+ new/datum/stack_recipe("empty magazine box (Desert Eagle High-Impact)", /obj/item/ammo_box/magazine/deagle/super/highimpact/empty), \
+ new/datum/stack_recipe("empty magazine box (Desert Eagle AP)", /obj/item/ammo_box/magazine/deagle/super/highimpact/ap/empty), \
+ null, \
+ new/datum/stack_recipe("empty magazine box (Spearhead HP)", /obj/item/ammo_box/magazine/spearhead/empty), \
+ new/datum/stack_recipe("empty magazine box (Spearhead)", /obj/item/ammo_box/magazine/spearhead/normalpoint/empty), \
+ null, \
new/datum/stack_recipe("empty magazine box (M16)", /obj/item/ammo_box/magazine/M16/empty), \
new/datum/stack_recipe("empty magazine box (M16 AP)", /obj/item/ammo_box/magazine/M16/ap/empty), \
null, \
+ new/datum/stack_recipe("empty magazine box (AR10)", /obj/item/ammo_box/magazine/ar10/empty), \
+ null, \
+ new/datum/stack_recipe("empty magazine box (MP5)", /obj/item/ammo_box/magazine/mp5/empty), \
+ null, \
+ new/datum/stack_recipe("empty magazine box (NSG 23)", /obj/item/ammo_box/magazine/nsg23/empty), \
+ new/datum/stack_recipe("empty magazine box (NSG 23 AP)", /obj/item/ammo_box/magazine/nsg23/ap/empty), \
+ new/datum/stack_recipe("empty magazine box (NSG 23 EX)", /obj/item/ammo_box/magazine/nsg23/ex/empty), \
+ null, \
new/datum/stack_recipe("empty magazine box (Type71)", /obj/item/ammo_box/magazine/type71/empty), \
new/datum/stack_recipe("empty magazine box (Type71 AP)", /obj/item/ammo_box/magazine/type71/ap/empty), \
null, \
+ new/datum/stack_recipe("empty magazine box (Type73)", /obj/item/ammo_box/magazine/type73/empty), \
+ new/datum/stack_recipe("empty magazine box (Type73 High-Impact)", /obj/item/ammo_box/magazine/type73/impact/empty), \
+ null, \
new/datum/stack_recipe("empty rifle ammo box (5.45x39mm)", /obj/item/ammo_box/rounds/type71/empty), \
new/datum/stack_recipe("empty rifle ammo box (5.45x39mm AP)", /obj/item/ammo_box/rounds/type71/ap/empty), \
)) \
-)
+))
/obj/item/stack/sheet/cardboard //BubbleWrap
name = "cardboard"
@@ -302,7 +350,7 @@ var/global/list/datum/stack_recipe/cardboard_recipes = list ( \
stack_id = "cardboard"
/obj/item/stack/sheet/cardboard/New(loc, amount=null)
- recipes = cardboard_recipes
+ recipes = GLOB.cardboard_recipes
return ..()
/obj/item/stack/sheet/cardboard/small_stack
@@ -317,9 +365,9 @@ var/global/list/datum/stack_recipe/cardboard_recipes = list ( \
/*
* Aluminum
*/
-var/global/list/datum/stack_recipe/aluminum_recipes = list ( \
+GLOBAL_LIST_INIT_TYPED(aluminium_recipes, /datum/stack_recipe, list ( \
new/datum/stack_recipe("flask", /obj/item/reagent_container/food/drinks/flask, 1)
- )
+ ))
/obj/item/stack/sheet/aluminum
name = "aluminum"
@@ -332,9 +380,9 @@ var/global/list/datum/stack_recipe/aluminum_recipes = list ( \
/*
* Copper
*/
-var/global/list/datum/stack_recipe/copper_recipes = list ( \
+GLOBAL_LIST_INIT_TYPED(copper_recipes, /datum/stack_recipe, list ( \
new/datum/stack_recipe("cable coil", /obj/item/stack/cable_coil, 2, 1, 20, time = 10, skill_req = SKILL_CONSTRUCTION, skill_lvl = SKILL_CONSTRUCTION_TRAINED)
- )
+ ))
/obj/item/stack/sheet/copper
name = "copper"
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index ac778c0569ed..82e091be9008 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -182,6 +182,11 @@ Also change the icon to reflect the amount of sheets, if possible.*/
to_chat(usr, SPAN_WARNING("The [R.title] cannot be built here!")) //might cause some friendly fire regarding other items like barbed wire, shouldn't be a problem?
return
+ var/obj/structure/tunnel/tunnel = locate(/obj/structure/tunnel) in usr.loc
+ if(tunnel)
+ to_chat(usr, SPAN_WARNING("The [R.title] cannot be constructed on a tunnel!"))
+ return
+
if((R.flags & RESULT_REQUIRES_SNOW) && !(istype(usr.loc, /turf/open/snow) || istype(usr.loc, /turf/open/auto_turf/snow)))
to_chat(usr, SPAN_WARNING("The [R.title] must be built on snow!"))
return
@@ -202,13 +207,21 @@ Also change the icon to reflect the amount of sheets, if possible.*/
if(check_one_per_turf(R,usr))
return
- var/atom/O = new R.result_type(usr.loc, usr)
- usr.visible_message(SPAN_NOTICE("[usr] assembles \a [O]."),
- SPAN_NOTICE("You assemble \a [O]."))
- O.setDir(usr.dir)
+ var/atom/new_item
+ if(ispath(R.result_type, /turf))
+ var/turf/current_turf = get_turf(usr)
+ if(!current_turf)
+ return
+ new_item = current_turf.ChangeTurf(R.result_type)
+ else
+ new_item = new R.result_type(usr.loc, usr)
+
+ usr.visible_message(SPAN_NOTICE("[usr] assembles \a [new_item]."),
+ SPAN_NOTICE("You assemble \a [new_item]."))
+ new_item.setDir(usr.dir)
if(R.max_res_amount > 1)
- var/obj/item/stack/new_item = O
- new_item.amount = R.res_amount * multiplier
+ var/obj/item/stack/new_stack = new_item
+ new_stack.amount = R.res_amount * multiplier
amount -= R.req_amount * multiplier
update_icon()
@@ -218,25 +231,25 @@ Also change the icon to reflect the amount of sheets, if possible.*/
usr.drop_inv_item_on_ground(oldsrc)
qdel(oldsrc)
- if(istype(O,/obj/item/stack)) //floor stacking convenience
- var/obj/item/stack/S = O
- for(var/obj/item/stack/F in usr.loc)
- if(S.stack_id == F.stack_id && S != F)
- var/diff = F.max_amount - F.amount
- if (S.amount < diff)
- F.amount += S.amount
- qdel(S)
+ if(istype(new_item,/obj/item/stack)) //floor stacking convenience
+ var/obj/item/stack/stack_item = new_item
+ for(var/obj/item/stack/found_item in usr.loc)
+ if(stack_item.stack_id == found_item.stack_id && stack_item != found_item)
+ var/diff = found_item.max_amount - found_item.amount
+ if (stack_item.amount < diff)
+ found_item.amount += stack_item.amount
+ qdel(stack_item)
else
- S.amount -= diff
- F.amount += diff
+ stack_item.amount -= diff
+ found_item.amount += diff
break
- O?.add_fingerprint(usr)
+ new_item?.add_fingerprint(usr)
//BubbleWrap - so newly formed boxes are empty
- if(isstorage(O))
- for (var/obj/item/I in O)
- qdel(I)
+ if(isstorage(new_item))
+ for (var/obj/item/found_item in new_item)
+ qdel(found_item)
//BubbleWrap END
if(src && usr.interactee == src) //do not reopen closed window
INVOKE_ASYNC(src, PROC_REF(interact), usr)
@@ -300,6 +313,8 @@ Also change the icon to reflect the amount of sheets, if possible.*/
if(mods["alt"])
if(!CAN_PICKUP(user, src))
return
+ if(amount <= 1)
+ return
var/desired = tgui_input_number(user, "How much would you like to split off from this stack?", "How much?", 1, amount-1, 1)
if(!desired)
return
diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm
index 3b65811b05b3..29c4ec15d03a 100644
--- a/code/game/objects/items/storage/backpack.dm
+++ b/code/game/objects/items/storage/backpack.dm
@@ -17,6 +17,7 @@
/obj/item/storage/firstaid = list(SKILL_MEDICAL, SKILL_MEDICAL_MEDIC),
/obj/item/storage/toolkit = list(SKILL_ENGINEER, SKILL_ENGINEER_ENGI),
)
+ drop_sound = "armorequip"
var/worn_accessible = FALSE //whether you can access its content while worn on the back
var/obj/item/card/id/locking_id = null
var/is_id_lockable = FALSE
@@ -72,9 +73,9 @@
return FALSE
// Create their vis object if needed
- if(!xeno.backpack_icon_carrier)
- xeno.backpack_icon_carrier = new(null, xeno)
- xeno.vis_contents += xeno.backpack_icon_carrier
+ if(!xeno.backpack_icon_holder)
+ xeno.backpack_icon_holder = new(null, xeno)
+ xeno.vis_contents += xeno.backpack_icon_holder
target_mob.put_in_back(src)
return FALSE
@@ -460,6 +461,12 @@
icon_state = "marinebigsatch"
max_storage_space = 20
+/obj/item/storage/backpack/marine/satchel/intel/chestrig
+ name = "\improper USCM expedition chestrig"
+ desc = "A heavy-duty IMP based chestrig, can quickly be accessed with only one hand. Usually issued to USCM intelligence officers."
+ icon_state = "intel_chestrig"
+ max_storage_space = 20
+
/obj/item/storage/backpack/marine/satchel
name = "\improper USCM satchel"
desc = "A heavy-duty satchel carried by some USCM soldiers and support personnel."
@@ -566,6 +573,18 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r
/obj/item/storage/backpack/marine/satchel/rto/pickup(mob/user)
. = ..()
+ autoset_phone_id(user)
+
+/obj/item/storage/backpack/marine/satchel/rto/equipped(mob/user, slot)
+ . = ..()
+ autoset_phone_id(user)
+
+/// Automatically sets the phone_id based on the current or updated user
+/obj/item/storage/backpack/marine/satchel/rto/proc/autoset_phone_id(mob/user)
+ if(!user)
+ internal_transmitter.phone_id = "[src]"
+ internal_transmitter.enabled = FALSE
+ return
if(ishuman(user))
var/mob/living/carbon/human/H = user
if(H.comm_title)
@@ -579,13 +598,11 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r
internal_transmitter.phone_id += " ([H.assigned_squad.name])"
else
internal_transmitter.phone_id = "[user]"
-
internal_transmitter.enabled = TRUE
/obj/item/storage/backpack/marine/satchel/rto/dropped(mob/user)
. = ..()
- internal_transmitter.phone_id = "[src]"
- internal_transmitter.enabled = FALSE
+ autoset_phone_id(null) // Disable phone when dropped
/obj/item/storage/backpack/marine/satchel/rto/proc/use_phone(mob/user)
internal_transmitter.attack_hand(user)
@@ -745,6 +762,7 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r
RegisterSignal(H, COMSIG_GRENADE_PRE_PRIME, PROC_REF(cloak_grenade_callback))
RegisterSignal(H, COMSIG_HUMAN_EXTINGUISH, PROC_REF(wrapper_fizzle_camouflage))
+ RegisterSignal(H, COMSIG_MOB_EFFECT_CLOAK_CANCEL, PROC_REF(deactivate_camouflage))
camo_active = TRUE
ADD_TRAIT(H, TRAIT_CLOAKED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK))
@@ -756,9 +774,9 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r
H.FF_hit_evade = 1000
H.allow_gun_usage = allow_gun_usage
- var/datum/mob_hud/security/advanced/SA = huds[MOB_HUD_SECURITY_ADVANCED]
+ var/datum/mob_hud/security/advanced/SA = GLOB.huds[MOB_HUD_SECURITY_ADVANCED]
SA.remove_from_hud(H)
- var/datum/mob_hud/xeno_infection/XI = huds[MOB_HUD_XENO_INFECTION]
+ var/datum/mob_hud/xeno_infection/XI = GLOB.huds[MOB_HUD_XENO_INFECTION]
XI.remove_from_hud(H)
anim(H.loc, H, 'icons/mob/mob.dmi', null, "cloak", null, H.dir)
@@ -774,12 +792,14 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r
deactivate_camouflage(wearer, TRUE, TRUE)
/obj/item/storage/backpack/marine/satchel/scout_cloak/proc/deactivate_camouflage(mob/living/carbon/human/H, anim = TRUE, forced)
+ SIGNAL_HANDLER
if(!istype(H))
return FALSE
UnregisterSignal(H, list(
COMSIG_GRENADE_PRE_PRIME,
- COMSIG_HUMAN_EXTINGUISH
+ COMSIG_HUMAN_EXTINGUISH,
+ COMSIG_MOB_EFFECT_CLOAK_CANCEL,
))
if(forced)
@@ -793,9 +813,9 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r
H.alpha = initial(H.alpha)
H.FF_hit_evade = initial(H.FF_hit_evade)
- var/datum/mob_hud/security/advanced/SA = huds[MOB_HUD_SECURITY_ADVANCED]
+ var/datum/mob_hud/security/advanced/SA = GLOB.huds[MOB_HUD_SECURITY_ADVANCED]
SA.add_to_hud(H)
- var/datum/mob_hud/xeno_infection/XI = huds[MOB_HUD_XENO_INFECTION]
+ var/datum/mob_hud/xeno_infection/XI = GLOB.huds[MOB_HUD_XENO_INFECTION]
XI.add_to_hud(H)
if(anim)
@@ -829,7 +849,7 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r
/datum/action/item_action/specialist/toggle_cloak/can_use_action()
var/mob/living/carbon/human/H = owner
- if(istype(H) && !H.is_mob_incapacitated() && !H.lying && holder_item == H.back)
+ if(istype(H) && !H.is_mob_incapacitated() && holder_item == H.back)
return TRUE
/datum/action/item_action/specialist/toggle_cloak/action_activate()
@@ -1114,6 +1134,10 @@ GLOBAL_LIST_EMPTY_TYPED(radio_packs, /obj/item/storage/backpack/marine/satchel/r
max_storage_space = 21
camo_alpha = 10
+/obj/item/storage/backpack/marine/satchel/scout_cloak/upp/weak
+ desc = "A thermo-optic camouflage cloak commonly used by UPP commando units. This one is less effective than normal."
+ actions_types = null
+
//----------TWE SECTION----------
/obj/item/storage/backpack/rmc
has_gamemode_skin = FALSE
diff --git a/code/game/objects/items/storage/belt.dm b/code/game/objects/items/storage/belt.dm
index 301f6de2bc70..40953eb97395 100644
--- a/code/game/objects/items/storage/belt.dm
+++ b/code/game/objects/items/storage/belt.dm
@@ -151,7 +151,7 @@
storage_slots = 14
max_w_class = SIZE_MEDIUM
max_storage_space = 28
- var/mode = 0 //Pill picking mode
+ var/mode = 1 //Picking from pill bottle mode
can_hold = list(
/obj/item/device/healthanalyzer,
@@ -648,7 +648,7 @@
/obj/item/storage/belt/shotgun/full/random/fill_preset_inventory()
for(var/i = 1 to storage_slots)
- var/random_shell_type = pick(shotgun_handfuls_12g)
+ var/random_shell_type = pick(GLOB.shotgun_handfuls_12g)
new random_shell_type(src)
/obj/item/storage/belt/shotgun/attackby(obj/item/W, mob/user)
diff --git a/code/game/objects/items/storage/boxes.dm b/code/game/objects/items/storage/boxes.dm
index 6266f0eef77d..8e4ffb90d2bd 100644
--- a/code/game/objects/items/storage/boxes.dm
+++ b/code/game/objects/items/storage/boxes.dm
@@ -151,6 +151,7 @@
RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PRESETUP, PROC_REF(handle_delete_clash_contents))
/obj/item/storage/box/flashbangs/proc/handle_delete_clash_contents()
+ SIGNAL_HANDLER
if(MODE_HAS_FLAG(MODE_FACTION_CLASH))
var/grenade_count = 0
var/grenades_desired = 4
@@ -760,3 +761,211 @@
else if(!isopened)
isopened = 1
icon_state = "mealpackopened"
+
+//food boxes for storage in bulk
+
+//meat
+/obj/item/storage/box/meat
+ name = "box of meat"
+
+/obj/item/storage/box/meat/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/meat/monkey(src)
+
+//fish
+/obj/item/storage/box/fish
+ name = "box of fish"
+
+/obj/item/storage/box/fish/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/carpmeat(src)
+
+//grocery
+
+//milk
+/obj/item/storage/box/milk
+ name = "box of milk"
+
+/obj/item/storage/box/milk/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/drinks/milk(src)
+
+//soymilk
+/obj/item/storage/box/soymilk
+ name = "box of soymilk"
+
+/obj/item/storage/box/soymilk/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/drinks/soymilk(src)
+
+//enzyme
+/obj/item/storage/box/enzyme
+ name = "box of enzyme"
+
+/obj/item/storage/box/enzyme/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/condiment/enzyme(src)
+
+//dry storage
+
+//flour
+/obj/item/storage/box/flour
+ name = "box of flour"
+
+/obj/item/storage/box/flour/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/flour(src)
+
+//sugar
+/obj/item/storage/box/sugar
+ name = "box of sugar"
+
+/obj/item/storage/box/sugar/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/condiment/sugar(src)
+
+//saltshaker
+/obj/item/storage/box/saltshaker
+ name = "box of saltshakers"
+
+/obj/item/storage/box/saltshaker/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/condiment/saltshaker(src)
+
+//peppermill
+/obj/item/storage/box/peppermill
+ name = "box of peppermills"
+
+/obj/item/storage/box/peppermill/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/condiment/peppermill(src)
+
+//mint
+/obj/item/storage/box/mint
+ name = "box of mints"
+
+/obj/item/storage/box/mint/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/mint(src)
+
+// ORGANICS
+
+//apple
+/obj/item/storage/box/apple
+ name = "box of apples"
+
+/obj/item/storage/box/apple/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/apple(src)
+
+//banana
+/obj/item/storage/box/banana
+ name = "box of bananas"
+
+/obj/item/storage/box/banana/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/banana(src)
+
+//chanterelle
+/obj/item/storage/box/chanterelles
+ name = "box of chanterelle"
+
+/obj/item/storage/box/chanterelle/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/mushroom/chanterelle(src)
+
+//cherries
+/obj/item/storage/box/cherries
+ name = "box of cherries"
+
+/obj/item/storage/box/cherries/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/cherries(src)
+
+//chili
+/obj/item/storage/box/chili
+ name = "box of chili"
+
+/obj/item/storage/box/chili/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/chili(src)
+
+//cabbage
+/obj/item/storage/box/cabbage
+ name = "box of cabbages"
+
+/obj/item/storage/box/cabbage/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/cabbage(src)
+
+//carrot
+/obj/item/storage/box/carrot
+ name = "box of carrots"
+
+/obj/item/storage/box/carrot/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/carrot(src)
+
+//corn
+/obj/item/storage/box/corn
+ name = "box of corn"
+
+/obj/item/storage/box/corn/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/corn(src)
+
+//eggplant
+/obj/item/storage/box/eggplant
+ name = "box of eggplants"
+
+/obj/item/storage/box/eggplant/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/eggplant(src)
+
+//lemon
+/obj/item/storage/box/lemon
+ name = "box of lemons"
+
+/obj/item/storage/box/lemon/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/lemon(src)
+
+//lime
+/obj/item/storage/box/lime
+ name = "box of limes"
+
+/obj/item/storage/box/lime/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/lime(src)
+
+//orange
+/obj/item/storage/box/orange
+ name = "box of oranges"
+
+/obj/item/storage/box/orange/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/orange(src)
+
+//potato
+/obj/item/storage/box/potato
+ name = "box of potatoes"
+
+/obj/item/storage/box/potato/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/potato(src)
+
+//tomato
+/obj/item/storage/box/tomato
+ name = "box of tomatoes"
+
+/obj/item/storage/box/tomato/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/tomato(src)
+
+//whitebeet
+/obj/item/storage/box/whitebeet
+ name = "box of whitebeet"
+
+/obj/item/storage/box/whitebeet/fill_preset_inventory()
+ for(var/i in 1 to 7)
+ new /obj/item/reagent_container/food/snacks/grown/whitebeet(src)
diff --git a/code/game/objects/items/storage/fancy.dm b/code/game/objects/items/storage/fancy.dm
index ea43d6b074b9..d12f09c2042e 100644
--- a/code/game/objects/items/storage/fancy.dm
+++ b/code/game/objects/items/storage/fancy.dm
@@ -71,7 +71,7 @@
storage_slots = 5
throwforce = 2
flags_equip_slot = SLOT_WAIST
-
+ can_hold = list(/obj/item/tool/candle)
/obj/item/storage/fancy/candle_box/fill_preset_inventory()
for(var/i=1; i <= storage_slots; i++)
@@ -302,7 +302,7 @@
if(istype(W) && !W.heat_source && !W.burnt)
if(prob(burn_chance))
to_chat(user, SPAN_WARNING("\The [W] lights, but you burn your hand in the process! Ouch!"))
- user.apply_damage(3, BRUTE, pick("r_hand", "l_hand"))
+ user.apply_damage(3, BURN, pick("r_hand", "l_hand"))
if((user.pain.feels_pain) && prob(25))
user.emote("scream")
W.light_match()
diff --git a/code/game/objects/items/storage/firstaid.dm b/code/game/objects/items/storage/firstaid.dm
index 509690a8dc2a..06337995479f 100644
--- a/code/game/objects/items/storage/firstaid.dm
+++ b/code/game/objects/items/storage/firstaid.dm
@@ -98,6 +98,11 @@
/obj/item/storage/firstaid/regular/empty/fill_preset_inventory()
return
+/obj/item/storage/firstaid/regular/response
+ desc = "It's an emergency medical kit containing basic medication and equipment. No training required to use. This one is simpler and requires no training to store."
+ required_skill_for_nest_opening = SKILL_MEDICAL
+ required_skill_level_for_nest_opening = SKILL_MEDICAL_DEFAULT
+
/obj/item/storage/firstaid/robust
icon_state = "firstaid"
@@ -645,19 +650,19 @@
if(!idlock)
return TRUE
- var/mob/living/carbon/human/H = user
+ var/mob/living/carbon/human/human_user = user
- if(!allowed(user))
+ if(!allowed(human_user))
to_chat(user, SPAN_NOTICE("It must have some kind of ID lock..."))
return FALSE
- var/obj/item/card/id/I = H.wear_id
- if(!istype(I)) //not wearing an ID
- to_chat(H, SPAN_NOTICE("It must have some kind of ID lock..."))
+ var/obj/item/card/id/idcard = human_user.wear_id
+ if(!istype(idcard)) //not wearing an ID
+ to_chat(human_user, SPAN_NOTICE("It must have some kind of ID lock..."))
return FALSE
- if(I.registered_name != H.real_name)
- to_chat(H, SPAN_WARNING("Wrong ID card owner detected."))
+ if(!idcard.check_biometrics(human_user))
+ to_chat(human_user, SPAN_WARNING("Wrong ID card owner detected."))
return FALSE
return TRUE
diff --git a/code/game/objects/items/storage/internal.dm b/code/game/objects/items/storage/internal.dm
index 68bdda8d7e7b..a491df12f086 100644
--- a/code/game/objects/items/storage/internal.dm
+++ b/code/game/objects/items/storage/internal.dm
@@ -25,10 +25,10 @@
//Items that use internal storage have the option of calling this to emulate default storage MouseDrop behaviour.
//Returns 1 if the master item's parent's MouseDrop() should be called, 0 otherwise. It's strange, but no other way of
//Doing it without the ability to call another proc's parent, really.
-/obj/item/storage/internal/proc/handle_mousedrop(mob/user as mob, obj/over_object as obj)
+/obj/item/storage/internal/proc/handle_mousedrop(mob/living/carbon/human/user, obj/over_object as obj)
if(ishuman(user))
- if(user.lying) //Can't use your inventory when lying
+ if(user.body_position == LYING_DOWN) //Can't use your inventory when lying //what about stuns? don't argue
return
if(QDELETED(master_object))
@@ -84,8 +84,8 @@
//Items that use internal storage have the option of calling this to emulate default storage attack_hand behaviour.
//Returns 1 if the master item's parent's attack_hand() should be called, 0 otherwise.
//It's strange, but no other way of doing it without the ability to call another proc's parent, really.
-/obj/item/storage/internal/proc/handle_attack_hand(mob/user as mob, mods)
- if(user.lying)
+/obj/item/storage/internal/proc/handle_attack_hand(mob/living/user as mob, mods)
+ if(user.body_position == LYING_DOWN) // what about stuns? huh?
return FALSE
if(ishuman(user))
diff --git a/code/game/objects/items/storage/large_holster.dm b/code/game/objects/items/storage/large_holster.dm
index ef2bcfb7216a..3f653926f8b3 100644
--- a/code/game/objects/items/storage/large_holster.dm
+++ b/code/game/objects/items/storage/large_holster.dm
@@ -75,20 +75,20 @@
desc = "A large leather scabbard used to carry a M2132 machete. It can be strapped to the back or the armor."
icon_state = "machete_holster"
flags_equip_slot = SLOT_WAIST|SLOT_BACK
- can_hold = list(/obj/item/weapon/claymore/mercsword/machete)
+ can_hold = list(/obj/item/weapon/sword/machete)
/obj/item/storage/large_holster/machete/full/fill_preset_inventory()
- new /obj/item/weapon/claymore/mercsword/machete(src)
+ new /obj/item/weapon/sword/machete(src)
/obj/item/storage/large_holster/machete/arnold
name = "\improper QH20 pattern M2100 custom machete scabbard"
desc = "A large leather scabbard used to carry a M2100 \"Ngájhe\" machete. It can be strapped to the back or the armor."
icon_state = "arnold-machete-pouch"
flags_equip_slot = SLOT_WAIST|SLOT_BACK
- can_hold = list(/obj/item/weapon/claymore/mercsword/machete)
+ can_hold = list(/obj/item/weapon/sword/machete)
/obj/item/storage/large_holster/machete/arnold/full/fill_preset_inventory()
- new /obj/item/weapon/claymore/mercsword/machete/arnold(src)
+ new /obj/item/weapon/sword/machete/arnold(src)
/obj/item/storage/large_holster/katana
name = "\improper katana scabbard"
@@ -97,10 +97,10 @@
force = 12
attack_verb = list("bludgeoned", "struck", "cracked")
flags_equip_slot = SLOT_WAIST|SLOT_BACK
- can_hold = list(/obj/item/weapon/katana)
+ can_hold = list(/obj/item/weapon/sword/katana)
/obj/item/storage/large_holster/katana/full/fill_preset_inventory()
- new /obj/item/weapon/katana(src)
+ new /obj/item/weapon/sword/katana(src)
/obj/item/storage/large_holster/ceremonial_sword
name = "ceremonial sword scabbard"
@@ -108,10 +108,10 @@
icon_state = "ceremonial_sword_holster"//object icon is duplicate of katana holster, needs new icon at some point.
force = 12
flags_equip_slot = SLOT_WAIST
- can_hold = list(/obj/item/weapon/claymore/mercsword/ceremonial)
+ can_hold = list(/obj/item/weapon/sword/ceremonial)
/obj/item/storage/large_holster/ceremonial_sword/full/fill_preset_inventory()
- new /obj/item/weapon/claymore/mercsword/ceremonial(src)
+ new /obj/item/weapon/sword/ceremonial(src)
/obj/item/storage/large_holster/m39
name = "\improper M276 pattern M39 holster rig"
@@ -249,9 +249,16 @@
if(!ishuman(user) || user.is_mob_incapacitated())
return FALSE
- var/obj/item/weapon/gun/flamer/M240T/F = user.get_active_hand()
- if(!istype(F))
- to_chat(usr, "You must be holding the M240-T incinerator unit to use [src]")
+ if(user.back != src)
+ to_chat(user, SPAN_WARNING("[src] must be equipped before you can switch types."))
+ return
+
+ if(!linked_flamer)
+ to_chat(user, SPAN_WARNING("An incinerator unit must be linked in order to switch fuel types."))
+ return
+
+ if(user.get_active_hand() != linked_flamer)
+ to_chat(user, SPAN_WARNING("You must be holding [linked_flamer] to use [src]."))
return
if(!active_fuel)
@@ -267,14 +274,13 @@
else
active_fuel = fuelB
- for(var/X in actions)
- var/datum/action/A = X
- A.update_button_icon()
+ for(var/datum/action/action_added as anything in actions)
+ action_added.update_button_icon()
to_chat(user, "You switch the fuel tank to [active_fuel.caliber]")
playsound(src, 'sound/machines/click.ogg', 25, TRUE)
- F.current_mag = active_fuel
- F.update_icon()
+ linked_flamer.current_mag = active_fuel
+ linked_flamer.update_icon()
return TRUE
@@ -326,7 +332,7 @@
/obj/item/storage/large_holster/fuelpack/get_examine_text(mob/user)
. = ..()
if(contents.len)
- . += "It is storing \a M240-T incinerator unit."
+ . += "It is storing a M240-T incinerator unit."
if (get_dist(user, src) <= 1)
if(fuel)
. += "The [fuel.caliber] currently contains: [round(fuel.get_ammo_percent())]% fuel."
@@ -364,7 +370,7 @@
/datum/action/item_action/specialist/toggle_fuel/can_use_action()
var/mob/living/carbon/human/H = owner
- if(istype(H) && !H.is_mob_incapacitated() && !H.lying && holder_item == H.back)
+ if(istype(H) && !H.is_mob_incapacitated() && H.body_position == STANDING_UP && holder_item == H.back)
return TRUE
/datum/action/item_action/specialist/toggle_fuel/action_activate()
diff --git a/code/game/objects/items/storage/pouch.dm b/code/game/objects/items/storage/pouch.dm
index a443a3b27cd0..acb87e988879 100644
--- a/code/game/objects/items/storage/pouch.dm
+++ b/code/game/objects/items/storage/pouch.dm
@@ -142,9 +142,9 @@
/obj/item/storage/pouch/survival
name = "survival pouch"
- desc = "It can carry flashlights, a pill, a crowbar, metal sheets, and some bandages."
+ desc = "A pouch given to colonists in the event of an emergency."
icon_state = "tools"
- storage_slots = 6
+ storage_slots = 7
max_w_class = SIZE_MEDIUM
can_hold = list(
/obj/item/device/flashlight,
@@ -153,6 +153,7 @@
/obj/item/stack/medical/bruise_pack,
/obj/item/device/radio,
/obj/item/attachable/bayonet,
+ /obj/item/stack/medical/splint,
)
/obj/item/storage/pouch/survival/full/fill_preset_inventory()
@@ -162,12 +163,12 @@
new /obj/item/stack/medical/bruise_pack(src)
new /obj/item/device/radio(src)
new /obj/item/attachable/bayonet(src)
-
+ new /obj/item/stack/medical/splint(src)
/obj/item/storage/pouch/survival/synth
name = "synth survival pouch"
desc = "An emergency pouch given to synthetics in the event of an emergency."
icon_state = "tools"
- storage_slots = 7
+ storage_slots = 6
max_w_class = SIZE_MEDIUM
can_hold = list(
/obj/item/device/flashlight,
@@ -180,7 +181,6 @@
)
/obj/item/storage/pouch/survival/synth/full/fill_preset_inventory()
- new /obj/item/device/flashlight(src)
new /obj/item/tool/crowbar/red(src)
new /obj/item/tool/weldingtool(src)
new /obj/item/stack/cable_coil(src)
@@ -683,6 +683,18 @@
new /obj/item/reagent_container/hypospray/autoinjector/stimulant/redemption_stimulant(src)
new /obj/item/reagent_container/hypospray/autoinjector/stimulant/speed_stimulant(src)
+/obj/item/storage/pouch/medical/socmed/not_op/fill_preset_inventory()
+ new /obj/item/device/healthanalyzer(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/advanced/bruise_pack(src)
+ new /obj/item/stack/medical/advanced/ointment(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/bicaridine(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/kelotane(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/oxycodone(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/emergency(src)
+ new /obj/item/reagent_container/hypospray/autoinjector/emergency(src)
+ new /obj/item/tool/extinguisher/mini(src)
+
/obj/item/storage/pouch/medical/socmed/dutch
name = "\improper Dutch's Medical Pouch"
desc = "A pouch bought from a black market trader by Dutch quite a few years ago. Rumoured to be stolen from secret USCM assets. Its contents have been slowly used up and replaced over the years."
@@ -833,6 +845,15 @@
new /obj/item/stack/medical/advanced/ointment(src)
new /obj/item/stack/medical/splint(src)
+/obj/item/storage/pouch/medkit/full/toxin/fill_preset_inventory()
+ new /obj/item/device/healthanalyzer(src)
+ new /obj/item/storage/pill_bottle/antitox(src)
+ new /obj/item/storage/pill_bottle/antitox(src)
+ new /obj/item/roller(src)
+ new /obj/item/stack/medical/splint(src)
+ new /obj/item/stack/medical/advanced/bruise_pack(src)
+ new /obj/item/stack/medical/advanced/ointment(src)
+
/obj/item/storage/pouch/pressurized_reagent_canister
name = "Pressurized Reagent Canister Pouch"
max_w_class = SIZE_SMALL
@@ -1172,23 +1193,37 @@
/obj/item/storage/pouch/tools
name = "tools pouch"
- desc = "It's designed to hold maintenance tools - screwdriver, wrench, cable coil, etc. It also has a hook for an entrenching tool."
+ desc = "It's designed to hold maintenance tools - screwdriver, wrench, cable coil, etc. It also has a hook for an entrenching tool or light replacer."
storage_slots = 4
max_w_class = SIZE_MEDIUM
icon_state = "tools"
can_hold = list(
- /obj/item/tool/wirecutters,
- /obj/item/tool/shovel/etool,
- /obj/item/tool/screwdriver,
/obj/item/tool/crowbar,
+ /obj/item/tool/screwdriver,
/obj/item/tool/weldingtool,
- /obj/item/device/multitool,
+ /obj/item/tool/wirecutters,
/obj/item/tool/wrench,
- /obj/item/stack/cable_coil,
/obj/item/tool/extinguisher/mini,
/obj/item/tool/shovel/etool,
+ /obj/item/stack/cable_coil,
+ /obj/item/weapon/gun/smg/nailgun/compact,
+ /obj/item/cell,
+ /obj/item/circuitboard,
+ /obj/item/stock_parts,
+ /obj/item/device/demo_scanner,
+ /obj/item/device/reagent_scanner,
+ /obj/item/device/assembly,
+ /obj/item/device/multitool,
+ /obj/item/device/flashlight,
+ /obj/item/device/t_scanner,
+ /obj/item/device/analyzer,
+ /obj/item/explosive/plastic,
+ /obj/item/device/lightreplacer,
+ )
+ bypass_w_limit = list(
+ /obj/item/tool/shovel/etool,
+ /obj/item/device/lightreplacer,
)
- bypass_w_limit = list(/obj/item/tool/shovel/etool)
/obj/item/storage/pouch/tools/tactical
name = "tactical tools pouch"
@@ -1358,7 +1393,7 @@
item_state = "machete_holster"
max_w_class = SIZE_LARGE
storage_flags = STORAGE_FLAGS_POUCH|STORAGE_USING_DRAWING_METHOD|STORAGE_ALLOW_QUICKDRAW
- can_hold = list(/obj/item/weapon/claymore/mercsword/machete)
+ can_hold = list(/obj/item/weapon/sword/machete)
var/sheathe_sound = 'sound/weapons/gun_rifle_draw.ogg'
var/draw_sound = 'sound/weapons/gun_rifle_draw.ogg'
@@ -1378,4 +1413,4 @@
playsound(src, draw_sound, vol = 15, vary = TRUE)
/obj/item/storage/pouch/machete/full/fill_preset_inventory()
- new /obj/item/weapon/claymore/mercsword/machete(src)
+ new /obj/item/weapon/sword/machete(src)
diff --git a/code/game/objects/items/storage/smartpack.dm b/code/game/objects/items/storage/smartpack.dm
index 8df079c92ca4..d012e773617b 100644
--- a/code/game/objects/items/storage/smartpack.dm
+++ b/code/game/objects/items/storage/smartpack.dm
@@ -144,7 +144,7 @@
immobile_form = FALSE
M.status_flags |= CANPUSH
M.anchored = FALSE
- M.unfreeze()
+ REMOVE_TRAIT(M, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK))
..()
/obj/item/storage/backpack/marine/smartpack/attack_self(mob/user)
@@ -223,7 +223,7 @@
user.remove_filter("synth_protective_form")
-/obj/item/storage/backpack/marine/smartpack/proc/immobile_form(mob/user)
+/obj/item/storage/backpack/marine/smartpack/proc/immobile_form(mob/living/user)
if(activated_form)
return
@@ -236,7 +236,7 @@
battery_charge -= IMMOBILE_COST
user.status_flags &= ~CANPUSH
user.anchored = TRUE
- user.frozen = TRUE
+ ADD_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK))
to_chat(user, SPAN_DANGER("[name] beeps, \"You are anchored in place and cannot be moved.\""))
to_chat(user, SPAN_INFO("The current charge reads [battery_charge]/[SMARTPACK_MAX_POWER_STORED]"))
@@ -248,7 +248,7 @@
else
user.status_flags |= CANPUSH
user.anchored = FALSE
- user.unfreeze()
+ REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_EQUIPMENT(WEAR_BACK))
to_chat(user, SPAN_DANGER("[name] beeps, \"You can now move again.\""))
user.remove_filter("synth_immobile_form")
diff --git a/code/game/objects/items/storage/storage.dm b/code/game/objects/items/storage/storage.dm
index e3fbe86c0e3b..6e7e891d6ba8 100644
--- a/code/game/objects/items/storage/storage.dm
+++ b/code/game/objects/items/storage/storage.dm
@@ -22,7 +22,7 @@
var/atom/movable/screen/storage/storage_start = null //storage UI
var/atom/movable/screen/storage/storage_continue = null
var/atom/movable/screen/storage/storage_end = null
- var/datum/item_storage_box/stored_ISB = null // This contains what previously was known as stored_start, stored_continue, and stored_end
+ var/datum/item_storage_box/stored_ISB //! This contains what previously was known as stored_start, stored_continue, and stored_end
var/atom/movable/screen/close/closer = null
var/foldable = null
var/use_sound = "rustle" //sound played when used. null for no sound.
@@ -212,16 +212,17 @@
if (storage_flags & STORAGE_SHOW_FULLNESS)
boxes.update_fullness(src)
-var/list/global/item_storage_box_cache = list()
+GLOBAL_LIST_EMPTY_TYPED(item_storage_box_cache, /datum/item_storage_box)
/datum/item_storage_box
- var/atom/movable/screen/storage/start = null
- var/atom/movable/screen/storage/continued = null
- var/atom/movable/screen/storage/end = null
- /// The index that indentifies me inside item_storage_box_cache
+ var/atom/movable/screen/storage/start
+ var/atom/movable/screen/storage/continued
+ var/atom/movable/screen/storage/end
+ /// The index that indentifies me inside GLOB.item_storage_box_cache
var/index
/datum/item_storage_box/New()
+ . = ..()
start = new()
start.icon_state = "stored_start"
continued = new()
@@ -233,7 +234,7 @@ var/list/global/item_storage_box_cache = list()
QDEL_NULL(start)
QDEL_NULL(continued)
QDEL_NULL(end)
- item_storage_box_cache[index] = null // Or would it be better to -= src?
+ GLOB.item_storage_box_cache -= index
return ..()
/obj/item/storage/proc/space_orient_objs(list/obj/item/display_contents)
@@ -271,7 +272,7 @@ var/list/global/item_storage_box_cache = list()
click_border_start.Add(startpoint)
click_border_end.Add(endpoint)
- if(!item_storage_box_cache[isb_index])
+ if(!GLOB.item_storage_box_cache[isb_index])
var/datum/item_storage_box/box = new()
var/matrix/M_start = matrix()
var/matrix/M_continue = matrix()
@@ -284,9 +285,9 @@ var/list/global/item_storage_box_cache = list()
box.continued.apply_transform(M_continue)
box.end.apply_transform(M_end)
box.index = isb_index
- item_storage_box_cache[isb_index] = box
+ GLOB.item_storage_box_cache[isb_index] = box
- var/datum/item_storage_box/ISB = item_storage_box_cache[isb_index]
+ var/datum/item_storage_box/ISB = GLOB.item_storage_box_cache[isb_index]
stored_ISB = ISB
storage_start.overlays += ISB.start
@@ -851,6 +852,7 @@ W is always an item. stop_warning prevents messaging. user may be null.**/
return ..()
/obj/item/storage/emp_act(severity)
+ . = ..()
if(!istype(src.loc, /mob/living))
for(var/obj/O in contents)
O.emp_act(severity)
diff --git a/code/game/objects/items/tools/experimental_tools.dm b/code/game/objects/items/tools/experimental_tools.dm
index d27272881e1e..221aa279a53b 100644
--- a/code/game/objects/items/tools/experimental_tools.dm
+++ b/code/game/objects/items/tools/experimental_tools.dm
@@ -279,7 +279,7 @@
return
if(ishuman(user))
- if(user.stat || user.blinded || user.lying)
+ if(user.stat || user.blinded || user.body_position == LYING_DOWN)
return
if(attaching)
diff --git a/code/game/objects/items/tools/flame_tools.dm b/code/game/objects/items/tools/flame_tools.dm
index 130bd567098b..8fc97f973702 100644
--- a/code/game/objects/items/tools/flame_tools.dm
+++ b/code/game/objects/items/tools/flame_tools.dm
@@ -180,7 +180,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
flags_atom = CAN_BE_SYRINGED
attack_verb = list("burnt", "singed")
blood_overlay_type = ""
- light_color = LIGHT_COLOUR_ORANGE
+ light_color = LIGHT_COLOR_ORANGE
/// Note - these are in masks.dmi not in cigarette.dmi
var/icon_on = "cigon"
var/icon_off = "cigoff"
@@ -233,12 +233,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
light(SPAN_NOTICE("[user] fiddles with [W], and manages to light their [name]."))
else if(istype(W, /obj/item/attachable/attached_gun/flamer))
- light(SPAN_NOTICE("[user] lights their [src] with the [W]."))
+ light(SPAN_NOTICE("[user] lights their [name] with [W]."))
else if(istype(W, /obj/item/weapon/gun/flamer))
var/obj/item/weapon/gun/flamer/F = W
if(!(F.flags_gun_features & GUN_TRIGGER_SAFETY))
- light(SPAN_NOTICE("[user] lights their [src] with the pilot light of the [F]."))
+ light(SPAN_NOTICE("[user] lights their [name] with the pilot light of [F]."))
else
to_chat(user, SPAN_WARNING("Turn on the pilot light first!"))
@@ -246,20 +246,20 @@ CIGARETTE PACKETS ARE IN FANCY.DM
var/obj/item/weapon/gun/G = W
for(var/slot in G.attachments)
if(istype(G.attachments[slot], /obj/item/attachable/attached_gun/flamer))
- light(SPAN_NOTICE("[user] lights their [src] with [G.attachments[slot]]."))
+ light(SPAN_NOTICE("[user] lights their [name] with [G.attachments[slot]]."))
break
else if(istype(W, /obj/item/tool/surgery/cautery))
- light(SPAN_NOTICE("[user] lights their [src] with the [W]."))
+ light(SPAN_NOTICE("[user] lights their [name] with [W]."))
else if(istype(W, /obj/item/clothing/mask/cigarette))
var/obj/item/clothing/mask/cigarette/C = W
if(C.item_state == icon_on)
- light(SPAN_NOTICE("[user] lights their [src] with the [C] after a few attempts."))
+ light(SPAN_NOTICE("[user] lights their [name] with [C] after a few attempts."))
else if(istype(W, /obj/item/tool/candle))
if(W.heat_source > 200)
- light(SPAN_NOTICE("[user] lights their [src] with the [W] after a few attempts."))
+ light(SPAN_NOTICE("[user] lights their [name] with [W] after a few attempts."))
return
@@ -529,12 +529,12 @@ CIGARETTE PACKETS ARE IN FANCY.DM
light(SPAN_NOTICE("[user] fiddles with [W], and manages to light their [name] with the power of science."))
else if(istype(W, /obj/item/attachable/attached_gun/flamer))
- light(SPAN_NOTICE("[user] lights their [src] with the [W], bet that would have looked cooler if it was attached to something first!"))
+ light(SPAN_NOTICE("[user] lights their [name] with [W], bet that would have looked cooler if it was attached to something first!"))
else if(istype(W, /obj/item/weapon/gun/flamer))
var/obj/item/weapon/gun/flamer/F = W
if(!(F.flags_gun_features & GUN_TRIGGER_SAFETY))
- light(SPAN_NOTICE("[user] lights their [src] with the pilot light of the [F], the glint of pyromania in their eye."))
+ light(SPAN_NOTICE("[user] lights their [name] with the pilot light of [F], the glint of pyromania in their eye."))
else
to_chat(user, SPAN_WARNING("Turn on the pilot light first!"))
@@ -546,16 +546,16 @@ CIGARETTE PACKETS ARE IN FANCY.DM
break
else if(istype(W, /obj/item/tool/surgery/cautery))
- light(SPAN_NOTICE("[user] lights their [src] with the [W], that can't be sterile!"))
+ light(SPAN_NOTICE("[user] lights their [name] with [W], that can't be sterile!"))
else if(istype(W, /obj/item/clothing/mask/cigarette))
var/obj/item/clothing/mask/cigarette/C = W
if(C.item_state == icon_on)
- light(SPAN_NOTICE("[user] lights their [src] with the [C] after a few attempts."))
+ light(SPAN_NOTICE("[user] lights their [name] with [C] after a few attempts."))
else if(istype(W, /obj/item/tool/candle))
if(W.heat_source > 200)
- light(SPAN_NOTICE("[user] lights their [src] with the [W] after a few attempts."))
+ light(SPAN_NOTICE("[user] lights their [name] with [W] after a few attempts."))
/////////////////
//SMOKING PIPES//
@@ -642,7 +642,39 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon_off = "cobpipeoff"
smoketime = 800 SECONDS
+/obj/item/clothing/mask/electronic_cigarette
+ name = "electronic cigarette"
+ desc = "An electronic cigarette by The American Tobacco Company, who also made Lucky Strikes."
+ icon_state = "cigoff"
+ item_state = "cigoff"
+ w_class = SIZE_SMALL
+ flags_equip_slot = SLOT_EAR|SLOT_FACE
+ var/icon_on = "cigon"
+ var/icon_off = "cigoff"
+ var/enabled = FALSE
+
+/obj/item/clothing/mask/electronic_cigarette/update_icon()
+ . = ..()
+ if(enabled)
+ icon_state = icon_on
+ item_state = icon_on
+ return
+ icon_state = icon_off
+ item_state = icon_off
+/obj/item/clothing/mask/electronic_cigarette/attack_self(mob/user)
+ . = ..()
+ to_chat(user, SPAN_NOTICE("You [enabled ? "disable" : "enable"] [src]."))
+ enabled = !enabled
+ update_icon()
+
+/obj/item/clothing/mask/electronic_cigarette/cigar
+ name = "electronic cigar"
+ desc = "A luxury electronic cigar, with its labels scratched off. Where could this be from?"
+ icon_state = "cigar_off"
+ item_state = "cigar_off"
+ icon_on = "cigar_on"
+ icon_off = "cigar_off"
/////////
//ZIPPO//
@@ -653,7 +685,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
icon = 'icons/obj/items/items.dmi'
icon_state = "lighter_g"
item_state = "lighter_g"
- light_color = LIGHT_COLOUR_LAVA
+ light_color = LIGHT_COLOR_LAVA
var/icon_on = "lighter_g_on"
var/icon_off = "lighter_g"
var/clr = "g"
@@ -719,7 +751,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
else
playsound(src.loc,"lighter",10, 1, 3)
if(prob(95))
- user.visible_message(SPAN_NOTICE("After a few attempts, [user] manages to light the [src]."))
+ user.visible_message(SPAN_NOTICE("After a few attempts, [user] manages to light [src]."))
else
to_chat(user, SPAN_WARNING("You burn yourself while lighting the lighter."))
@@ -727,7 +759,7 @@ CIGARETTE PACKETS ARE IN FANCY.DM
user.apply_damage(2,BURN,"l_hand")
else
user.apply_damage(2,BURN,"r_hand")
- user.visible_message(SPAN_NOTICE("After a few attempts, [user] manages to light the [src], they however burn their finger in the process."))
+ user.visible_message(SPAN_NOTICE("After a few attempts, [user] manages to light [src], they however burn their finger in the process."))
set_light_range(2)
set_light_on(TRUE)
@@ -745,10 +777,10 @@ CIGARETTE PACKETS ARE IN FANCY.DM
item_state = icon_off
if(!silent)
if(istype(src, /obj/item/tool/lighter/zippo) )
- bearer.visible_message("You hear a quiet click, as [bearer] shuts off [src] without even looking at what they're doing.")
+ bearer.visible_message(SPAN_ROSE("You hear a quiet click, as [bearer] shuts off [src] without even looking at what they're doing."))
playsound(src.loc,"zippo_close",10, 1, 3)
else
- bearer.visible_message(SPAN_NOTICE("[bearer] quietly shuts off the [src]."))
+ bearer.visible_message(SPAN_NOTICE("[bearer] quietly shuts off [src]."))
set_light_on(FALSE)
STOP_PROCESSING(SSobj, src)
@@ -773,4 +805,3 @@ CIGARETTE PACKETS ARE IN FANCY.DM
cig.light(SPAN_NOTICE("[user] holds the [name] out for [M], and lights the [cig.name]."))
else
..()
-
diff --git a/code/game/objects/items/tools/kitchen_tools.dm b/code/game/objects/items/tools/kitchen_tools.dm
index bb763ada9911..2cff941be8d6 100644
--- a/code/game/objects/items/tools/kitchen_tools.dm
+++ b/code/game/objects/items/tools/kitchen_tools.dm
@@ -218,7 +218,7 @@
var/cooldown = 0
/obj/item/tool/kitchen/tray/attack(mob/living/carbon/M, mob/living/carbon/user)
- to_chat(user, SPAN_WARNING("You accidentally slam yourself with the [src]!"))
+ to_chat(user, SPAN_WARNING("You accidentally slam yourself with [src]!"))
user.apply_effect(1, WEAKEN)
user.take_limb_damage(2)
diff --git a/code/game/objects/items/tools/maintenance_tools.dm b/code/game/objects/items/tools/maintenance_tools.dm
index a326808bf491..574d08e6a15b 100644
--- a/code/game/objects/items/tools/maintenance_tools.dm
+++ b/code/game/objects/items/tools/maintenance_tools.dm
@@ -96,8 +96,8 @@
if(E)
var/safety = H.get_eye_protection()
if(!safety)
- to_chat(user, SPAN_DANGER("You stab [H] in the eyes with the [src]!"))
- visible_message(SPAN_DANGER("[user] stabs [H] in the eyes with the [src]!"))
+ user.visible_message(SPAN_DANGER("[user] stabs [H] in the eyes with [src]!"),
+ SPAN_DANGER("You stab [H] in the eyes with [src]!"))
E.take_damage(rand(8,20))
return ..()
/obj/item/tool/screwdriver/tactical
@@ -162,6 +162,7 @@
drop_sound = 'sound/handling/weldingtool_drop.ogg'
flags_atom = FPRINT|CONDUCT
flags_equip_slot = SLOT_WAIST
+ var/base_icon_state = ""
//Amount of OUCH when it's thrown
force = 3
@@ -192,6 +193,7 @@
. = ..()
create_reagents(max_fuel)
reagents.add_reagent("fuel", max_fuel)
+ base_icon_state = initial(icon_state)
return
/obj/item/tool/weldingtool/Destroy()
@@ -336,7 +338,7 @@
weld_tick += 8 //turning the tool on does not consume fuel directly, but it advances the process that regularly consumes fuel.
force = 15
damtype = "fire"
- icon_state = "welder1"
+ icon_state = base_icon_state + "_on"
w_class = SIZE_LARGE
heat_source = 3800
START_PROCESSING(SSobj, src)
@@ -348,7 +350,7 @@
playsound(loc, 'sound/items/weldingtool_off.ogg', 25)
force = 3
damtype = "brute"
- icon_state = "welder"
+ icon_state = base_icon_state
welding = 0
w_class = initial(w_class)
heat_source = 0
@@ -415,6 +417,7 @@
name = "industrial blowtorch"
max_fuel = 60
matter = list("metal" = 70, "glass" = 60)
+ icon_state = "welder_c"
/obj/item/tool/weldingtool/hugetank
@@ -442,9 +445,9 @@
name = "\improper ME3 hand welder"
desc = "A compact, handheld welding torch used by the marines of the United States Colonial Marine Corps for cutting and welding jobs on the field. Due to the small size and slow strength, its function is limited compared to a full-sized technician's blowtorch."
max_fuel = 5
- color = "#cc0000"
has_welding_screen = TRUE
inherent_traits = list(TRAIT_TOOL_SIMPLE_BLOWTORCH)
+ icon_state = "welder_b"
/*
* Crowbar
diff --git a/code/game/objects/items/tools/misc_tools.dm b/code/game/objects/items/tools/misc_tools.dm
index b5be55eed540..44aaab771db8 100644
--- a/code/game/objects/items/tools/misc_tools.dm
+++ b/code/game/objects/items/tools/misc_tools.dm
@@ -132,7 +132,7 @@
qdel(I) //delete the paper item
labels_left = initial(labels_left)
else
- to_chat(user, SPAN_NOTICE("The [src] is already full."))
+ to_chat(user, SPAN_NOTICE("[src] is already full."))
/*
Instead of updating labels_left to user every label used,
@@ -173,7 +173,7 @@
playsound(user.loc, "sound/items/pen_click_[on? "on": "off"].ogg", 100, 1, 5)
update_pen_state()
-/obj/item/tool/pen/Initialize()
+/obj/item/tool/pen/Initialize(mapload, ...)
. = ..()
update_pen_state()
@@ -284,21 +284,24 @@
matter = list("metal" = 20, "gold" = 10)
var/static/list/colour_list = list("red", "blue", "green", "yellow", "purple", "pink", "brown", "black", "orange") // Can add more colors as required
var/current_colour_index = 1
- var/owner = "hard to read text"
+ var/owner_name
-/obj/item/tool/pen/fountain/Initialize(mapload, mob/living/carbon/human/user)
+/obj/item/tool/pen/fountain/pickup(mob/user, silent)
. = ..()
- var/turf/current_turf = get_turf(src)
- var/mob/living/carbon/human/new_owner = locate() in current_turf
- if(new_owner)
- owner = new_owner.real_name
- var/obj/structure/machinery/cryopod/new_owners_pod = locate() in current_turf
- if(new_owners_pod)
- owner = new_owners_pod.occupant?.real_name
+ if(!owner_name)
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(set_owner), override = TRUE)
+
+///Sets the owner of the pen to who it spawns with, requires var/source for signals
+/obj/item/tool/pen/fountain/proc/set_owner(datum/source)
+ SIGNAL_HANDLER
+ UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE)
+ var/mob/living/carbon/human/user = source
+ owner_name = user.name
/obj/item/tool/pen/fountain/get_examine_text(mob/user)
. = ..()
- . += "There's a laser engraving of [owner] on it."
+ if(owner_name)
+ . += "There's a laser engraving of [owner_name] on it."
/obj/item/tool/pen/fountain/attack_self(mob/living/carbon/human/user)
if(on)
diff --git a/code/game/objects/items/tools/shovel_tools.dm b/code/game/objects/items/tools/shovel_tools.dm
index 008b37705fe3..ad74dca54e88 100644
--- a/code/game/objects/items/tools/shovel_tools.dm
+++ b/code/game/objects/items/tools/shovel_tools.dm
@@ -151,7 +151,7 @@
/obj/item/tool/shovel/proc/dump_shovel(atom/target, mob/user)
var/turf/T = target
- to_chat(user, SPAN_NOTICE("you dump the [dirt_type_to_name(dirt_type)]!"))
+ to_chat(user, SPAN_NOTICE("You dump the [dirt_type_to_name(dirt_type)]!"))
playsound(user.loc, "rustle", 30, 1, 6)
if(dirt_type == DIRT_TYPE_SNOW)
var/obj/item/stack/snow/S = locate() in T
diff --git a/code/game/objects/items/tools/surgery_tools.dm b/code/game/objects/items/tools/surgery_tools.dm
index 8582e08111f7..9f6ae67baf35 100644
--- a/code/game/objects/items/tools/surgery_tools.dm
+++ b/code/game/objects/items/tools/surgery_tools.dm
@@ -235,7 +235,7 @@
/obj/item/tool/surgery/surgical_line
name = "\proper surgical line"
desc = "A roll of military-grade surgical line, able to seamlessly sew up any wound. Also works as a robust fishing line for maritime deployments."
- icon_state = "line"
+ icon_state = "line_brute"
force = 0
throwforce = 1
w_class = SIZE_SMALL
@@ -253,10 +253,7 @@
name = "Synth-Graft"
desc = "An applicator for synthetic skin field grafts. The stuff reeks, itches like the dickens, hurts going on, and the color is \
a perfectly averaged multiethnic tone that doesn't blend with anyone's complexion. But at least you don't have to stay in sickbay."
- /// Placeholder.
- icon_state = "line"
- /// Placeholder, to distinguish from surgical line.
- color = "yellow"
+ icon_state = "line_burn"
force = 0
throwforce = 1
w_class = SIZE_SMALL
diff --git a/code/game/objects/items/toys/cards.dm b/code/game/objects/items/toys/cards.dm
index b6e3bb558ec4..2debd83f9bab 100644
--- a/code/game/objects/items/toys/cards.dm
+++ b/code/game/objects/items/toys/cards.dm
@@ -21,7 +21,6 @@
icon = 'icons/obj/items/playing_cards.dmi'
icon_state = "deck"
w_class = SIZE_TINY
- flags_item = NOTABLEMERGE
var/base_icon = "deck"
var/max_cards = 52
@@ -262,7 +261,6 @@
icon = 'icons/obj/items/playing_cards.dmi'
icon_state = "empty"
w_class = SIZE_TINY
- flags_item = NOTABLEMERGE
var/concealed = FALSE
var/pile_state = FALSE
diff --git a/code/game/objects/items/toys/crayons.dm b/code/game/objects/items/toys/crayons.dm
index 5bd4d05f317f..c02b59289fa1 100644
--- a/code/game/objects/items/toys/crayons.dm
+++ b/code/game/objects/items/toys/crayons.dm
@@ -73,7 +73,7 @@
var/drawtype = tgui_input_list(usr, "Choose what you'd like to draw.", "Crayon scribbles", list("graffiti","rune","letter"))
switch(drawtype)
if("letter")
- drawtype = tgui_input_list(usr, "Choose the letter.", "Crayon scribbles", alphabet_lowercase)
+ drawtype = tgui_input_list(usr, "Choose the letter.", "Crayon scribbles", GLOB.alphabet_lowercase)
to_chat(user, "You start drawing a letter on the [target.name].")
if("graffiti")
to_chat(user, "You start drawing graffiti on the [target.name].")
diff --git a/code/game/objects/items/toys/toy_weapons.dm b/code/game/objects/items/toys/toy_weapons.dm
index 9acf6f2943c3..ce32cfdb67a9 100644
--- a/code/game/objects/items/toys/toy_weapons.dm
+++ b/code/game/objects/items/toys/toy_weapons.dm
@@ -130,7 +130,7 @@
for(var/mob/living/M in D.loc)
if(!istype(M,/mob/living)) continue
if(M == user) continue
- for(var/mob/O in viewers(world_view_size, D))
+ for(var/mob/O in viewers(GLOB.world_view_size, D))
O.show_message(SPAN_DANGER("[M] was hit by the foam dart!"), SHOW_MESSAGE_VISIBLE)
new /obj/item/toy/crossbow_ammo(M.loc)
qdel(D)
@@ -152,14 +152,14 @@
return
else if (bullets == 0)
user.apply_effect(5, WEAKEN)
- for(var/mob/O in viewers(world_view_size, user))
+ for(var/mob/O in viewers(GLOB.world_view_size, user))
O.show_message(SPAN_DANGER("[user] realized they were out of ammo and starting scrounging for some!"), SHOW_MESSAGE_VISIBLE)
-/obj/item/toy/crossbow/attack(mob/M as mob, mob/user as mob)
+/obj/item/toy/crossbow/attack(mob/living/M as mob, mob/user as mob)
src.add_fingerprint(user)
- if (src.bullets > 0 && M.lying)
+ if (src.bullets > 0 && M.body_position == LYING_DOWN)
for(var/mob/O in viewers(M, null))
if(O.client)
@@ -169,7 +169,7 @@
playsound(user.loc, 'sound/items/syringeproj.ogg', 15, 1)
new /obj/item/toy/crossbow_ammo(M.loc)
src.bullets--
- else if (M.lying && src.bullets == 0)
+ else if (M.body_position == LYING_DOWN && src.bullets == 0)
for(var/mob/O in viewers(M, null))
if (O.client)
O.show_message(SPAN_DANGER("[user] casually lines up a shot with [M]'s head, pulls the trigger, then realizes they are out of ammo and drops to the floor in search of some!"), SHOW_MESSAGE_VISIBLE, SPAN_DANGER("You hear someone fall"), SHOW_MESSAGE_AUDIBLE)
diff --git a/code/game/objects/items/toys/toys.dm b/code/game/objects/items/toys/toys.dm
index b2a66becd869..65234c59b89b 100644
--- a/code/game/objects/items/toys/toys.dm
+++ b/code/game/objects/items/toys/toys.dm
@@ -44,7 +44,7 @@
if(!proximity) return
if (istype(A, /obj/structure/reagent_dispensers/watertank) && get_dist(src,A) <= 1)
A.reagents.trans_to(src, 10)
- to_chat(user, SPAN_NOTICE(" You fill the balloon with the contents of [A]."))
+ to_chat(user, SPAN_NOTICE("You fill the balloon with the contents of [A]."))
src.desc = "A translucent balloon with some form of liquid sloshing around in it."
src.update_icon()
return
@@ -53,22 +53,22 @@
if(istype(O, /obj/item/reagent_container/glass))
if(O.reagents)
if(O.reagents.total_volume < 1)
- to_chat(user, "The [O] is empty.")
+ to_chat(user, SPAN_WARNING("[O] is empty."))
else if(O.reagents.total_volume >= 1)
if(O.reagents.has_reagent("pacid", 1))
- to_chat(user, "The acid chews through the balloon!")
+ to_chat(user, SPAN_WARNING("The acid chews through the balloon!"))
O.reagents.reaction(user)
qdel(src)
else
src.desc = "A translucent balloon with some form of liquid sloshing around in it."
- to_chat(user, SPAN_NOTICE(" You fill the balloon with the contents of [O]."))
+ to_chat(user, SPAN_NOTICE("You fill the balloon with the contents of [O]."))
O.reagents.trans_to(src, 10)
src.update_icon()
return
/obj/item/toy/balloon/launch_impact(atom/hit_atom)
if(src.reagents.total_volume >= 1)
- src.visible_message(SPAN_DANGER("The [src] bursts!"),"You hear a pop and a splash.")
+ src.visible_message(SPAN_DANGER("[src] bursts!"),"You hear a pop and a splash.")
src.reagents.reaction(get_turf(hit_atom))
for(var/atom/A in get_turf(hit_atom))
src.reagents.reaction(A)
@@ -318,56 +318,6 @@
desc = "Mini-Mecha action figure! Collect them all! 11/11."
icon_state = "phazonprize"
-
-/obj/item/toy/therapy_red
- name = "red therapy doll"
- desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is red."
- icon = 'icons/obj/items/toy.dmi'
- icon_state = "therapyred"
- item_state = "egg4" // It's the red egg in items_left/righthand
- w_class = SIZE_TINY
-
-/obj/item/toy/therapy_purple
- name = "purple therapy doll"
- desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is purple."
- icon = 'icons/obj/items/toy.dmi'
- icon_state = "therapypurple"
- item_state = "egg1" // It's the magenta egg in items_left/righthand
- w_class = SIZE_TINY
-
-/obj/item/toy/therapy_blue
- name = "blue therapy doll"
- desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is blue."
- icon = 'icons/obj/items/toy.dmi'
- icon_state = "therapyblue"
- item_state = "egg2" // It's the blue egg in items_left/righthand
- w_class = SIZE_TINY
-
-/obj/item/toy/therapy_yellow
- name = "yellow therapy doll"
- desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is yellow."
- icon = 'icons/obj/items/toy.dmi'
- icon_state = "therapyyellow"
- item_state = "egg5" // It's the yellow egg in items_left/righthand
- w_class = SIZE_TINY
-
-/obj/item/toy/therapy_orange
- name = "orange therapy doll"
- desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is orange."
- icon = 'icons/obj/items/toy.dmi'
- icon_state = "therapyorange"
- item_state = "egg4" // It's the red one again, lacking an orange item_state and making a new one is pointless
- w_class = SIZE_TINY
-
-/obj/item/toy/therapy_green
- name = "green therapy doll"
- desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles. This one is green."
- icon = 'icons/obj/items/toy.dmi'
- icon_state = "therapygreen"
- item_state = "egg3" // It's the green egg in items_left/righthand
- w_class = SIZE_TINY
-
-
/obj/item/toy/inflatable_duck
name = "inflatable duck"
desc = "No bother to sink or swim when you can just float!"
@@ -377,7 +327,6 @@
flags_equip_slot = SLOT_WAIST
black_market_value = 20
-
/obj/item/toy/beach_ball
name = "beach ball"
icon_state = "beachball"
@@ -394,7 +343,6 @@
user.drop_held_item()
throw_atom(target, throw_range, throw_speed, user)
-
/obj/item/toy/dice
name = "d6"
desc = "A die with six sides."
@@ -427,10 +375,6 @@
SPAN_NOTICE("You throw [src]. It lands on a [result]. [comment]"), \
SPAN_NOTICE("You hear [src] landing on a [result]. [comment]"))
-
-
-
-
/obj/item/toy/bikehorn
name = "bike horn"
desc = "A horn off of a bicycle."
@@ -455,47 +399,6 @@
src.add_fingerprint(user)
addtimer(VARSET_CALLBACK(src, spam_flag, FALSE), 2 SECONDS)
-
-
-/obj/item/toy/farwadoll
- name = "Farwa plush doll"
- desc = "A Farwa plush doll. It's soft and comforting!"
- w_class = SIZE_TINY
- icon_state = "farwaplush"
- black_market_value = 25
- COOLDOWN_DECLARE(last_hug_time)
-
-/obj/item/toy/farwadoll/attack_self(mob/user)
- ..()
-
- if(COOLDOWN_FINISHED(src, last_hug_time))
- user.visible_message(SPAN_NOTICE("[user] hugs [src]! How cute! "), \
- SPAN_NOTICE("You hug [src]. Dawwww... "))
- COOLDOWN_START(src, last_hug_time, 5 SECONDS)
-
-/obj/item/toy/farwadoll/pred
- name = "strange plush doll"
- desc = "A plush doll depicting some sort of tall humanoid biped..?"
- w_class = SIZE_TINY
- icon_state = "predplush"
-
-/obj/item/toy/plushie_cade
- name = "plushie barricade"
- desc = "Great for squeezing whenever you're scared. Or lightly hurt. Or in any other situation."
- icon_state = "plushie_cade"
- item_state = "plushie_cade"
- w_class = SIZE_SMALL
- COOLDOWN_DECLARE(last_hug_time)
-
-/obj/item/toy/plushie_cade/attack_self(mob/user)
- ..()
-
- if(COOLDOWN_FINISHED(src, last_hug_time))
- user.visible_message(SPAN_NOTICE("[user] hugs [src] tightly!"), SPAN_NOTICE("You hug [src]. You feel safe."))
- playsound(user, "plush", 25, TRUE)
- COOLDOWN_START(src, last_hug_time, 2.5 SECONDS)
-
-
/obj/item/computer3_part
name = "computer part"
desc = "Holy jesus you donnit now"
@@ -567,3 +470,188 @@
/obj/item/toy/festivizer/xeno
name = "strange resin-covered festivizer decorator"
desc = "This bizarre festivizer is covered in goopy goop and schmuck. Ew! It's so sticky, *anything* could grab onto it! Grab it and touch other things to festivize them!"
+
+/obj/item/toy/plush
+ name = "generic plushie"
+ desc = "perfectly generic"
+ icon = 'icons/obj/items/plush.dmi'
+ icon_state = "debug"
+ w_class = SIZE_SMALL
+ COOLDOWN_DECLARE(last_hug_time)
+ black_market_value = 10
+
+/obj/item/toy/plush/attack_self(mob/user)
+ ..()
+ if(!COOLDOWN_FINISHED(src, last_hug_time))
+ return
+ user.visible_message(SPAN_NOTICE("[user] hugs [src] tightly!"), SPAN_NOTICE("You hug [src]."))
+ playsound(user, "plush", 25, TRUE)
+ COOLDOWN_START(src, last_hug_time, 2.5 SECONDS)
+
+/obj/item/toy/plush/farwa
+ name = "Farwa plush"
+ desc = "A Farwa plush doll. It's soft and comforting!"
+ icon_state = "farwa"
+ black_market_value = 25
+
+/obj/item/toy/plush/barricade
+ name = "plushie barricade"
+ desc = "Great for squeezing whenever you're scared. Or lightly hurt. Or in any other situation."
+ icon_state = "barricade"
+ item_state = "cade_plush"
+
+/obj/item/toy/plush/shark //A few more generic plushies to increase the size of the plushie loot pool
+ name = "shark plush"
+ desc = "A plushie depicting a somewhat cartoonish shark. The tag notes that it was made by an obscure furniture manufacturer in Scandinavia."
+ icon_state = "shark"
+
+/obj/item/toy/plush/bee
+ name = "bee plush"
+ desc = "A cute toy that awakens the warrior spirit in the most reserved marine."
+ icon_state = "bee"
+
+/obj/item/toy/plush/moth
+ name = "moth plush"
+ desc = "A plush doll of a bug."
+ icon_state = "moth"
+
+/obj/item/toy/plush/rock
+ name = "rock plush"
+ desc = "It says it is a plush on the tag, at least."
+ icon_state = "rock"
+
+/obj/item/toy/plush/therapy
+ name = "therapy plush"
+ desc = "A therapeutic toy to assist marines in recovering from mental and behavioral disorders after experiencing the trauma of battles."
+ icon_state = "therapy"
+
+/obj/item/toy/plush/therapy/red
+ name = "red therapy plush"
+ color = "#FC5274"
+
+/obj/item/toy/plush/therapy/blue
+ name = "blue therapy plush"
+ color = "#9EBAE0"
+
+/obj/item/toy/plush/therapy/green
+ name = "green therapy plush"
+ color = "#A3C940"
+
+/obj/item/toy/plush/therapy/orange
+ name = "orange therapy plush"
+ color = "#FD8535"
+
+/obj/item/toy/plush/therapy/purple
+ name = "purple therapy plush"
+ color = "#A26AC7"
+
+/obj/item/toy/plush/therapy/yellow
+ name = "yellow therapy plush"
+ color = "#FFE492"
+
+/obj/item/toy/plush/therapy/random_color
+ ///Hexadecimal 0-F (0-15)
+ var/static/list/hexadecimal = list("0", "1", "2", "3" , "4", "5", "6", "7", "8", "9", "A", "B", "C", "D", "E", "F")
+
+/obj/item/toy/plush/therapy/random_color/Initialize(mapload, ...)
+ . = ..()
+ var/color_code = "#[pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)][pick(hexadecimal)]" //This is dumb and I hope theres a better way I'm missing
+ color = color_code
+ desc = "A custom therapy plush, in a unique color."
+
+/obj/item/toy/plush/random_plushie //Not using an effect so it can fit into storage from loadout
+ name = "random plush"
+ desc = "This plush looks awfully standard and bland. Is it actually yours?"
+ /// Standard plushies for the spawner to pick from
+ var/list/plush_list = list(
+ /obj/item/toy/plush/farwa,
+ /obj/item/toy/plush/barricade,
+ /obj/item/toy/plush/bee,
+ /obj/item/toy/plush/shark,
+ /obj/item/toy/plush/moth,
+ /obj/item/toy/plush/rock,
+ )
+ ///Therapy plushies left separately to not flood the entire list
+ var/list/therapy_plush_list = list(
+ /obj/item/toy/plush/therapy,
+ /obj/item/toy/plush/therapy/red,
+ /obj/item/toy/plush/therapy/blue,
+ /obj/item/toy/plush/therapy/green,
+ /obj/item/toy/plush/therapy/orange,
+ /obj/item/toy/plush/therapy/purple,
+ /obj/item/toy/plush/therapy/yellow,
+ /obj/item/toy/plush/therapy/random_color,
+ )
+
+/obj/item/toy/plush/random_plushie/Initialize(mapload, ...)
+ . = ..()
+ if(mapload) //Placed in mapping, will be randomized instantly on spawn
+ create_plushie()
+ return INITIALIZE_HINT_QDEL
+
+/obj/item/toy/plush/random_plushie/pickup(mob/user, silent)
+ . = ..()
+ RegisterSignal(user, COMSIG_POST_SPAWN_UPDATE, PROC_REF(create_plushie), override = TRUE)
+
+///The randomizer picking and spawning a plushie on either the ground or in the humans backpack. Needs var/source due to signals
+/obj/item/toy/plush/random_plushie/proc/create_plushie(datum/source)
+ SIGNAL_HANDLER
+ if(source)
+ UnregisterSignal(source, COMSIG_POST_SPAWN_UPDATE)
+ var/turf/spawn_location = get_turf(src)
+ var/plush_list_variety = pick(60; plush_list, 40; therapy_plush_list)
+ var/random_plushie = pick(plush_list_variety)
+ var/obj/item/toy/plush/plush = new random_plushie(spawn_location) //Starts on floor by default
+ var/mob/living/carbon/human/user = source
+
+ if(!user) //If it didn't spawn on a humanoid
+ qdel(src)
+ return
+
+ var/obj/item/storage/backpack/storage = locate() in user //If the user has a backpack, put it there
+ if(storage?.can_be_inserted(plush, user, stop_messages = TRUE))
+ storage.attempt_item_insertion(plush, TRUE, user)
+ if(plush.loc == spawn_location) // Still on the ground
+ user.put_in_hands(plush, drop_on_fail = TRUE)
+ qdel(src)
+
+//Admin plushies
+/obj/item/toy/plush/yautja
+ name = "strange plush"
+ desc = "A plush doll depicting some sort of tall humanoid biped..?"
+ icon_state = "yautja"
+ black_market_value = 100
+
+/obj/item/toy/plush/runner
+ name = "\improper XX-121 therapy plush"
+ desc = "Don't be sad! Be glad (that you're alive)!"
+ icon_state = "runner"
+ /// If the runner is wearing a beret
+ var/beret = FALSE
+
+/obj/item/toy/plush/runner/Initialize(mapload, ...)
+ . = ..()
+ if(beret)
+ update_icon()
+
+/obj/item/toy/plush/runner/attackby(obj/item/attacking_object, mob/user)
+ . = ..()
+ if(beret)
+ return
+ if(!istypestrict(attacking_object, /obj/item/clothing/head/beret/marine/mp))
+ return
+ var/beret_attack = attacking_object
+ to_chat(user, SPAN_NOTICE("You put [beret_attack] on [src]."))
+ qdel(beret_attack)
+ beret = TRUE
+ update_icon()
+
+/obj/item/toy/plush/runner/update_icon()
+ . = ..()
+ if(beret)
+ icon_state = "runner_beret"
+ return
+ icon_state = "runner"
+
+/obj/item/toy/plush/shark/alt
+ icon_state = "shark_alt"
diff --git a/code/game/objects/items/weapons/blades.dm b/code/game/objects/items/weapons/blades.dm
index 4b4b31539064..a2a4aa8db75d 100644
--- a/code/game/objects/items/weapons/blades.dm
+++ b/code/game/objects/items/weapons/blades.dm
@@ -1,38 +1,36 @@
-/obj/item/weapon/claymore
- name = "claymore"
- desc = "What are you standing around staring at this for? Get to killing!"
- icon_state = "claymore"
- item_state = "claymore"
+/obj/item/weapon/sword
+ 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."
+ icon_state = "mercsword"
+ item_state = "machete"
flags_atom = FPRINT|CONDUCT
flags_equip_slot = SLOT_WAIST
force = MELEE_FORCE_STRONG
throwforce = MELEE_FORCE_WEAK
sharp = IS_SHARP_ITEM_BIG
edge = 1
- w_class = SIZE_MEDIUM
+ w_class = SIZE_LARGE
hitsound = 'sound/weapons/bladeslice.ogg'
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
attack_speed = 9
-/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."
- icon_state = "mercsword"
- item_state = "machete"
+/obj/item/weapon/sword/claymore
+ name = "claymore"
+ desc = "What are you standing around staring at this for? Get to killing!"
+ icon_state = "claymore"
+ item_state = "claymore"
-/obj/item/weapon/claymore/mercsword/ceremonial
+/obj/item/weapon/sword/ceremonial
name = "Ceremonial Sword"
desc = "A fancy ceremonial sword passed down from generation to generation. Despite this, it has been very well cared for, and is in top condition."
icon_state = "ceremonial"
- item_state = "machete"
-/obj/item/weapon/claymore/mercsword/machete
+/obj/item/weapon/sword/machete
name = "\improper M2132 machete"
desc = "Latest issue of the USCM Machete. Great for clearing out jungle or brush on outlying colonies. Found commonly in the hands of scouts and trackers, but difficult to carry with the usual kit."
icon_state = "machete"
- w_class = SIZE_LARGE
-/obj/item/weapon/claymore/mercsword/machete/attack_self(mob/user)
+/obj/item/weapon/sword/machete/attack_self(mob/user)
if(user.action_busy)
return
@@ -49,14 +47,13 @@
return ..()
-/obj/item/weapon/claymore/mercsword/machete/arnold
+/obj/item/weapon/sword/machete/arnold
name = "\improper M2100 \"Ngájhe\" machete"
desc = "An older issue USCM machete, never left testing. Designed in the Central African Republic. The notching made it hard to clean, and as such the USCM refused to adopt it - despite the superior bludgeoning power offered. Difficult to carry with the usual kit."
icon_state = "arnold-machete"
- w_class = SIZE_LARGE
force = MELEE_FORCE_TIER_11
-/obj/item/weapon/claymore/hefa
+/obj/item/weapon/sword/hefa
name = "HEFA sword"
icon_state = "hefasword"
item_state = "hefasword"
@@ -65,7 +62,7 @@
var/primed = FALSE
-/obj/item/weapon/claymore/hefa/proc/apply_explosion_overlay()
+/obj/item/weapon/sword/hefa/proc/apply_explosion_overlay()
var/obj/effect/overlay/O = new /obj/effect/overlay(loc)
O.name = "grenade"
O.icon = 'icons/effects/explosion.dmi'
@@ -73,7 +70,7 @@
QDEL_IN(O, 7)
return
-/obj/item/weapon/claymore/hefa/attack_self(mob/user)
+/obj/item/weapon/sword/hefa/attack_self(mob/user)
..()
primed = !primed
@@ -82,7 +79,7 @@
msg = "You de-activate \the [src]!"
to_chat(user, SPAN_NOTICE(msg))
-/obj/item/weapon/claymore/hefa/attack(mob/target, mob/user)
+/obj/item/weapon/sword/hefa/attack(mob/target, mob/user)
. = ..()
if(!primed)
return
@@ -97,22 +94,15 @@
cell_explosion(epicenter, 40, 18, EXPLOSION_FALLOFF_SHAPE_LINEAR, user.dir, cause_data)
qdel(src)
-/obj/item/weapon/katana
+/obj/item/weapon/sword/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 = FPRINT|CONDUCT
+ item_state = "katana"
force = MELEE_FORCE_VERY_STRONG
- throwforce = MELEE_FORCE_WEAK
- sharp = IS_SHARP_ITEM_BIG
- edge = 1
- w_class = SIZE_MEDIUM
- hitsound = 'sound/weapons/bladeslice.ogg'
- attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
- attack_speed = 9
//To do: replace the toys.
-/obj/item/weapon/katana/replica
+/obj/item/weapon/sword/katana/replica
name = "replica katana"
desc = "A cheap knock-off commonly found in regular knife stores. Can still do some damage."
force = MELEE_FORCE_WEAK
@@ -223,6 +213,8 @@
else
INVOKE_ASYNC(embedded_human, TYPE_PROC_REF(/mob, emote), "me", 1, pick("winces.", "grimaces.", "flinches."))
+ SEND_SIGNAL(embedded_human, COMSIG_HUMAN_SHRAPNEL_REMOVED)
+
else
to_chat(user, SPAN_NOTICE("You couldn't find any shrapnel."))
@@ -246,3 +238,142 @@
WEAR_L_HAND = 'icons/mob/humans/onmob/items_lefthand_64.dmi',
WEAR_R_HAND = 'icons/mob/humans/onmob/items_righthand_64.dmi'
)
+
+/obj/item/weapon/straight_razor
+ name = "straight razor"
+ desc = "The commandant's favorite weapon against marines who dare break the grooming standards."
+ icon_state = "razor"
+ hitsound = 'sound/weapons/genhit3.ogg'
+ force = MELEE_FORCE_TIER_1
+ throwforce = MELEE_FORCE_TIER_1
+ throw_speed = SPEED_VERY_FAST
+ throw_range = 6
+ ///Icon state for opened razor
+ var/enabled_icon = "razor"
+ ///Icon state for closed razor
+ var/disabled_icon = "razor_off"
+ ///If the razor is able to be used
+ var/razor_opened = FALSE
+ ///Time taken to open/close the razor
+ var/interaction_time = 3 SECONDS
+
+/obj/item/weapon/straight_razor/Initialize(mapload, ...)
+ . = ..()
+ RegisterSignal(src, COMSIG_ITEM_ATTEMPTING_EQUIP, PROC_REF(can_fit_in_shoe))
+ change_razor_state(razor_opened)
+ if(prob(1))
+ desc += " There is phrase etched into it, \"It can guarantee the closest shave you'll ever know.\"..."
+
+/obj/item/weapon/straight_razor/update_icon()
+ . = ..()
+ if(razor_opened)
+ icon_state = enabled_icon
+ return
+ icon_state = disabled_icon
+
+/obj/item/weapon/straight_razor/attack_hand(mob/user)
+ if(loc != user) //Only do unique stuff if you are holding it
+ return ..()
+
+ if(!do_after(user, interaction_time, INTERRUPT_INCAPACITATED, BUSY_ICON_HOSTILE))
+ return
+ playsound(user, 'sound/weapons/flipblade.ogg', 15, 1)
+ change_razor_state(!razor_opened)
+ to_chat(user, SPAN_NOTICE("You [razor_opened ? "reveal" : "hide"] [src]'s blade."))
+
+///Check if the item can fit as a boot knife, var/source for signals
+/obj/item/weapon/straight_razor/proc/can_fit_in_shoe(source = src, mob/user, slot)
+ if(slot != WEAR_IN_SHOES) //Only check if you try putting it in a shoe
+ return
+ if(razor_opened)
+ to_chat(user, SPAN_NOTICE("You cannot store [src] in your shoes until the blade is hidden."))
+ return COMPONENT_CANCEL_EQUIP
+
+///Changes all the vars for the straight razor
+/obj/item/weapon/straight_razor/proc/change_razor_state(opening = FALSE)
+ razor_opened = opening
+ update_icon()
+ if(opening)
+ force = MELEE_FORCE_NORMAL
+ throwforce = MELEE_FORCE_NORMAL
+ sharp = IS_SHARP_ITEM_ACCURATE
+ edge = TRUE
+ attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
+ hitsound = 'sound/weapons/slash.ogg'
+ if(!(flags_item & CAN_DIG_SHRAPNEL))
+ flags_item |= CAN_DIG_SHRAPNEL
+ return
+ force = MELEE_FORCE_TIER_1
+ throwforce = MELEE_FORCE_TIER_1
+ sharp = FALSE
+ edge = FALSE
+ attack_verb = list("smashed", "beaten", "slammed", "struck", "smashed", "battered", "cracked")
+ hitsound = 'sound/weapons/genhit3.ogg'
+ if(flags_item & CAN_DIG_SHRAPNEL)
+ flags_item &= ~CAN_DIG_SHRAPNEL
+
+/obj/item/weapon/straight_razor/verb/change_hair_style()
+ set name = "Change Hair Style"
+ set desc = "Change your hair style"
+ set category = "Object"
+ set src in usr
+
+ var/mob/living/carbon/human/human_user = usr
+ if(!istype(human_user))
+ return
+
+ if(!razor_opened)
+ to_chat(human_user, SPAN_NOTICE("You need to reveal [src]'s blade to change your hairstyle."))
+ return
+
+ var/list/species_facial_hair = GLOB.facial_hair_styles_list
+ var/list/species_hair = GLOB.hair_styles_list
+
+ if(human_user.species) //Facial hair
+ species_facial_hair = list()
+ for(var/current_style in GLOB.facial_hair_styles_list)
+ var/datum/sprite_accessory/facial_hair/temp_beard_style = GLOB.facial_hair_styles_list[current_style]
+ if(!(human_user.species.name in temp_beard_style.species_allowed))
+ continue
+ if(!temp_beard_style.selectable)
+ continue
+ species_facial_hair += current_style
+
+ if(human_user.species) //Hair
+ species_hair = list()
+ for(var/current_style in GLOB.hair_styles_list)
+ var/datum/sprite_accessory/hair/temp_hair_style = GLOB.hair_styles_list[current_style]
+ if(!(human_user.species.name in temp_hair_style.species_allowed))
+ continue
+ if(!temp_hair_style.selectable)
+ continue
+ species_hair += current_style
+
+ var/new_beard_style
+ var/new_hair_style
+ if(human_user.gender == MALE)
+ new_beard_style = tgui_input_list(human_user, "Select a facial hair style", "Grooming", species_facial_hair)
+ new_hair_style = tgui_input_list(human_user, "Select a hair style", "Grooming", species_hair)
+
+ if(loc != human_user)
+ to_chat(human_user, SPAN_NOTICE("You are too far from [src] to change your hair styles."))
+ return
+
+ if(!new_beard_style && !new_hair_style)
+ return
+
+ if(!do_after(human_user, interaction_time, INTERRUPT_ALL, BUSY_ICON_GENERIC))
+ return
+
+ if(!razor_opened)
+ to_chat(human_user, SPAN_NOTICE("You need to reveal [src]'s blade to change your hairstyle."))
+ return
+
+ if(new_beard_style)
+ human_user.f_style = new_beard_style
+ if(new_hair_style)
+ human_user.h_style = new_hair_style
+
+ human_user.apply_damage(rand(1,5), BRUTE, "head", src)
+ human_user.update_hair()
+
diff --git a/code/game/objects/items/weapons/shields.dm b/code/game/objects/items/weapons/shields.dm
index 20bf8ac951e9..0497a410a373 100644
--- a/code/game/objects/items/weapons/shields.dm
+++ b/code/game/objects/items/weapons/shields.dm
@@ -89,7 +89,7 @@
/obj/item/weapon/shield/riot/attackby(obj/item/W as obj, mob/user as mob)
if(cooldown < world.time - 25)
- if(istype(W, /obj/item/weapon/baton) || istype(W, /obj/item/weapon/claymore) || istype(W, /obj/item/weapon/baseballbat) || istype(W, /obj/item/weapon/katana) || istype(W, /obj/item/weapon/twohanded/fireaxe) || istype(W, /obj/item/weapon/chainofcommand))
+ if(istype(W, /obj/item/weapon/baton) || istype(W, /obj/item/weapon/sword) || istype(W, /obj/item/weapon/baseballbat) || istype(W, /obj/item/weapon/twohanded/fireaxe) || istype(W, /obj/item/weapon/chainofcommand))
user.visible_message(SPAN_WARNING("[user] bashes [src] with [W]!"))
playsound(user.loc, 'sound/effects/shieldbash.ogg', 25, 1)
cooldown = world.time
diff --git a/code/game/objects/items/weapons/stunbaton.dm b/code/game/objects/items/weapons/stunbaton.dm
index 6cb9f58aae37..310c53dd5d0f 100644
--- a/code/game/objects/items/weapons/stunbaton.dm
+++ b/code/game/objects/items/weapons/stunbaton.dm
@@ -106,7 +106,7 @@
bcell.update_icon()
bcell.forceMove(get_turf(src.loc))
bcell = null
- to_chat(user, SPAN_NOTICE("You remove the cell from the [src]."))
+ to_chat(user, SPAN_NOTICE("You remove the cell from [src]."))
status = 0
update_icon()
return
@@ -183,10 +183,10 @@
// Logging
if(user == L)
- user.attack_log += "\[[time_stamp()]\] [key_name(user)] stunned themselves with the [src] in [get_area(user)]"
+ user.attack_log += "\[[time_stamp()]\] [key_name(user)] stunned themselves with [src] in [get_area(user)]"
else
- msg_admin_attack("[key_name(user)] stunned [key_name(L)] with the [src] in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z]).", user.loc.x, user.loc.y, user.loc.z)
- var/logentry = "\[[time_stamp()]\] [key_name(user)] stunned [key_name(L)] with the [src] in [get_area(user)]"
+ msg_admin_attack("[key_name(user)] stunned [key_name(L)] with [src] in [get_area(user)] ([user.loc.x],[user.loc.y],[user.loc.z]).", user.loc.x, user.loc.y, user.loc.z)
+ var/logentry = "\[[time_stamp()]\] [key_name(user)] stunned [key_name(L)] with [src] in [get_area(user)]"
L.attack_log += logentry
user.attack_log += logentry
@@ -197,9 +197,9 @@
return TRUE
/obj/item/weapon/baton/emp_act(severity)
+ . = ..()
if(bcell)
bcell.emp_act(severity) //let's not duplicate code everywhere if we don't have to please.
- ..()
//secborg stun baton module
/obj/item/weapon/baton/robot/attack_self(mob/user)
diff --git a/code/game/objects/items/weapons/weaponry.dm b/code/game/objects/items/weapons/weaponry.dm
index aaa2a33d4e63..f3c76bcff638 100644
--- a/code/game/objects/items/weapons/weaponry.dm
+++ b/code/game/objects/items/weapons/weaponry.dm
@@ -113,7 +113,7 @@
w_class = SIZE_MEDIUM
attack_verb = list("attacked", "slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut")
else
- to_chat(user, SPAN_NOTICE("The [src] can now be concealed."))
+ to_chat(user, SPAN_NOTICE("[src] can now be concealed."))
force = initial(force)
edge = 0
sharp = 0
@@ -167,7 +167,7 @@
update_icon(user)
-/obj/item/weapon/katana/sharp
+/obj/item/weapon/sword/katana/sharp
name = "absurdly sharp katana"
desc = "
That's it. I'm sick of all this \"Masterwork Bastard Sword\" bullshit that's going on in CM-SS13 right now. Katanas deserve much better than that. Much, much better than that.
\
I should know what I'm talking about. I myself commissioned a genuine katana in Japan for 2,400,000 Yen (that's about $20,000) and have been practicing with it for almost 2 years now. I can even cut slabs of solid steel with my katana.
\
@@ -190,7 +190,7 @@
attack_verb = list("sliced", "diced", "cut")
-/obj/item/weapon/katana/sharp/attack(mob/living/M, mob/living/user)
+/obj/item/weapon/sword/katana/sharp/attack(mob/living/M, mob/living/user)
if(flags_item & NOBLUDGEON)
return
@@ -223,7 +223,7 @@
//if the target also has a katana (and we aren't attacking ourselves), we add some suspense
- if( ( istype(M.get_active_hand(), /obj/item/weapon/katana) || istype(M.get_inactive_hand(), /obj/item/weapon/katana) ) && M != user )
+ if( ( istype(M.get_active_hand(), /obj/item/weapon/sword/katana) || istype(M.get_inactive_hand(), /obj/item/weapon/sword/katana) ) && M != user )
if(prob(50))
user.visible_message(SPAN_DANGER("[M] and [user] cross blades!"))
@@ -260,7 +260,7 @@
M.apply_effect(kill_delay/15, STUN)
- for (var/mob/O in hearers(world_view_size, M))
+ for (var/mob/O in hearers(GLOB.world_view_size, M))
O << sound('sound/effects/Heart Beat.ogg', repeat = 1, wait = 0, volume = 100, channel = 2) //play on same channel as ambience
spawn(kill_delay)
O << sound(, , , , channel = 2) //cut sound
diff --git a/code/game/objects/objs.dm b/code/game/objects/objs.dm
index 184fc51bd507..7747a45ed9da 100644
--- a/code/game/objects/objs.dm
+++ b/code/game/objects/objs.dm
@@ -14,7 +14,8 @@
/// If we have a user using us, this will be set on. We will check if the user has stopped using us, and thus stop updating and LAGGING EVERYTHING!
var/in_use = FALSE
var/mob/living/buckled_mob
- var/buckle_lying = FALSE //Is the mob buckled in a lying position
+ /// Bed-like behaviour, forces mob.lying = buckle_lying if not set to [NO_BUCKLE_LYING].
+ var/buckle_lying = NO_BUCKLE_LYING
var/can_buckle = FALSE
/**Applied to surgery times for mobs buckled prone to it or lying on the same tile, if the surgery
cares about surface conditions. The lowest multiplier of objects on the tile is used.**/
@@ -224,15 +225,20 @@
else . = ..()
/obj/proc/afterbuckle(mob/M as mob) // Called after somebody buckled / unbuckled
- handle_rotation()
+ handle_rotation() // To be removed when we have full dir support in set_buckled
SEND_SIGNAL(src, COSMIG_OBJ_AFTER_BUCKLE, buckled_mob)
+ if(!buckled_mob)
+ UnregisterSignal(M, COMSIG_PARENT_QDELETING)
+ else
+ RegisterSignal(buckled_mob, COMSIG_PARENT_QDELETING, PROC_REF(unbuckle))
return buckled_mob
/obj/proc/unbuckle()
+ SIGNAL_HANDLER
if(buckled_mob && buckled_mob.buckled == src)
- buckled_mob.buckled = null
+ buckled_mob.clear_alert(ALERT_BUCKLED)
+ buckled_mob.set_buckled(null)
buckled_mob.anchored = initial(buckled_mob.anchored)
- buckled_mob.update_canmove()
var/M = buckled_mob
REMOVE_TRAITS_IN(buckled_mob, TRAIT_SOURCE_BUCKLE)
@@ -263,7 +269,7 @@
//trying to buckle a mob
/obj/proc/buckle_mob(mob/M, mob/user)
- if (!ismob(M) || (get_dist(src, user) > 1) || user.is_mob_restrained() || user.lying || user.stat || buckled_mob || M.buckled || !isturf(user.loc))
+ if (!ismob(M) || (get_dist(src, user) > 1) || user.is_mob_restrained() || user.stat || buckled_mob || M.buckled || !isturf(user.loc))
return
if (isxeno(user))
@@ -272,6 +278,11 @@
if (iszombie(user))
return
+ // mobs that become immobilized should not be able to buckle themselves.
+ if(M == user && HAS_TRAIT(user, TRAIT_IMMOBILIZED))
+ to_chat(user, SPAN_WARNING("You are unable to do this in your current state."))
+ return
+
if(density)
density = FALSE
if(!step(M, get_dir(M, src)) && loc != M.loc)
@@ -294,20 +305,16 @@
// the actual buckling proc
// Yes I know this is not style but its unreadable otherwise
-/obj/proc/do_buckle(mob/target, mob/user)
+/obj/proc/do_buckle(mob/living/target, mob/user)
send_buckling_message(target, user)
if (src && src.loc)
- target.buckled = src
+ target.throw_alert(ALERT_BUCKLED, /atom/movable/screen/alert/buckled)
+ target.set_buckled(src)
target.forceMove(src.loc)
target.setDir(dir)
- target.update_canmove()
src.buckled_mob = target
src.add_fingerprint(user)
afterbuckle(target)
- if(buckle_lying) // Make sure buckling to beds/nests etc only turns, and doesn't give a random offset
- var/matrix/new_matrix = matrix()
- new_matrix.Turn(90)
- target.apply_transform(new_matrix)
return TRUE
/obj/proc/send_buckling_message(mob/M, mob/user)
@@ -387,7 +394,7 @@
else if(LAZYISIN(item_icons, slot))
mob_icon = item_icons[slot]
else
- mob_icon = default_onmob_icons[slot]
+ mob_icon = GLOB.default_onmob_icons[slot]
var/image/overlay_img
diff --git a/code/game/objects/prop.dm b/code/game/objects/prop.dm
index e59c24b30d5f..c067a9730e70 100644
--- a/code/game/objects/prop.dm
+++ b/code/game/objects/prop.dm
@@ -11,6 +11,66 @@
w_class = SIZE_SMALL
garbage = TRUE
+/obj/item/prop/geiger_counter
+ name = "geiger counter"
+ desc = "A geiger counter measures the radiation it receives. This type automatically records and transfers any information it reads, provided it has a battery, with no user input required beyond being enabled."
+ icon = 'icons/obj/items/devices.dmi'
+ icon_state = "geiger"
+ item_state = ""
+ w_class = SIZE_SMALL
+ flags_equip_slot = SLOT_WAIST
+ ///Whether the geiger counter is on or off
+ var/toggled_on = FALSE
+ ///Iconstate of geiger counter when on
+ var/enabled_state = "geiger_on"
+ ///Iconstate of geiger counter when off
+ var/disabled_state = "geiger"
+ ///New battery it will spawn with
+ var/starting_battery = /obj/item/cell/crap
+ ///Battery inside geiger counter
+ var/obj/item/cell/battery //It doesn't drain the battery, but it has a battery for emergency use
+
+/obj/item/prop/geiger_counter/Initialize(mapload, ...)
+ . = ..()
+ if(!starting_battery)
+ return
+ battery = new starting_battery(src)
+
+/obj/item/prop/geiger_counter/Destroy()
+ . = ..()
+ if(battery)
+ qdel(battery)
+
+/obj/item/prop/geiger_counter/attack_self(mob/user)
+ . = ..()
+ toggled_on = !toggled_on
+ if(!battery)
+ to_chat(user, SPAN_NOTICE("[src] is missing a battery."))
+ return
+ to_chat(user, SPAN_NOTICE("You [toggled_on ? "enable" : "disable"] [src]."))
+ update_icon()
+
+/obj/item/prop/geiger_counter/attackby(obj/item/attacking_item, mob/user)
+ . = ..()
+ if(!HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER) && !HAS_TRAIT(attacking_item, TRAIT_TOOL_CROWBAR))
+ return
+
+ if(!battery)
+ to_chat(user, SPAN_NOTICE("There is no battery for you to remove."))
+ return
+ to_chat(user, SPAN_NOTICE("You jam [battery] out of [src] with [attacking_item], prying it out irreversibly."))
+ user.put_in_hands(battery)
+ battery = null
+ update_icon()
+
+/obj/item/prop/geiger_counter/update_icon()
+ . = ..()
+
+ if(battery && toggled_on)
+ icon_state = enabled_state
+ return
+ icon_state = disabled_state
+
/obj/item/prop/tableflag
name = "United Americas table flag"
icon = 'icons/obj/items/items.dmi'
diff --git a/code/game/objects/structures.dm b/code/game/objects/structures.dm
index 9b0b8cf30aae..2519ed2940d5 100644
--- a/code/game/objects/structures.dm
+++ b/code/game/objects/structures.dm
@@ -150,7 +150,8 @@
for(var/mob/living/M in get_turf(src))
- if(M.lying) return //No spamming this on people.
+ if(HAS_TRAIT(M, TRAIT_FLOORED))
+ return //No spamming this on people.
M.apply_effect(5, WEAKEN)
to_chat(M, SPAN_WARNING("You topple as \the [src] moves under you!"))
@@ -191,7 +192,7 @@
H.updatehealth()
return
-/obj/structure/proc/can_touch(mob/user)
+/obj/structure/proc/can_touch(mob/living/user)
if(!user)
return 0
if(!Adjacent(user) || !isturf(user.loc))
@@ -199,7 +200,7 @@
if(user.is_mob_restrained() || user.buckled)
to_chat(user, SPAN_NOTICE("You need your hands and legs free for this."))
return 0
- if(user.is_mob_incapacitated(TRUE) || user.lying)
+ if(user.is_mob_incapacitated(TRUE) || user.body_position == LYING_DOWN)
return 0
if(isRemoteControlling(user))
to_chat(user, SPAN_NOTICE("You need hands for this."))
@@ -208,7 +209,7 @@
/obj/structure/proc/toggle_anchored(obj/item/W, mob/user)
if(!wrenchable)
- to_chat(user, SPAN_WARNING("The [src] cannot be [anchored ? "un" : ""]anchored."))
+ to_chat(user, SPAN_WARNING("[src] cannot be [anchored ? "un" : ""]anchored."))
return FALSE
else
// Wrenching is faster if we are better at engineering
diff --git a/code/game/objects/structures/airlock_assembly.dm b/code/game/objects/structures/airlock_assembly.dm
index 0679e1287ff7..d9e55e868016 100644
--- a/code/game/objects/structures/airlock_assembly.dm
+++ b/code/game/objects/structures/airlock_assembly.dm
@@ -22,9 +22,11 @@
var/airlock_type = "generic" //the type path of the airlock once completed
var/glass = AIRLOCK_NOGLASS // see defines
var/created_name = null
+ /// Used for multitile assemblies
+ var/width = 1
+
/obj/structure/airlock_assembly/Initialize(mapload, ...)
. = ..()
-
update_icon()
/obj/structure/airlock_assembly/get_examine_text(mob/user)
@@ -35,23 +37,26 @@
switch(state)
if(STATE_STANDARD)
if(anchored)
- helpmessage += "It looks like a [SPAN_HELPFUL("wrench")] will unsecure it. Insert a [SPAN_HELPFUL("airlock circuit")]."
+ var/temp = ""
+ if(width == 1)
+ temp += "It looks like a [SPAN_HELPFUL("wrench")] will unsecure it. "
+ helpmessage += "[temp]You can insert an [SPAN_HELPFUL("airlock circuit")]. "
if(!glass)
- helpmessage += "Insert some [SPAN_HELPFUL("glass sheets")] to add windows to it."
+ helpmessage += "Insert some [SPAN_HELPFUL("glass sheets")] to add windows to it. "
else if(glass == AIRLOCK_GLASSIN)
- helpmessage += "You can take out the windows with a [SPAN_HELPFUL("screwdriver")]."
+ helpmessage += "You can take out the windows with a [SPAN_HELPFUL("screwdriver")]. "
else
- helpmessage += "It looks like a [SPAN_HELPFUL("wrench")] will secure it."
+ helpmessage += "It looks like a [SPAN_HELPFUL("wrench")] will secure it. "
if(STATE_CIRCUIT)
- helpmessage += "Add [SPAN_HELPFUL("cable coil")] to the circuit."
+ helpmessage += "Add [SPAN_HELPFUL("cable coil")] to the circuit. "
if(STATE_WIRES)
- helpmessage += "Secure the circuit with a [SPAN_HELPFUL("screwdriver")]."
+ helpmessage += "Secure the circuit with a [SPAN_HELPFUL("screwdriver")]. "
if(STATE_SCREWDRIVER)
- helpmessage += "[SPAN_HELPFUL("Weld")] it all in place."
+ helpmessage += "[SPAN_HELPFUL("Weld")] it all in place. "
helpmessage += "You can name it with a [SPAN_HELPFUL("pen")]."
. += SPAN_NOTICE(helpmessage)
-/obj/structure/airlock_assembly/attackby(obj/item/W as obj, mob/user as mob)
+/obj/structure/airlock_assembly/attackby(obj/item/attacking_item as obj, mob/user as mob)
if(user.action_busy)
return TRUE //no afterattack
@@ -59,16 +64,16 @@
to_chat(user, SPAN_WARNING("You are not trained to configure \the [src]..."))
return
- if(HAS_TRAIT(W, TRAIT_TOOL_PEN))
- var/t = copytext(stripped_input(user, "Enter the name for the airlock.", name, created_name), 1, MAX_NAME_LEN)
- if(!t || !in_range(src, usr) && loc != usr)
+ if(HAS_TRAIT(attacking_item, TRAIT_TOOL_PEN))
+ var/input_text = copytext(stripped_input(user, "Enter the name for the airlock.", name, created_name), 1, MAX_NAME_LEN)
+ if(!input_text || !in_range(src, usr) && loc != usr)
return
- created_name = t
+ created_name = input_text
playsound(src, "paper_writing", 15, TRUE)
return
- if(istype(W, /obj/item/stack/sheet/glass))
- var/obj/item/stack/sheet/glass/G = W
+ if(istype(attacking_item, /obj/item/stack/sheet/glass))
+ var/obj/item/stack/sheet/glass/glass_sheet = attacking_item
if(!anchored)
to_chat(user, SPAN_NOTICE("The airlock is not secured!"))
return
@@ -83,7 +88,7 @@
return
if(!do_after(user, 20 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
return
- if(G.use(5))
+ if(glass_sheet.use(5))
playsound(loc, 'sound/items/Deconstruct.ogg', 25, 1)
glass = AIRLOCK_GLASSIN
to_chat(user, SPAN_NOTICE("You insert some glass into \the [src], adding windows to it."))
@@ -93,7 +98,7 @@
to_chat(user, SPAN_WARNING("You need five sheets of glass to add windows to \the [src]!"))
return
- if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR))
+ if(HAS_TRAIT(attacking_item, TRAIT_TOOL_CROWBAR))
to_chat(user, SPAN_NOTICE("You start pulling \the [src] apart."))
playsound(loc, 'sound/items/Crowbar.ogg', 25, 1)
if(!do_after(user, 20 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
@@ -108,10 +113,14 @@
switch(state)
if(STATE_STANDARD)
- if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH))
+ if(HAS_TRAIT(attacking_item, TRAIT_TOOL_WRENCH))
+ //Moving wide doors is wonky and doesn't work properly, if it's fixed we could make it unwrenchable again
+ if(width > 1 && anchored)
+ to_chat(user, SPAN_WARNING("[src] cannot be unwrenched."))
+ return
if(!anchored)
- var/turf/open/T = loc
- if(!(istype(T) && T.allow_construction))
+ var/turf/open/checked_turf = loc
+ if(!(istype(checked_turf) && checked_turf.allow_construction))
to_chat(user, SPAN_WARNING("\The [src] cannot be secured here!"))
return
playsound(loc, 'sound/items/Ratchet.ogg', 25, 1)
@@ -127,10 +136,10 @@
to_chat(user, SPAN_NOTICE("The airlock is not secured!"))
return ..()
- if(istype(W, /obj/item/circuitboard/airlock))
- var/obj/item/circuitboard/airlock/C = W
- if(C.fried) // guess what this used to check? ICON STATE!!
- to_chat(user, SPAN_WARNING("\The [C] are totally broken!"))
+ if(istype(attacking_item, /obj/item/circuitboard/airlock))
+ var/obj/item/circuitboard/airlock/airlock_circuit = attacking_item
+ if(airlock_circuit.fried) // guess what this used to check? ICON STATE!!
+ to_chat(user, SPAN_WARNING("\The [airlock_circuit] are totally broken!"))
return
playsound(loc, 'sound/items/Screwdriver.ogg', 25, 1)
to_chat(user, SPAN_NOTICE("You start installing the airlock electronics."))
@@ -138,14 +147,14 @@
return
playsound(loc, 'sound/items/Screwdriver.ogg', 25, 1)
user.drop_held_item()
- W.forceMove(src)
+ attacking_item.forceMove(src)
to_chat(user, SPAN_NOTICE("You installed the airlock electronics!"))
state = STATE_CIRCUIT
- electronics = W
+ electronics = attacking_item
update_icon()
return
- if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER))
+ if(HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER))
if(!anchored)
to_chat(user, SPAN_NOTICE("The airlock is not secured!"))
return
@@ -163,22 +172,22 @@
if(STATE_CIRCUIT)
- if(istype(W, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/C = W
- if (C.get_amount() < 1)
+ if(istype(attacking_item, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/airlock_circuit = attacking_item
+ if (airlock_circuit.get_amount() < 1)
to_chat(user, SPAN_WARNING("You need one length of coil to wire the airlock assembly."))
return
to_chat(user, SPAN_NOTICE("You start to wire the circuit."))
if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
return
- if(C.use(1))
+ if(airlock_circuit.use(1))
state = STATE_WIRES
to_chat(user, SPAN_NOTICE("You wire the circuit."))
update_icon()
return
if(STATE_WIRES)
- if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER))
+ if(HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER))
playsound(loc, 'sound/items/Screwdriver.ogg', 25, 1)
to_chat(user, SPAN_NOTICE("You start securing the circuit"))
if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
@@ -190,27 +199,23 @@
return
if(STATE_SCREWDRIVER)
- if(iswelder(W))
- if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH))
+ if(iswelder(attacking_item))
+ if(!HAS_TRAIT(attacking_item, TRAIT_TOOL_BLOWTORCH))
to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
return
- var/obj/item/tool/weldingtool/WT = W
- if(!WT.remove_fuel(5, user))
+ var/obj/item/tool/weldingtool/welder = attacking_item
+ if(!welder.remove_fuel(5, user))
return
playsound(loc, 'sound/items/Welder2.ogg', 25, 1)
to_chat(user, SPAN_NOTICE("Now finishing the airlock."))
if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
- WT.remove_fuel(-5)
+ welder.remove_fuel(-5)
return
playsound(loc, 'sound/items/Welder2.ogg', 25, 1)
to_chat(user, SPAN_NOTICE("You finish the airlock!"))
- var/path
- if (glass == AIRLOCK_GLASSIN)
- path = text2path("/obj/structure/machinery/door/airlock/almayer/[airlock_type]/glass")
- else
- path = text2path("/obj/structure/machinery/door/airlock/almayer/[airlock_type]")
+ var/path = get_airlock_path()
var/obj/structure/machinery/door/airlock/door = new path(loc)
door.assembly_type = type
door.electronics = electronics
@@ -225,7 +230,7 @@
door.name = created_name
else
door.name = base_name
-
+ door.handle_multidoor()
electronics.forceMove(door)
qdel(src)
return
@@ -238,107 +243,107 @@
else
icon_state = "door_as_[base_icon_state][state]"
+/obj/structure/airlock_assembly/proc/get_airlock_path()
+ //For some reason multi_tile doors have different paths... can't say it isn't annoying
+ if (width > 1)
+ return "/obj/structure/machinery/door/airlock/multi_tile/almayer/[airlock_type][glass ? "" : "/solid"]"
+ return "/obj/structure/machinery/door/airlock/almayer/[airlock_type][glass ? "/glass" : ""]"
+
+/// Used for overloading proc in multi_tile
+/obj/structure/airlock_assembly/proc/update_collision_box()
+ return
+
/obj/structure/airlock_assembly/airlock_assembly_com
base_icon_state = "com"
base_name = "Command Airlock"
- airlock_type = "/command"
+ airlock_type = "command"
/obj/structure/airlock_assembly/airlock_assembly_sec
base_icon_state = "sec"
base_name = "Security Airlock"
- airlock_type = "/security"
+ airlock_type = "security"
/obj/structure/airlock_assembly/airlock_assembly_eng
base_icon_state = "eng"
base_name = "Engineering Airlock"
- airlock_type = "/engineering"
+ airlock_type = "engineering"
/obj/structure/airlock_assembly/airlock_assembly_min
base_icon_state = "min"
base_name = "Mining Airlock"
- airlock_type = "/mining"
+ airlock_type = "mining"
/obj/structure/airlock_assembly/airlock_assembly_atmo
base_icon_state = "atmo"
base_name = "Atmospherics Airlock"
- airlock_type = "/atmos"
+ airlock_type = "atmos"
/obj/structure/airlock_assembly/airlock_assembly_research
base_icon_state = "res"
base_name = "Research Airlock"
- airlock_type = "/research"
+ airlock_type = "research"
/obj/structure/airlock_assembly/airlock_assembly_science
base_icon_state = "sci"
base_name = "Science Airlock"
- airlock_type = "/science"
+ airlock_type = "science"
/obj/structure/airlock_assembly/airlock_assembly_med
base_icon_state = "med"
base_name = "Medical Airlock"
- airlock_type = "/medical"
+ airlock_type = "medical"
/obj/structure/airlock_assembly/airlock_assembly_mai
base_icon_state = "mai"
base_name = "Maintenance Airlock"
- airlock_type = "/maintenance"
+ airlock_type = "maintenance"
glass = AIRLOCK_CANTGLASS
/obj/structure/airlock_assembly/airlock_assembly_ext
base_icon_state = "ext"
base_name = "External Airlock"
- airlock_type = "/external"
+ airlock_type = "external"
glass = AIRLOCK_CANTGLASS
/obj/structure/airlock_assembly/airlock_assembly_fre
base_icon_state = "fre"
base_name = "Freezer Airlock"
- airlock_type = "/freezer"
+ airlock_type = "freezer"
glass = AIRLOCK_CANTGLASS
/obj/structure/airlock_assembly/airlock_assembly_hatch
base_icon_state = "hatch"
base_name = "Airtight Hatch"
- airlock_type = "/hatch"
+ airlock_type = "hatch"
glass = AIRLOCK_CANTGLASS
/obj/structure/airlock_assembly/airlock_assembly_mhatch
base_icon_state = "mhatch"
base_name = "Maintenance Hatch"
- airlock_type = "/maintenance_hatch"
+ airlock_type = "maintenance_hatch"
glass = AIRLOCK_CANTGLASS
/obj/structure/airlock_assembly/airlock_assembly_highsecurity // Borrowing this until WJohnston makes sprites for the assembly
base_icon_state = "highsec"
base_name = "High Security Airlock"
- airlock_type = "/highsecurity"
+ airlock_type = "highsecurity"
glass = AIRLOCK_CANTGLASS
/obj/structure/airlock_assembly/multi_tile
icon = 'icons/obj/structures/doors/airlock_assembly2x1.dmi'
- icon_state = "door_as_g0"
- dir = EAST
- var/width = 1
-
-/*Temporary until we get sprites.
- airlock_type = "/multi_tile/maint"
- glass = 1*/
- base_icon_state = "g" //Remember to delete this line when reverting "glass" var to 1.
- airlock_type = "/multi_tile/glass"
- glass = AIRLOCK_CANTGLASS //To prevent bugs in deconstruction process.
+ icon_state = "door_as_0"
+ width = 2
/obj/structure/airlock_assembly/multi_tile/Initialize(mapload, ...)
. = ..()
- if(dir in list(EAST, WEST))
- bound_width = width * world.icon_size
- bound_height = world.icon_size
- else
- bound_width = world.icon_size
- bound_height = width * world.icon_size
+ update_collision_box()
update_icon()
/obj/structure/airlock_assembly/multi_tile/Move()
. = ..()
+ update_collision_box()
+
+/obj/structure/airlock_assembly/multi_tile/update_collision_box()
if(dir in list(EAST, WEST))
bound_width = width * world.icon_size
bound_height = world.icon_size
diff --git a/code/game/objects/structures/barricade/barricade.dm b/code/game/objects/structures/barricade/barricade.dm
index 0ca2ccb1ddbc..b23e07f707f2 100644
--- a/code/game/objects/structures/barricade/barricade.dm
+++ b/code/game/objects/structures/barricade/barricade.dm
@@ -19,6 +19,7 @@
var/force_level_absorption = 5 //How much force an item needs to even damage it at all.
var/barricade_hitsound
var/barricade_type = "barricade" //"metal", "plasteel", etc.
+ var/wire_icon = 'icons/obj/structures/barricades.dmi' //! Icon file used for the wiring
var/can_change_dmg_state = TRUE
var/damage_state = BARRICADE_DMG_NONE
var/closed = FALSE
@@ -78,7 +79,7 @@
switch(dir)
if(SOUTH)
layer = ABOVE_MOB_LAYER
- else if(NORTH)
+ if(NORTH)
layer = initial(layer) - 0.01
else
layer = initial(layer)
@@ -102,9 +103,9 @@
if(is_wired)
if(!closed)
- overlays += image('icons/obj/structures/barricades.dmi', icon_state = "[src.barricade_type]_wire")
+ overlays += image(wire_icon, icon_state = "[barricade_type]_wire")
else
- overlays += image('icons/obj/structures/barricades.dmi', icon_state = "[src.barricade_type]_closed_wire")
+ overlays += image(wire_icon, icon_state = "[barricade_type]_closed_wire")
..()
diff --git a/code/game/objects/structures/barricade/deployable.dm b/code/game/objects/structures/barricade/deployable.dm
index 77aa6b7e6816..0d5275f98a3d 100644
--- a/code/game/objects/structures/barricade/deployable.dm
+++ b/code/game/objects/structures/barricade/deployable.dm
@@ -63,7 +63,7 @@
if(!ishuman(usr))
return
- if(usr.lying)
+ if(usr.is_mob_incapacitated())
return
if(over_object == usr && Adjacent(usr))
diff --git a/code/game/objects/structures/barricade/handrail.dm b/code/game/objects/structures/barricade/handrail.dm
index ea10dc7256de..ae166dbbf985 100644
--- a/code/game/objects/structures/barricade/handrail.dm
+++ b/code/game/objects/structures/barricade/handrail.dm
@@ -24,7 +24,7 @@
switch(dir)
if(SOUTH)
layer = ABOVE_MOB_LAYER
- else if(NORTH)
+ if(NORTH)
layer = initial(layer) - 0.01
else
layer = initial(layer)
diff --git a/code/game/objects/structures/barricade/metal.dm b/code/game/objects/structures/barricade/metal.dm
index 4056ac9021f8..4f250eed50e9 100644
--- a/code/game/objects/structures/barricade/metal.dm
+++ b/code/game/objects/structures/barricade/metal.dm
@@ -110,7 +110,7 @@
to_chat(user, SPAN_NOTICE("You lack the required metal."))
return
if((usr.get_active_hand()) != metal)
- to_chat(user, SPAN_WARNING("You must be holding the [metal] to upgrade \the [src]!"))
+ to_chat(user, SPAN_WARNING("You must be holding [metal] to upgrade [src]!"))
return
switch(choice)
@@ -150,7 +150,7 @@
to_chat(user, SPAN_NOTICE("You lack the required metal."))
return
if((usr.get_active_hand()) != metal)
- to_chat(user, SPAN_WARNING("You must be holding the [metal] to upgrade \the [src]!"))
+ to_chat(user, SPAN_WARNING("You must be holding [metal] to upgrade [src]!"))
return
switch(choice)
diff --git a/code/game/objects/structures/barricade/plasteel.dm b/code/game/objects/structures/barricade/plasteel.dm
index d1a42c9b61ab..dd95aa3f1baf 100644
--- a/code/game/objects/structures/barricade/plasteel.dm
+++ b/code/game/objects/structures/barricade/plasteel.dm
@@ -30,7 +30,7 @@
/obj/structure/barricade/plasteel/update_icon()
..()
if(linked)
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
for(var/obj/structure/barricade/plasteel/cade in get_step(src, direction))
if(((dir & (NORTH|SOUTH) && get_dir(src, cade) & (EAST|WEST)) || (dir & (EAST|WEST) && get_dir(src, cade) & (NORTH|SOUTH))) && dir == cade.dir && cade.linked && cade.closed == src.closed && hasconnectionoverlay)
if(closed)
@@ -125,10 +125,10 @@
user.visible_message(SPAN_NOTICE("[user] sets up [src] for linking."),
SPAN_NOTICE("You set up [src] for linking."))
else
- to_chat(user, SPAN_WARNING("The [src] has no linking points..."))
+ to_chat(user, SPAN_WARNING("[src] has no linking points..."))
return
linked = !linked
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
for(var/obj/structure/barricade/plasteel/cade in get_step(src, direction))
cade.update_icon()
update_icon()
@@ -210,7 +210,7 @@
if(closed)
if(recentlyflipped)
- to_chat(user, SPAN_NOTICE("The [src] has been flipped too recently!"))
+ to_chat(user, SPAN_NOTICE("[src] has been flipped too recently!"))
return
user.visible_message(SPAN_NOTICE("[user] flips [src] open."),
SPAN_NOTICE("You flip [src] open."))
@@ -222,7 +222,7 @@
else
if(recentlyflipped)
- to_chat(user, SPAN_NOTICE("The [src] has been flipped too recently!"))
+ to_chat(user, SPAN_NOTICE("[src] has been flipped too recently!"))
return
user.visible_message(SPAN_NOTICE("[user] flips [src] closed."),
SPAN_NOTICE("You flip [src] closed."))
@@ -239,7 +239,7 @@
closed = 0
density = TRUE
if(linked)
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
for(var/obj/structure/barricade/plasteel/cade in get_step(src, direction))
if(((dir & (NORTH|SOUTH) && get_dir(src, cade) & (EAST|WEST)) || (dir & (EAST|WEST) && get_dir(src, cade) & (NORTH|SOUTH))) && dir == cade.dir && cade != origin && cade.linked)
cade.open(src)
@@ -252,7 +252,7 @@
closed = 1
density = FALSE
if(linked)
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
for(var/obj/structure/barricade/plasteel/cade in get_step(src, direction))
if(((dir & (NORTH|SOUTH) && get_dir(src, cade) & (EAST|WEST)) || (dir & (EAST|WEST) && get_dir(src, cade) & (NORTH|SOUTH))) && dir == cade.dir && cade != origin && cade.linked)
cade.close(src)
diff --git a/code/game/objects/structures/blocker.dm b/code/game/objects/structures/blocker.dm
index 284daf0028aa..f85b1e65fff5 100644
--- a/code/game/objects/structures/blocker.dm
+++ b/code/game/objects/structures/blocker.dm
@@ -105,9 +105,21 @@
/obj/structure/blocker/forcefield/vehicles
types = list(/obj/vehicle/)
+
+/obj/structure/blocker/forcefield/vehicles/handle_vehicle_bump(obj/vehicle/multitile/multitile_vehicle)
+ if(multitile_vehicle.vehicle_flags & VEHICLE_BYPASS_BLOCKERS)
+ return TRUE
+ return FALSE
+
/obj/structure/blocker/forcefield/multitile_vehicles
types = list(/obj/vehicle/multitile/)
+
+/obj/structure/blocker/forcefield/multitile_vehicles/handle_vehicle_bump(obj/vehicle/multitile/multitile_vehicle)
+ if(multitile_vehicle.vehicle_flags & VEHICLE_BYPASS_BLOCKERS)
+ return TRUE
+ return FALSE
+
/obj/structure/blocker/forcefield/human
types = list(/mob/living/carbon/human)
icon_state = "purple_line"
diff --git a/code/game/objects/structures/bookcase.dm b/code/game/objects/structures/bookcase.dm
index c71b2853ea07..ce338de47b35 100644
--- a/code/game/objects/structures/bookcase.dm
+++ b/code/game/objects/structures/bookcase.dm
@@ -33,7 +33,7 @@
if(contents.len)
var/obj/item/book/choice = input("Which book would you like to remove from the shelf?") as null|obj in contents
if(choice)
- if(!usr.canmove || usr.stat || usr.is_mob_restrained() || !in_range(loc, usr))
+ if(usr.is_mob_incapacitated() || !in_range(loc, usr))
return
if(ishuman(user))
if(!user.get_active_hand())
@@ -58,8 +58,6 @@
contents_explosion(severity)
deconstruct(FALSE)
return
- else
- return
/obj/structure/bookcase/update_icon()
if(contents.len < 5)
diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm
index a7394f3a7586..fa87cd6b2b71 100644
--- a/code/game/objects/structures/crates_lockers/closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets.dm
@@ -79,10 +79,11 @@
M.forceMove(loc)
if(exit_stun)
M.apply_effect(exit_stun, STUN) //Action delay when going out of a closet
- M.update_canmove() //Force the delay to go in action immediately
- if(!M.lying)
- M.visible_message(SPAN_WARNING("[M] suddenly gets out of [src]!"),
- SPAN_WARNING("You get out of [src] and get your bearings!"))
+ if(isliving(M))
+ var/mob/living/living_M = M
+ if(living_M.mobility_flags & MOBILITY_MOVE)
+ M.visible_message(SPAN_WARNING("[M] suddenly gets out of [src]!"),
+ SPAN_WARNING("You get out of [src] and get your bearings!"))
/obj/structure/closet/proc/open()
if(opened)
@@ -157,10 +158,15 @@
/obj/structure/closet/proc/take_damage(damage)
+ if(health <= 0)
+ return
+
health = max(health - damage, 0)
if(health <= 0)
- for(var/atom/movable/A as anything in src)
- A.forceMove(src.loc)
+ for(var/atom/movable/movable as anything in src)
+ if(!loc)
+ break
+ movable.forceMove(loc)
playsound(loc, 'sound/effects/meteorimpact.ogg', 25, 1)
qdel(src)
@@ -194,7 +200,7 @@
/obj/structure/closet/attack_animal(mob/living/user)
if(user.wall_smash)
- visible_message(SPAN_DANGER("[user] destroys the [src]. "))
+ visible_message(SPAN_DANGER("[user] destroys [src]."))
for(var/atom/movable/A as mob|obj in src)
A.forceMove(src.loc)
qdel(src)
@@ -333,7 +339,7 @@
set category = "Object"
set name = "Toggle Open"
- if(!usr.canmove || usr.stat || usr.is_mob_restrained())
+ if(usr.is_mob_incapacitated())
return
if(usr.loc == src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm
index ffd993777644..9b473d91f46e 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm
@@ -32,6 +32,8 @@ GLOBAL_LIST_EMPTY(co_secure_boxes)
/obj/structure/closet/secure_closet/securecom/Initialize()
. = ..()
+ new /obj/item/storage/box/kit/honorguard(src)
+ new /obj/item/storage/box/kit/honorguard(src)
GLOB.co_secure_boxes += src
/obj/structure/closet/secure_closet/securecom/Destroy()
@@ -104,7 +106,7 @@ GLOBAL_LIST_EMPTY(co_secure_boxes)
new /obj/item/clothing/shoes/marine(src)
new /obj/item/storage/belt/gun/m4a3(src)
new /obj/item/storage/backpack/marine/satchel/intel(src)
- new /obj/item/clothing/suit/storage/marine/rto/intel(src)
+ new /obj/item/clothing/suit/storage/marine/medium/rto/intel(src)
new /obj/item/storage/pouch/document(src)
new /obj/item/storage/pouch/document(src)
new /obj/item/device/motiondetector/intel(src)
@@ -178,7 +180,7 @@ GLOBAL_LIST_EMPTY(co_secure_boxes)
/obj/structure/closet/secure_closet/warrant_officer
name = "chief MP's locker"
- req_access = list(ACCESS_MARINE_BRIG)
+ req_access = list(ACCESS_MARINE_ARMORY)
icon_state = "secure_locked_warrant"
icon_closed = "secure_unlocked_warrant"
icon_locked = "secure_locked_warrant"
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/guncabinet.dm
similarity index 85%
rename from code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm
rename to code/game/objects/structures/crates_lockers/closets/secure/guncabinet/guncabinet.dm
index db20a738c8ed..4531a68c42dd 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/guncabinet.dm
@@ -65,21 +65,7 @@
contents_explosion(severity - EXPLOSION_THRESHOLD_LOW)
deconstruct(FALSE)
-/obj/structure/closet/secure_closet/guncabinet/mp_armory
-// req_access = list(ACCESS_MARINE_BRIG)
- req_level = SEC_LEVEL_RED
-
-/obj/structure/closet/secure_closet/guncabinet/mp_armory/Initialize()
- . = ..()
- new /obj/item/weapon/gun/shotgun/combat(src)
- new /obj/item/weapon/gun/shotgun/combat(src)
- new /obj/item/ammo_magazine/shotgun/slugs(src)
- new /obj/item/ammo_magazine/shotgun/buckshot(src)
- new /obj/item/ammo_magazine/shotgun/buckshot(src)
- new /obj/item/ammo_magazine/shotgun/buckshot(src)
-
-
-
+//this is used on corsat.(leaving it as a prop i guess)
/obj/structure/closet/secure_closet/guncabinet/riot_control
name = "riot control equipment closet"
// req_access = list(ACCESS_MARINE_BRIG)
@@ -111,15 +97,10 @@
new /obj/item/clothing/suit/armor/riot/marine(src)
new /obj/item/storage/box/flashbangs(src)
-
/obj/structure/closet/secure_closet/guncabinet/green
name = "green level gun cabinet"
req_level = SEC_LEVEL_GREEN
-/obj/structure/closet/secure_closet/guncabinet/blue
- name = "blue level gun cabinet"
- req_level = SEC_LEVEL_BLUE
-
/obj/structure/closet/secure_closet/guncabinet/red
name = "red level gun cabinet"
req_level = SEC_LEVEL_RED
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_blue.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_blue.dm
new file mode 100644
index 000000000000..acc43c302e6d
--- /dev/null
+++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_blue.dm
@@ -0,0 +1,37 @@
+/obj/structure/closet/secure_closet/guncabinet/blue
+ name = "blue level gun cabinet"
+ req_level = SEC_LEVEL_BLUE
+
+//riot gear control cabinet adding vehicle clamp to it to...
+// make more sense than in red alert cabinet.
+
+/obj/structure/closet/secure_closet/guncabinet/blue/riot_control
+ name = "riot control equipment closet"
+ storage_capacity = 55 //lots of stuff to fit in
+ req_level = SEC_LEVEL_BLUE
+
+/obj/structure/closet/secure_closet/guncabinet/blue/riot_control/Initialize()
+ . = ..()
+ new /obj/item/weapon/gun/shotgun/combat/riot(src, TRUE)
+ new /obj/item/weapon/gun/shotgun/combat/riot(src, TRUE)
+ new /obj/item/weapon/gun/shotgun/combat/riot(src, TRUE)
+ new /obj/item/weapon/shield/riot(src)
+ new /obj/item/weapon/shield/riot(src)
+ new /obj/item/weapon/shield/riot(src)
+ new /obj/item/ammo_magazine/shotgun/beanbag/riot(src)
+ new /obj/item/ammo_magazine/shotgun/beanbag/riot(src)
+ new /obj/item/ammo_magazine/shotgun/beanbag/riot(src)
+ new /obj/item/ammo_magazine/shotgun/beanbag/riot(src)
+ new /obj/item/weapon/gun/launcher/grenade/m81/riot(src, TRUE)
+ new /obj/item/storage/box/nade_box/tear_gas(src)
+ new /obj/item/clothing/mask/gas(src)
+ new /obj/item/clothing/mask/gas(src)
+ new /obj/item/clothing/mask/gas(src)
+ new /obj/item/clothing/head/helmet/riot(src)
+ new /obj/item/clothing/head/helmet/riot(src)
+ new /obj/item/clothing/head/helmet/riot(src)
+ new /obj/item/clothing/suit/armor/riot/marine(src)
+ new /obj/item/clothing/suit/armor/riot/marine(src)
+ new /obj/item/clothing/suit/armor/riot/marine(src)
+ new /obj/item/storage/box/flashbangs(src)
+ new /obj/item/vehicle_clamp(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_red.dm b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_red.dm
new file mode 100644
index 000000000000..487ffd546d8e
--- /dev/null
+++ b/code/game/objects/structures/crates_lockers/closets/secure/guncabinet/level_red.dm
@@ -0,0 +1,112 @@
+/obj/structure/closet/secure_closet/guncabinet/red
+ name = "red level gun cabinet"
+ req_level = SEC_LEVEL_RED
+
+// MP ARMORY
+
+// 3 shotgun cabinet are in brig armory
+/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_shotgun
+
+/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_shotgun/Initialize()
+ . = ..()
+ new /obj/item/weapon/gun/shotgun/combat(src)
+ new /obj/item/weapon/gun/shotgun/combat(src)
+ new /obj/item/weapon/gun/shotgun/combat(src)
+ new /obj/item/ammo_box/magazine/shotgun/buckshot(src)
+ new /obj/item/ammo_box/magazine/shotgun(src)
+
+// 2 M39 cabinet are in brig armory (4 M39 and 12 mags)
+/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_m39_submachinegun
+
+/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_m39_submachinegun/Initialize()
+ . = ..()
+ new /obj/item/weapon/gun/smg/m39(src)
+ new /obj/item/weapon/gun/smg/m39(src)
+ new /obj/item/weapon/gun/smg/m39(src)
+ new /obj/item/weapon/gun/smg/m39(src)
+ new /obj/item/ammo_box/magazine/m39(src)
+
+// 2 m4ra cabinet are in brig armory (m4ra guns and 12 mags)
+/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_m4ra_rifle
+
+/obj/structure/closet/secure_closet/guncabinet/red/mp_armory_m4ra_rifle/Initialize()
+ . = ..()
+ new /obj/item/weapon/gun/rifle/m4ra(src)
+ new /obj/item/weapon/gun/rifle/m4ra(src)
+ new /obj/item/weapon/gun/rifle/m4ra(src)
+ new /obj/item/weapon/gun/rifle/m4ra(src)
+ new /obj/item/ammo_box/magazine/m4ra(src)
+
+// EXECUTION CHAMBER might add that here need to ask first... will reskin if asked.
+
+
+
+// CIC ARMORY
+
+// 4 shotgun cabinet are in cic armory
+/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_shotgun
+
+/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_shotgun/Initialize()
+ . = ..()
+ new /obj/item/weapon/gun/shotgun/combat(src)
+ new /obj/item/ammo_magazine/shotgun/slugs(src)
+ new /obj/item/ammo_magazine/shotgun/buckshot(src)
+
+//4 MK1 cabinet(using guncase because it fit well here it seem)
+/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_mk1_rifle
+
+/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_mk1_rifle/Initialize()
+ . = ..()
+ new /obj/item/storage/box/guncase/m41aMK1(src)
+
+//4 MK1 (with AP) cabinet(using guncase because it fit well here it seem)
+/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_mk1_rifle_ap
+
+/obj/structure/closet/secure_closet/guncabinet/red/cic_armory_mk1_rifle_ap/Initialize()
+ . = ..()
+ new /obj/item/storage/box/guncase/m41aMK1AP(src)
+
+// UPPER MEDBAY ARMORY
+
+//1 shotgun armory closet 2 guns and 4 mags
+/obj/structure/closet/secure_closet/guncabinet/red/armory_shotgun
+
+/obj/structure/closet/secure_closet/guncabinet/red/armory_shotgun/Initialize()
+ . = ..()
+ new /obj/item/weapon/gun/shotgun/combat(src)
+ new /obj/item/weapon/gun/shotgun/combat(src)
+ new /obj/item/ammo_magazine/shotgun/slugs(src)
+ new /obj/item/ammo_magazine/shotgun/slugs(src)
+ new /obj/item/ammo_magazine/shotgun/buckshot(src)
+ new /obj/item/ammo_magazine/shotgun/buckshot(src)
+
+// 2 pistol amory closet maybe to replace with full pistol belt...
+/obj/structure/closet/secure_closet/guncabinet/red/armory_m4a3_pistol
+
+/obj/structure/closet/secure_closet/guncabinet/red/armory_m4a3_pistol/Initialize()
+ . = ..()
+ new /obj/item/storage/belt/gun/m4a3/full(src)
+ new /obj/item/storage/belt/gun/m4a3/full(src)
+ new /obj/item/storage/belt/gun/m4a3/full(src)
+ new /obj/item/storage/belt/gun/m4a3/full(src)
+ new /obj/item/ammo_box/magazine/m4a3(src)
+
+// 2 M39 cabinet are in medical armory (4 M39 and 12 mags)
+/obj/structure/closet/secure_closet/guncabinet/red/armory_m39_submachinegun
+
+/obj/structure/closet/secure_closet/guncabinet/red/armory_m39_submachinegun/Initialize()
+ . = ..()
+ new /obj/item/weapon/gun/smg/m39(src)
+ new /obj/item/weapon/gun/smg/m39(src)
+ new /obj/item/weapon/gun/smg/m39(src)
+ new /obj/item/weapon/gun/smg/m39(src)
+ new /obj/item/ammo_box/magazine/m39(src)
+
+// UPPER ENGI ARMORY
+// same as medical
+
+// REQ ARMORY
+// same as medical
+
+// Small office in hangar armory same as brig armory....
+// same as brig armory
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/kitchen.dm b/code/game/objects/structures/crates_lockers/closets/secure/kitchen.dm
new file mode 100644
index 000000000000..d8b0c984d4b1
--- /dev/null
+++ b/code/game/objects/structures/crates_lockers/closets/secure/kitchen.dm
@@ -0,0 +1,143 @@
+//standart fridge
+
+/obj/structure/closet/secure_closet/fridge
+ name = "Refrigerator"
+ icon = 'icons/obj/structures/machinery/kitchen.dmi'
+ icon_state = "fridge1"
+ icon_closed = "fridge"
+ icon_locked = "fridge1"
+ icon_opened = "fridgeopen"
+ icon_broken = "fridgebroken"
+ icon_off = "fridge1"
+ storage_capacity = 60 //give extra storage capacity so that everything can fit.
+
+/obj/structure/closet/secure_closet/fridge/update_icon()
+ if(broken)
+ icon_state = icon_broken
+ else
+ if(!opened)
+ if(locked)
+ icon_state = icon_locked
+ else
+ icon_state = icon_closed
+ else
+ icon_state = icon_opened
+
+// for almayer.
+
+// Kitchen preparation room small quantity out of boxes...
+
+//standart organic storage.
+
+/obj/structure/closet/secure_closet/fridge/organic
+ name = "Organic"
+
+/obj/structure/closet/secure_closet/fridge/organic/Initialize()
+ . = ..()
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_container/food/snacks/grown/apple(src)
+ new /obj/item/reagent_container/food/snacks/grown/cabbage(src)
+ new /obj/item/reagent_container/food/snacks/grown/carrot(src)
+ new /obj/item/reagent_container/food/snacks/grown/mushroom/chanterelle(src)
+ new /obj/item/reagent_container/food/snacks/grown/chili(src)
+ new /obj/item/reagent_container/food/snacks/grown/corn(src)
+ new /obj/item/reagent_container/food/snacks/grown/eggplant(src)
+ new /obj/item/reagent_container/food/snacks/grown/potato(src)
+ new /obj/item/reagent_container/food/snacks/grown/tomato(src)
+ new /obj/item/reagent_container/food/snacks/grown/whitebeet(src)
+ new /obj/item/reagent_container/food/snacks/grown/cherries(src)
+ new /obj/item/reagent_container/food/snacks/grown/lime(src)
+ new /obj/item/reagent_container/food/snacks/grown/lemon(src)
+ new /obj/item/reagent_container/food/snacks/grown/orange(src)
+ new /obj/item/reagent_container/food/snacks/grown/banana(src)
+
+//DRy
+
+/obj/structure/closet/secure_closet/fridge/dry
+ name = "dry"
+
+/obj/structure/closet/secure_closet/fridge/dry/Initialize()
+ . = ..()
+ for(var/i in 1 to 6)
+ new /obj/item/reagent_container/food/snacks/flour(src)
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_container/food/condiment/sugar(src)
+
+//grocery
+
+/obj/structure/closet/secure_closet/fridge/groceries
+ name = "Groceries"
+
+/obj/structure/closet/secure_closet/fridge/groceries/Initialize()
+ . = ..()
+ for(var/i in 1 to 2)
+ new /obj/item/reagent_container/food/drinks/milk(src)
+ new /obj/item/reagent_container/food/drinks/soymilk(src)
+ new /obj/item/storage/fancy/egg_box(src)
+ new /obj/item/reagent_container/food/condiment/enzyme(src)
+
+// Kitchen Reserve big quantity stored in boxes
+
+//meat surplus
+/obj/structure/closet/secure_closet/fridge/meat/stock
+ name = "meat"
+
+/obj/structure/closet/secure_closet/fridge/meat/stock/Initialize()
+ . = ..()
+ for(var/i in 1 to 2)
+ new /obj/item/storage/box/meat(src)
+
+//fish surplus
+/obj/structure/closet/secure_closet/fridge/fish/stock
+ name = "fish"
+
+/obj/structure/closet/secure_closet/fridge/fish/stock/Initialize()
+ . = ..()
+ for(var/i in 1 to 2)
+ new /obj/item/storage/box/fish(src)
+
+//groceries to hold milk in bulk
+/obj/structure/closet/secure_closet/fridge/groceries/stock
+ name = "Groceries"
+
+/obj/structure/closet/secure_closet/fridge/groceries/stock/Initialize()
+ . = ..()
+ for(var/i in 1 to 2)
+ new /obj/item/storage/box/milk(src)
+ new /obj/item/storage/box/soymilk(src)
+ for(var/i in 1 to 7)
+ new /obj/item/storage/fancy/egg_box(src)
+ new /obj/item/storage/box/enzyme(src)
+
+//dry storage for dry food only... not a fridge
+/obj/structure/closet/secure_closet/fridge/dry/stock
+ name = "dry"
+
+/obj/structure/closet/secure_closet/fridge/dry/stock/Initialize()
+ . = ..()
+ for(var/i in 1 to 4)
+ new /obj/item/storage/box/flour(src)
+ new /obj/item/storage/box/sugar(src)
+
+// organic storage in bulk
+
+/obj/structure/closet/secure_closet/fridge/organic/stock
+ name = "Organic"
+
+/obj/structure/closet/secure_closet/fridge/organic/stock/Initialize()
+ . = ..()
+ new /obj/item/storage/box/apple(src)
+ new /obj/item/storage/box/banana(src)
+ new /obj/item/storage/box/chanterelle(src)
+ new /obj/item/storage/box/cherries(src)
+ new /obj/item/storage/box/chili(src)
+ new /obj/item/storage/box/cabbage(src)
+ new /obj/item/storage/box/carrot(src)
+ new /obj/item/storage/box/corn(src)
+ new /obj/item/storage/box/eggplant(src)
+ new /obj/item/storage/box/lemon(src)
+ new /obj/item/storage/box/lime(src)
+ new /obj/item/storage/box/orange(src)
+ new /obj/item/storage/box/potato(src)
+ new /obj/item/storage/box/tomato(src)
+ new /obj/item/storage/box/whitebeet(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 d6b4a35b04f7..3206da86b197 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/personal.dm
@@ -78,7 +78,7 @@
set src in oview(1) // One square distance
set category = "Object"
set name = "Reset Lock"
- if(!usr.canmove || usr.stat || usr.is_mob_restrained()) // Don't use it if you're not able to! Checks for stuns, ghost and restrain
+ if(usr.is_mob_incapacitated()) // Don't use it if you're not able to! Checks for stuns, ghost and restrain
return
if(ishuman(usr))
src.add_fingerprint(usr)
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 e290a23a61e9..ba974a8e722a 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
@@ -30,6 +30,7 @@
return 0
/obj/structure/closet/secure_closet/emp_act(severity)
+ . = ..()
for(var/obj/O in src)
O.emp_act(severity)
if(!broken)
@@ -42,7 +43,6 @@
else
src.req_access = list()
src.req_access += pick(get_access(ACCESS_LIST_MARINE_MAIN))
- ..()
/obj/structure/closet/secure_closet/proc/togglelock(mob/living/user)
if(src.opened)
@@ -121,7 +121,7 @@
set category = "Object"
set name = "Toggle Lock"
- if(!usr.canmove || usr.stat || usr.is_mob_restrained()) // Don't use it if you're not able to! Checks for stuns, ghost and restrain
+ if(usr.is_mob_incapacitated()) // Don't use it if you're not able to! Checks for stuns, ghost and restrain
return
if(ishuman(usr))
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 9557013268bf..c668f299db73 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/security.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/security.dm
@@ -196,6 +196,59 @@
locked = TRUE
var/id = null
+/obj/structure/closet/secure_closet/brig/prisoner
+
+/obj/structure/closet/secure_closet/brig/prisoner/Initialize()
+ . = ..()
+ new /obj/item/clothing/under/color/orange(src)
+ new /obj/item/clothing/shoes/orange(src)
+ new /obj/item/device/radio/headset(src)
+
+/obj/structure/closet/secure_closet/brig/prison_uni
+ name = "Spare Prison Uniforms"
+ req_one_access = list(ACCESS_MARINE_BRIG, ACCESS_CIVILIAN_BRIG)
+ anchored = TRUE
+ locked = TRUE
+
+
+/obj/structure/closet/secure_closet/brig/prison_uni/Initialize()
+ . = ..()
+ new /obj/item/clothing/shoes/orange(src)
+ new /obj/item/clothing/shoes/orange(src)
+ new /obj/item/clothing/shoes/orange(src)
+ new /obj/item/clothing/shoes/orange(src)
+ new /obj/item/clothing/shoes/orange(src)
+ new /obj/item/clothing/under/color/orange(src)
+ new /obj/item/clothing/under/color/orange(src)
+ new /obj/item/clothing/under/color/orange(src)
+ new /obj/item/clothing/under/color/orange(src)
+ new /obj/item/clothing/under/color/orange(src)
+ new /obj/item/device/radio/headset(src)
+ new /obj/item/device/radio/headset(src)
+ new /obj/item/device/radio/headset(src)
+ new /obj/item/device/radio/headset(src)
+ new /obj/item/device/radio/headset(src)
+
+/obj/structure/closet/secure_closet/brig/restraints
+ name = "Spare Restraints"
+ req_one_access = list(ACCESS_MARINE_BRIG, ACCESS_CIVILIAN_BRIG)
+ anchored = TRUE
+ locked = TRUE
+
+
+/obj/structure/closet/secure_closet/brig/restraints/Initialize()
+ . = ..()
+ new /obj/item/clothing/suit/straight_jacket(src)
+ new /obj/item/clothing/suit/straight_jacket(src)
+ new /obj/item/clothing/suit/straight_jacket(src)
+ new /obj/item/clothing/suit/straight_jacket(src)
+ new /obj/item/clothing/suit/straight_jacket(src)
+ new /obj/item/clothing/glasses/sunglasses/blindfold(src)
+ new /obj/item/clothing/glasses/sunglasses/blindfold(src)
+ new /obj/item/clothing/glasses/sunglasses/blindfold(src)
+ new /obj/item/clothing/glasses/sunglasses/blindfold(src)
+ new /obj/item/clothing/glasses/sunglasses/blindfold(src)
+
/obj/structure/closet/secure_closet/brig/Initialize()
. = ..()
new /obj/item/clothing/under/color/orange(src)
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 7848aaba4897..b000fd5733a2 100644
--- a/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/utility_closets.dm
@@ -51,8 +51,6 @@
new /obj/item/clothing/mask/gas(src)
new /obj/item/clothing/mask/gas(src)
new /obj/item/storage/firstaid/o2(src)
- if ("nothing")
- // doot
// teehee - Ah, tg coders...
if ("delete")
diff --git a/code/game/objects/structures/crates_lockers/crates.dm b/code/game/objects/structures/crates_lockers/crates.dm
index 7c9faaf1a027..119615ab7aed 100644
--- a/code/game/objects/structures/crates_lockers/crates.dm
+++ b/code/game/objects/structures/crates_lockers/crates.dm
@@ -12,6 +12,19 @@
throwpass = 1 //prevents moving crates by hurling things at them
store_mobs = FALSE
var/rigged = 0
+ /// Types this crate can be made into
+ var/list/crate_customizing_types = list(
+ "Plain" = /obj/structure/closet/crate,
+ "Weapons" = /obj/structure/closet/crate/weapon,
+ "Supply" = /obj/structure/closet/crate/supply,
+ "Ammo" = /obj/structure/closet/crate/ammo,
+ "Construction" = /obj/structure/closet/crate/construction,
+ "Explosives" = /obj/structure/closet/crate/explosives,
+ "Alpha" = /obj/structure/closet/crate/alpha,
+ "Bravo" = /obj/structure/closet/crate/bravo,
+ "Charlie" = /obj/structure/closet/crate/charlie,
+ "Delta" = /obj/structure/closet/crate/delta,
+ )
/obj/structure/closet/crate/initialize_pass_flags(datum/pass_flags_container/PF)
..()
@@ -130,8 +143,6 @@
contents_explosion(severity)
deconstruct(FALSE)
return
- else
- return
/obj/structure/closet/crate/alpha
name = "alpha squad crate"
@@ -209,6 +220,7 @@
icon_state = "closed_freezer"
icon_opened = "open_freezer"
icon_closed = "closed_freezer"
+ crate_customizing_types = null
var/target_temp = T0C - 40
var/cooling_power = 40
diff --git a/code/game/objects/structures/crates_lockers/largecrate.dm b/code/game/objects/structures/crates_lockers/largecrate.dm
index 2f2877ba7539..e9e3a9a7b5d6 100644
--- a/code/game/objects/structures/crates_lockers/largecrate.dm
+++ b/code/game/objects/structures/crates_lockers/largecrate.dm
@@ -28,9 +28,8 @@
material_sheet = new parts_type(current_turf, 2)
// Move the objects back to the turf, above the crate material
- for(var/atom/movable/moving_atom in contents)
- var/atom/movable/current_atom = contents[1]
- current_atom.forceMove(current_turf)
+ for(var/atom/movable/moving_atom as anything in contents)
+ moving_atom.forceMove(current_turf)
deconstruct(TRUE)
@@ -252,8 +251,80 @@
name = "blue barrel"
desc = "A blue storage barrel."
icon_state = "barrel_blue"
+ var/strap_overlay = "+straps"
parts_type = /obj/item/stack/sheet/metal
unpacking_sound = 'sound/effects/metalhit.ogg'
+ var/straps = FALSE
+
+/obj/structure/largecrate/random/barrel/true_random
+ name = "barrel"
+ desc = "A barrel."
+ icon_state = "barrel_recolorable"
+ desc_lore = "From the future."
+ var/cap_doodad_state = ""
+ var/center_doodad_state = ""
+ var/color_override = null
+
+
+GLOBAL_LIST_EMPTY(rbarrel_cap_states) // Will be set up in generate_barrel_states
+GLOBAL_LIST_INIT(rbarrel_center_states, generate_barrel_states())
+GLOBAL_LIST_INIT(rbarrel_color_list, list(COLOR_SILVER,
+ COLOR_FLOORTILE_GRAY,
+ COLOR_MAROON,
+ COLOR_SOFT_RED,
+ COLOR_LIGHT_GRAYISH_RED,
+ COLOR_VERY_SOFT_YELLOW,
+ COLOR_OLIVE,
+ COLOR_DARK_MODERATE_LIME_GREEN,
+ COLOR_TEAL,
+ COLOR_MODERATE_BLUE,
+ COLOR_PURPLE,
+ COLOR_STRONG_VIOLET,
+ COLOR_BEIGE,
+ COLOR_DARK_MODERATE_ORANGE,
+ COLOR_BROWN,
+ COLOR_DARK_BROWN))
+
+/proc/generate_barrel_states()
+ var/list/rbarrel_center_states = list()
+ var/icon/icon = new('icons/obj/structures/crates.dmi')
+ var/list/icon_list = icon_states(icon)
+ for(var/state in icon_list)
+ if(findtext(state,"+cap"))
+ GLOB.rbarrel_cap_states.Add(state)
+ if(findtext(state,"+center"))
+ rbarrel_center_states.Add(state)
+ // We are returning rbarrel_center_states (rather than setting GLOB) because we are called by the global initializer to set it
+ return rbarrel_center_states
+
+/obj/structure/largecrate/random/barrel/true_random/Initialize()
+ . = ..()
+
+ var/image/center_coloring = image(icon, src,"+_center")
+
+ if(!color_override)
+ center_coloring.color = pick(GLOB.rbarrel_color_list)
+
+ center_coloring.appearance_flags = RESET_COLOR|KEEP_APART
+ overlays += center_coloring
+ if(prob(25))
+ cap_doodad_state = pick(GLOB.rbarrel_cap_states)
+ overlays += image(icon,src,cap_doodad_state)
+ if(prob(50))
+ center_doodad_state = pick(GLOB.rbarrel_center_states)
+ overlays += image(icon,src,center_doodad_state)
+
+/obj/structure/largecrate/random/barrel/Initialize()
+ . = ..()
+ if(overlays)
+ overlays.Cut()
+ if(straps)
+ overlays += image(icon,icon_state = "+straps")
+
+/obj/structure/largecrate/random/barrel/unpack()
+ if(overlays)
+ overlays.Cut()
+ . = ..()
/obj/structure/largecrate/random/barrel/blue
name = "blue barrel"
@@ -264,6 +335,7 @@
name = "red barrel"
desc = "A red storage barrel."
icon_state = "barrel_red"
+ straps = TRUE//the original sprite had straps, anyway, this is a harmless instance
/obj/structure/largecrate/random/barrel/green
name = "green barrel"
diff --git a/code/game/objects/structures/crates_lockers/secure_crates.dm b/code/game/objects/structures/crates_lockers/secure_crates.dm
index a308c4c0a21c..6b025a57c78b 100644
--- a/code/game/objects/structures/crates_lockers/secure_crates.dm
+++ b/code/game/objects/structures/crates_lockers/secure_crates.dm
@@ -4,6 +4,7 @@
icon_state = "secure_locked_basic"
icon_opened = "secure_open_basic"
icon_closed = "secure_locked_basic"
+ crate_customizing_types = null
var/icon_locked = "secure_locked_basic"
var/icon_unlocked = "secure_unlocked_basic"
var/sparks = "securecratesparks"
@@ -52,7 +53,7 @@
set category = "Object"
set name = "Toggle Lock"
- if(!usr.canmove || usr.stat || usr.is_mob_restrained()) // Don't use it if you're not able to! Checks for stuns, ghost and restrain
+ if(usr.is_mob_incapacitated()) // Don't use it if you're not able to! Checks for stuns, ghost and restrain
return
if(ishuman(usr))
@@ -86,6 +87,7 @@
..()
/obj/structure/closet/crate/secure/emp_act(severity)
+ . = ..()
for(var/obj/O in src)
O.emp_act(severity)
if(!broken && !opened && prob(50/severity))
@@ -105,7 +107,6 @@
else
src.req_access = list()
src.req_access += pick(get_access(ACCESS_LIST_MARINE_MAIN))
- ..()
//------------------------------------
diff --git a/code/game/objects/structures/extinguisher.dm b/code/game/objects/structures/extinguisher.dm
index 7b54f0447fae..e4ee4a1b662b 100644
--- a/code/game/objects/structures/extinguisher.dm
+++ b/code/game/objects/structures/extinguisher.dm
@@ -5,13 +5,15 @@
icon_state = "extinguisher"
anchored = TRUE
density = FALSE
- var/obj/item/tool/extinguisher/has_extinguisher = new/obj/item/tool/extinguisher
+ var/obj/item/tool/extinguisher/has_extinguisher
var/opened = 0
var/base_icon
/obj/structure/extinguisher_cabinet/Initialize()
. = ..()
base_icon = initial(icon_state)
+ has_extinguisher = new /obj/item/tool/extinguisher()
+ has_extinguisher.forceMove(src)
/obj/structure/extinguisher_cabinet/lifeboat
name = "extinguisher cabinet"
@@ -21,15 +23,15 @@
/obj/structure/extinguisher_cabinet/alt
icon_state = "extinguisher_alt"
-/obj/structure/extinguisher_cabinet/attackby(obj/item/O, mob/user)
+/obj/structure/extinguisher_cabinet/attackby(obj/item/item, mob/user)
if(isrobot(user))
return
- if(istype(O, /obj/item/tool/extinguisher))
+ if(istype(item, /obj/item/tool/extinguisher))
if(!has_extinguisher && opened)
user.drop_held_item()
- contents += O
- has_extinguisher = O
- to_chat(user, SPAN_NOTICE("You place [O] in [src]."))
+ item.forceMove(src)
+ has_extinguisher = item
+ to_chat(user, SPAN_NOTICE("You place [item] in [src]."))
else
opened = !opened
else
@@ -45,7 +47,7 @@
user.put_in_hands(has_extinguisher)
to_chat(user, SPAN_NOTICE("You take [has_extinguisher] from [src]."))
has_extinguisher = null
- opened = 1
+ opened = TRUE
else
opened = !opened
update_icon()
diff --git a/code/game/objects/structures/fence.dm b/code/game/objects/structures/fence.dm
index b29c69e8af18..db24dfdfebdd 100644
--- a/code/game/objects/structures/fence.dm
+++ b/code/game/objects/structures/fence.dm
@@ -209,7 +209,7 @@
//This proc is used to update the icons of nearby windows.
/obj/structure/fence/proc/update_nearby_icons()
update_icon()
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
for(var/obj/structure/fence/W in get_step(src, direction))
W.update_icon()
diff --git a/code/game/objects/structures/flora.dm b/code/game/objects/structures/flora.dm
index 9c1f46de50d5..0e4a20cf989a 100644
--- a/code/game/objects/structures/flora.dm
+++ b/code/game/objects/structures/flora.dm
@@ -72,7 +72,8 @@ PLANT_CUT_MACHETE = 3 = Needs at least a machete to be cut down
addtimer(CALLBACK(src, PROC_REF(burn_up)), spread_time + 5 SECONDS)
/obj/structure/flora/proc/spread_fire()
- for(var/D in cardinal) //Spread fire
+ SIGNAL_HANDLER
+ for(var/D in GLOB.cardinals) //Spread fire
var/turf/T = get_step(src.loc, D)
if(T)
for(var/obj/structure/flora/F in T)
@@ -82,6 +83,7 @@ PLANT_CUT_MACHETE = 3 = Needs at least a machete to be cut down
new /obj/flamer_fire(T, create_cause_data("wildfire"))
/obj/structure/flora/proc/burn_up()
+ SIGNAL_HANDLER
new /obj/effect/decal/cleanable/dirt(loc)
if(center)
new /obj/effect/decal/cleanable/dirt(loc) //Produces more ash at the center
@@ -717,13 +719,13 @@ ICEY GRASS. IT LOOKS LIKE IT'S MADE OF ICE.
//hatchets and shiet can clear away undergrowth
if(I && (I.sharp >= IS_SHARP_ITEM_ACCURATE) && !stump)
var/damage = rand(2,5)
- if(istype(I,/obj/item/weapon/claymore/mercsword))
+ if(istype(I,/obj/item/weapon/sword))
damage = rand(8,18)
if(indestructable)
//this bush marks the edge of the map, you can't destroy it
to_chat(user, SPAN_DANGER("You flail away at the undergrowth, but it's too thick here."))
else
- user.visible_message(SPAN_DANGER("[user] flails away at the [src] with [I]."),SPAN_DANGER("You flail away at the [src] with [I]."))
+ user.visible_message(SPAN_DANGER("[user] flails away at [src] with [I]."), SPAN_DANGER("You flail away at [src] with [I]."))
playsound(src.loc, 'sound/effects/vegetation_hit.ogg', 25, 1)
health -= damage
if(health < 0)
@@ -756,4 +758,3 @@ ICEY GRASS. IT LOOKS LIKE IT'S MADE OF ICE.
desc = "Looks like some of that fruit might be edible."
icon_tag = "plant"
variations = 7
-
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index e719359ab439..6cd6a5cd0300 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -173,6 +173,14 @@
return do_reinforced_wall(W, user)
if(STATE_DISPLACED)
if(HAS_TRAIT(W, TRAIT_TOOL_CROWBAR))
+ var/turf/open/floor = loc
+ if(!floor.allow_construction)
+ to_chat(user, SPAN_WARNING("The girder must be secured on a proper surface!"))
+ return
+ var/obj/structure/tunnel/tunnel = locate(/obj/structure/tunnel) in loc
+ if(tunnel)
+ to_chat(user, SPAN_WARNING("The girder cannot be secured on a tunnel!"))
+ return
playsound(loc, 'sound/items/Crowbar.ogg', 25, 1)
to_chat(user, SPAN_NOTICE("Now securing the girder..."))
if(!do_after(user, 40 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index 0f864ee2f116..063f6a337290 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -166,7 +166,7 @@
if (ST.use(1))
var/obj/structure/window/WD = new wtype(loc)
WD.set_constructed_window(dir_to_set)
- to_chat(user, SPAN_NOTICE("You place the [WD] on [src]."))
+ to_chat(user, SPAN_NOTICE("You place [WD] on [src]."))
return
//window placing end
diff --git a/code/game/objects/structures/ladders.dm b/code/game/objects/structures/ladders.dm
index f2e6b172ad88..0fda8c5d9631 100644
--- a/code/game/objects/structures/ladders.dm
+++ b/code/game/objects/structures/ladders.dm
@@ -67,8 +67,8 @@
else //wtf make your ladders properly assholes
icon_state = "ladder00"
-/obj/structure/ladder/attack_hand(mob/user)
- if(user.stat || get_dist(user, src) > 1 || user.blinded || user.lying || user.buckled || user.anchored) return
+/obj/structure/ladder/attack_hand(mob/living/user)
+ if(user.stat || get_dist(user, src) > 1 || user.blinded || user.body_position == LYING_DOWN || user.buckled || user.anchored) return
if(busy)
to_chat(user, SPAN_WARNING("Someone else is currently using [src]."))
return
@@ -94,7 +94,7 @@
SPAN_NOTICE("You start climbing [ladder_dir_name] [src]."))
busy = TRUE
if(do_after(user, 20, INTERRUPT_INCAPACITATED|INTERRUPT_OUT_OF_RANGE|INTERRUPT_RESIST, BUSY_ICON_GENERIC, src, INTERRUPT_NONE))
- if(!user.is_mob_incapacitated() && get_dist(user, src) <= 1 && !user.blinded && !user.lying && !user.buckled && !user.anchored)
+ if(!user.is_mob_incapacitated() && get_dist(user, src) <= 1 && !user.blinded && user.body_position != LYING_DOWN && !user.buckled && !user.anchored)
visible_message(SPAN_NOTICE("[user] climbs [ladder_dir_name] [src].")) //Hack to give a visible message to the people here without duplicating user message
user.visible_message(SPAN_NOTICE("[user] climbs [ladder_dir_name] [src]."),
SPAN_NOTICE("You climb [ladder_dir_name] [src]."))
@@ -103,9 +103,9 @@
busy = FALSE
add_fingerprint(user)
-/obj/structure/ladder/check_eye(mob/user)
+/obj/structure/ladder/check_eye(mob/living/user)
//Are we capable of looking?
- if(user.is_mob_incapacitated() || get_dist(user, src) > 1 || user.blinded || user.lying || !user.client)
+ if(user.is_mob_incapacitated() || get_dist(user, src) > 1 || user.blinded || user.body_position == LYING_DOWN || !user.client)
user.unset_interaction()
//Are ladder cameras ok?
@@ -140,7 +140,7 @@
//Peeking up/down
/obj/structure/ladder/MouseDrop(over_object, src_location, over_location)
if((over_object == usr && (in_range(src, usr))))
- if(islarva(usr) || isobserver(usr) || usr.is_mob_incapacitated() || usr.blinded || usr.lying)
+ if(islarva(usr) || isobserver(usr) || usr.is_mob_incapacitated() || usr.blinded)
to_chat(usr, "You can't do that in your current state.")
return
if(is_watching)
@@ -262,11 +262,8 @@
/obj/structure/ladder/fragile_almayer/Initialize()
. = ..()
- GLOB.hijack_bustable_ladders += src
-
-/obj/structure/ladder/fragile_almayer/Destroy()
- GLOB.hijack_bustable_ladders -= src
- return ..()
+ if(is_mainship_level(z))
+ RegisterSignal(SSdcs, COMSIG_GLOB_HIJACK_IMPACTED, PROC_REF(deconstruct))
/obj/structure/ladder/fragile_almayer/deconstruct()
new /obj/structure/prop/broken_ladder(loc)
diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm
index 38201e052c50..dd427adfabb9 100644
--- a/code/game/objects/structures/lattice.dm
+++ b/code/game/objects/structures/lattice.dm
@@ -19,14 +19,14 @@
icon = 'icons/obj/structures/props/smoothlattice.dmi'
icon_state = "latticeblank"
updateOverlays()
- for (var/dir in cardinal)
+ for (var/dir in GLOB.cardinals)
var/obj/structure/lattice/L
if(locate(/obj/structure/lattice, get_step(src, dir)))
L = locate(/obj/structure/lattice, get_step(src, dir))
L.updateOverlays()
/obj/structure/lattice/Destroy()
- for (var/dir in cardinal)
+ for (var/dir in GLOB.cardinals)
var/obj/structure/lattice/L
if(locate(/obj/structure/lattice, get_step(src, dir)))
L = locate(/obj/structure/lattice, get_step(src, dir))
@@ -43,8 +43,6 @@
if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY)
deconstruct(FALSE)
return
- else
- return
/obj/structure/lattice/attackby(obj/item/C as obj, mob/user as mob)
@@ -75,7 +73,7 @@
var/dir_sum = 0
- for (var/direction in cardinal)
+ for (var/direction in GLOB.cardinals)
if(locate(/obj/structure/lattice, get_step(src, direction)))
dir_sum += direction
else
diff --git a/code/game/objects/structures/misc.dm b/code/game/objects/structures/misc.dm
index d290925d4cdf..89bc3da6ab23 100644
--- a/code/game/objects/structures/misc.dm
+++ b/code/game/objects/structures/misc.dm
@@ -189,3 +189,126 @@
/obj/structure/computer3frame/laptop
name = "laptop frame"
+
+// Dartboard
+#define DOUBLE_BAND 2
+#define TRIPLE_BAND 3
+
+/obj/structure/dartboard
+ name = "dartboard"
+ desc = "A dartboard, loosely secured."
+ icon = 'icons/obj/structures/props/props.dmi'
+ icon_state = "dart_board"
+ density = TRUE
+ unslashable = TRUE
+
+/obj/structure/dartboard/get_examine_text()
+ . = ..()
+ if(length(contents))
+ var/is_are = "is"
+ if(length(contents) != 1)
+ is_are = "are"
+
+ . += SPAN_NOTICE("There [is_are] [length(contents)] item\s embedded into [src].")
+
+/obj/structure/dartboard/initialize_pass_flags(datum/pass_flags_container/pass_flags)
+ ..()
+ if(pass_flags)
+ pass_flags.flags_can_pass_all = PASS_MOB_IS
+
+/obj/structure/dartboard/get_projectile_hit_boolean(obj/projectile/projectile)
+ . = ..()
+ visible_message(SPAN_DANGER("[projectile] hits [src], collapsing it!"))
+ collapse()
+
+/obj/structure/dartboard/proc/flush_contents()
+ for(var/atom/movable/embedded_items as anything in contents)
+ embedded_items.forceMove(loc)
+
+/obj/structure/dartboard/proc/collapse()
+ playsound(src, 'sound/effects/thud1.ogg', 50)
+ new /obj/item/dartboard/(loc)
+ qdel(src)
+
+/obj/structure/dartboard/attack_hand(mob/user)
+ if(length(contents))
+ user.visible_message(SPAN_NOTICE("[user] starts recovering items from [src]..."), SPAN_NOTICE("You start recovering items from [src]..."))
+ if(do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_FRIENDLY, user, INTERRUPT_MOVED, BUSY_ICON_GENERIC))
+ flush_contents()
+ else
+ to_chat(user, SPAN_WARNING("[src] has nothing embedded!"))
+
+/obj/structure/dartboard/Destroy()
+ flush_contents()
+ . = ..()
+
+/obj/structure/dartboard/hitby(obj/item/thrown_item)
+ if(thrown_item.sharp != IS_SHARP_ITEM_ACCURATE && !istype(thrown_item, /obj/item/weapon/dart))
+ visible_message(SPAN_DANGER("[thrown_item] hits [src], collapsing it!"))
+ collapse()
+ return
+
+ contents += thrown_item
+ playsound(src, 'sound/weapons/tablehit1.ogg', 50)
+ var/score = rand(1,21)
+ if(score == 21)
+ visible_message(SPAN_DANGER("[thrown_item] embeds into [src], striking the bullseye! 50 points."))
+ return
+
+ var/band = "single"
+ var/band_number = rand(1,3)
+ score *= band_number
+ switch(band_number)
+ if(DOUBLE_BAND)
+ band = "double"
+ if(TRIPLE_BAND)
+ band = "triple"
+ visible_message(SPAN_DANGER("[thrown_item] embeds into [src], striking [band] for [score] point\s."))
+
+/obj/structure/dartboard/attackby(obj/item/item, mob/user)
+ user.visible_message(SPAN_DANGER("[user] hits [src] with [item], collapsing it!"), SPAN_DANGER("You collapse [src] with [item]!"))
+ collapse()
+
+/obj/structure/dartboard/MouseDrop(over_object, src_location, over_location)
+ . = ..()
+ if(over_object != usr || !Adjacent(usr))
+ return
+
+ if(!ishuman(usr))
+ return
+
+ visible_message(SPAN_NOTICE("[usr] unsecures [src]."))
+ var/obj/item/dartboard/unsecured_board = new(loc)
+ usr.put_in_hands(unsecured_board)
+ qdel(src)
+
+/obj/item/dartboard
+ name = "dartboard"
+ desc = "A dartboard for darts."
+ icon = 'icons/obj/structures/props/props.dmi'
+ icon_state = "dart_board"
+
+/obj/item/dartboard/attack_self(mob/user)
+ . = ..()
+
+ var/turf_ahead = get_step(user, user.dir)
+ if(!istype(turf_ahead, /turf/closed))
+ to_chat(user, SPAN_WARNING("[src] needs a wall to be secured to!"))
+ return
+
+ var/obj/structure/dartboard/secured_board = new(user.loc)
+ switch(user.dir)
+ if(NORTH)
+ secured_board.pixel_y = 32
+ if(EAST)
+ secured_board.pixel_x = 32
+ if(SOUTH)
+ secured_board.pixel_y = -32
+ if(WEST)
+ secured_board.pixel_x = -32
+
+ to_chat(user, SPAN_NOTICE("You secure [secured_board] to [turf_ahead]."))
+ qdel(src)
+
+#undef DOUBLE_BAND
+#undef TRIPLE_BAND
diff --git a/code/game/objects/structures/morgue.dm b/code/game/objects/structures/morgue.dm
index dc8cf08d13f1..f1717f5bf0f5 100644
--- a/code/game/objects/structures/morgue.dm
+++ b/code/game/objects/structures/morgue.dm
@@ -113,13 +113,12 @@
else
. = ..()
-/obj/structure/morgue/relaymove(mob/user)
+/obj/structure/morgue/relaymove(mob/living/user)
if(user.is_mob_incapacitated())
return
if(exit_stun)
- user.stunned = max(user.stunned, exit_stun) //Action delay when going out of a closet (or morgue in this case)
- user.update_canmove() //Force the delay to go in action immediately
- if(!user.lying)
+ user.apply_effect(exit_stun, STUN)
+ if(user.mobility_flags & MOBILITY_MOVE)
user.visible_message(SPAN_WARNING("[user] suddenly gets out of [src]!"),
SPAN_WARNING("You get out of [src] and get your bearings!"))
toggle_morgue(user)
diff --git a/code/game/objects/structures/props.dm b/code/game/objects/structures/props.dm
index 9eea571961f7..e14eee13b1dd 100644
--- a/code/game/objects/structures/props.dm
+++ b/code/game/objects/structures/props.dm
@@ -805,13 +805,15 @@
/obj/structure/prop/brazier/campfire/attackby(obj/item/attacking_item, mob/user)
if(!istype(attacking_item, /obj/item/stack/sheet/wood))
- to_chat(SPAN_NOTICE("You cannot fuel [src] with [attacking_item]."))
+ to_chat(user, SPAN_NOTICE("You cannot fuel [src] with [attacking_item]."))
return
var/obj/item/stack/sheet/wood/fuel = attacking_item
if(remaining_fuel >= initial(remaining_fuel))
to_chat(user, SPAN_NOTICE("You cannot fuel [src] further."))
+ return
if(!fuel.use(1))
- to_chat(SPAN_NOTICE("You do not have enough [attacking_item] to fuel [src]."))
+ to_chat(user, SPAN_NOTICE("You do not have enough [attacking_item] to fuel [src]."))
+ return
visible_message(SPAN_NOTICE("[user] fuels [src] with [fuel]."))
remaining_fuel++
@@ -1177,7 +1179,7 @@
new_info_tag.fallen_names = list(dogtag_name)
new_info_tag.fallen_assgns = list(dogtag_assign)
new_info_tag.fallen_blood_types = list(dogtag_blood)
- fallen_list_cross -= dogtag_name
+ GLOB.fallen_list_cross -= dogtag_name
return ..()
/obj/structure/prop/wooden_cross/attackby(obj/item/W, mob/living/user)
@@ -1185,18 +1187,18 @@
var/obj/item/dogtag/dog = W
if(!tagged)
tagged = TRUE
- user.visible_message(SPAN_NOTICE("[user] drapes the [W] around the [src]."))
+ user.visible_message(SPAN_NOTICE("[user] drapes [W] around [src]."))
dogtag_name = popleft(dog.fallen_names)
dogtag_assign = popleft(dog.fallen_assgns)
dogtag_blood = popleft(dog.fallen_blood_types)
- fallen_list_cross += dogtag_name
+ GLOB.fallen_list_cross += dogtag_name
update_icon()
if(!length(dog.fallen_names))
qdel(dog)
else
return
else
- to_chat(user, SPAN_WARNING("There's already a dog tag on the [src]!"))
+ to_chat(user, SPAN_WARNING("There's already a dog tag on [src]!"))
balloon_alert(user, "already a tag here!")
if(istype(W, /obj/item/clothing/head))
@@ -1370,4 +1372,3 @@
if(initial(emote.sound))
playsound(loc, initial(emote.sound), 50, FALSE)
return TRUE
-
diff --git a/code/game/objects/structures/reagent_dispensers.dm b/code/game/objects/structures/reagent_dispensers.dm
index 7dc6d883a2d5..6471dfa21520 100644
--- a/code/game/objects/structures/reagent_dispensers.dm
+++ b/code/game/objects/structures/reagent_dispensers.dm
@@ -119,8 +119,6 @@
if(EXPLOSION_THRESHOLD_MEDIUM to INFINITY)
deconstruct(FALSE)
return
- else
- return
/obj/structure/reagent_dispensers/attack_hand()
if(!reagents || reagents.locked)
diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm
index 87e713ad0af8..011fa2a17f48 100644
--- a/code/game/objects/structures/safe.dm
+++ b/code/game/objects/structures/safe.dm
@@ -222,3 +222,28 @@ FLOOR SAFES
/obj/structure/safe/floor/hide(intact)
invisibility = intact ? 101 : 0
+
+//almayer
+
+/obj/structure/safe/co_office
+
+/obj/structure/safe/co_office/Initialize()
+ . = ..()
+ new /obj/item/clothing/glasses/monocle(src)
+ new /obj/item/book/codebook(src)
+ new /obj/item/coin/silver/falcon(src)
+ new /obj/item/weapon/telebaton(src)
+ new /obj/item/moneybag(src)
+
+/obj/structure/safe/cl_office
+
+/obj/structure/safe/cl_office/Initialize()
+ . = ..()
+ new /obj/item/clothing/suit/armor/bulletproof(src)
+ new /obj/item/weapon/gun/pistol/es4(src)
+ new /obj/item/ammo_magazine/pistol/es4(src)
+ new /obj/item/ammo_magazine/pistol/es4(src)
+ new /obj/item/clothing/accessory/storage/holster(src)
+ new /obj/item/spacecash/c1000/counterfeit(src)
+ new /obj/item/spacecash/c1000/counterfeit(src)
+ new /obj/item/coin/platinum(src)
diff --git a/code/game/objects/structures/signs.dm b/code/game/objects/structures/signs.dm
index fbd6920875ad..adabf0c54141 100644
--- a/code/game/objects/structures/signs.dm
+++ b/code/game/objects/structures/signs.dm
@@ -17,6 +17,7 @@
S.desc = desc
S.icon_state = icon_state
S.sign_state = icon_state
+ S.icon = icon
deconstruct(FALSE)
else ..()
@@ -45,6 +46,7 @@
S.name = name
S.desc = desc
S.icon_state = sign_state
+ S.icon = icon
to_chat(user, "You fasten \the [S] with your [tool].")
qdel(src)
else ..()
@@ -568,7 +570,7 @@
/obj/structure/sign/ROsign
name = "\improper USCM Requisitions Office Guidelines"
- desc = " 1. You are not entitled to service or equipment. Attachments are a privilege, not a right.\n 2. You must be fully dressed to obtain service. Cyrosleep underwear is non-permissible.\n 3. The Requsitions Officer has the final say and the right to decline service. Only the Acting Commanding Officer may override their decisions.\n 4. Please treat your Requsitions staff with respect. They work hard."
+ desc = " 1. You are not entitled to service or equipment. Attachments are a privilege, not a right.\n 2. You must be fully dressed to obtain service. Cryosleep underwear is non-permissible.\n 3. The Quartermaster has the final say and the right to decline service. Only the Acting Commanding Officer may override their decisions.\n 4. Please treat your Requsitions staff with respect. They work hard."
icon_state = "roplaque"
/obj/structure/sign/prop1
@@ -592,9 +594,3 @@
desc = "An unbelievably creepy cat clock that surveys the room with every tick and every tock."
icon = 'icons/obj/structures/props/catclock.dmi'
icon_state = "cat_clock_motion"
-
-/obj/structure/sign/dartboard
- name = "dartboard"
- desc = "A dartboard, secured with a nail and a string. It has bullet holes and knife stab marks over and around it."
- icon = 'icons/obj/structures/props/props.dmi'
- icon_state = "dart_board"
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 7979994915f4..ee2c2bcee882 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/bed.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/bed.dm
@@ -13,7 +13,7 @@
icon_state = "bed"
icon = 'icons/obj/objects.dmi'
can_buckle = TRUE
- buckle_lying = TRUE
+ buckle_lying = 90
throwpass = TRUE
debris = list(/obj/item/stack/sheet/metal)
var/buildstacktype = /obj/item/stack/sheet/metal
@@ -310,7 +310,7 @@
//////////////////////////////////////////////
//List of all activated medevac stretchers
-var/global/list/activated_medevac_stretchers = list()
+GLOBAL_LIST_EMPTY(activated_medevac_stretchers)
/obj/structure/bed/medevac_stretcher
name = "medevac stretcher"
@@ -322,13 +322,14 @@ var/global/list/activated_medevac_stretchers = list()
base_bed_icon = "stretcher"
accepts_bodybag = TRUE
var/stretcher_activated
+ var/view_range = 5
var/obj/structure/dropship_equipment/medevac_system/linked_medevac
surgery_duration_multiplier = SURGERY_SURFACE_MULT_AWFUL //On the one hand, it's a big stretcher. On the other hand, you have a big sheet covering the patient and those damned Fulton hookups everywhere.
/obj/structure/bed/medevac_stretcher/Destroy()
if(stretcher_activated)
stretcher_activated = FALSE
- activated_medevac_stretchers -= src
+ GLOB.activated_medevac_stretchers -= src
if(linked_medevac)
linked_medevac.linked_stretcher = null
linked_medevac = null
@@ -352,6 +353,14 @@ var/global/list/activated_medevac_stretchers = list()
toggle_medevac_beacon(usr)
+// Used to pretend to be a camera
+/obj/structure/bed/medevac_stretcher/proc/can_use()
+ return TRUE
+
+// Used to pretend to be a camera
+/obj/structure/bed/medevac_stretcher/proc/isXRay()
+ return FALSE
+
/obj/structure/bed/medevac_stretcher/proc/toggle_medevac_beacon(mob/user)
if(!ishuman(user))
return
@@ -366,7 +375,7 @@ var/global/list/activated_medevac_stretchers = list()
if(stretcher_activated)
stretcher_activated = FALSE
- activated_medevac_stretchers -= src
+ GLOB.activated_medevac_stretchers -= src
if(linked_medevac)
linked_medevac.linked_stretcher = null
linked_medevac = null
@@ -384,7 +393,7 @@ var/global/list/activated_medevac_stretchers = list()
return
stretcher_activated = TRUE
- activated_medevac_stretchers += src
+ GLOB.activated_medevac_stretchers += src
to_chat(user, SPAN_NOTICE("You activate [src]'s beacon."))
update_icon()
@@ -404,7 +413,17 @@ var/global/list/activated_medevac_stretchers = list()
//bedroll
/obj/structure/bed/bedroll
- name = "bedroll"
- desc = "bedroll"
+ name = "unfolded bedroll"
+ desc = "Perfect for those long missions, when there's nowhere else to sleep, you remembered to bring at least one thing of comfort."
+ icon = 'icons/monkey_icos.dmi'
icon_state = "bedroll_o"
+ buckling_y = 0
+ foldabletype = /obj/item/roller/bedroll
+ accepts_bodybag = FALSE
+
+/obj/item/roller/bedroll
+ name = "folded bedroll"
+ desc = "A standard issue USCMC bedroll, They've been in service for as long as you can remember. The tag on it states to unfold it before rest, but who needs rules anyway, right?"
icon = 'icons/monkey_icos.dmi'
+ icon_state = "bedroll"
+ rollertype = /obj/structure/bed/bedroll
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 4186ae8608a9..e523906f4cfe 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/chairs.dm
@@ -6,7 +6,7 @@
name = "chair"
desc = "A rectangular metallic frame sitting on four legs with a back panel. Designed to fit the sitting position, more or less comfortably."
icon_state = "chair"
- buckle_lying = FALSE
+ buckle_lying = 0
var/propelled = FALSE //Check for fire-extinguisher-driven chairs
var/can_rotate = TRUE
var/picked_up_item = /obj/item/weapon/twohanded/folded_metal_chair
diff --git a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm
index 2b42e641f0cf..986ae99739aa 100644
--- a/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm
+++ b/code/game/objects/structures/stool_bed_chair_nest/wheelchair.dm
@@ -20,7 +20,7 @@
if(world.time <= l_move_time + move_delay)
return
// Redundant check?
- if(user.is_mob_incapacitated() || user.lying)
+ if(user.is_mob_incapacitated())
return
if(propelled) //can't manually move it mid-propelling.
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 7a4274c2c16e..63681d948620 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
@@ -10,7 +10,7 @@
health = 100
layer = ABOVE_MOB_LAYER
plane = GAME_PLANE
- buckle_lying = FALSE
+ buckle_lying = 0
var/on_fire = 0
var/resisting = 0
var/resisting_ready = 0
@@ -53,7 +53,7 @@
current_mob.pixel_y = buckling_y["[dir]"]
current_mob.pixel_x = buckling_x["[dir]"]
current_mob.dir = turn(dir, 180)
- current_mob.density = FALSE
+ ADD_TRAIT(current_mob, TRAIT_UNDENSE, XENO_NEST_TRAIT)
pixel_y = buckling_y["[dir]"]
pixel_x = buckling_x["[dir]"]
if(dir == SOUTH)
@@ -67,7 +67,7 @@
current_mob.pixel_y = initial(buckled_mob.pixel_y)
current_mob.pixel_x = initial(buckled_mob.pixel_x)
- current_mob.density = !(current_mob.lying || current_mob.stat == DEAD)
+ REMOVE_TRAIT(current_mob, TRAIT_UNDENSE, XENO_NEST_TRAIT)
if(dir == SOUTH)
current_mob.layer = initial(current_mob.layer)
if(!ishuman(current_mob))
@@ -98,7 +98,7 @@
if(iscarbon(user))
var/mob/living/carbon/carbon = user
if(HIVE_ALLIED_TO_HIVE(carbon.hivenumber, hivenumber))
- to_chat(user, SPAN_XENOWARNING("You shouldn't interfere with the nest, leave that to the drones."))
+ to_chat(user, SPAN_XENOWARNING("We shouldn't interfere with the nest, leave that to the drones."))
return
if(buckled_mob)
if(iswelder(W))
@@ -145,18 +145,18 @@
if(!(buckled_mob && buckled_mob.buckled == src && buckled_mob != user))
return
- if(user.stat || user.lying || user.is_mob_restrained())
+ if(user.body_position == LYING_DOWN || user.is_mob_incapacitated())
return
if(isxeno(user))
var/mob/living/carbon/xenomorph/X = user
if(!X.hive.unnesting_allowed && !isxeno_builder(X) && HIVE_ALLIED_TO_HIVE(X.hivenumber, hivenumber))
- to_chat(X, SPAN_XENOWARNING("You shouldn't interfere with the nest, leave that to the drones."))
+ to_chat(X, SPAN_XENOWARNING("We shouldn't interfere with the nest, leave that to the drones."))
return
else if(iscarbon(user))
var/mob/living/carbon/H = user
if(HIVE_ALLIED_TO_HIVE(H.hivenumber, hivenumber))
- to_chat(H, SPAN_XENOWARNING("You shouldn't interfere with the nest, leave that to the drones."))
+ to_chat(H, SPAN_XENOWARNING("We shouldn't interfere with the nest, leave that to the drones."))
return
if(ishuman(buckled_mob) && isxeno(user))
@@ -165,9 +165,9 @@
to_chat(user, SPAN_WARNING("[H] was nested recently. Wait a bit."))
return
if(H.stat != DEAD)
- if(alert(user, "[H] is still alive and kicking! Are you sure you want to remove them from the nest?", "Confirmation", "Yes", "No") != "Yes")
+ if(alert(user, "[H] is still alive and kicking! Are we sure we want to remove them from the nest?", "Confirmation", "Yes", "No") != "Yes")
return
- if(!buckled_mob || !user.Adjacent(H) || user.stat || user.lying || user.is_mob_restrained())
+ if(!buckled_mob || !user.Adjacent(H) || user.is_mob_incapacitated(FALSE))
return
if(ishuman(user))
@@ -191,11 +191,11 @@
/obj/structure/bed/nest/buckle_mob(mob/mob, mob/user)
. = FALSE
- if(!isliving(mob) || islarva(user) || (get_dist(src, user) > 1) || user.is_mob_restrained() || user.stat || user.lying || mob.buckled || !iscarbon(user))
+ if(!isliving(mob) || islarva(user) || (get_dist(src, user) > 1) || user.is_mob_incapacitated(FALSE))
return
if(isxeno(mob))
- to_chat(user, SPAN_WARNING("You can't buckle your sisters."))
+ to_chat(user, SPAN_WARNING("We can't buckle our sisters."))
return
if(buckled_mob)
@@ -207,7 +207,7 @@
return
if(!isxeno(user) || issynth(mob))
- to_chat(user, SPAN_WARNING("Gross! You're not touching that stuff."))
+ to_chat(user, SPAN_WARNING("Gross! We're not touching that stuff."))
return
if(isyautja(mob) && !force_nest)
@@ -220,7 +220,7 @@
var/mob/living/carbon/human/human = null
if(ishuman(mob))
human = mob
- if(!human.lying) //Don't ask me why is has to be
+ if(human.body_position != LYING_DOWN) //Don't ask me why is has to be
to_chat(user, SPAN_WARNING("[mob] is resisting, ground them."))
return
@@ -242,7 +242,7 @@
return
if(human) //Improperly stunned Marines won't be nested
- if(!human.lying) //Don't ask me why is has to be
+ if(human.body_position != LYING_DOWN) //Don't ask me why is has to be
to_chat(user, SPAN_WARNING("[mob] is resisting, ground them."))
return
@@ -321,7 +321,7 @@
if(M.a_intent == INTENT_HARM && !buckled_mob) //can't slash nest with an occupant.
M.animation_attack_on(src)
M.visible_message(SPAN_DANGER("\The [M] claws at \the [src]!"), \
- SPAN_DANGER("You claw at \the [src]."))
+ SPAN_DANGER("We claw at \the [src]."))
playsound(loc, "alien_resin_break", 25)
health -= (M.melee_damage_upper + 25) //Beef up the damage a bit
healthcheck()
diff --git a/code/game/objects/structures/surface.dm b/code/game/objects/structures/surface.dm
index 3a2dbd3e8d5c..13a81af2dc3d 100644
--- a/code/game/objects/structures/surface.dm
+++ b/code/game/objects/structures/surface.dm
@@ -1,160 +1,20 @@
//Surface structures are structures that can have items placed on them
/obj/structure/surface
health = 100
- var/list/update_types = list(
- /obj/item/reagent_container/glass,
- /obj/item/storage,
- /obj/item/reagent_container/food/snacks
- )
- //add items there that behave like structures for whatever dumb reason
- var/list/blacklisted_item_types = list(
- /obj/item/device/radio/intercom,
- /obj/item/device/sentry_computer
- )
-/obj/structure/surface/Initialize()
- . = ..()
- return INITIALIZE_HINT_LATELOAD
-
-/obj/structure/surface/LateInitialize()
- attach_all()
- update_icon()
-
-/obj/structure/surface/Destroy()
- detach_all()
- . = ..()
-
-/obj/structure/surface/ex_act(severity, direction, datum/cause_data/cause_data)
- health -= severity
- if(health <= 0)
- var/location = get_turf(src)
- handle_debris(severity, direction)
- detach_all()
- for(var/obj/item/O in loc)
- O.explosion_throw(severity, direction)
- qdel(src)
- if(prob(66))
- create_shrapnel(location, rand(1,4), direction, , /datum/ammo/bullet/shrapnel/light, cause_data)
- return TRUE
-
-/obj/structure/surface/proc/attach_all()
- for(var/obj/item/O in loc)
- if(in_blacklist(O))
- continue
- attach_item(O, FALSE)
- draw_item_overlays()
-
-/obj/structure/surface/proc/in_blacklist(obj/item/O)
- for(var/allowed_type in blacklisted_item_types)
- if(istype(O, allowed_type))
- return TRUE
- return FALSE
-
-/obj/structure/surface/proc/attach_item(obj/item/O, update = TRUE)
- if(!O)
+/obj/structure/surface/attackby(obj/item/attacking_item, mob/user, click_data)
+ if(!user.drop_inv_item_to_loc(attacking_item, loc))
return
- if(O.luminosity) //it can't make light as an overlay
- return
- O.forceMove(src)
- RegisterSignal(O, COMSIG_ATOM_DECORATED, PROC_REF(decorate_update))
- if(update)
- draw_item_overlays()
-
-/obj/structure/surface/proc/detach_item(obj/item/O)
- O.pixel_x = initial(O.pixel_x)
- O.pixel_y = initial(O.pixel_y)
- UnregisterSignal(O, COMSIG_ATOM_DECORATED)
- draw_item_overlays()
- return
-
-/obj/structure/surface/proc/decorate_update(obj/item/O)
- SIGNAL_HANDLER
- draw_item_overlays()
-/obj/structure/surface/proc/detach_all()
- overlays.Cut()
- for(var/obj/item/O in contents)
- UnregisterSignal(O, COMSIG_ATOM_DECORATED)
- O.forceMove(loc)
+ auto_align(attacking_item, click_data)
+ user.next_move = world.time + 2
+ return TRUE
-/obj/structure/surface/proc/get_item(list/click_data)
- var/i = LAZYLEN(contents)
- if(!click_data)
- return
- if(i < 1)
- return FALSE
- for(i, i >= 1, i--)//starting from the end because that's where the topmost is
- var/obj/item/O = contents[i]
- var/bounds_x = text2num(click_data["icon-x"])-1 - O.pixel_x
- var/bounds_y = text2num(click_data["icon-y"])-1 - O.pixel_y
- if(bounds_x < 0 || bounds_y < 0)
- continue
- var/icon/I = icon(O.icon, O.icon_state)
- var/p = I.GetPixel(bounds_x, bounds_y)
- if(p)
- return O
- return FALSE
-
-/obj/structure/surface/proc/draw_item_overlays()
- overlays.Cut()
- for(var/obj/item/O in contents)
- var/image/I = image(O.icon)
- I.appearance = O.appearance
- I.appearance_flags |= RESET_COLOR
- I.overlays = O.overlays
- LAZYADD(overlays, I)
-
-/obj/structure/surface/clicked(mob/user, list/mods)
- if(mods["shift"] && !mods["middle"])
- var/obj/item/O = get_item(mods)
- if(!O)
- return ..()
- if(O.can_examine(user))
- O.examine(user)
- return TRUE
- ..()
-
-/obj/structure/surface/proc/try_to_open_container(mob/user, mods)
- if(!Adjacent(user))
- return
-
- if(ishuman(user) || isrobot(user))
- var/obj/item/O = get_item(mods)
- if(O && isstorage(O))
- var/obj/item/storage/S = O
- S.open(usr)
- return TRUE
-
-/obj/structure/surface/attack_hand(mob/user, click_data)
- . = ..()
- if(click_data && click_data["alt"])
- return
- var/obj/item/O = get_item(click_data)
- if(!O)
- return
- O.attack_hand(user)
- if(!LAZYISIN(contents, O))//in case attack_hand did not pick up the item
- detach_item(O)
-
-/obj/structure/surface/attackby(obj/item/W, mob/user, click_data)
- var/obj/item/O = get_item(click_data)
- if(!O || click_data["ctrl"])//holding the ctrl key will force it to place the object
- // Placing stuff on tables
- if(user.drop_inv_item_to_loc(W, loc))
- auto_align(W, click_data)
- user.next_move = world.time + 2
- return TRUE
- else if(!O.attackby(W, user))
- W.afterattack(O, user, TRUE)
- for(var/type in update_types)
- if(istype(O, type))
- draw_item_overlays()
-
-/obj/structure/surface/proc/auto_align(obj/item/W, click_data)
- if(!W.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy.
- W.pixel_x = rand(-W.randpixel, W.randpixel)
- W.pixel_y = rand(-W.randpixel, W.randpixel)
- W.pixel_z = 0
+/obj/structure/surface/proc/auto_align(obj/item/new_item, click_data)
+ if(!new_item.center_of_mass) // Clothing, material stacks, generally items with large sprites where exact placement would be unhandy.
+ new_item.pixel_x = rand(-new_item.randpixel, new_item.randpixel)
+ new_item.pixel_y = rand(-new_item.randpixel, new_item.randpixel)
+ new_item.pixel_z = 0
return
if(!click_data)
@@ -170,16 +30,8 @@
var/cell_x = Clamp(round(mouse_x/CELLSIZE), 0, CELLS-1) // Ranging from 0 to CELLS-1
var/cell_y = Clamp(round(mouse_y/CELLSIZE), 0, CELLS-1)
- var/list/center = cached_key_number_decode(W.center_of_mass)
-
- W.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"]
- W.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"]
- W.pixel_z = 0
-
- if(!(W.flags_item & NOTABLEMERGE))
- attach_item(W)
+ var/list/center = cached_key_number_decode(new_item.center_of_mass)
-/obj/structure/surface/MouseDrop(atom/over)
- . = ..()
- if(over == usr && usr && usr.client && usr.client.lmb_last_mousedown_mods)
- return try_to_open_container(usr, usr.client.lmb_last_mousedown_mods)
+ new_item.pixel_x = (CELLSIZE * (cell_x + 0.5)) - center["x"]
+ new_item.pixel_y = (CELLSIZE * (cell_y + 0.5)) - center["y"]
+ new_item.pixel_z = 0
diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm
index db3ce98339a3..2ed19485acc9 100644
--- a/code/game/objects/structures/tables_racks.dm
+++ b/code/game/objects/structures/tables_racks.dm
@@ -143,7 +143,7 @@
dir_sum += 128
var/table_type = 0 //stand_alone table
- if((dir_sum%16) in cardinal)
+ if((dir_sum%16) in GLOB.cardinals)
table_type = 1 //endtable
dir_sum %= 16
if((dir_sum%16) in list(3, 12))
@@ -274,19 +274,23 @@
var/mob/living/M = G.grabbed_thing
if(user.a_intent == INTENT_HARM)
if(user.grab_level > GRAB_AGGRESSIVE)
- if (prob(15)) M.apply_effect(5, WEAKEN)
+ if (prob(15))
+ M.KnockDown(5)
+ M.Stun(5)
M.apply_damage(8, def_zone = "head")
- user.visible_message(SPAN_DANGER("[user] slams [M]'s face against [src]!"),
- SPAN_DANGER("You slam [M]'s face against [src]!"))
+ user.visible_message(SPAN_DANGER("[user] slams [M]'s face against [src]!"),
+ SPAN_DANGER("You slam [M]'s face against [src]!"))
playsound(src.loc, 'sound/weapons/tablehit1.ogg', 25, 1)
else
to_chat(user, SPAN_WARNING("You need a better grip to do that!"))
return
else if(user.grab_level >= GRAB_AGGRESSIVE)
M.forceMove(loc)
- M.apply_effect(5, WEAKEN)
- user.visible_message(SPAN_DANGER("[user] throws [M] on [src]."),
- SPAN_DANGER("You throw [M] on [src]."))
+ M.KnockDown(5)
+ M.Stun(5)
+ playsound(loc, 'sound/weapons/thudswoosh.ogg', 25, 1, 7)
+ user.visible_message(SPAN_DANGER("[user] throws [M] on [src], stunning them!"),
+ SPAN_DANGER("You throw [M] on [src], stunning them!"))
return
if(HAS_TRAIT(W, TRAIT_TOOL_WRENCH) && !(user.a_intent == INTENT_HELP))
@@ -434,8 +438,6 @@
verbs -= /obj/structure/surface/table/verb/do_flip
verbs += /obj/structure/surface/table/proc/do_put
- detach_all()
-
var/list/targets = list(get_step(src, dir), get_step(src, turn(dir, 45)), get_step(src, turn(dir, -45)))
for(var/atom/movable/movable_on_table in get_turf(src))
if(!movable_on_table.anchored)
@@ -479,7 +481,6 @@
var/obj/structure/surface/table/T = locate() in get_step(src.loc,D)
if(T && T.flipped && T.dir == src.dir)
T.unflip()
- attach_all()
update_icon()
update_adjacent()
diff --git a/code/game/objects/structures/vulture_spotter.dm b/code/game/objects/structures/vulture_spotter.dm
index 50505ab239b8..d90a1ec1615a 100644
--- a/code/game/objects/structures/vulture_spotter.dm
+++ b/code/game/objects/structures/vulture_spotter.dm
@@ -78,7 +78,7 @@
try_scope(user)
-/obj/structure/vulture_spotter_tripod/on_set_interaction(mob/user)
+/obj/structure/vulture_spotter_tripod/on_set_interaction(mob/living/user)
var/obj/item/attachable/vulture_scope/scope = get_vulture_scope()
scope.spotter_spotting = TRUE
to_chat(scope.scope_user, SPAN_NOTICE("You notice that [scope] drifts less."))
@@ -92,7 +92,7 @@
user.lighting_alpha = 127
user.sync_lighting_plane_alpha()
user.overlay_fullscreen("vulture_spotter", /atom/movable/screen/fullscreen/vulture/spotter)
- user.freeze()
+ ADD_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Vulture spotter"))
user.status_flags |= IMMOBILE_ACTION
user.visible_message(SPAN_NOTICE("[user] looks through [src]."),SPAN_NOTICE("You look through [src], ready to go!"))
user.forceMove(loc)
@@ -102,13 +102,13 @@
give_action(user, /datum/action/vulture_tripod_unscope, null, null, src)
set_scope_loc(user, scope)
-/obj/structure/vulture_spotter_tripod/on_unset_interaction(mob/user)
+/obj/structure/vulture_spotter_tripod/on_unset_interaction(mob/living/user)
user.status_flags &= ~IMMOBILE_ACTION
user.visible_message(SPAN_NOTICE("[user] looks up from [src]."),SPAN_NOTICE("You look up from [src]."))
- user.unfreeze()
+ REMOVE_TRAIT(user, TRAIT_IMMOBILIZED, TRAIT_SOURCE_ABILITY("Vulture spotter"))
user.reset_view(null)
user.Move(get_step(src, reverse_direction(src.dir)))
- user.client?.change_view(world_view_size, src)
+ user.client?.change_view(GLOB.world_view_size, src)
user.setDir(dir) //set the direction of the player to the direction the gun is facing
update_pixels(FALSE)
remove_action(user, /datum/action/vulture_tripod_unscope)
@@ -238,7 +238,7 @@
user.pixel_x = 0
user.pixel_y = 0
if(user.client)
- user.client.change_view(world_view_size, src)
+ user.client.change_view(GLOB.world_view_size, src)
user.client.pixel_x = 0
user.client.pixel_y = 0
UnregisterSignal(user.client, COMSIG_PARENT_QDELETING)
diff --git a/code/game/objects/structures/watercloset.dm b/code/game/objects/structures/watercloset.dm
index cccc1211bfb0..daf4a47a8ef6 100644
--- a/code/game/objects/structures/watercloset.dm
+++ b/code/game/objects/structures/watercloset.dm
@@ -8,6 +8,7 @@
density = FALSE
anchored = TRUE
can_buckle = TRUE
+ buckle_lying = 0
var/open = 0 //if the lid is up
var/cistern = 0 //if the cistern bit is open
var/w_items = 0 //the combined w_class of all the items in the cistern
@@ -150,7 +151,7 @@
GM.apply_damage(5, OXY)
swirlie = null
else
- user.visible_message(SPAN_DANGER("[user] slams [GM.name] into the [src]!"), SPAN_NOTICE("You slam [GM.name] into the [src]!"))
+ user.visible_message(SPAN_DANGER("[user] slams [GM.name] into [src]!"), SPAN_NOTICE("You slam [GM.name] into [src]!"))
GM.apply_damage(8, BRUTE)
else
to_chat(user, SPAN_NOTICE("You need a tighter grip."))
@@ -188,7 +189,7 @@
if(!GM.loc == get_turf(src))
to_chat(user, SPAN_NOTICE("[GM.name] needs to be on the urinal."))
return
- user.visible_message(SPAN_DANGER("[user] slams [GM.name] into the [src]!"), SPAN_NOTICE("You slam [GM.name] into the [src]!"))
+ user.visible_message(SPAN_DANGER("[user] slams [GM.name] into [src]!"), SPAN_NOTICE("You slam [GM.name] into [src]!"))
GM.apply_damage(8, BRUTE)
else
to_chat(user, SPAN_NOTICE("You need a tighter grip."))
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index d0651eb5e993..6ab70b8266f4 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -81,7 +81,7 @@
junction = 0
if(anchored)
var/turf/TU
- for(var/dirn in cardinal)
+ for(var/dirn in GLOB.cardinals)
TU = get_step(src, dirn)
var/obj/structure/window/W = locate() in TU
if(W && W.anchored && W.density && W.legacy_full) //Only counts anchored, non-destroyed, legacy full-tile windows.
@@ -353,7 +353,7 @@
//This proc is used to update the icons of nearby windows.
/obj/structure/window/proc/update_nearby_icons()
update_icon()
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
for(var/obj/structure/window/W in get_step(src, direction))
W.update_icon()
@@ -455,11 +455,8 @@
/obj/structure/window/reinforced/ultra/Initialize()
. = ..()
- GLOB.hijack_bustable_windows += src
-
-/obj/structure/window/reinforced/ultra/Destroy()
- GLOB.hijack_bustable_windows -= src
- return ..()
+ if(is_mainship_level(z))
+ RegisterSignal(SSdcs, COMSIG_GLOB_HIJACK_IMPACTED, PROC_REF(deconstruct))
/obj/structure/window/reinforced/full
flags_atom = FPRINT
@@ -585,11 +582,9 @@
/obj/structure/window/framed/almayer/hull/hijack_bustable/Initialize()
. = ..()
- GLOB.hijack_bustable_windows += src
+ if(is_mainship_level(z))
+ RegisterSignal(SSdcs, COMSIG_GLOB_HIJACK_IMPACTED, PROC_REF(deconstruct))
-/obj/structure/window/framed/almayer/hull/hijack_bustable/Destroy()
- GLOB.hijack_bustable_windows -= src
- return ..()
/obj/structure/window/framed/almayer/white
icon_state = "white_rwindow0"
basestate = "white_rwindow"
@@ -865,7 +860,7 @@
return
triggered = TRUE
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
if(direction == from_dir)
continue //doesn't check backwards
for(var/obj/structure/window/framed/prison/reinforced/hull/W in get_step(src,direction) )
@@ -958,7 +953,7 @@
return
triggered = 1
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
if(direction == from_dir)
continue //doesn't check backwards
diff --git a/code/game/runtimes.dm b/code/game/runtimes.dm
index 1332309168a3..2cdc955aa426 100644
--- a/code/game/runtimes.dm
+++ b/code/game/runtimes.dm
@@ -11,7 +11,6 @@
GLOBAL_REAL(stui_init_runtimes, /list) //! Shorthand of Static Initializer errors only, for use in STUI
GLOBAL_REAL(full_init_runtimes, /list) //! Full text of all Static Initializer + World Init errors, for log backfilling
GLOBAL_REAL_VAR(runtime_logging_ready) //! Truthy when init is done and we don't need these shenanigans anymore
-GLOBAL_REAL_VAR(init_runtimes_count) //! Count of runtimes that occured before logging is ready, for in-game reporting
// Deduplication of errors via hash to reduce spamming
GLOBAL_REAL(runtime_hashes, /list)
@@ -24,8 +23,6 @@ GLOBAL_REAL_VAR(total_runtimes)
if(!total_runtimes)
total_runtimes = 0
total_runtimes += 1
- if(!init_runtimes_count)
- init_runtimes_count = 0
if(!stui_init_runtimes)
stui_init_runtimes = list()
if(!full_init_runtimes)
@@ -33,7 +30,6 @@ GLOBAL_REAL_VAR(total_runtimes)
// If this occured during early init, we store the full error to write it to world.log when it's available
if(!runtime_logging_ready)
- init_runtimes_count += 1
full_init_runtimes += E.desc
// Runtime was already reported once, dedup it for STUI
diff --git a/code/game/sim_manager/datums/simulator.dm b/code/game/sim_manager/datums/simulator.dm
index 04ddb7faa088..1f1aedad8153 100644
--- a/code/game/sim_manager/datums/simulator.dm
+++ b/code/game/sim_manager/datums/simulator.dm
@@ -1,18 +1,21 @@
+#define GRID_CLEARING_SIZE 16
+
/datum/simulator
// Necessary to prevent multiple users from simulating at the same time.
var/static/detonation_cooldown = 0
+ var/static/detonation_cooldown_time = 2 MINUTES
var/static/sim_reboot_state = TRUE
- var/looking_at_simulation = FALSE
- var/detonation_cooldown_time = 2 MINUTES
var/dummy_mode = CLF_MODE
var/obj/structure/machinery/camera/simulation/sim_camera
- var/grid_clearing_size = 16
// garbage collection,
var/static/list/delete_targets = list()
+ // list of users currently inside the simulator
+ var/static/list/users_in_sim = list()
+
/*
unarmoured humans are unnencessary clutter as they tend to explode easily
and litter the sim room with body parts, best left out.
@@ -29,7 +32,7 @@
/datum/simulator/proc/start_watching(mob/living/user)
- if(looking_at_simulation)
+ if(user in users_in_sim)
to_chat(user, SPAN_WARNING("You are already looking at the simulation."))
return
if(!sim_camera)
@@ -37,17 +40,19 @@
if(!sim_camera)
to_chat(user, SPAN_WARNING("GPU damaged! Unable to start simulation."))
return
- if(user.client.view != world_view_size)
+ if(user.client.view != GLOB.world_view_size)
to_chat(user, SPAN_WARNING("You're too busy looking at something else."))
return
user.reset_view(sim_camera)
- looking_at_simulation = TRUE
+ users_in_sim += user
/datum/simulator/proc/stop_watching(mob/living/user)
+ if(!(user in users_in_sim))
+ return
user.unset_interaction()
user.reset_view(null)
user.cameraFollow = null
- looking_at_simulation = FALSE
+ users_in_sim -= user
/datum/simulator/proc/sim_turf_garbage_collection()
@@ -67,8 +72,8 @@
y:2 | x: 1 2 3 4 ... 16
y:1 | x: 1 2 3 4 ... 16
*/
- for (var/y_pos in 1 to grid_clearing_size)// outer y
- for (var/x_pos in 1 to grid_clearing_size) // inner x
+ for (var/y_pos in 1 to GRID_CLEARING_SIZE)// outer y
+ for (var/x_pos in 1 to GRID_CLEARING_SIZE) // inner x
var/turf/current_grid = locate(sim_grid_start_pos.x + x_pos,sim_grid_start_pos.y + y_pos,sim_grid_start_pos.z)
current_grid.empty(/turf/open/floor/engine)
@@ -101,3 +106,4 @@
addtimer(CALLBACK(src, PROC_REF(sim_turf_garbage_collection)), 30 SECONDS, TIMER_STOPPABLE)
+#undef GRID_CLEARING_SIZE
diff --git a/code/game/smoothwall.dm b/code/game/smoothwall.dm
index a06ed7750c26..b9284639976c 100644
--- a/code/game/smoothwall.dm
+++ b/code/game/smoothwall.dm
@@ -13,7 +13,7 @@
var/j //second iterator
var/k //third iterator (I know, that's a lot, but I'm trying to make this modular, so bear with me)
- for(i in cardinal) //For all cardinal dir turfs
+ for(i in GLOB.cardinals) //For all cardinal dir turfs
T = get_step(src, i)
if(!istype(T)) continue
for(j in tiles_with) //And for all types that we tile with
@@ -34,7 +34,7 @@
var/j //second iterator
var/atom/k //third iterator (I know, that's a lot, but I'm trying to make this modular, so bear with me)
- for(i in cardinal) //For all cardinal dir turfs
+ for(i in GLOB.cardinals) //For all cardinal dir turfs
T = get_step(src, i)
if(!istype(T)) continue
for(j in tiles_with) //And for all types that we tile with
@@ -61,7 +61,7 @@
var/j
var/k
- for(i in cardinal)
+ for(i in GLOB.cardinals)
T = get_step(src, i)
if(!istype(T)) continue
for(j in tiles_with)
@@ -93,7 +93,7 @@
var/j
var/k
- for(i in cardinal)
+ for(i in GLOB.cardinals)
T = get_step(src, i)
if(!istype(T)) continue
for(j in tiles_with)
@@ -170,6 +170,11 @@
setDir(NORTH)
/obj/structure/window/framed/handle_icon_junction(jun_1, jun_2)
+ if(!icon_exists(icon, "[basestate][jun_2 ? jun_2 : jun_1]")) //Missing states for 5, 6, 7, 9, 10, 11, 13, 14, 15 for the vast majority of /obj/structure/window/framed
+ icon_state = "[basestate]0"
+ junction = 0
+ return
+
icon_state = "[basestate][jun_2 ? jun_2 : jun_1]" //Use junction 2 if possible, junction 1 otherwise.
if(jun_2)
junction = jun_2
@@ -177,6 +182,11 @@
junction = jun_1
/obj/structure/window_frame/handle_icon_junction(jun_1, jun_2)
+ if(!icon_exists(icon, "[basestate][jun_2 ? jun_2 : jun_1]_frame")) //Missing states for 5, 6, 7, 9, 10, 11, 13, 14, 15 for the vast majority of /obj/structure/window_frame
+ icon_state = "[basestate]0_frame"
+ junction = 0
+ return
+
icon_state = "[basestate][jun_2 ? jun_2 : jun_1]_frame" //Use junction 2 if possible, junction 1 otherwise.
if(jun_2)
junction = jun_2
@@ -217,7 +227,7 @@
var/j //second iterator
var/k //third iterator (I know, that's a lot, but I'm trying to make this modular, so bear with me)
- for(i in alldirs) //For all cardinal dir turfs
+ for(i in GLOB.alldirs) //For all cardinal dir turfs
T = get_step(src, i)
if(!istype(T)) continue
for(j in tiles_with) //And for all types that we tile with
@@ -239,7 +249,7 @@
var/j //second iterator
var/k //third iterator (I know, that's a lot, but I'm trying to make this modular, so bear with me)
- for(i in alldirs) //For all cardinal dir turfs
+ for(i in GLOB.alldirs) //For all cardinal dir turfs
T = get_step(src, i)
if(!istype(T)) continue
for(j in tiles_with) //And for all types that we tile with
diff --git a/code/game/sound.dm b/code/game/sound.dm
index 6adaab109794..ac863a3bc51e 100644
--- a/code/game/sound.dm
+++ b/code/game/sound.dm
@@ -344,7 +344,7 @@
S = pick('sound/voice/alien_queen_command.ogg','sound/voice/alien_queen_command2.ogg','sound/voice/alien_queen_command3.ogg')
// Human
if("male_scream")
- S = pick('sound/voice/human_male_scream_1.ogg','sound/voice/human_male_scream_2.ogg','sound/voice/human_male_scream_3.ogg','sound/voice/human_male_scream_4.ogg',5;'sound/voice/human_male_scream_5.ogg',5;'sound/voice/human_jackson_scream.ogg',5;'sound/voice/human_ack_scream.ogg')
+ S = pick('sound/voice/human_male_scream_1.ogg','sound/voice/human_male_scream_2.ogg','sound/voice/human_male_scream_3.ogg','sound/voice/human_male_scream_4.ogg',5;'sound/voice/human_male_scream_5.ogg',5;'sound/voice/human_jackson_scream.ogg',5;'sound/voice/human_ack_scream.ogg','sound/voice/human_male_scream_6.ogg')
if("male_pain")
S = pick('sound/voice/human_male_pain_1.ogg','sound/voice/human_male_pain_2.ogg','sound/voice/human_male_pain_3.ogg',5;'sound/voice/tomscream.ogg',5;'sound/voice/human_bobby_pain.ogg',5;'sound/voice/human_tantrum_scream.ogg', 5;'sound/voice/human_male_pain_rare_1.ogg')
if("male_fragout")
diff --git a/code/game/supplyshuttle.dm b/code/game/supplyshuttle.dm
index 3d774cedc616..8214ee76d091 100644
--- a/code/game/supplyshuttle.dm
+++ b/code/game/supplyshuttle.dm
@@ -9,35 +9,33 @@
#define KILL_MENDOZA -1
GLOBAL_LIST_EMPTY_TYPED(asrs_empty_space_tiles_list, /turf/open/floor/almayer/empty)
+GLOBAL_SUBTYPE_PATHS_LIST_INDEXED(supply_packs_types, /datum/supply_packs, name)
+GLOBAL_REFERENCE_LIST_INDEXED_SORTED(supply_packs_datums, /datum/supply_packs, type)
-var/datum/controller/supply/supply_controller = new()
+GLOBAL_DATUM_INIT(supply_controller, /datum/controller/supply, new())
/area/supply
ceiling = CEILING_METAL
-/area/supply/station //DO NOT TURN THE lighting_use_dynamic STUFF ON FOR SHUTTLES. IT BREAKS THINGS.
+/area/supply/station
name = "Supply Shuttle"
icon_state = "shuttle3"
- base_lighting_alpha = 255
requires_power = 0
ambience_exterior = AMBIENCE_ALMAYER
-/area/supply/dock //DO NOT TURN THE lighting_use_dynamic STUFF ON FOR SHUTTLES. IT BREAKS THINGS.
+/area/supply/dock
name = "Supply Shuttle"
icon_state = "shuttle3"
- base_lighting_alpha = 255
requires_power = 0
-/area/supply/station_vehicle //DO NOT TURN THE lighting_use_dynamic STUFF ON FOR SHUTTLES. IT BREAKS THINGS.
+/area/supply/station_vehicle
name = "Vehicle ASRS"
icon_state = "shuttle3"
- base_lighting_alpha = 255
requires_power = 0
-/area/supply/dock_vehicle //DO NOT TURN THE lighting_use_dynamic STUFF ON FOR SHUTTLES. IT BREAKS THINGS.
+/area/supply/dock_vehicle
name = "Vehicle ASRS"
icon_state = "shuttle3"
- base_lighting_alpha = 255
requires_power = 0
//SUPPLY PACKS MOVED TO /code/defines/obj/supplypacks.dm
@@ -113,11 +111,11 @@ var/datum/controller/supply/supply_controller = new()
/obj/structure/machinery/computer/supplycomp/Initialize()
. = ..()
- LAZYADD(supply_controller.bound_supply_computer_list, src)
+ LAZYADD(GLOB.supply_controller.bound_supply_computer_list, src)
/obj/structure/machinery/computer/supplycomp/Destroy()
. = ..()
- LAZYREMOVE(supply_controller.bound_supply_computer_list, src)
+ LAZYREMOVE(GLOB.supply_controller.bound_supply_computer_list, src)
/obj/structure/machinery/computer/supplycomp/attackby(obj/item/hit_item, mob/user)
if(istype(hit_item, /obj/item/spacecash))
@@ -127,7 +125,7 @@ var/datum/controller/supply/supply_controller = new()
to_chat(user, SPAN_NOTICE("You find a small horizontal slot at the bottom of the console. You try to feed \the [slotted_cash] into it, but it rejects it! Maybe it's counterfeit?"))
return
to_chat(user, SPAN_NOTICE("You find a small horizontal slot at the bottom of the console. You feed \the [slotted_cash] into it.."))
- supply_controller.black_market_points += slotted_cash.worth
+ GLOB.supply_controller.black_market_points += slotted_cash.worth
qdel(slotted_cash)
else
to_chat(user, SPAN_NOTICE("You find a small horizontal slot at the bottom of the console. You try to feed \the [hit_item] into it, but it's seemingly blocked off from the inside."))
@@ -136,17 +134,17 @@ var/datum/controller/supply/supply_controller = new()
/obj/structure/machinery/computer/supplycomp/proc/toggle_contraband(contraband_enabled = FALSE)
can_order_contraband = contraband_enabled
- for(var/obj/structure/machinery/computer/supplycomp/computer as anything in supply_controller.bound_supply_computer_list)
+ for(var/obj/structure/machinery/computer/supplycomp/computer as anything in GLOB.supply_controller.bound_supply_computer_list)
if(computer.can_order_contraband)
- supply_controller.black_market_enabled = TRUE
+ GLOB.supply_controller.black_market_enabled = TRUE
return
- supply_controller.black_market_enabled = FALSE
+ GLOB.supply_controller.black_market_enabled = FALSE
//If any computers are able to order contraband, it's enabled. Otherwise, it's disabled!
/// Prevents use of black market, even if it is otherwise enabled. If any computer has black market locked out, it applies across all of the currently established ones.
/obj/structure/machinery/computer/supplycomp/proc/lock_black_market(market_locked = FALSE)
- for(var/obj/structure/machinery/computer/supplycomp/computer as anything in supply_controller.bound_supply_computer_list)
+ for(var/obj/structure/machinery/computer/supplycomp/computer as anything in GLOB.supply_controller.bound_supply_computer_list)
if(market_locked)
computer.black_market_lockout = TRUE
@@ -194,7 +192,7 @@ var/datum/controller/supply/supply_controller = new()
var/list/data = list()
var/list/squad_list = list()
- for(var/datum/squad/current_squad in RoleAuthority.squads)
+ for(var/datum/squad/current_squad in GLOB.RoleAuthority.squads)
if(current_squad.active && current_squad.faction == faction && current_squad.equipment_color)
squad_list += list(list(
"squad_name" = current_squad.name,
@@ -327,7 +325,7 @@ var/datum/controller/supply/supply_controller = new()
M.count_niche_stat(STATISTICS_NICHE_CRATES)
playsound(C.loc,'sound/effects/bamf.ogg', 50, 1) //Ehh
- var/obj/structure/droppod/supply/pod = new()
+ var/obj/structure/droppod/supply/pod = new(null, C)
C.forceMove(pod)
pod.launch(T)
visible_message("[icon2html(src, viewers(src))] [SPAN_BOLDNOTICE("'[C.name]' supply drop launched! Another launch will be available in five minutes.")]")
@@ -367,10 +365,12 @@ var/datum/controller/supply/supply_controller = new()
/datum/controller/supply
var/processing = 1
- var/processing_interval = 300
+ var/processing_interval = 30 SECONDS
var/iteration = 0
- //supply points
- var/points = 120
+ /// Current supply points
+ var/points = 0
+ /// Multiplier to the amount of points awarded based on marine scale
+ var/points_scale = 120
var/points_per_process = 1.5
var/points_per_slip = 1
var/points_per_crate = 2
@@ -389,15 +389,18 @@ var/datum/controller/supply/supply_controller = new()
/// If the players killed him by sending a live hostile below.. this goes false and they can't order any more contraband.
var/mendoza_status = TRUE
- var/base_random_crate_interval = 10 //Every how many processing intervals do we get a random crates.
+ /// How many processing intervals do we get random crates for each pool. Currently only [ASRS_POOL_MAIN] gets scaled amount of crates.
+ var/list/base_random_crate_intervals = list(ASRS_POOL_MAIN = 10, ASRS_POOL_FOOD = 60)
+ /// How many partial crates are stored in ASRS per pool to smooth amount given out
+ var/list/random_crates_carry = list()
+ /// Pools mapped to list of random ASRS packs that belong to it
+ var/list/asrs_supply_packs_by_pool
var/crate_iteration = 0
//control
var/ordernum
var/list/shoppinglist = list()
var/list/requestlist = list()
- var/list/supply_packs = list()
- var/list/random_supply_packs = list()
//shuttle movement
var/datum/shuttle/ferry/supply/shuttle
@@ -436,72 +439,91 @@ var/datum/controller/supply/supply_controller = new()
var/tank_points = 0
/datum/controller/supply/New()
+ . = ..()
ordernum = rand(1,9000)
LAZYINITLIST(black_market_sold_items)
+ asrs_supply_packs_by_pool = list()
+ for(var/subtype in subtypesof(/datum/supply_packs_asrs))
+ var/datum/supply_packs_asrs/initial_datum = subtype
+ var/pool = initial(initial_datum.pool)
+ if(!pool)
+ continue
+ LAZYADD(asrs_supply_packs_by_pool[pool], new subtype())
+ random_crates_carry = list()
+ for(var/pool in base_random_crate_intervals)
+ random_crates_carry[pool] = 0
+
+/datum/controller/supply/proc/start_processing()
+ START_PROCESSING(SSslowobj, src)
//Supply shuttle ticker - handles supply point regenertion and shuttle travelling between centcomm and the station
-/datum/controller/supply/process()
- for(var/typepath in subtypesof(/datum/supply_packs))
- var/datum/supply_packs/supply_pack = new typepath()
- if(supply_pack.group == "ASRS")
- random_supply_packs += supply_pack
- else
- supply_packs[supply_pack.name] = supply_pack
- spawn(0)
- set background = 1
- while(1)
- if(processing)
- iteration++
- points += points_per_process
- if(iteration >= 20 && iteration % base_random_crate_interval == 0 && supply_controller.shoppinglist.len <= 20)
- add_random_crates()
- crate_iteration++
- sleep(processing_interval)
+/datum/controller/supply/process(delta_time)
+ iteration++
+ points += points_per_process
+ if(iteration < 20)
+ return
+ for(var/pool in base_random_crate_intervals)
+ var/interval = base_random_crate_intervals[pool]
+ if(interval && iteration % interval == 0 && shoppinglist.len <= 20)
+ add_random_crates(pool)
+ crate_iteration++
//This adds function adds the amount of crates that calculate_crate_amount returns
-/datum/controller/supply/proc/add_random_crates()
- for(var/I=0, I= 1)
+ var/additional_crates = round(total_carry)
+ random_crates_carry[pool] -= additional_crates
+ unit_crate_amount += additional_crates
+
+ return unit_crate_amount
//Here we pick what crate type to send to the marines.
//This is a weighted pick based upon their cost.
//Their cost will go up if the crate is picked
-/datum/controller/supply/proc/add_random_crate()
- var/datum/supply_packs/C = supply_controller.pick_weighted_crate(random_supply_packs)
- if(C == null)
+/datum/controller/supply/proc/add_random_crate(pool)
+ if(!asrs_supply_packs_by_pool[pool])
+ return
+ var/datum/supply_packs_asrs/supply_info = pick_weighted_crate(asrs_supply_packs_by_pool[pool])
+ if(!GLOB.supply_packs_datums[supply_info.reference_package])
return
- C.cost = round(C.cost * ASRS_COST_MULTIPLIER) //We still do this to raise the weight
+
+ supply_info.cost = round(supply_info.cost * ASRS_COST_MULTIPLIER) //We still do this to raise the weight
//We have to create a supply order to make the system spawn it. Here we transform a crate into an order.
var/datum/supply_order/supply_order = new /datum/supply_order()
- supply_order.ordernum = supply_controller.ordernum
- supply_order.object = C
+ supply_order.ordernum = ordernum++
+ supply_order.object = GLOB.supply_packs_datums[supply_info.reference_package]
supply_order.orderedby = "ASRS"
supply_order.approvedby = "ASRS"
//We add the order to the shopping list
- supply_controller.shoppinglist += supply_order
+ shoppinglist += supply_order
//Here we weigh the crate based upon it's cost
-/datum/controller/supply/proc/pick_weighted_crate(list/cratelist)
- var/weighted_crate_list[]
- for(var/datum/supply_packs/crate in cratelist)
- var/crate_to_add[0]
+/datum/controller/supply/proc/pick_weighted_crate(list/datum/supply_packs_asrs/cratelist)
+ var/list/datum/supply_packs_asrs/weighted_crate_list = list()
+ for(var/datum/supply_packs_asrs/crate in cratelist)
var/weight = (round(10000/crate.cost))
- if(iteration > crate.iteration_needed)
- crate_to_add[crate] = weight
- weighted_crate_list += crate_to_add
+ weighted_crate_list[crate] = weight
return pickweight(weighted_crate_list)
//To stop things being sent to centcomm which should not be sent to centcomm. Recursively checks for these types.
@@ -590,8 +612,8 @@ var/datum/controller/supply/supply_controller = new()
if(order.object.contraband == TRUE && prob(5))
// Mendoza loaded the wrong order in. What a dunce!
var/list/contraband_list
- for(var/supply_name in supply_controller.supply_packs)
- var/datum/supply_packs/supply_pack = supply_controller.supply_packs[supply_name]
+ for(var/supply_type in GLOB.supply_packs_datums)
+ var/datum/supply_packs/supply_pack = GLOB.supply_packs_datums[supply_type]
if(supply_pack.contraband == FALSE)
continue
LAZYADD(contraband_list, supply_pack)
@@ -645,9 +667,12 @@ var/datum/controller/supply/supply_controller = new()
var/list/packages
-/obj/item/paper/manifest/read_paper(mob/user)
+/obj/item/paper/manifest/read_paper(mob/user, scramble = FALSE)
+ var/paper_info = info
+ if(scramble)
+ paper_info = stars_decode_html(info)
// Tossing ref in widow id as this allows us to read multiple manifests at same time
- show_browser(user, "[info][stamps]", null, "manifest\ref[src]", "size=550x650")
+ show_browser(user, "[paper_info][stamps]", null, "manifest\ref[src]", "size=550x650")
onclose(user, "manifest\ref[src]")
/obj/item/paper/manifest/proc/generate_contents()
@@ -711,10 +736,10 @@ var/datum/controller/supply/supply_controller = new()
if(temp)
dat = temp
else
- var/datum/shuttle/ferry/supply/shuttle = supply_controller.shuttle
+ var/datum/shuttle/ferry/supply/shuttle = GLOB.supply_controller.shuttle
if (shuttle)
dat += {"Location: [shuttle.has_arrive_time() ? "Raising platform":shuttle.at_station() ? "Raised":"Lowered"]
- Supply budget: $[supply_controller.points * SUPPLY_TO_MONEY_MUPLTIPLIER]
+ Supply budget: $[GLOB.supply_controller.points * SUPPLY_TO_MONEY_MUPLTIPLIER]
Unauthorized Access Removed. This console is currently under CMB investigation. Thank you for your cooperation.
"
return
temp += "KHZKNHZH#0-"
- if(!supply_controller.mendoza_status) // he's daed
+ if(!GLOB.supply_controller.mendoza_status) // he's daed
temp += "........."
return
handle_mendoza_dialogue() //mendoza has been in there for a while. he gets lonely sometimes
temp += "[last_viewed_group]
"
- for(var/supply_group_name in supply_controller.contraband_supply_groups)
+ for(var/supply_group_name in GLOB.supply_controller.contraband_supply_groups)
temp += "[supply_group_name] "
/obj/structure/machinery/computer/supplycomp/proc/handle_black_market_groups()
- temp = "W-Y Dollars: $[supply_controller.black_market_points] "
+ temp = "W-Y Dollars: $[GLOB.supply_controller.black_market_points] "
temp += "Back to black market categories
"
temp += "Purchase from: [last_viewed_group]
"
- for(var/supply_name in supply_controller.supply_packs )
- var/datum/supply_packs/supply_pack = supply_controller.supply_packs[supply_name]
+ for(var/supply_type in GLOB.supply_packs_datums)
+ var/datum/supply_packs/supply_pack = GLOB.supply_packs_datums[supply_type]
if(!is_buyable(supply_pack))
continue
- temp += "[supply_name] Cost: $[round(supply_pack.dollar_cost)] "
+ temp += "[supply_pack.name] Cost: $[round(supply_pack.dollar_cost)] "
/obj/structure/machinery/computer/supplycomp/proc/handle_mendoza_dialogue()
@@ -1186,7 +1214,7 @@ var/datum/controller/supply/supply_controller = new()
return_value = movable_atom.black_market_value
// so they cant sell the same thing over and over and over
- return_value = POSITIVE(return_value - supply_controller.black_market_sold_items[movable_atom.type] * 0.5)
+ return_value = POSITIVE(return_value - GLOB.supply_controller.black_market_sold_items[movable_atom.type] * 0.5)
return return_value
/datum/controller/supply/proc/kill_mendoza()
@@ -1252,7 +1280,7 @@ var/datum/controller/supply/supply_controller = new()
/datum/controller/supply/proc/black_market_investigation()
black_market_heat = -1
- SSticker.mode.get_specific_call("Inspection - Colonial Marshal Ledger Investigation Team", TRUE, TRUE, FALSE)
+ SSticker.mode.get_specific_call("Inspection - Colonial Marshal Ledger Investigation Team", TRUE, TRUE)
log_game("Black Market Inspection auto-triggered.")
/obj/structure/machinery/computer/supplycomp/proc/is_buyable(datum/supply_packs/supply_pack)
@@ -1316,6 +1344,14 @@ var/datum/controller/supply/supply_controller = new()
/datum/vehicle_order/tank/has_vehicle_lock()
return
+/datum/vehicle_order/tank/broken
+ name = "Smashed M34A2 Longstreet Light Tank"
+ ordered_vehicle = /obj/effect/vehicle_spawner/tank/hull/broken
+
+/datum/vehicle_order/tank/plain
+ name = "M34A2 Longstreet Light Tank"
+ ordered_vehicle = /obj/effect/vehicle_spawner/tank
+
/datum/vehicle_order/apc
name = "M577 Armored Personnel Carrier"
ordered_vehicle = /obj/effect/vehicle_spawner/apc/decrepit
@@ -1328,23 +1364,24 @@ var/datum/controller/supply/supply_controller = new()
name = "M577-CMD Armored Personnel Carrier"
ordered_vehicle = /obj/effect/vehicle_spawner/apc_cmd/decrepit
+/datum/vehicle_order/apc/empty
+ name = "Barebones M577 Armored Personal Carrier"
+ ordered_vehicle = /obj/effect/vehicle_spawner/apc/unarmed/broken
+
/obj/structure/machinery/computer/supplycomp/vehicle/Initialize()
. = ..()
vehicles = list(
- /datum/vehicle_order/apc,
- /datum/vehicle_order/apc/med,
- /datum/vehicle_order/apc/cmd,
+ new /datum/vehicle_order/apc(),
+ new /datum/vehicle_order/apc/med(),
+ new /datum/vehicle_order/apc/cmd(),
)
- for(var/order as anything in vehicles)
- new order
-
- if(!VehicleElevatorConsole)
- VehicleElevatorConsole = src
+ if(!GLOB.VehicleElevatorConsole)
+ GLOB.VehicleElevatorConsole = src
/obj/structure/machinery/computer/supplycomp/vehicle/Destroy()
- VehicleElevatorConsole = null
+ GLOB.VehicleElevatorConsole = null
return ..()
/obj/structure/machinery/computer/supplycomp/vehicle/attack_hand(mob/living/carbon/human/H as mob)
@@ -1400,15 +1437,16 @@ var/datum/controller/supply/supply_controller = new()
return
if(spent)
return
- if(!supply_controller)
- world.log << "## ERROR: Eek. The supply_controller controller datum is missing somehow."
+ if(!GLOB.supply_controller)
+ world.log << "## ERROR: Eek. The GLOB.supply_controller controller datum is missing somehow."
return
if (!SSshuttle.vehicle_elevator)
world.log << "## ERROR: Eek. The supply/elevator datum is missing somehow."
return
- if(!is_admin_level(SSshuttle.vehicle_elevator.z))
+ if(!should_block_game_interaction(SSshuttle.vehicle_elevator))
+ to_chat(usr, SPAN_WARNING("The elevator needs to be in the cargo bay dock to call a vehicle up. Ask someone to send it away."))
return
if(ismaintdrone(usr))
diff --git a/code/game/turfs/auto_turf.dm b/code/game/turfs/auto_turf.dm
index 45756c30bb9c..e07f7324bcc2 100644
--- a/code/game/turfs/auto_turf.dm
+++ b/code/game/turfs/auto_turf.dm
@@ -53,7 +53,7 @@
return
bleed_layer = max(0, new_layer)
- for(var/direction in alldirs)
+ for(var/direction in GLOB.alldirs)
var/turf/open/T = get_step(src, direction)
if(istype(T))
T.update_icon()
@@ -169,7 +169,7 @@
if(istype(I, /obj/item/lightstick))
var/obj/item/lightstick/L = I
if(locate(/obj/item/lightstick) in get_turf(src))
- to_chat(user, "There's already a [L] at this position!")
+ to_chat(user, "There's already \a [L] at this position!")
return
to_chat(user, "Now planting \the [L].")
diff --git a/code/game/turfs/floor.dm b/code/game/turfs/floor.dm
index 5f99aba26c09..1be6235cd2ac 100644
--- a/code/game/turfs/floor.dm
+++ b/code/game/turfs/floor.dm
@@ -69,7 +69,7 @@
..()
if(is_grass_floor())
var/dir_sum = 0
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
var/turf/T = get_step(src,direction)
if(!(T.is_grass_floor()))
dir_sum += direction
diff --git a/code/game/turfs/floor_types.dm b/code/game/turfs/floor_types.dm
index 4e47fd004f74..f957686fac22 100644
--- a/code/game/turfs/floor_types.dm
+++ b/code/game/turfs/floor_types.dm
@@ -203,6 +203,13 @@
icon_state = "default"
plating_type = /turf/open/floor/plating/almayer
+/// Admin level thunderdome floor. Doesn't get damaged by explosions and such for pristine testing
+/turf/open/floor/tdome
+ icon = 'icons/turf/almayer.dmi'
+ icon_state = "plating"
+ plating_type = /turf/open/floor/tdome
+ hull_floor = TRUE
+
//Cargo elevator
/turf/open/floor/almayer/empty
name = "empty space"
@@ -242,10 +249,10 @@
qdel(AM)
return
var/mob/living/carbon/human/thrown_human = AM
- for(var/atom/computer as anything in supply_controller.bound_supply_computer_list)
+ for(var/atom/computer as anything in GLOB.supply_controller.bound_supply_computer_list)
computer.balloon_alert_to_viewers("you hear horrifying noises coming from the elevator!")
- var/area/area_shuttle = supply_controller.shuttle?.get_location_area()
+ var/area/area_shuttle = GLOB.supply_controller.shuttle?.get_location_area()
if(!area_shuttle)
return
var/list/turflist = list()
@@ -452,7 +459,7 @@
/turf/open/floor/grass/LateInitialize()
. = ..()
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
if(istype(get_step(src,direction),/turf/open/floor))
var/turf/open/floor/FF = get_step(src,direction)
FF.update_icon() //so siding get updated properly
@@ -497,7 +504,7 @@
if(!broken && !burnt)
if(icon_state != "carpetsymbol")
var/connectdir = 0
- for(var/direction in cardinal)
+ for(var/direction in GLOB.cardinals)
if(istype(get_step(src, direction), /turf/open/floor))
var/turf/open/floor/FF = get_step(src, direction)
if(FF.is_carpet_floor())
@@ -538,7 +545,7 @@
icon_state = "carpet[connectdir]-[diagonalconnect]"
/turf/open/floor/carpet/make_plating()
- for(var/direction in alldirs)
+ for(var/direction in GLOB.alldirs)
if(istype(get_step(src, direction), /turf/open/floor))
var/turf/open/floor/FF = get_step(src,direction)
FF.update_icon() // So siding get updated properly
diff --git a/code/game/turfs/light.dm b/code/game/turfs/light.dm
index 219e79e93ef2..e8b7038bcb51 100644
--- a/code/game/turfs/light.dm
+++ b/code/game/turfs/light.dm
@@ -1,9 +1,21 @@
+#define LIGHT_FLOOR_COLOR_BLUE 0
+#define LIGHT_FLOOR_COLOR_RED 1
+#define LIGHT_FLOOR_COLOR_GREEN 2
+#define LIGHT_FLOOR_COLOR_YELLOW 3
+#define LIGHT_FLOOR_COLOR_PURPLE 4
+#define LIGHT_FLOOR_COLOR_WHITE 5
+
/turf/open/floor/light
name = "light floor"
desc = "Beware of breakdancing on these tiles, glass shards embedded in the head is not a fun time."
+ icon_state = "light_on"
tile_type = /obj/item/stack/tile/light
var/on = TRUE
- var/state = 0
+ var/state = LIGHT_FLOOR_COLOR_BLUE
+
+/turf/open/floor/light/get_examine_text(mob/user)
+ . = ..()
+ . += "[src] is [broken ? "broken, and requires a replacement lightbulb":"[on ? "on" : "off"]"]."
/turf/open/floor/light/is_light_floor()
return TRUE
@@ -12,22 +24,22 @@
. = ..()
if(on && !broken) //manages color, I feel like this switch is a sin.
switch(state)
- if(0)
+ if(LIGHT_FLOOR_COLOR_BLUE)
icon_state = "light_on"
set_light(5)
- if(1)
+ if(LIGHT_FLOOR_COLOR_RED)
icon_state = "light_on-r"
set_light(5)
- if(2)
+ if(LIGHT_FLOOR_COLOR_GREEN)
icon_state = "light_on-g"
set_light(5)
- if(3)
+ if(LIGHT_FLOOR_COLOR_YELLOW)
icon_state = "light_on-y"
set_light(5)
- if(4)
+ if(LIGHT_FLOOR_COLOR_PURPLE)
icon_state = "light_on-p"
set_light(5)
- if(5,-1)
+ if(LIGHT_FLOOR_COLOR_WHITE,-1) //change this later
icon_state = "light_on-w"
set_light(5)
state = -1
@@ -84,3 +96,68 @@
broken = TRUE
update_icon()
return XENO_ATTACK_ACTION
+
+/turf/open/floor/light/red
+ icon_state = "light_on-r"
+ state = LIGHT_FLOOR_COLOR_RED
+
+/turf/open/floor/light/green
+ icon_state = "light_on-g"
+ state = LIGHT_FLOOR_COLOR_GREEN
+
+/turf/open/floor/light/yellow
+ icon_state = "light_on-y"
+ state = LIGHT_FLOOR_COLOR_YELLOW
+
+/turf/open/floor/light/purple
+ icon_state = "light_on-p"
+ state = LIGHT_FLOOR_COLOR_PURPLE
+
+/turf/open/floor/light/white
+ icon_state = "light_on-w"
+ state = LIGHT_FLOOR_COLOR_WHITE
+
+/turf/open/floor/light/off
+ icon_state = "light_off"
+ on = FALSE
+
+/turf/open/floor/light/off/red
+ state = LIGHT_FLOOR_COLOR_RED
+
+/turf/open/floor/light/off/green
+ state = LIGHT_FLOOR_COLOR_GREEN
+
+/turf/open/floor/light/off/yellow
+ state = LIGHT_FLOOR_COLOR_YELLOW
+
+/turf/open/floor/light/off/purple
+ state = LIGHT_FLOOR_COLOR_PURPLE
+
+/turf/open/floor/light/off/white
+ state = LIGHT_FLOOR_COLOR_WHITE
+
+/turf/open/floor/light/broken
+ icon_state = "light_broken"
+ broken = TRUE
+
+/turf/open/floor/light/broken/red
+ state = LIGHT_FLOOR_COLOR_RED
+
+/turf/open/floor/light/broken/green
+ state = LIGHT_FLOOR_COLOR_GREEN
+
+/turf/open/floor/light/broken/yellow
+ state = LIGHT_FLOOR_COLOR_YELLOW
+
+/turf/open/floor/light/broken/purple
+ state = LIGHT_FLOOR_COLOR_PURPLE
+
+/turf/open/floor/light/broken/white
+ state = LIGHT_FLOOR_COLOR_WHITE
+
+#undef LIGHT_FLOOR_COLOR_BLUE
+#undef LIGHT_FLOOR_COLOR_RED
+#undef LIGHT_FLOOR_COLOR_GREEN
+#undef LIGHT_FLOOR_COLOR_YELLOW
+#undef LIGHT_FLOOR_COLOR_PURPLE
+#undef LIGHT_FLOOR_COLOR_WHITE
diff --git a/code/game/turfs/open.dm b/code/game/turfs/open.dm
index a4781e1a6609..7d9dd6303c64 100644
--- a/code/game/turfs/open.dm
+++ b/code/game/turfs/open.dm
@@ -24,7 +24,7 @@
add_cleanable_overlays()
var/list/turf/open/auto_turf/auto_turf_dirs = list()
- for(var/direction in alldirs)
+ for(var/direction in GLOB.alldirs)
var/turf/open/auto_turf/T = get_step(src, direction)
if(!istype(T))
continue
@@ -36,7 +36,7 @@
var/list/handled_dirs = list()
var/list/unhandled_dirs = list()
- for(var/direction in diagonals)
+ for(var/direction in GLOB.diagonals)
var/x_dir = direction & (direction-1)
var/y_dir = direction - x_dir
@@ -90,7 +90,7 @@
if(!T.icon_state_before_scorching)
T.icon_state_before_scorching = T.icon_state
var/direction_from_neighbor_towards_src = get_dir(T, src)
- var/icon/culling_mask = icon(T.icon, "[T.scorchable]_mask[turf_edgeinfo_cache[T.icon_state_before_scorching][dir2indexnum(T.dir)][dir2indexnum(direction_from_neighbor_towards_src)]]", direction_from_neighbor_towards_src)
+ var/icon/culling_mask = icon(T.icon, "[T.scorchable]_mask[GLOB.turf_edgeinfo_cache[T.icon_state_before_scorching][dir2indexnum(T.dir)][dir2indexnum(direction_from_neighbor_towards_src)]]", direction_from_neighbor_towards_src)
edge_overlay.Blend(culling_mask, ICON_OVERLAY)
edge_overlay.SwapColor(rgb(255, 0, 255, 255), rgb(0, 0, 0, 0))
overlays += edge_overlay
@@ -185,6 +185,7 @@
name = "cave"
icon = 'icons/turf/floors/bigred.dmi'
icon_state = "mars_cave_1"
+ is_groundmap_turf = TRUE
/turf/open/mars_cave/Initialize(mapload, ...)
@@ -283,6 +284,7 @@
name = "ground dirt"
icon = 'icons/turf/ground_map.dmi'
icon_state = "desert"
+ is_groundmap_turf = TRUE
/turf/open/gm/attackby(obj/item/I, mob/user)
@@ -290,7 +292,7 @@
if(istype(I, /obj/item/lightstick))
var/obj/item/lightstick/L = I
if(locate(/obj/item/lightstick) in get_turf(src))
- to_chat(user, "There's already a [L] at this position!")
+ to_chat(user, "There's already \a [L] at this position!")
return
to_chat(user, "Now planting \the [L].")
@@ -368,16 +370,16 @@
/turf/open/gm/grass/Initialize(mapload, ...)
. = ..()
- if(!locate(icon_state) in turf_edgeinfo_cache)
+ if(!locate(icon_state) in GLOB.turf_edgeinfo_cache)
switch(icon_state)
if("grass1")
- turf_edgeinfo_cache["grass1"] = GLOB.edgeinfo_full
+ GLOB.turf_edgeinfo_cache["grass1"] = GLOB.edgeinfo_full
if("grass2")
- turf_edgeinfo_cache["grass2"] = GLOB.edgeinfo_full
+ GLOB.turf_edgeinfo_cache["grass2"] = GLOB.edgeinfo_full
if("grassbeach")
- turf_edgeinfo_cache["grassbeach"] = GLOB.edgeinfo_edge
+ GLOB.turf_edgeinfo_cache["grassbeach"] = GLOB.edgeinfo_edge
if("gbcorner")
- turf_edgeinfo_cache["gbcorner"] = GLOB.edgeinfo_corner
+ GLOB.turf_edgeinfo_cache["gbcorner"] = GLOB.edgeinfo_corner
/turf/open/gm/dirt2
name = "dirt"
@@ -433,14 +435,14 @@
/turf/open/gm/dirtgrassborder/Initialize(mapload, ...)
. = ..()
- if(!locate(icon_state) in turf_edgeinfo_cache)
+ if(!locate(icon_state) in GLOB.turf_edgeinfo_cache)
switch(icon_state)
if("grassdirt_edge")
- turf_edgeinfo_cache["grassdirt_edge"] = GLOB.edgeinfo_edge
+ GLOB.turf_edgeinfo_cache["grassdirt_edge"] = GLOB.edgeinfo_edge
if("grassdirt_corner")
- turf_edgeinfo_cache["grassdirt_corner"] = GLOB.edgeinfo_corner
+ GLOB.turf_edgeinfo_cache["grassdirt_corner"] = GLOB.edgeinfo_corner
if("grassdirt_corner2")
- turf_edgeinfo_cache["grassdirt_corner2"] = GLOB.edgeinfo_corner2
+ GLOB.turf_edgeinfo_cache["grassdirt_corner2"] = GLOB.edgeinfo_corner2
/turf/open/gm/dirtgrassborder2
name = "grass"
@@ -646,6 +648,7 @@
baseturfs = /turf/open/gm/riverdeep
supports_surgery = FALSE
minimap_color = MINIMAP_WATER
+ is_groundmap_turf = FALSE // Not real ground
/turf/open/gm/riverdeep/Initialize(mapload, ...)
@@ -724,6 +727,7 @@
allow_construction = FALSE
var/bushes_spawn = 1
var/plants_spawn = 1
+ is_groundmap_turf = TRUE
name = "wet grass"
desc = "Thick, long, wet grass."
icon = 'icons/turf/floors/jungle.dmi'
@@ -783,7 +787,7 @@
if(istype(I, /obj/item/lightstick))
var/obj/item/lightstick/L = I
if(locate(/obj/item/lightstick) in get_turf(src))
- to_chat(user, "There's already a [L] at this position!")
+ to_chat(user, "There's already \a [L] at this position!")
return
to_chat(user, "Now planting \the [L].")
diff --git a/code/game/turfs/snow.dm b/code/game/turfs/snow.dm
index 72b1f35d0aff..f7fb746cfbbc 100644
--- a/code/game/turfs/snow.dm
+++ b/code/game/turfs/snow.dm
@@ -16,7 +16,7 @@
if(istype(I, /obj/item/lightstick))
var/obj/item/lightstick/L = I
if(locate(/obj/item/lightstick) in get_turf(src))
- to_chat(user, "There's already a [L] at this position!")
+ to_chat(user, "There's already \a [L] at this position!")
return
to_chat(user, "Now planting \the [L].")
@@ -77,7 +77,7 @@
if(update_full)
var/turf/open/T
if(!skip_sides)
- for(var/dirn in alldirs)
+ for(var/dirn in GLOB.alldirs)
var/turf/open/snow/D = get_step(src,dirn)
if(istype(D))
//Update turfs that are near us, but only once
@@ -85,7 +85,7 @@
overlays.Cut()
- for(var/dirn in alldirs)
+ for(var/dirn in GLOB.alldirs)
T = get_step(src, dirn)
if(istype(T))
if(bleed_layer > T.bleed_layer && T.bleed_layer < 1)
@@ -148,6 +148,3 @@
/turf/open/snow/layer3
icon_state = "snow_3"
bleed_layer = 3
-
-
-
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 837610d5d7fe..22fe85bdde65 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -72,9 +72,8 @@
// by default, vis_contents is inherited from the turf that was here before
vis_contents.Cut()
- turfs += src
- if(is_ground_level(z))
- z1turfs += src
+ GLOB.turfs += src
+
assemble_baseturfs()
@@ -82,11 +81,11 @@
visibilityChanged()
- pass_flags = pass_flags_cache[type]
+ pass_flags = GLOB.pass_flags_cache[type]
if (isnull(pass_flags))
pass_flags = new()
initialize_pass_flags(pass_flags)
- pass_flags_cache[type] = pass_flags
+ GLOB.pass_flags_cache[type] = pass_flags
else
initialize_pass_flags()
diff --git a/code/game/turfs/walls/wall_icon.dm b/code/game/turfs/walls/wall_icon.dm
index 9e47612964c4..2b414ca46af8 100644
--- a/code/game/turfs/walls/wall_icon.dm
+++ b/code/game/turfs/walls/wall_icon.dm
@@ -86,7 +86,7 @@
break
if(success)
- if(get_dir(src, T) in cardinal)
+ if(get_dir(src, T) in GLOB.cardinals)
wall_dirs += get_dir(src, T)
for(var/neighbor in wall_dirs)
diff --git a/code/game/turfs/walls/wall_types.dm b/code/game/turfs/walls/wall_types.dm
index 2548801cc7b1..05c97a681be9 100644
--- a/code/game/turfs/walls/wall_types.dm
+++ b/code/game/turfs/walls/wall_types.dm
@@ -24,19 +24,27 @@
/obj/structure/girder,
/obj/structure/machinery/door,
/obj/structure/machinery/cm_vending/sorted/attachments/blend,
- /obj/structure/machinery/cm_vending/sorted/cargo_ammo/blend,
- /obj/structure/machinery/cm_vending/sorted/cargo_guns/blend,
+ /obj/structure/machinery/cm_vending/sorted/cargo_ammo/cargo/blend,
+ /obj/structure/machinery/cm_vending/sorted/cargo_guns/cargo/blend,
)
+ /// The type of wall decoration we use, to avoid the wall changing icon all the time
+ var/decoration_type
+
+/turf/closed/wall/almayer/Initialize(mapload, ...)
+ if(!special_icon && prob(20))
+ decoration_type = rand(0,3)
+ return ..()
+
/turf/closed/wall/almayer/update_icon()
- ..()
- if(special_icon)
- return
+ if(decoration_type == null)
+ return ..()
if(neighbors_list in list(EAST|WEST))
- var/r1 = rand(0,10) //Make a random chance for this to happen
- var/r2 = rand(0,3) // Which wall if we do choose it
- if(r1 >= 9)
- overlays += image(icon, icon_state = "almayer_deco_wall[r2]")
+ special_icon = TRUE
+ icon_state = "almayer_deco_wall[decoration_type]"
+ else // Wall connection was broken, return to normality
+ special_icon = FALSE
+ return ..()
/turf/closed/wall/almayer/take_damage(dam, mob/M)
var/damage_check = max(0, damage + dam)
@@ -51,6 +59,24 @@
damage_cap = HEALTH_WALL_REINFORCED
icon_state = "reinforced"
+/// Acts like /turf/closed/wall/almayer/outer until post-hijack where it reverts to /turf/closed/wall/almayer/reinforced.
+/turf/closed/wall/almayer/reinforced/temphull
+ name = "heavy reinforced hull"
+ desc = "A highly reinforced metal wall used to separate rooms and make up the ship. It would take a great impact to weaken this wall."
+ damage_cap = HEALTH_WALL_REINFORCED
+ icon_state = "temphull"
+ hull = TRUE
+
+/turf/closed/wall/almayer/reinforced/temphull/Initialize()
+ . = ..()
+ if(is_mainship_level(z))
+ RegisterSignal(SSdcs, COMSIG_GLOB_HIJACK_IMPACTED, PROC_REF(de_hull))
+
+/turf/closed/wall/almayer/reinforced/temphull/proc/de_hull()
+ SIGNAL_HANDLER
+ hull = FALSE
+ desc = "A highly reinforced metal wall used to separate rooms and make up the ship. It has been weakened by a great impact."
+
/turf/closed/wall/almayer/outer
name = "outer hull"
desc = "A metal wall used to separate space from the ship"
@@ -255,15 +281,15 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen)
tag = "LOBBYART"
/proc/force_lobby_art(art_id)
- displayed_lobby_art = art_id
+ GLOB.displayed_lobby_art = art_id
var/turf/closed/wall/indestructible/splashscreen/SS = locate("LOBBYART")
var/list/lobby_arts = CONFIG_GET(str_list/lobby_art_images)
var/list/lobby_authors = CONFIG_GET(str_list/lobby_art_authors)
- SS.icon_state = lobby_arts[displayed_lobby_art]
- SS.desc = "Artwork by [lobby_authors[displayed_lobby_art]]"
+ SS.icon_state = lobby_arts[GLOB.displayed_lobby_art]
+ SS.desc = "Artwork by [lobby_authors[GLOB.displayed_lobby_art]]"
for(var/client/C in GLOB.clients)
- if(displayed_lobby_art != -1)
- var/author = lobby_authors[displayed_lobby_art]
+ if(GLOB.displayed_lobby_art != -1)
+ var/author = lobby_authors[GLOB.displayed_lobby_art]
if(author != "Unknown")
to_chat_forced(C, SPAN_ROUNDBODY("This round's lobby art is brought to you by [author]"))
@@ -814,7 +840,7 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen)
var/datum/movable_wall_group/MWG = new()
MWG.add_structure(current)
- for(var/dir in cardinal)
+ for(var/dir in GLOB.cardinals)
connected = locate() in get_step(current, dir)
if(connected in current_walls)
if(connected.group == src)
@@ -949,7 +975,7 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen)
/obj/structure/alien/movable_wall/proc/update_connections(propagate = FALSE)
var/list/wall_dirs = list()
- for(var/dir in alldirs)
+ for(var/dir in GLOB.alldirs)
var/obj/structure/alien/movable_wall/MW = locate() in get_step(src, dir)
if(!(MW in group.walls))
continue
@@ -1003,7 +1029,7 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen)
/obj/structure/alien/movable_wall/proc/recalculate_structure()
var/list/found_structures = list()
var/current_walls = 0
- for(var/i in cardinal)
+ for(var/i in GLOB.cardinals)
var/turf/T = get_step(src, i)
var/obj/structure/alien/movable_wall/MW = locate() in T
if(!MW)
@@ -1060,7 +1086,7 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen)
return COMPONENT_TURF_ALLOW_MOVEMENT
/obj/structure/alien/movable_wall/Move(NewLoc, direct)
- if(!(direct in cardinal))
+ if(!(direct in GLOB.cardinals))
return
group.try_move_in_direction(direct)
@@ -1114,6 +1140,10 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen)
if(src in P.permutated)
return
+ //Ineffective if someone is sitting on the wall
+ if(locate(/mob) in contents)
+ return ..()
+
if(!prob(chance_to_reflect))
if(P.ammo.damage_type == BRUTE)
P.damage *= brute_multiplier
@@ -1189,7 +1219,7 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen)
M.animation_attack_on(src)
M.visible_message(SPAN_XENONOTICE("\The [M] claws \the [src]!"), \
- SPAN_XENONOTICE("You claw \the [src]."))
+ SPAN_XENONOTICE("We claw \the [src]."))
playsound(src, "alien_resin_break", 25)
if (M.hivenumber == hivenumber)
take_damage(Ceiling(HEALTH_WALL_XENO * 0.25)) //Four hits for a regular wall
@@ -1230,7 +1260,7 @@ INITIALIZE_IMMEDIATE(/turf/closed/wall/indestructible/splashscreen)
. = ..()
if(.)
var/turf/T
- for(var/i in cardinal)
+ for(var/i in GLOB.cardinals)
T = get_step(src, i)
if(!istype(T)) continue
for(var/obj/structure/mineral_door/resin/R in T)
diff --git a/code/game/turfs/walls/walls.dm b/code/game/turfs/walls/walls.dm
index 2387a2086192..77143384e7e7 100644
--- a/code/game/turfs/walls/walls.dm
+++ b/code/game/turfs/walls/walls.dm
@@ -73,7 +73,7 @@
. = ..()
if(.) //successful turf change
var/turf/T
- for(var/i in cardinal)
+ for(var/i in GLOB.cardinals)
T = get_step(src, i)
//nearby glowshrooms updated
@@ -88,7 +88,7 @@
if(istype(found_object, /obj/structure/sign/poster))
var/obj/structure/sign/poster/found_poster = found_object
found_poster.roll_and_drop(src)
- if(istype(found_object, /obj/effect/alien/weeds))
+ if(istype(found_object, /obj/effect/alien/weeds/weedwall))
qdel(found_object)
var/list/turf/cardinal_neighbors = list(get_step(src, NORTH), get_step(src, SOUTH), get_step(src, EAST), get_step(src, WEST))
@@ -170,6 +170,9 @@
if (acided_hole)
. += SPAN_WARNING("There's a large hole in the wall that could've been caused by some sort of acid.")
+ if(flags_turf & TURF_ORGANIC)
+ return // Skip the part below. 'Organic' walls aren't deconstructable with tools.
+
switch(d_state)
if(WALL_STATE_WELD)
. += SPAN_INFO("The outer plating is intact. A blowtorch should slice it open.")
diff --git a/code/game/verbs/discord.dm b/code/game/verbs/discord.dm
index 210038084caa..2446c89aafe5 100644
--- a/code/game/verbs/discord.dm
+++ b/code/game/verbs/discord.dm
@@ -29,7 +29,7 @@
var/datum/entity/discord_identifier/new_identifier = DB_ENTITY(/datum/entity/discord_identifier)
var/not_unique = TRUE
- var/long_list = operation_postfixes + operation_prefixes + operation_titles
+ var/long_list = GLOB.operation_postfixes + GLOB.operation_prefixes + GLOB.operation_titles
var/token
while(not_unique)
diff --git a/code/game/verbs/ooc.dm b/code/game/verbs/ooc.dm
index 3c964cf4011b..2fe22ef3d4da 100644
--- a/code/game/verbs/ooc.dm
+++ b/code/game/verbs/ooc.dm
@@ -15,10 +15,10 @@
return
if(!admin_holder || !(admin_holder.rights & R_MOD))
- if(!ooc_allowed) //Send to LOOC instead
+ if(!GLOB.ooc_allowed) //Send to LOOC instead
looc(msg)
return
- if(!dooc_allowed && (mob.stat == DEAD || isobserver(mob)))
+ if(!GLOB.dooc_allowed && (mob.stat == DEAD || isobserver(mob)))
to_chat(usr, SPAN_DANGER("OOC for dead mobs has been turned off."))
return
if(prefs.muted & MUTE_OOC)
@@ -108,10 +108,10 @@
return
if(!admin_holder || !(admin_holder.rights & R_MOD))
- if(!looc_allowed)
+ if(!GLOB.looc_allowed)
to_chat(src, SPAN_DANGER("LOOC is globally muted"))
return
- if(!dlooc_allowed && (mob.stat != CONSCIOUS || isobserver(mob)))
+ if(!GLOB.dlooc_allowed && (mob.stat != CONSCIOUS || isobserver(mob)))
to_chat(usr, SPAN_DANGER("Sorry, you cannot utilize LOOC while dead or incapacitated."))
return
if(prefs.muted & MUTE_OOC)
@@ -150,7 +150,7 @@
if(C.prefs.toggles_chat & CHAT_LOOC)
to_chat(C, "LOOC:[display_name]:[msg]")
- if(mob.looc_overhead || ooc_allowed)
+ if(mob.looc_overhead || GLOB.ooc_allowed)
var/transmit_language = isxeno(mob) ? LANGUAGE_XENOMORPH : LANGUAGE_ENGLISH
mob.langchat_speech(msg, heard, GLOB.all_languages[transmit_language], "#ff47d7")
diff --git a/code/game/verbs/records.dm b/code/game/verbs/records.dm
index f09de72da2e6..6b80d19bbabf 100644
--- a/code/game/verbs/records.dm
+++ b/code/game/verbs/records.dm
@@ -84,7 +84,7 @@
var/list/options = list()
if(CLIENT_IS_STAFF(src))
- options = note_categories.Copy()
+ options = GLOB.note_categories.Copy()
if(admin_holder.rights & R_PERMISSIONS)
MA = TRUE
else if(!isCouncil(src))
@@ -97,13 +97,13 @@
return
target = ckey(target)
- if(RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_COMMANDER_COUNCIL)
+ if(GLOB.RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_COMMANDER_COUNCIL)
options |= "Commanding Officer"
edit_C = TRUE
- if(RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_SYNTHETIC_COUNCIL)
+ if(GLOB.RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_SYNTHETIC_COUNCIL)
options |= "Synthetic"
edit_S = TRUE
- if(RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_YAUTJA_COUNCIL)
+ if(GLOB.RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_YAUTJA_COUNCIL)
options |= "Yautja"
edit_Y = TRUE
@@ -116,17 +116,17 @@
if("Merit")
show_other_record(NOTE_MERIT, choice, target, TRUE)
if("Commanding Officer")
- if(MA || (RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_COMMANDER_LEADER))
+ if(MA || (GLOB.RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_COMMANDER_LEADER))
show_other_record(NOTE_COMMANDER, choice, target, TRUE, TRUE)
else
show_other_record(NOTE_COMMANDER, choice, target, edit_C)
if("Synthetic")
- if(MA || (RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_SYNTHETIC_LEADER))
+ if(MA || (GLOB.RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_SYNTHETIC_LEADER))
show_other_record(NOTE_SYNTHETIC, choice, target, TRUE, TRUE)
else
show_other_record(NOTE_SYNTHETIC, choice, target, edit_S)
if("Yautja")
- if(MA || (RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_YAUTJA_LEADER))
+ if(MA || (GLOB.RoleAuthority.roles_whitelist[src.ckey] & WHITELIST_YAUTJA_LEADER))
show_other_record(NOTE_YAUTJA, choice, target, TRUE, TRUE)
else
show_other_record(NOTE_YAUTJA, choice, target, edit_Y)
@@ -143,7 +143,7 @@
dat += ""
var/color = "#008800"
- var/add_dat = "Add Admin Note Add Confidential Admin Note "
+ var/add_dat = "Add Admin Note Add Confidential Admin Note "
switch(note_category)
if(NOTE_MERIT)
color = "#9e3dff"
@@ -181,3 +181,47 @@
dat += ""
show_browser(src, dat, "[target]'s [category_text] Notes", "otherplayersinfo", "size=480x480")
+
+GLOBAL_DATUM_INIT(medals_view_tgui, /datum/medals_view_tgui, new)
+
+/datum/medals_view_tgui/tgui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "MedalsViewer", "[user.ckey]'s Medals")
+ ui.open()
+
+/datum/medals_view_tgui/ui_static_data(mob/user)
+ . = ..()
+ .["medals"] = list()
+
+ for(var/datum/view_record/medal_view/medal as anything in DB_VIEW(/datum/view_record/medal_view, DB_COMP("player_id", DB_EQUALS, user.client.player_data.id)))
+ var/xeno_medal = FALSE
+ if(medal.medal_type in GLOB.xeno_medals)
+ xeno_medal = TRUE
+
+ var/list/current_medal = list(
+ "round_id" = medal.round_id,
+ "medal_type" = medal.medal_type,
+ "medal_icon" = replacetext(medal.medal_type, " ", "-"),
+ "xeno_medal" = xeno_medal,
+ "recipient_name" = medal.recipient_name,
+ "recipient_role" = medal.recipient_role,
+ "giver_name" = medal.giver_name,
+ "citation" = medal.citation
+ )
+
+ .["medals"] += list(current_medal)
+
+/datum/medals_view_tgui/ui_state(mob/user)
+ return GLOB.always_state
+
+/datum/medals_view_tgui/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/medal)
+ )
+
+/client/verb/view_own_medals()
+ set name = "View Own Medals"
+ set category = "OOC.Records"
+
+ GLOB.medals_view_tgui.tgui_interact(mob)
diff --git a/code/game/verbs/who.dm b/code/game/verbs/who.dm
index 8a249d297cbe..5871fdc7a152 100644
--- a/code/game/verbs/who.dm
+++ b/code/game/verbs/who.dm
@@ -42,6 +42,8 @@
var/list/Lines = list()
if(admin_holder && ((R_ADMIN & admin_holder.rights) || (R_MOD & admin_holder.rights)))
for(var/client/C in GLOB.clients)
+ if(!CLIENT_HAS_RIGHTS(src, R_STEALTH) && (CLIENT_IS_STEALTHED(C)))
+ continue
var/entry = "[C.key]"
if(C.mob) //Juuuust in case
if(istype(C.mob, /mob/new_player))
@@ -83,7 +85,7 @@
counted_humanoids["Infected humans"]++
if(C.mob.faction == FACTION_MARINE)
counted_humanoids[FACTION_MARINE]++
- if(C.mob.job in (ROLES_MARINES))
+ if(C.mob.job in (GLOB.ROLES_MARINES))
counted_humanoids["USCM Marines"]++
else
counted_humanoids[C.mob.faction]++
@@ -139,7 +141,7 @@
else
for(var/client/C in GLOB.clients)
- if(C.admin_holder && C.admin_holder.fakekey)
+ if((C.admin_holder && C.admin_holder.fakekey) || (CLIENT_IS_STEALTHED(C)))
continue
Lines += C.key
@@ -160,7 +162,7 @@
if(CONFIG_GET(flag/show_manager))
LAZYSET(mappings, "Management", R_PERMISSIONS)
if(CONFIG_GET(flag/show_devs))
- LAZYSET(mappings, "Maintainers", R_PROFILER)
+ LAZYSET(mappings, "Maintainers", R_PROFILER)
LAZYSET(mappings, "Admins", R_ADMIN)
if(CONFIG_GET(flag/show_mods))
LAZYSET(mappings, "Moderators", R_MOD)
@@ -172,6 +174,8 @@
LAZYSET(listings, category, list())
for(var/client/C in GLOB.admins)
+ if(CLIENT_IS_STEALTHED(C) && !CLIENT_HAS_RIGHTS(src, R_STEALTH))
+ continue
if(C.admin_holder?.fakekey && !CLIENT_IS_STAFF(src))
continue
for(var/category in mappings)
@@ -182,12 +186,14 @@
for(var/category in listings)
dat += " Current [category] ([length(listings[category])]): \n"
for(var/client/entry in listings[category])
- dat += "\t[entry.key] is a [entry.admin_holder.rank]"
+ dat += "\t[entry.key] is \a [entry.admin_holder.rank]"
if(entry.admin_holder.extra_titles?.len)
for(var/srank in entry.admin_holder.extra_titles)
dat += " & [srank]"
if(CLIENT_IS_STAFF(src))
- if(entry.admin_holder?.fakekey)
+ if(CLIENT_IS_STEALTHED(entry))
+ dat += " (STEALTHED)"
+ else if(entry.admin_holder?.fakekey)
dat += " (HIDDEN)"
if(istype(entry.mob, /mob/dead/observer))
dat += " - Observing"
diff --git a/code/game/world.dm b/code/game/world.dm
index fce40ca468ae..f68263412715 100644
--- a/code/game/world.dm
+++ b/code/game/world.dm
@@ -1,10 +1,8 @@
-var/world_view_size = 7
-var/lobby_view_size = 16
+GLOBAL_VAR_INIT(world_view_size, 7)
+GLOBAL_VAR_INIT(lobby_view_size, 16)
-var/internal_tick_usage = 0
-
-var/list/reboot_sfx = file2list("config/reboot_sfx.txt")
+GLOBAL_LIST_INIT(reboot_sfx, file2list("config/reboot_sfx.txt"))
/world
mob = /mob/new_player
turf = /turf/open/space/basic
@@ -18,7 +16,6 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt")
if (debug_server)
LIBCALL(debug_server, "auxtools_init")()
enable_debugging()
- internal_tick_usage = 0.2 * world.tick_lag
hub_password = "kMZy3U5jJHSiBQjr"
#ifdef BYOND_TRACY
@@ -49,8 +46,6 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt")
LoadBans()
load_motd()
load_tm_message()
- load_mode()
- loadShuttleInfoDatums()
populate_gear_list()
initialize_global_regex()
@@ -67,12 +62,10 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt")
// Only do offline sleeping when the server isn't running unit tests or hosting a local dev test
sleep_offline = (!running_tests && !testing_locally)
- if(!RoleAuthority)
- RoleAuthority = new /datum/authority/branch/role()
+ if(!GLOB.RoleAuthority)
+ GLOB.RoleAuthority = new /datum/authority/branch/role()
to_world(SPAN_DANGER("\b Job setup complete"))
- if(!EvacuationAuthority) EvacuationAuthority = new
-
initiate_minimap_icons()
change_tick_lag(CONFIG_GET(number/ticklag))
@@ -91,8 +84,8 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt")
update_status()
//Scramble the coords obsfucator
- obfs_x = rand(-500, 500) //A number between -100 and 100
- obfs_y = rand(-500, 500) //A number between -100 and 100
+ GLOB.obfs_x = rand(-500, 500) //A number between -100 and 100
+ GLOB.obfs_y = rand(-500, 500) //A number between -100 and 100
spawn(3000) //so we aren't adding to the round-start lag
if(CONFIG_GET(flag/ToRban))
@@ -101,7 +94,7 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt")
// If the server's configured for local testing, get everything set up ASAP.
// Shamelessly stolen from the test manager's host_tests() proc
if(testing_locally)
- master_mode = "Extended"
+ GLOB.master_mode = "Extended"
// Wait for the game ticker to initialize
while(!SSticker.initialized)
@@ -111,9 +104,6 @@ var/list/reboot_sfx = file2list("config/reboot_sfx.txt")
SSticker.request_start()
return
-var/world_topic_spam_protect_ip = "0.0.0.0"
-var/world_topic_spam_protect_time = world.timeofday
-
/proc/start_logging()
GLOB.round_id = SSentity_manager.round.id
@@ -174,11 +164,6 @@ var/world_topic_spam_protect_time = world.timeofday
response["response"] = "Payload too large"
return json_encode(response)
- if(SSfail_to_topic?.IsRateLimited(addr))
- response["statuscode"] = 429
- response["response"] = "Rate limited"
- return json_encode(response)
-
var/logging = CONFIG_GET(flag/log_world_topic)
var/topic_decoded = rustg_url_decode(T)
if(!rustg_json_is_valid(topic_decoded))
@@ -262,44 +247,29 @@ var/world_topic_spam_protect_time = world.timeofday
shutdown()
/world/proc/send_tgs_restart()
- if(CONFIG_GET(string/new_round_alert_channel) && CONFIG_GET(string/new_round_alert_role_id))
- if(round_statistics)
- send2chat("[round_statistics.round_name][GLOB.round_id ? " (Round [GLOB.round_id])" : ""] completed!", CONFIG_GET(string/new_round_alert_channel))
- if(SSmapping.next_map_configs)
- var/datum/map_config/next_map = SSmapping.next_map_configs[GROUND_MAP]
- if(next_map)
- send2chat("<@&[CONFIG_GET(string/new_round_alert_role_id)]> Restarting! Next map is [next_map.map_name]", CONFIG_GET(string/new_round_alert_channel))
- else
- send2chat("<@&[CONFIG_GET(string/new_round_alert_role_id)]> Restarting!", CONFIG_GET(string/new_round_alert_channel))
- return
+ if(!CONFIG_GET(string/new_round_alert_channel))
+ return
+
+ if(!GLOB.round_statistics)
+ return
+
+ send2chat(new /datum/tgs_message_content("[GLOB.round_statistics.round_name][GLOB.round_id ? " (Round [GLOB.round_id])" : ""] completed!"), CONFIG_GET(string/new_round_alert_channel))
/world/proc/send_reboot_sound()
- var/reboot_sound = SAFEPICK(reboot_sfx)
+ var/reboot_sound = SAFEPICK(GLOB.reboot_sfx)
if(reboot_sound)
var/sound/reboot_sound_ref = sound(reboot_sound)
for(var/client/client as anything in GLOB.clients)
if(client?.prefs.toggles_sound & SOUND_REBOOT)
SEND_SOUND(client, reboot_sound_ref)
-/world/proc/load_mode()
- var/list/Lines = file2list("data/mode.txt")
- if(Lines.len)
- if(Lines[1])
- master_mode = Lines[1]
- log_misc("Saved mode is '[master_mode]'")
-
-/world/proc/save_mode(the_mode)
- var/F = file("data/mode.txt")
- fdel(F)
- F << the_mode
-
/world/proc/load_motd()
- join_motd = file2text("config/motd.txt")
+ GLOB.join_motd = file2text("config/motd.txt")
/world/proc/load_tm_message()
var/datum/getrev/revdata = GLOB.revdata
if(revdata.testmerge.len)
- current_tms = revdata.GetTestMergeInfo()
+ GLOB.current_tms = revdata.GetTestMergeInfo()
/world/proc/update_status()
//Note: Hub content is limited to 254 characters, including limited HTML/CSS.
@@ -317,32 +287,10 @@ var/world_topic_spam_protect_time = world.timeofday
world.status = s
-#define FAILED_DB_CONNECTION_CUTOFF 1
-var/failed_db_connections = 0
-var/failed_old_db_connections = 0
-
-// /hook/startup/proc/connectDB()
-// if(!setup_database_connection())
-// world.log << "Your server failed to establish a connection with the feedback database."
-// else
-// world.log << "Feedback database connection established."
-// return 1
-
-var/datum/BSQL_Connection/connection
-/proc/setup_database_connection()
-
- if(failed_db_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore.
- return 0
-
-
- return .
-
/proc/set_global_view(view_size)
- world_view_size = view_size
+ GLOB.world_view_size = view_size
for(var/client/c in GLOB.clients)
- c.view = world_view_size
-
-#undef FAILED_DB_CONNECTION_CUTOFF
+ c.view = GLOB.world_view_size
/proc/give_image_to_client(obj/O, icon_text)
var/image/I = image(null, O)
diff --git a/code/global.dm b/code/global.dm
index bdde529a9af8..f141dc5d68ac 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -33,148 +33,9 @@
#define CLIENT_HAS_RIGHTS(cli, flags) ((cli?.admin_holder?.rights & flags) == flags)
#define CLIENT_IS_STAFF(cli) (cli?.admin_holder?.rights & (R_MOD|R_ADMIN))
#define CLIENT_IS_MENTOR(cli) CLIENT_HAS_RIGHTS(cli, R_MENTOR)
+#define CLIENT_IS_STEALTHED(cli) (CLIENT_HAS_RIGHTS(cli, R_STEALTH) && cli.prefs?.toggles_admin & ADMIN_STEALTHMODE)
#define AHOLD_IS_MOD(ahold) (ahold && (ahold.rights & R_MOD))
#define AHOLD_IS_ADMIN(ahold) (ahold && (ahold.rights & R_ADMIN))
//items that ask to be called every cycle
-
-//////////////
-var/list/paper_tag_whitelist = list("center","p","div","span","h1","h2","h3","h4","h5","h6","hr","pre", \
- "big","small","font","i","u","b","s","sub","sup","tt","br","hr","ol","ul","li","caption","col", \
- "table","td","th","tr")
-
-///////////////
-
-var/command_name = "Central Command"
-var/station_name = "[MAIN_SHIP_NAME]"
-var/game_version = "Colonial Marines"
-var/game_year = 2182
-
-var/going = 1
-var/master_mode = "Distress Signal"
-
-/// If this is anything but "secret", the secret rotation will forceably choose this mode.
-var/secret_force_mode = "secret"
-
-var/host = null
-var/ooc_allowed = 1
-var/looc_allowed = 1
-var/dsay_allowed = 1
-var/dooc_allowed = 1
-var/dlooc_allowed = 0
-var/abandon_allowed = 1
-var/enter_allowed = 1
-var/shuttle_frozen = 0
-var/shuttle_left = 0
-var/midi_playing = 0
-var/heard_midi = 0
-var/total_silenced = 0
-
-var/list/admin_log = list()
-var/list/asset_log = list()
-
-var/CELLRATE = 0.006 // multiplier for watts per tick <> cell storage (eg: 0.02 means if there is a load of 1000 watts, 20 units will be taken from a cell per second)
- //It's a conversion constant. power_used*CELLRATE = charge_provided, or charge_used/CELLRATE = power_provided
-var/CHARGELEVEL = 0.001 // Cap for how fast cells charge, as a percentage-per-tick (0.01 means cellcharge is capped to 1% per second)
-
-var/VehicleElevatorConsole
-var/VehicleGearConsole
-
-//Spawnpoints.
-var/list/fallen_list = list()
-/// This is for dogtags placed on crosses- they will show up at the end-round memorial.
-var/list/fallen_list_cross = list()
-var/list/cardinal = list(NORTH, SOUTH, EAST, WEST)
-var/list/diagonals = list(NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
-var/list/alldirs = list(NORTH, SOUTH, EAST, WEST, NORTHEAST, NORTHWEST, SOUTHEAST, SOUTHWEST)
-var/list/reverse_dir = list(2, 1, 3, 8, 10, 9, 11, 4, 6, 5, 7, 12, 14, 13, 15, 32, 34, 33, 35, 40, 42, 41, 43, 36, 38, 37, 39, 44, 46, 45, 47, 16, 18, 17, 19, 24, 26, 25, 27, 20, 22, 21, 23, 28, 30, 29, 31, 48, 50, 49, 51, 56, 58, 57, 59, 52, 54, 53, 55, 60, 62, 61, 63)
-
-var/list/combatlog = list()
-var/list/IClog = list()
-var/list/OOClog = list()
-var/list/adminlog = list()
-
-var/Debug = 0 // global debug switch
-
-var/datum/moduletypes/mods = new()
-
-var/join_motd = null
-var/current_tms
-
-// nanomanager, the manager for Nano UIs
-var/datum/nanomanager/nanomanager = new()
-
-var/list/BorgWireColorToFlag = RandomBorgWires()
-var/list/BorgIndexToFlag
-var/list/BorgIndexToWireColor
-var/list/BorgWireColorToIndex
-var/list/AAlarmWireColorToFlag = RandomAAlarmWires()
-var/list/AAlarmIndexToFlag
-var/list/AAlarmIndexToWireColor
-var/list/AAlarmWireColorToIndex
-
-//Don't set this very much higher then 1024 unless you like inviting people in to dos your server with message spam
-#define MAX_MESSAGE_LEN 1024
-#define MAX_EMOTE_LEN 256
-#define MAX_PAPER_MESSAGE_LEN 3072
-#define MAX_BOOK_MESSAGE_LEN 9216
-#define MAX_NAME_LEN 26
-
-/// 3 minutes in the station.
-#define shuttle_time_in_station 3 MINUTES
-/// 10 minutes to arrive.
-#define shuttle_time_to_arrive 10 MINUTES
-
- // MySQL configuration
-
-var/sqladdress = "localhost"
-var/sqlport = "3306"
-var/sqldb = "cmdb"
-var/sqllogin = "root"
-var/sqlpass = ""
-
-
- // For FTP requests. (i.e. downloading runtime logs.)
- // However it'd be ok to use for accessing attack logs and such too, which are even laggier.
-var/fileaccess_timer = 0
-
-// Reference list for disposal sort junctions. Filled up by sorting junction's New()
-/var/list/tagger_locations = list()
-
-//added for Xenoarchaeology, might be useful for other stuff
-var/list/alphabet_uppercase = list("A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z")
-var/list/alphabet_lowercase = list("a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z")
-
-var/list/greek_letters = list("Alpha", "Beta", "Gamma", "Delta", "Epsilon", "Zeta", "Eta", "Theta", "Iota", "Kappa", "Lambda", "Mu", "Nu", "Xi", "Omnicron", "Pi", "Rho", "Sigma", "Tau", "Upsilon", "Phi", "Chi", "Psi", "Omega")
-var/list/nato_phonetic_alphabet = list("Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliett", "Kilo", "Lima", "Mike", "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-Ray", "Yankee", "Zulu")
-
-//Used for autocall procs on ERT
-var/distress_cancel = 0
-var/destroy_cancel = 0
-
-//Coordinate obsfucator
-//Used by the rangefinders and linked systems to prevent coords collection/prefiring
-
-/// A number between -500 and 500.
-var/global/obfs_x = 0
-/// A number between -500 and 500.
-var/global/obfs_y = 0
-
-// Which lobby art is on display
-// This is updated by the lobby art turf when it initializes
-var/displayed_lobby_art = -1
-
-// Last global ID that was assigned to a mob (for round recording purposes)
-var/last_mob_gid = 0
-
-// be careful messing with this. the section names are hardcoded here, while defines are used everywhere else
-// see the big commented block for an explanation
-var/list/almayer_ship_sections = list(
- "Upper deck Foreship",
- "Upper deck Midship",
- "Upper deck Aftship",
- "Lower deck Foreship",
- "Lower deck Midship",
- "Lower deck Aftship"
-)
diff --git a/code/js/byjax.dm b/code/js/byjax.dm
deleted file mode 100644
index 8e196ef013f4..000000000000
--- a/code/js/byjax.dm
+++ /dev/null
@@ -1,50 +0,0 @@
-//this function places received data into element with specified id.
-var/const/js_byjax = {"
-
-function replaceContent() {
- var args = Array.prototype.slice.call(arguments);
- var id = args\[0\];
- var content = args\[1\];
- var callback = null;
- if(args\[2\]){
- callback = args\[2\];
- if(args\[3\]){
- args = args.slice(3);
- }
- }
- var parent = document.getElementById(id);
- if(typeof(parent)!=='undefined' && parent!=null){
- parent.innerHTML = content?content:'';
- }
- if(callback && window\[callback\]){
- window\[callback\].apply(null,args);
- }
-}
-"}
-
-/*
-sends data to control_id:replaceContent
-
-receiver - mob
-control_id - window id (for windows opened with browse(), it'll be "windowname.browser")
-target_element - HTML element id
-new_content - HTML content
-callback - js function that will be called after the data is sent
-callback_args - arguments for callback function
-
-Be sure to include required js functions in your page, or it'll raise an exception.
-*/
-/proc/send_byjax(receiver, control_id, target_element, new_content=null, callback=null, list/callback_args=null)
- if(receiver && target_element && control_id) // && winexists(receiver, control_id))
- var/list/argums = list(target_element, new_content)
- if(callback)
- argums += callback
- if(callback_args)
- argums += callback_args
- argums = list2params(argums)
-/* if(callback_args)
- argums += "&[list2params(callback_args)]"
-*/
- receiver << output(argums,"[control_id]:replaceContent")
- return
-
diff --git a/code/js/menus.dm b/code/js/menus.dm
deleted file mode 100644
index 0064522c2f81..000000000000
--- a/code/js/menus.dm
+++ /dev/null
@@ -1,37 +0,0 @@
-var/const/js_dropdowns = {"
-function dropdowns() {
- var divs = document.getElementsByTagName('div');
- var headers = new Array();
- var links = new Array();
- for(var i=0;i=0) {
- elem.className = elem.className.replace('visible','hidden');
- this.className = this.className.replace('open','closed');
- this.innerHTML = this.innerHTML.replace('-','+');
- }
- else {
- elem.className = elem.className.replace('hidden','visible');
- this.className = this.className.replace('closed','open');
- this.innerHTML = this.innerHTML.replace('+','-');
- }
- return false;
- }
- })(links\[i\]);
- }
- }
-}
-"}
diff --git a/code/modules/admin/IsBanned.dm b/code/modules/admin/IsBanned.dm
index bf6d8e261ab3..94f40629fc6a 100644
--- a/code/modules/admin/IsBanned.dm
+++ b/code/modules/admin/IsBanned.dm
@@ -18,7 +18,7 @@
return list("reason"="guest", "desc"="\nReason: Guests not allowed. Please sign in with a byond account.")
WAIT_DB_READY
- if(admin_datums[ckey] && (admin_datums[ckey].rights & R_MOD))
+ if(GLOB.admin_datums[ckey] && (GLOB.admin_datums[ckey].rights & R_MOD))
return ..()
if(CONFIG_GET(number/limit_players) && CONFIG_GET(number/limit_players) < GLOB.clients.len)
diff --git a/code/modules/admin/NewBan.dm b/code/modules/admin/NewBan.dm
index b64b1e4682fd..7dca354129ff 100644
--- a/code/modules/admin/NewBan.dm
+++ b/code/modules/admin/NewBan.dm
@@ -1,75 +1,75 @@
-var/CMinutes = null
-var/savefile/Banlist
+GLOBAL_VAR(CMinutes)
+GLOBAL_DATUM(Banlist, /savefile)
/proc/CheckBan(ckey, id, address)
- if(!Banlist) // if Banlist cannot be located for some reason
+ if(!GLOB.Banlist) // if GLOB.Banlist cannot be located for some reason
LoadBans() // try to load the bans
- if(!Banlist) // uh oh, can't find bans!
+ if(!GLOB.Banlist) // uh oh, can't find bans!
return 0 // ABORT ABORT ABORT
. = list()
var/appeal
if(CONFIG_GET(string/banappeals))
appeal = "\nFor more information on your ban, or to appeal, head to [CONFIG_GET(string/banappeals)]"
- Banlist.cd = "/base"
- if( "[ckey][id]" in Banlist.dir )
- Banlist.cd = "[ckey][id]"
- if (Banlist["temp"])
- if (!GetExp(Banlist["minutes"]))
+ GLOB.Banlist.cd = "/base"
+ if( "[ckey][id]" in GLOB.Banlist.dir )
+ GLOB.Banlist.cd = "[ckey][id]"
+ if (GLOB.Banlist["temp"])
+ if (!GetExp(GLOB.Banlist["minutes"]))
ClearTempbans()
return 0
else
- .["desc"] = "\nReason: [Banlist["reason"]]\nExpires: [GetExp(Banlist["minutes"])]\nBy: [Banlist["bannedby"]][appeal]"
+ .["desc"] = "\nReason: [GLOB.Banlist["reason"]]\nExpires: [GetExp(GLOB.Banlist["minutes"])]\nBy: [GLOB.Banlist["bannedby"]][appeal]"
else
- Banlist.cd = "/base/[ckey][id]"
- .["desc"] = "\nReason: [Banlist["reason"]]\nExpires: PERMENANT\nBy: [Banlist["bannedby"]][appeal]"
+ GLOB.Banlist.cd = "/base/[ckey][id]"
+ .["desc"] = "\nReason: [GLOB.Banlist["reason"]]\nExpires: PERMENANT\nBy: [GLOB.Banlist["bannedby"]][appeal]"
.["reason"] = "ckey/id"
return .
else
- for (var/A in Banlist.dir)
- Banlist.cd = "/base/[A]"
+ for (var/A in GLOB.Banlist.dir)
+ GLOB.Banlist.cd = "/base/[A]"
var/matches
- if( ckey == Banlist["key"] )
+ if( ckey == GLOB.Banlist["key"] )
matches += "ckey"
- if( id == Banlist["id"] )
+ if( id == GLOB.Banlist["id"] )
if(matches)
matches += "/"
matches += "id"
- if( address == Banlist["ip"] )
+ if( address == GLOB.Banlist["ip"] )
if(matches)
matches += "/"
matches += "ip"
if(matches)
- if(Banlist["temp"])
- if (!GetExp(Banlist["minutes"]))
+ if(GLOB.Banlist["temp"])
+ if (!GetExp(GLOB.Banlist["minutes"]))
ClearTempbans()
return 0
else
- .["desc"] = "\nReason: [Banlist["reason"]]\nExpires: [GetExp(Banlist["minutes"])]\nBy: [Banlist["bannedby"]][appeal]"
+ .["desc"] = "\nReason: [GLOB.Banlist["reason"]]\nExpires: [GetExp(GLOB.Banlist["minutes"])]\nBy: [GLOB.Banlist["bannedby"]][appeal]"
else
- .["desc"] = "\nReason: [Banlist["reason"]]\nExpires: PERMENANT\nBy: [Banlist["bannedby"]][appeal]"
+ .["desc"] = "\nReason: [GLOB.Banlist["reason"]]\nExpires: PERMENANT\nBy: [GLOB.Banlist["bannedby"]][appeal]"
.["reason"] = matches
return .
return 0
/proc/UpdateTime() //No idea why i made this a proc.
- CMinutes = (world.realtime / 10) / 60
+ GLOB.CMinutes = (world.realtime / 10) / 60
return 1
/proc/LoadBans()
- Banlist = new("data/banlist.bdb")
- log_admin("Loading Banlist")
+ GLOB.Banlist = new("data/banlist.bdb")
+ log_admin("Loading GLOB.Banlist")
- if (!length(Banlist.dir)) log_admin("Banlist is empty.")
+ if (!length(GLOB.Banlist.dir)) log_admin("GLOB.Banlist is empty.")
- if (!Banlist.dir.Find("base"))
- log_admin("Banlist missing base dir.")
- Banlist.dir.Add("base")
- Banlist.cd = "/base"
- else if (Banlist.dir.Find("base"))
- Banlist.cd = "/base"
+ if (!GLOB.Banlist.dir.Find("base"))
+ log_admin("GLOB.Banlist missing base dir.")
+ GLOB.Banlist.dir.Add("base")
+ GLOB.Banlist.cd = "/base"
+ else if (GLOB.Banlist.dir.Find("base"))
+ GLOB.Banlist.cd = "/base"
ClearTempbans()
return 1
@@ -77,64 +77,64 @@ var/savefile/Banlist
/proc/ClearTempbans()
UpdateTime()
- Banlist.cd = "/base"
- for (var/A in Banlist.dir)
- Banlist.cd = "/base/[A]"
- if (!Banlist["key"] || !Banlist["id"])
+ GLOB.Banlist.cd = "/base"
+ for (var/A in GLOB.Banlist.dir)
+ GLOB.Banlist.cd = "/base/[A]"
+ if (!GLOB.Banlist["key"] || !GLOB.Banlist["id"])
RemoveBan(A)
log_admin("Invalid Ban.")
message_admins("Invalid Ban.")
continue
- if (!Banlist["temp"]) continue
- if (CMinutes >= Banlist["minutes"]) RemoveBan(A)
+ if (!GLOB.Banlist["temp"]) continue
+ if (GLOB.CMinutes >= GLOB.Banlist["minutes"]) RemoveBan(A)
return 1
/proc/AddBan(ckey, computerid, reason, bannedby, temp, minutes, address)
- if(!Banlist) // if Banlist cannot be located for some reason
+ if(!GLOB.Banlist) // if GLOB.Banlist cannot be located for some reason
LoadBans() // try to load the bans
- if(!Banlist) // uh oh, can't find bans!
+ if(!GLOB.Banlist) // uh oh, can't find bans!
return 0 // ABORT ABORT ABORT
var/bantimestamp
if (temp)
UpdateTime()
- bantimestamp = CMinutes + minutes
+ bantimestamp = GLOB.CMinutes + minutes
- Banlist.cd = "/base"
- if ( Banlist.dir.Find("[ckey][computerid]"))
+ GLOB.Banlist.cd = "/base"
+ if ( GLOB.Banlist.dir.Find("[ckey][computerid]"))
RemoveBan("[ckey][computerid]") //have to remove dirs before processing
- Banlist.dir.Add("[ckey][computerid]")
- Banlist.cd = "/base/[ckey][computerid]"
- Banlist["key"] << ckey
- Banlist["id"] << computerid
- Banlist["ip"] << address
- Banlist["reason"] << reason
- Banlist["bannedby"] << bannedby
- Banlist["temp"] << temp
+ GLOB.Banlist.dir.Add("[ckey][computerid]")
+ GLOB.Banlist.cd = "/base/[ckey][computerid]"
+ GLOB.Banlist["key"] << ckey
+ GLOB.Banlist["id"] << computerid
+ GLOB.Banlist["ip"] << address
+ GLOB.Banlist["reason"] << reason
+ GLOB.Banlist["bannedby"] << bannedby
+ GLOB.Banlist["temp"] << temp
if (temp)
- Banlist["minutes"] << bantimestamp
+ GLOB.Banlist["minutes"] << bantimestamp
return 1
/proc/RemoveBan(foldername)
- if(!Banlist) // if Banlist cannot be located for some reason
+ if(!GLOB.Banlist) // if GLOB.Banlist cannot be located for some reason
LoadBans() // try to load the bans
- if(!Banlist) // uh oh, can't find bans!
+ if(!GLOB.Banlist) // uh oh, can't find bans!
return 0 // ABORT ABORT ABORT
var/key
var/id
- Banlist.cd = "/base/[foldername]"
- Banlist["key"] >> key
- Banlist["id"] >> id
- Banlist.cd = "/base"
+ GLOB.Banlist.cd = "/base/[foldername]"
+ GLOB.Banlist["key"] >> key
+ GLOB.Banlist["id"] >> id
+ GLOB.Banlist.cd = "/base"
- if (!Banlist.dir.Remove(foldername)) return 0
+ if (!GLOB.Banlist.dir.Remove(foldername)) return 0
if(!usr)
log_admin("Ban Expired: [key]")
@@ -143,18 +143,18 @@ var/savefile/Banlist
ban_unban_log_save("[key_name_admin(usr)] unbanned [key]")
log_admin("[key_name_admin(usr)] unbanned [key]")
message_admins("[key_name_admin(usr)] unbanned: [key]")
- for (var/A in Banlist.dir)
- Banlist.cd = "/base/[A]"
- if (key == Banlist["key"] /*|| id == Banlist["id"]*/)
- Banlist.cd = "/base"
- Banlist.dir.Remove(A)
+ for (var/A in GLOB.Banlist.dir)
+ GLOB.Banlist.cd = "/base/[A]"
+ if (key == GLOB.Banlist["key"] /*|| id == GLOB.Banlist["id"]*/)
+ GLOB.Banlist.cd = "/base"
+ GLOB.Banlist.dir.Remove(A)
continue
return 1
/proc/GetExp(minutes as num)
UpdateTime()
- var/exp = minutes - CMinutes
+ var/exp = minutes - GLOB.CMinutes
if (exp <= 0)
return 0
else
@@ -202,27 +202,27 @@ var/savefile/Banlist
var/a = pick(1,0)
var/b = pick(1,0)
if(b)
- Banlist.cd = "/base"
- Banlist.dir.Add("trash[i]trashid[i]")
- Banlist.cd = "/base/trash[i]trashid[i]"
- Banlist["key"] << "trash[i]"
+ GLOB.Banlist.cd = "/base"
+ GLOB.Banlist.dir.Add("trash[i]trashid[i]")
+ GLOB.Banlist.cd = "/base/trash[i]trashid[i]"
+ GLOB.Banlist["key"] << "trash[i]"
else
- Banlist.cd = "/base"
- Banlist.dir.Add("[last]trashid[i]")
- Banlist.cd = "/base/[last]trashid[i]"
- Banlist["key"] << last
- Banlist["id"] << "trashid[i]"
- Banlist["reason"] << "Trashban[i]."
- Banlist["temp"] << a
- Banlist["minutes"] << CMinutes + rand(1,2000)
- Banlist["bannedby"] << "trashmin"
+ GLOB.Banlist.cd = "/base"
+ GLOB.Banlist.dir.Add("[last]trashid[i]")
+ GLOB.Banlist.cd = "/base/[last]trashid[i]"
+ GLOB.Banlist["key"] << last
+ GLOB.Banlist["id"] << "trashid[i]"
+ GLOB.Banlist["reason"] << "Trashban[i]."
+ GLOB.Banlist["temp"] << a
+ GLOB.Banlist["minutes"] << GLOB.CMinutes + rand(1,2000)
+ GLOB.Banlist["bannedby"] << "trashmin"
last = "trash[i]"
- Banlist.cd = "/base"
+ GLOB.Banlist.cd = "/base"
/proc/ClearAllBans()
- Banlist.cd = "/base"
- for (var/A in Banlist.dir)
+ GLOB.Banlist.cd = "/base"
+ for (var/A in GLOB.Banlist.dir)
RemoveBan(A)
/client/proc/cmd_admin_do_ban(mob/M)
diff --git a/code/modules/admin/admin.dm b/code/modules/admin/admin.dm
index 5042167023e6..fe95affaffd2 100644
--- a/code/modules/admin/admin.dm
+++ b/code/modules/admin/admin.dm
@@ -121,10 +121,10 @@
var/t //text to show in the window
var/u //unban button href arg
var/dat = "
"
- for(r in jobban_keylist)
- L = jobban_keylist[r]
+ for(r in GLOB.jobban_keylist)
+ L = GLOB.jobban_keylist[r]
for(c in L)
- i = jobban_keylist[r][c] //These are already strings, as you're iterating through them. Anyway, establish jobban.
+ i = GLOB.jobban_keylist[r][c] //These are already strings, as you're iterating through them. Anyway, establish jobban.
t = "[c] - [r] ## [i]"
u = "[c] - [r]"
dat += "
"
if (refresh)
close_browser(src, "playersetup")
- show_browser(src, output, null, "playersetup", "size=240x[round_start ? 330 : 460];can_close=0;can_minimize=0")
+ show_browser(src, output, null, "playersetup", "size=240x[round_start ? 500 : 610];can_close=0;can_minimize=0")
return
/mob/new_player/Topic(href, href_list[])
@@ -97,14 +98,14 @@
if("ready")
if( (SSticker.current_state <= GAME_STATE_PREGAME) && !ready) // Make sure we don't ready up after the round has started
ready = TRUE
- readied_players++
+ GLOB.readied_players++
new_player_panel_proc()
if("unready")
if((SSticker.current_state <= GAME_STATE_PREGAME) && ready) // Make sure we don't ready up after the round has started
ready = FALSE
- readied_players--
+ GLOB.readied_players--
new_player_panel_proc()
@@ -145,12 +146,12 @@
mind.transfer_to(observer, TRUE)
if(observer.client)
- observer.client.change_view(world_view_size)
+ observer.client.change_view(GLOB.world_view_size)
observer.set_huds_from_prefs()
qdel(src)
- return 1
+ return TRUE
if("late_join")
@@ -162,6 +163,11 @@
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
+ if(client.player_data?.playtime_loaded && (client.get_total_human_playtime() < CONFIG_GET(number/notify_new_player_age)) && !length(client.prefs.completed_tutorials))
+ if(tgui_alert(src, "You have little playtime and haven't completed any tutorials. Would you like to go to the tutorial menu?", "Tutorial", list("Yes", "No")) == "Yes")
+ tutorial_menu()
+ return
+
if(client.prefs.species != "Human")
if(!is_alien_whitelisted(src, client.prefs.species) && CONFIG_GET(flag/usealienwhitelist))
to_chat(src, "You are currently not whitelisted to play [client.prefs.species].")
@@ -207,7 +213,7 @@
if("SelectedJob")
- if(!enter_allowed)
+ if(!GLOB.enter_allowed)
to_chat(usr, SPAN_WARNING("There is an administrative lock on entering the game! (The dropship likely crashed into the Almayer. This should take at most 20 minutes.)"))
return
@@ -224,20 +230,39 @@
AttemptLateSpawn(href_list["job_selected"])
return
+ if("tutorial")
+ tutorial_menu()
+
else
new_player_panel()
+/mob/new_player/proc/tutorial_menu()
+ if(SSticker.current_state <= GAME_STATE_SETTING_UP)
+ to_chat(src, SPAN_WARNING("Please wait for the round to start before entering a tutorial."))
+ return
+
+ if(SSticker.current_state == GAME_STATE_FINISHED)
+ to_chat(src, SPAN_WARNING("The round has ended. Please wait for the next round to enter a tutorial."))
+ return
+
+ if(SSticker.tutorial_disabled)
+ to_chat(src, SPAN_WARNING("Tutorials are currently disabled because something broke, sorry!"))
+ return
+
+ var/datum/tutorial_menu/menu = new(src)
+ menu.ui_interact(src)
+
/mob/new_player/proc/AttemptLateSpawn(rank)
- var/datum/job/player_rank = RoleAuthority.roles_for_mode[rank]
+ var/datum/job/player_rank = GLOB.RoleAuthority.roles_for_mode[rank]
if (src != usr)
return
if(SSticker.current_state != GAME_STATE_PLAYING)
to_chat(usr, SPAN_WARNING("The round is either not ready, or has already finished!"))
return
- if(!enter_allowed)
+ if(!GLOB.enter_allowed)
to_chat(usr, SPAN_WARNING("There is an administrative lock on entering the game! (The dropship likely crashed into the Almayer. This should take at most 20 minutes.)"))
return
- if(!RoleAuthority.assign_role(src, player_rank, 1))
+ if(!GLOB.RoleAuthority.assign_role(src, player_rank, 1))
to_chat(src, alert("[rank] is not available. Please try another."))
return
@@ -245,24 +270,25 @@
close_spawn_windows()
var/mob/living/carbon/human/character = create_character(TRUE) //creates the human and transfers vars and mind
- RoleAuthority.equip_role(character, player_rank, late_join = TRUE)
+ GLOB.RoleAuthority.equip_role(character, player_rank, late_join = TRUE)
EquipCustomItems(character)
- if((security_level > SEC_LEVEL_BLUE || EvacuationAuthority.evac_status) && player_rank.gets_emergency_kit)
- to_chat(character, SPAN_HIGHDANGER("As you stagger out of hypersleep, the sleep bay blares: '[EvacuationAuthority.evac_status ? "VESSEL UNDERGOING EVACUATION PROCEDURES, SELF DEFENSE KIT PROVIDED" : "VESSEL IN HEIGHTENED ALERT STATUS, SELF DEFENSE KIT PROVIDED"]'."))
+ if((GLOB.security_level > SEC_LEVEL_BLUE || SShijack.hijack_status) && player_rank.gets_emergency_kit)
+ to_chat(character, SPAN_HIGHDANGER("As you stagger out of hypersleep, the sleep bay blares: '[SShijack.evac_status ? "VESSEL UNDERGOING EVACUATION PROCEDURES, SELF DEFENSE KIT PROVIDED" : "VESSEL IN HEIGHTENED ALERT STATUS, SELF DEFENSE KIT PROVIDED"]'."))
character.put_in_hands(new /obj/item/storage/box/kit/cryo_self_defense(character.loc))
GLOB.data_core.manifest_inject(character)
SSticker.minds += character.mind//Cyborgs and AIs handle this in the transform proc. //TODO!!!!! ~Carn
- SSticker.mode.latejoin_tally += RoleAuthority.calculate_role_weight(player_rank)
+ SSticker.mode.latejoin_update(player_rank)
+ SSticker.mode.update_gear_scale()
- for(var/datum/squad/sq in RoleAuthority.squads)
+ for(var/datum/squad/sq in GLOB.RoleAuthority.squads)
if(sq)
sq.max_engineers = engi_slot_formula(GLOB.clients.len)
sq.max_medics = medic_slot_formula(GLOB.clients.len)
- if(SSticker.mode.latejoin_larva_drop && SSticker.mode.latejoin_tally >= SSticker.mode.latejoin_larva_drop)
- SSticker.mode.latejoin_tally -= SSticker.mode.latejoin_larva_drop
+ if(SSticker.mode.latejoin_larva_drop && SSticker.mode.latejoin_tally - SSticker.mode.latejoin_larva_used >= SSticker.mode.latejoin_larva_drop)
+ SSticker.mode.latejoin_larva_used += SSticker.mode.latejoin_larva_drop
var/datum/hive_status/hive
for(var/hivenumber in GLOB.hive_datum)
hive = GLOB.hive_datum[hivenumber]
@@ -276,11 +302,11 @@
if(player.get_playtime(STATISTIC_HUMAN) == 0 && player.get_playtime(STATISTIC_XENO) == 0)
msg_admin_niche("NEW JOIN: [key_name(character, 1, 1, 0)]. IP: [character.lastKnownIP], CID: [character.computer_id]")
if(character.client)
- var/client/C = character.client
- if(C.player_data && C.player_data.playtime_loaded && length(C.player_data.playtimes) == 0)
+ var/client/client = character.client
+ if(client.player_data && client.player_data.playtime_loaded && length(client.player_data.playtimes) == 0)
msg_admin_niche("NEW PLAYER: [key_name(character, 1, 1, 0)]. IP: [character.lastKnownIP], CID: [character.computer_id]")
- if(C.player_data && C.player_data.playtime_loaded && ((round(C.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1)) <= 5))
- msg_sea("NEW PLAYER: [key_name(character, 0, 1, 0)] only has [(round(C.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1))] hours as a human. Current role: [get_actual_job_name(character)] - Current location: [get_area(character)]")
+ if(client.player_data && client.player_data.playtime_loaded && ((round(client.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1)) <= CONFIG_GET(number/notify_new_player_age)))
+ msg_sea("NEW PLAYER: [key_name(character, 0, 1, 0)] only has [(round(client.get_total_human_playtime() DECISECONDS_TO_HOURS, 0.1))] hours as a human. Current role: [get_actual_job_name(character)] - Current location: [get_area(character)]")
character.client.init_verbs()
qdel(src)
@@ -295,52 +321,52 @@
var/dat = "
"
dat += "Round Duration: [round(hours)]h [round(mins)]m "
- if(EvacuationAuthority)
- switch(EvacuationAuthority.evac_status)
- if(EVACUATION_STATUS_INITIATING) dat += "The [MAIN_SHIP_NAME] is being evacuated. "
- if(EVACUATION_STATUS_COMPLETE) dat += "The [MAIN_SHIP_NAME] has undergone evacuation. "
+ if(SShijack)
+ switch(SShijack.evac_status)
+ if(EVACUATION_STATUS_INITIATED)
+ dat += "The [MAIN_SHIP_NAME] is being evacuated. "
dat += "Choose from the following open positions: "
var/roles_show = FLAG_SHOW_ALL_JOBS
- for(var/i in RoleAuthority.roles_for_mode)
- var/datum/job/J = RoleAuthority.roles_for_mode[i]
- if(!RoleAuthority.check_role_entry(src, J, TRUE))
+ for(var/i in GLOB.RoleAuthority.roles_for_mode)
+ var/datum/job/J = GLOB.RoleAuthority.roles_for_mode[i]
+ if(!GLOB.RoleAuthority.check_role_entry(src, J, TRUE))
continue
var/active = 0
// Only players with the job assigned and AFK for less than 10 minutes count as active
for(var/mob/M in GLOB.player_list)
if(M.client && M.job == J.title)
active++
- if(roles_show & FLAG_SHOW_CIC && ROLES_CIC.Find(J.title))
+ if(roles_show & FLAG_SHOW_CIC && GLOB.ROLES_CIC.Find(J.title))
dat += "Command: "
roles_show ^= FLAG_SHOW_CIC
- else if(roles_show & FLAG_SHOW_AUXIL_SUPPORT && ROLES_AUXIL_SUPPORT.Find(J.title))
+ else if(roles_show & FLAG_SHOW_AUXIL_SUPPORT && GLOB.ROLES_AUXIL_SUPPORT.Find(J.title))
dat += "Auxiliary Combat Support: "
roles_show ^= FLAG_SHOW_AUXIL_SUPPORT
- else if(roles_show & FLAG_SHOW_MISC && ROLES_MISC.Find(J.title))
+ else if(roles_show & FLAG_SHOW_MISC && GLOB.ROLES_MISC.Find(J.title))
dat += "Other: "
roles_show ^= FLAG_SHOW_MISC
- else if(roles_show & FLAG_SHOW_POLICE && ROLES_POLICE.Find(J.title))
+ else if(roles_show & FLAG_SHOW_POLICE && GLOB.ROLES_POLICE.Find(J.title))
dat += "Military Police: "
roles_show ^= FLAG_SHOW_POLICE
- else if(roles_show & FLAG_SHOW_ENGINEERING && ROLES_ENGINEERING.Find(J.title))
+ else if(roles_show & FLAG_SHOW_ENGINEERING && GLOB.ROLES_ENGINEERING.Find(J.title))
dat += "Engineering: "
roles_show ^= FLAG_SHOW_ENGINEERING
- else if(roles_show & FLAG_SHOW_REQUISITION && ROLES_REQUISITION.Find(J.title))
+ else if(roles_show & FLAG_SHOW_REQUISITION && GLOB.ROLES_REQUISITION.Find(J.title))
dat += "Requisitions: "
roles_show ^= FLAG_SHOW_REQUISITION
- else if(roles_show & FLAG_SHOW_MEDICAL && ROLES_MEDICAL.Find(J.title))
+ else if(roles_show & FLAG_SHOW_MEDICAL && GLOB.ROLES_MEDICAL.Find(J.title))
dat += "Medbay: "
roles_show ^= FLAG_SHOW_MEDICAL
- else if(roles_show & FLAG_SHOW_MARINES && ROLES_MARINES.Find(J.title))
+ else if(roles_show & FLAG_SHOW_MARINES && GLOB.ROLES_MARINES.Find(J.title))
dat += "Squad Riflemen: "
roles_show ^= FLAG_SHOW_MARINES
@@ -369,31 +395,9 @@
new_character.lastarea = get_area(loc)
- client.prefs.copy_all_to(new_character, job, is_late_join)
-
- if (client.prefs.be_random_body)
- var/datum/preferences/TP = new()
- TP.randomize_appearance(new_character)
-
- if(mind)
- mind_initialize()
- mind.active = 0 //we wish to transfer the key manually
- mind.original = new_character
- mind.transfer_to(new_character) //won't transfer key since the mind is not active
- mind.setup_human_stats()
-
- new_character.job = job
- new_character.name = real_name
- new_character.voice = real_name
-
- // Update the character icons
- // This is done in set_species when the mob is created as well, but
- INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, regenerate_icons))
- INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_body), 1, 0)
- INVOKE_ASYNC(new_character, TYPE_PROC_REF(/mob/living/carbon/human, update_hair))
+ setup_human(new_character, src, is_late_join)
- new_character.key = key //Manually transfer the key to log them in
- new_character.client?.change_view(world_view_size)
+ new_character.client?.change_view(GLOB.world_view_size)
return new_character
diff --git a/code/modules/mob/new_player/preferences_setup.dm b/code/modules/mob/new_player/preferences_setup.dm
index fb4dbac3c160..a4525e16a6c6 100644
--- a/code/modules/mob/new_player/preferences_setup.dm
+++ b/code/modules/mob/new_player/preferences_setup.dm
@@ -198,6 +198,16 @@
arm_equipment(preview_dummy, J, FALSE, FALSE, owner, show_job_gear)
+ // If the dummy was equipped with marine armor.
+ var/jacket = preview_dummy.get_item_by_slot(WEAR_JACKET)
+ if(istype(jacket, /obj/item/clothing/suit/storage/marine))
+ var/obj/item/clothing/suit/storage/marine/armor = jacket
+ // If the armor has different sprite variants.
+ if(armor.armor_variation)
+ // Set its `icon_state` to the style the player picked as their 'Preferred Armor'.
+ armor.set_armor_style(preferred_armor)
+ armor.update_icon(preview_dummy)
+
if(isnull(preview_front))
preview_front = new()
owner.add_to_screen(preview_front)
@@ -237,9 +247,9 @@
if(JOB_SQUAD_TEAM_LEADER)
return /datum/equipment_preset/uscm/tl_equipped
if(JOB_CO)
- if(length(RoleAuthority.roles_whitelist))
- var/datum/job/J = RoleAuthority.roles_by_name[JOB_CO]
- return J.gear_preset_whitelist["[JOB_CO][J.get_whitelist_status(RoleAuthority.roles_whitelist, owner)]"]
+ if(length(GLOB.RoleAuthority.roles_whitelist))
+ var/datum/job/J = GLOB.RoleAuthority.roles_by_name[JOB_CO]
+ return J.gear_preset_whitelist["[JOB_CO][J.get_whitelist_status(GLOB.RoleAuthority.roles_whitelist, owner)]"]
return /datum/equipment_preset/uscm_ship/commander
if(JOB_SO)
return /datum/equipment_preset/uscm_ship/so
@@ -258,9 +268,9 @@
if(JOB_COMBAT_REPORTER)
return /datum/equipment_preset/uscm_ship/reporter
if(JOB_SYNTH)
- if(length(RoleAuthority.roles_whitelist))
- var/datum/job/J = RoleAuthority.roles_by_name[JOB_SYNTH]
- return J.gear_preset_whitelist["[JOB_SYNTH][J.get_whitelist_status(RoleAuthority.roles_whitelist, owner)]"]
+ if(length(GLOB.RoleAuthority.roles_whitelist))
+ var/datum/job/J = GLOB.RoleAuthority.roles_by_name[JOB_SYNTH]
+ return J.gear_preset_whitelist["[JOB_SYNTH][J.get_whitelist_status(GLOB.RoleAuthority.roles_whitelist, owner)]"]
return /datum/equipment_preset/synth/uscm
if(JOB_WORKING_JOE)
return /datum/equipment_preset/synth/working_joe
@@ -307,9 +317,9 @@
return pick(SSmapping.configs[GROUND_MAP].CO_survivor_types)
return /datum/equipment_preset/uscm_ship/commander
if(JOB_PREDATOR)
- if(length(RoleAuthority.roles_whitelist))
- var/datum/job/J = RoleAuthority.roles_by_name[JOB_PREDATOR]
- return J.gear_preset_whitelist["[JOB_PREDATOR][J.get_whitelist_status(RoleAuthority.roles_whitelist, owner)]"]
+ if(length(GLOB.RoleAuthority.roles_whitelist))
+ var/datum/job/J = GLOB.RoleAuthority.roles_by_name[JOB_PREDATOR]
+ return J.gear_preset_whitelist["[JOB_PREDATOR][J.get_whitelist_status(GLOB.RoleAuthority.roles_whitelist, owner)]"]
return /datum/equipment_preset/yautja/blooded
return /datum/equipment_preset/uscm/private_equipped
diff --git a/code/modules/mob/new_player/sprite_accessories/hair.dm b/code/modules/mob/new_player/sprite_accessories/hair.dm
index 0a112cadb11b..558884f26ff0 100644
--- a/code/modules/mob/new_player/sprite_accessories/hair.dm
+++ b/code/modules/mob/new_player/sprite_accessories/hair.dm
@@ -734,3 +734,29 @@
/datum/sprite_accessory/hair/croft
name = "Croft"
icon_state = "hair_croft"
+
+/datum/sprite_accessory/hair/aviator
+ name = "Aviator"
+ icon_state = "hair_aviator"
+
+/datum/sprite_accessory/hair/gantleponytail
+ name = "Gentle Ponytail"
+ icon_state = "hair_gantleponytail"
+ gender = FEMALE
+
+/datum/sprite_accessory/hair/edgar
+ name = "Edgar"
+ icon_state = "hair_edgar"
+
+/datum/sprite_accessory/hair/emobun
+ name = "Emo Little Bun"
+ icon_state = "hair_emobun"
+
+/datum/sprite_accessory/hair/taper
+ name = "Taper"
+ icon_state = "hair_taper"
+
+/datum/sprite_accessory/hair/gentlebraid
+ name = "Gentle Braid"
+ icon_state = "hair_braid3"
+ gender = FEMALE
diff --git a/code/modules/mob/say.dm b/code/modules/mob/say.dm
index 8cd5b148a161..032888f26709 100644
--- a/code/modules/mob/say.dm
+++ b/code/modules/mob/say.dm
@@ -66,7 +66,7 @@
return
if(!src.client.admin_holder || !(client.admin_holder.rights & R_MOD))
- if(!dsay_allowed)
+ if(!GLOB.dsay_allowed)
to_chat(src, SPAN_DANGER("Deadchat is globally muted"))
return
@@ -174,7 +174,7 @@ for it but just ignore it.
if(length(message) >= 2)
var/channel_prefix = copytext(message, 1 ,3)
- return department_radio_keys[channel_prefix]
+ return GLOB.department_radio_keys[channel_prefix]
return null
diff --git a/code/modules/mob/transform_procs.dm b/code/modules/mob/transform_procs.dm
index dcb478d0fc7c..6dda93e4d9c2 100644
--- a/code/modules/mob/transform_procs.dm
+++ b/code/modules/mob/transform_procs.dm
@@ -7,8 +7,8 @@
drop_inv_item_on_ground(W)
regenerate_icons()
monkeyizing = 1
- canmove = 0
- stunned = 1
+ anchored = TRUE
+ ADD_TRAIT(src, TRAIT_INCAPACITATED, "Terminal Monkeyziation")
icon = null
invisibility = 101
for(var/t in limbs)
@@ -68,7 +68,7 @@
for(var/obj/item/W in src)
drop_inv_item_on_ground(W)
monkeyizing = 1
- canmove = 0
+ ADD_TRAIT(src, TRAIT_INCAPACITATED, "Terminal Monkeyziation")
icon = null
invisibility = 101
return ..()
@@ -85,7 +85,7 @@
drop_inv_item_on_ground(W)
regenerate_icons()
monkeyizing = 1
- canmove = 0
+ ADD_TRAIT(src, TRAIT_INCAPACITATED, "Terminal Monkeyziation")
icon = null
invisibility = 101
for(var/t in limbs)
@@ -108,7 +108,7 @@
O.mind.original = O
else
O.key = key
- if(O.client) O.client.change_view(world_view_size)
+ if(O.client) O.client.change_view(GLOB.world_view_size)
O.forceMove(loc)
O.job = "Cyborg"
@@ -131,7 +131,7 @@
drop_inv_item_on_ground(W)
regenerate_icons()
monkeyizing = 1
- canmove = 0
+ ADD_TRAIT(src, TRAIT_INCAPACITATED, "Terminal Monkeyziation")
icon = null
invisibility = 101
for(var/t in limbs)
@@ -180,34 +180,12 @@
new_xeno.a_intent = INTENT_HARM
new_xeno.key = key
- if(new_xeno.client) new_xeno.client.change_view(world_view_size)
+ if(new_xeno.client) new_xeno.client.change_view(GLOB.world_view_size)
to_chat(new_xeno, "You are now an alien.")
qdel(src)
return
-/mob/living/carbon/human/proc/corgize()
- if (monkeyizing)
- return
- for(var/obj/item/W in src)
- drop_inv_item_on_ground(W)
- regenerate_icons()
- monkeyizing = 1
- canmove = 0
- icon = null
- invisibility = 101
- for(var/t in limbs) //this really should not be necessary
- qdel(t)
-
- var/mob/living/simple_animal/corgi/new_corgi = new /mob/living/simple_animal/corgi (loc)
- new_corgi.a_intent = INTENT_HARM
- new_corgi.key = key
- if(new_corgi.client) new_corgi.client.change_view(world_view_size)
-
- to_chat(new_corgi, "You are now a Corgi. Yap Yap!")
- qdel(src)
- return
-
/mob/living/carbon/human/Animalize()
var/list/mobtypes = typesof(/mob/living/simple_animal)
@@ -224,7 +202,7 @@
regenerate_icons()
monkeyizing = 1
- canmove = 0
+ ADD_TRAIT(src, TRAIT_INCAPACITATED, "Terminal Monkeyziation")
icon = null
invisibility = 101
@@ -234,7 +212,7 @@
var/mob/new_mob = new mobpath(src.loc)
new_mob.key = key
- if(new_mob.client) new_mob.client.change_view(world_view_size)
+ if(new_mob.client) new_mob.client.change_view(GLOB.world_view_size)
new_mob.a_intent = INTENT_HARM
@@ -254,7 +232,7 @@
var/mob/new_mob = new mobpath(src.loc)
new_mob.key = key
- if(new_mob.client) new_mob.client.change_view(world_view_size)
+ if(new_mob.client) new_mob.client.change_view(GLOB.world_view_size)
new_mob.a_intent = INTENT_HARM
to_chat(new_mob, "You feel more... animalistic")
diff --git a/code/modules/movement/launching/launching.dm b/code/modules/movement/launching/launching.dm
index 96db667fe2ff..f72a7c773490 100644
--- a/code/modules/movement/launching/launching.dm
+++ b/code/modules/movement/launching/launching.dm
@@ -120,7 +120,7 @@
return TRUE
// Proc for throwing items (should only really be used for throw)
-/atom/movable/proc/throw_atom(atom/target, range, speed = 0, atom/thrower, spin, launch_type = NORMAL_LAUNCH, pass_flags = NO_FLAGS)
+/atom/movable/proc/throw_atom(atom/target, range, speed = 0, atom/thrower, spin, launch_type = NORMAL_LAUNCH, pass_flags = NO_FLAGS, list/end_throw_callbacks, list/collision_callbacks)
var/temp_pass_flags = pass_flags
switch (launch_type)
if (NORMAL_LAUNCH)
@@ -135,6 +135,10 @@
LM.speed = speed
LM.thrower = thrower
LM.spin = spin
+ if(end_throw_callbacks)
+ LM.end_throw_callbacks = end_throw_callbacks
+ if(collision_callbacks)
+ LM.collision_callbacks = collision_callbacks
if(SEND_SIGNAL(src, COMSIG_MOVABLE_PRE_LAUNCH, LM) & COMPONENT_LAUNCH_CANCEL)
return
diff --git a/code/modules/nano/nanomapgen.dm b/code/modules/nano/nanomapgen.dm
deleted file mode 100644
index 749a07feb311..000000000000
--- a/code/modules/nano/nanomapgen.dm
+++ /dev/null
@@ -1,90 +0,0 @@
-// This file is a modified version of https://raw2.github.com/Baystation12/OldCode-BS12/master/code/TakePicture.dm
-
-#define NANOMAP_ICON_SIZE 4
-#define NANOMAP_MAX_ICON_DIMENSION 1024
-
-#define NANOMAP_TILES_PER_IMAGE (NANOMAP_MAX_ICON_DIMENSION / NANOMAP_ICON_SIZE)
-
-#define NANOMAP_TERMINALERR 5
-#define NANOMAP_INPROGRESS 2
-#define NANOMAP_BADOUTPUT 2
-#define NANOMAP_SUCCESS 1
-#define NANOMAP_WATCHDOGSUCCESS 4
-#define NANOMAP_WATCHDOGTERMINATE 3
-
-
-//Call these procs to dump your world to a series of image files (!!)
-//NOTE: Does not explicitly support non 32x32 icons or stuff with large pixel_* values, so don't blame me if it doesn't work perfectly
-
-/client/proc/nanomapgen_DumpImage()
- set name = "Generate NanoUI Map"
- set category = "Debug"
-
- if(admin_holder)
- nanomapgen_DumpTile(1, 1, text2num(input(usr,"Enter the Z level to generate")))
-
-/client/proc/nanomapgen_DumpTile(startX = 1, startY = 1, currentZ = 1, endX = -1, endY = -1)
-
- if (endX < 0 || endX > world.maxx)
- endX = world.maxx
-
- if (endY < 0 || endY > world.maxy)
- endY = world.maxy
-
- if (currentZ < 0 || currentZ > world.maxz)
- to_chat(usr, "NanoMapGen: ERROR: currentZ ([currentZ]) must be between 1 and [world.maxz]")
-
- sleep(3)
- return NANOMAP_TERMINALERR
-
- if (startX > endX)
- to_chat(usr, "NanoMapGen: ERROR: startX ([startX]) cannot be greater than endX ([endX])")
-
- sleep(3)
- return NANOMAP_TERMINALERR
-
- if (startY > endX)
- to_chat(usr, "NanoMapGen: ERROR: startY ([startY]) cannot be greater than endY ([endY])")
- sleep(3)
- return NANOMAP_TERMINALERR
-
- var/icon/Tile = icon(file("nano/mapbase1024.png"))
- if (Tile.Width() != NANOMAP_MAX_ICON_DIMENSION || Tile.Height() != NANOMAP_MAX_ICON_DIMENSION)
- world.log << "NanoMapGen: ERROR: BASE IMAGE DIMENSIONS ARE NOT [NANOMAP_MAX_ICON_DIMENSION]x[NANOMAP_MAX_ICON_DIMENSION]"
- sleep(3)
- return NANOMAP_TERMINALERR
-
- world.log << "NanoMapGen: GENERATE MAP ([startX],[startY],[currentZ]) to ([endX],[endY],[currentZ])"
- to_chat(usr, "NanoMapGen: GENERATE MAP ([startX],[startY],[currentZ]) to ([endX],[endY],[currentZ])")
-
- var/count = 0;
- for(var/WorldX = startX, WorldX <= endX, WorldX++)
- for(var/WorldY = startY, WorldY <= endY, WorldY++)
-
- var/atom/Turf = locate(WorldX, WorldY, currentZ)
-
- var/icon/TurfIcon = new(Turf.icon, Turf.icon_state)
- TurfIcon.Scale(NANOMAP_ICON_SIZE, NANOMAP_ICON_SIZE)
-
- Tile.Blend(TurfIcon, ICON_OVERLAY, ((WorldX - 1) * NANOMAP_ICON_SIZE), ((WorldY - 1) * NANOMAP_ICON_SIZE))
-
- count++
-
- if (count % 8000 == 0)
- world.log << "NanoMapGen: [count] tiles done"
- sleep(1)
-
- var/mapFilename = "nanomap_z[currentZ]-new.png"
-
- world.log << "NanoMapGen: sending [mapFilename] to client"
-
- usr << browse(Tile, "window=picture;file=[mapFilename];display=0")
-
- world.log << "NanoMapGen: Done."
-
- to_chat(usr, "NanoMapGen: Done. File [mapFilename] uploaded to your cache.")
-
- if (Tile.Width() != NANOMAP_MAX_ICON_DIMENSION || Tile.Height() != NANOMAP_MAX_ICON_DIMENSION)
- return NANOMAP_BADOUTPUT
-
- return NANOMAP_SUCCESS
diff --git a/code/modules/nano/nanoui.dm b/code/modules/nano/nanoui.dm
index ce01931f5daf..46a30b313bb8 100644
--- a/code/modules/nano/nanoui.dm
+++ b/code/modules/nano/nanoui.dm
@@ -105,7 +105,7 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/Destroy()
if(user)
- nanomanager.ui_closed(src)
+ SSnano.nanomanager.ui_closed(src)
close_browser(user, "[window_id]")
user = null
@@ -177,9 +177,13 @@ nanoui is used to open and update nano browser uis
close()
return
+ var/mob/living/living_user
+ if(isliving(user))
+ living_user = user
+
if ((allowed_user_stat > -1) && (user.stat > allowed_user_stat))
set_status(STATUS_DISABLED, push_update) // no updates, completely disabled (red visibility)
- else if (user.is_mob_restrained() || user.lying)
+ else if (user.is_mob_restrained() || (living_user && living_user.body_position == LYING_DOWN))
set_status(STATUS_UPDATE, push_update) // update only (orange visibility)
else if (!(src_object in view(4, user))) // If the src object is not in visable, set status to 0
set_status(STATUS_DISABLED, push_update) // interactive (green visibility)
@@ -440,7 +444,7 @@ nanoui is used to open and update nano browser uis
winset(user, "mapwindow.map", "focus=true") // return keyboard focus to map
on_close_winset()
//onclose(user, window_id)
- nanomanager.ui_opened(src)
+ SSnano.nanomanager.ui_opened(src)
/**
* Close this UI
@@ -449,7 +453,7 @@ nanoui is used to open and update nano browser uis
*/
/datum/nanoui/proc/close()
is_auto_updating = 0
- nanomanager.ui_closed(src)
+ SSnano.nanomanager.ui_closed(src)
close_browser(user, "[window_id]")
qdel(src)
@@ -516,7 +520,7 @@ nanoui is used to open and update nano browser uis
map_update = 1
if ((src_object && src_object.Topic(href, href_list)) || map_update)
- nanomanager.update_uis(src_object) // update all UIs attached to src_object
+ SSnano.nanomanager.update_uis(src_object) // update all UIs attached to src_object
/**
* Process this UI, updating the entire UI or just the status (aka visibility)
diff --git a/code/modules/objectives/data_retrieval.dm b/code/modules/objectives/data_retrieval.dm
index 955d2cc8e63e..f66c578f48fb 100644
--- a/code/modules/objectives/data_retrieval.dm
+++ b/code/modules/objectives/data_retrieval.dm
@@ -14,7 +14,7 @@
/datum/cm_objective/retrieve_data/New()
. = ..()
- decryption_password = "[pick(alphabet_uppercase)][rand(100,999)][pick(alphabet_uppercase)][rand(10,99)]"
+ decryption_password = "[pick(GLOB.alphabet_uppercase)][rand(100,999)][pick(GLOB.alphabet_uppercase)][rand(10,99)]"
/datum/cm_objective/retrieve_data/pre_round_start()
SSobjectives.statistics["data_retrieval_total_instances"]++
@@ -177,6 +177,8 @@
var/datum/cm_objective/retrieve_item/document/retrieve_objective
var/display_color = "white"
var/disk_color = "White"
+ ground_offset_x = 9
+ ground_offset_y = 8
/obj/item/disk/objective/Initialize(mapload, ...)
. = ..()
@@ -206,12 +208,10 @@
disk_color = "Bloodied blue"
display_color = "#5296e3"
- label = "[pick(greek_letters)]-[rand(100,999)]"
+ label = "[pick(GLOB.greek_letters)]-[rand(100,999)]"
name = "[disk_color] computer disk [label]"
objective = new /datum/cm_objective/retrieve_data/disk(src)
retrieve_objective = new /datum/cm_objective/retrieve_item/document(src)
- pixel_y = rand(-8, 8)
- pixel_x = rand(-9, 9)
w_class = SIZE_TINY
/obj/item/disk/objective/Destroy()
@@ -237,7 +237,7 @@
/obj/structure/machinery/computer/objective/Initialize()
. = ..()
- label = "[pick(greek_letters)]-[rand(100,999)]"
+ label = "[pick(GLOB.greek_letters)]-[rand(100,999)]"
name = "data terminal [label]"
objective = new /datum/cm_objective/retrieve_data/terminal(src)
diff --git a/code/modules/objectives/documents.dm b/code/modules/objectives/documents.dm
index 14bef02245f0..8562f1985e7f 100644
--- a/code/modules/objectives/documents.dm
+++ b/code/modules/objectives/documents.dm
@@ -122,17 +122,17 @@
unacidable = TRUE
indestructible = 1
is_objective = TRUE
+ ground_offset_x = 9
+ ground_offset_y = 8
var/label // label on the document
var/renamed = FALSE //Once someone reads a document the item gets renamed based on the objective they are linked to)
/obj/item/document_objective/Initialize(mapload, ...)
. = ..()
- label = "[pick(alphabet_uppercase)][rand(100,999)]"
+ label = "[pick(GLOB.alphabet_uppercase)][rand(100,999)]"
objective = new objective_type(src)
retrieve_objective = new /datum/cm_objective/retrieve_item/document(src)
LAZYADD(objective.enables_objectives, retrieve_objective)
- pixel_y = rand(-8, 8)
- pixel_x = rand(-9, 9)
/obj/item/document_objective/Destroy()
qdel(objective)
diff --git a/code/modules/objectives/objective_memory_storage.dm b/code/modules/objectives/objective_memory_storage.dm
index 08dfc8cdb2c2..161c78d4d1ba 100644
--- a/code/modules/objectives/objective_memory_storage.dm
+++ b/code/modules/objectives/objective_memory_storage.dm
@@ -77,26 +77,26 @@
/datum/objective_memory_storage/proc/synchronize_objectives()
clean_objectives()
- if(!intel_system || !intel_system.oms)
+ if(!GLOB.intel_system || !GLOB.intel_system.oms)
return
- intel_system.oms.clean_objectives()
+ GLOB.intel_system.oms.clean_objectives()
- for(var/datum/cm_objective/O in intel_system.oms.folders)
+ for(var/datum/cm_objective/O in GLOB.intel_system.oms.folders)
addToListNoDupe(folders, O)
- for(var/datum/cm_objective/O in intel_system.oms.progress_reports)
+ for(var/datum/cm_objective/O in GLOB.intel_system.oms.progress_reports)
addToListNoDupe(progress_reports, O)
- for(var/datum/cm_objective/O in intel_system.oms.technical_manuals)
+ for(var/datum/cm_objective/O in GLOB.intel_system.oms.technical_manuals)
addToListNoDupe(technical_manuals, O)
- for(var/datum/cm_objective/O in intel_system.oms.terminals)
+ for(var/datum/cm_objective/O in GLOB.intel_system.oms.terminals)
addToListNoDupe(terminals, O)
- for(var/datum/cm_objective/O in intel_system.oms.disks)
+ for(var/datum/cm_objective/O in GLOB.intel_system.oms.disks)
addToListNoDupe(disks, O)
- for(var/datum/cm_objective/O in intel_system.oms.retrieve_items)
+ for(var/datum/cm_objective/O in GLOB.intel_system.oms.retrieve_items)
addToListNoDupe(retrieve_items, O)
- for(var/datum/cm_objective/O in intel_system.oms.other)
+ for(var/datum/cm_objective/O in GLOB.intel_system.oms.other)
addToListNoDupe(other, O)
-var/global/datum/intel_system/intel_system = new()
+GLOBAL_DATUM_INIT(intel_system, /datum/intel_system, new())
/datum/intel_system
var/datum/objective_memory_storage/oms = new()
@@ -127,7 +127,7 @@ var/global/datum/intel_system/intel_system = new()
if(!powered())
to_chat(user, SPAN_WARNING("This computer has no power!"))
return FALSE
- if(!intel_system)
+ if(!GLOB.intel_system)
to_chat(user, SPAN_WARNING("The computer doesn't seem to be connected to anything..."))
return FALSE
if(user.action_busy)
@@ -197,9 +197,9 @@ var/global/datum/intel_system/intel_system = new()
return TRUE
/obj/structure/machinery/computer/intel/proc/transfer_intel(mob/living/user, datum/cm_objective/O)
- if(!intel_system || !intel_system.oms)
+ if(!GLOB.intel_system || !GLOB.intel_system.oms)
return 0
- if(intel_system.oms.has_objective(O))
+ if(GLOB.intel_system.oms.has_objective(O))
return 0
if(user.action_busy)
return 0
@@ -215,7 +215,7 @@ var/global/datum/intel_system/intel_system = new()
return -1
to_chat(user, SPAN_NOTICE("...something about \"[clue]\"..."))
- intel_system.store_single_objective(O)
+ GLOB.intel_system.store_single_objective(O)
return 1
// --------------------------------------------
@@ -236,7 +236,7 @@ var/global/datum/intel_system/intel_system = new()
if(!powered())
to_chat(user, SPAN_WARNING("This computer has no power!"))
return FALSE
- if(!intel_system)
+ if(!GLOB.intel_system)
to_chat(user, SPAN_WARNING("The computer doesn't seem to be connected to anything..."))
return FALSE
if(user.action_busy)
diff --git a/code/modules/objectives/power_objectives.dm b/code/modules/objectives/power_objectives.dm
index ecd192caa32e..8f18af9337ea 100644
--- a/code/modules/objectives/power_objectives.dm
+++ b/code/modules/objectives/power_objectives.dm
@@ -16,7 +16,7 @@
/datum/cm_objective/power/pre_round_start()
if(uses_smes)
- for(var/obj/structure/machinery/power/smes/colony_smes in machines)
+ for(var/obj/structure/machinery/power/smes/colony_smes in GLOB.machines)
if(!is_ground_level(colony_smes.loc.z))
continue
LAZYADD(power_objects, colony_smes)
diff --git a/code/modules/organs/limbs.dm b/code/modules/organs/limbs.dm
index 58d0a4780681..949104c5d673 100644
--- a/code/modules/organs/limbs.dm
+++ b/code/modules/organs/limbs.dm
@@ -171,6 +171,7 @@
*/
/obj/limb/emp_act(severity)
+ . = ..()
if(!(status & (LIMB_ROBOT|LIMB_SYNTHSKIN))) //meatbags do not care about EMP
return
var/probability = 30
@@ -546,6 +547,7 @@ This function completely restores a damaged organ to perfect condition.
/obj/limb/proc/remove_all_bleeding(external = FALSE, internal = FALSE)
+ SEND_SIGNAL(src, COMSIG_LIMB_STOP_BLEEDING, external, internal)
if(external)
for(var/datum/effects/bleeding/external/B in bleeding_effects_list)
qdel(B)
@@ -944,7 +946,7 @@ This function completely restores a damaged organ to perfect condition.
if(organ)
//Throw organs around
- var/lol = pick(cardinal)
+ var/lol = pick(GLOB.cardinals)
step(organ,lol)
owner.update_body() //Among other things, this calls update_icon() and updates our visuals.
@@ -953,7 +955,13 @@ This function completely restores a damaged organ to perfect condition.
// OK so maybe your limb just flew off, but if it was attached to a pair of cuffs then hooray! Freedom!
release_restraints()
- if(vital) owner.death(cause)
+ if(vital)
+ var/mob/caused_mob
+ if(istype(cause, /mob))
+ caused_mob = cause
+ if(!istype(cause, /datum/cause_data))
+ cause = create_cause_data("lost vital limb", caused_mob)
+ owner.death(cause)
/*
HELPERS
diff --git a/code/modules/paperwork/clipboard.dm b/code/modules/paperwork/clipboard.dm
index f38f4505796f..9f00aa3a659a 100644
--- a/code/modules/paperwork/clipboard.dm
+++ b/code/modules/paperwork/clipboard.dm
@@ -50,7 +50,7 @@
W.forceMove(src)
if(istype(W, /obj/item/paper))
toppaper = W
- to_chat(user, SPAN_NOTICE("You clip the [W] onto \the [src]."))
+ to_chat(user, SPAN_NOTICE("You clip [W] onto [src]."))
update_icon()
else if(istype(toppaper) && HAS_TRAIT(W, TRAIT_TOOL_PEN))
diff --git a/code/modules/paperwork/folders.dm b/code/modules/paperwork/folders.dm
index 478dcc0a8e04..ad9da68a591d 100644
--- a/code/modules/paperwork/folders.dm
+++ b/code/modules/paperwork/folders.dm
@@ -48,7 +48,7 @@
/obj/item/folder/attackby(obj/item/W as obj, mob/user as mob)
if(istype(W, /obj/item/paper) || istype(W, /obj/item/photo) || istype(W, /obj/item/paper_bundle))
if(user.drop_inv_item_to_loc(W, src))
- to_chat(user, SPAN_NOTICE("You put the [W] into \the [src]."))
+ to_chat(user, SPAN_NOTICE("You put [W] into [src]."))
update_icon()
else if(HAS_TRAIT(W, TRAIT_TOOL_PEN))
var/n_name = strip_html(input(usr, "What would you like to label the folder?", "Folder Labelling", null) as text)
diff --git a/code/modules/paperwork/paper.dm b/code/modules/paperwork/paper.dm
index 71d1090b20e0..8220f60e77ed 100644
--- a/code/modules/paperwork/paper.dm
+++ b/code/modules/paperwork/paper.dm
@@ -19,6 +19,8 @@
flags_equip_slot = SLOT_HEAD
flags_armor_protection = BODY_FLAG_HEAD
attack_verb = list("bapped")
+ ground_offset_x = 9
+ ground_offset_y = 8
var/info //What's actually written on the paper.
var/info_links //A different version of the paper which includes html links at fields and EOF
@@ -42,8 +44,6 @@
/obj/item/paper/Initialize(mapload, photo_list)
. = ..()
- pixel_y = rand(-8, 8)
- pixel_x = rand(-9, 9)
stamps = ""
src.photo_list = photo_list
@@ -75,26 +75,25 @@
/obj/item/paper/get_examine_text(mob/user)
. = ..()
- if(in_range(user, src) || istype(user, /mob/dead/observer))
+ if(in_range(user, src) || isobserver(user))
if(!(istype(user, /mob/dead/observer) || istype(user, /mob/living/carbon/human) || isRemoteControlling(user)))
// Show scrambled paper if they aren't a ghost, human, or silicone.
- if(photo_list)
- for(var/photo in photo_list)
- user << browse_rsc(photo_list[photo], photo)
- show_browser(user, "[stars(info)][stamps]", name, name, "size=650x700")
- onclose(user, name)
+ read_paper(user,scramble = TRUE)
else
read_paper(user)
else
. += SPAN_NOTICE("It is too far away.")
-/obj/item/paper/proc/read_paper(mob/user)
+/obj/item/paper/proc/read_paper(mob/user, scramble = FALSE)
var/datum/asset/asset_datum = get_asset_datum(/datum/asset/simple/paper)
asset_datum.send(user)
if(photo_list)
for(var/photo in photo_list)
user << browse_rsc(photo_list[photo], photo)
- show_browser(user, "[info][stamps]", name, name, "size=650x700")
+ var/paper_info = info
+ if(scramble)
+ paper_info = stars_decode_html(info)
+ show_browser(user, "[paper_info][stamps]", name, name, "size=650x700")
onclose(user, name)
/obj/item/paper/verb/rename()
@@ -227,10 +226,10 @@
t = replacetext(t, "\[large\]", "")
t = replacetext(t, "\[/large\]", "")
t = replacetext(t, "\[sign\]", "[user ? user.real_name : "Anonymous"]")
- t = replacetext(t, "\[date\]", "[time2text(REALTIMEOFDAY, "Day DD Month [game_year]")]")
- t = replacetext(t, "\[shortdate\]", "[time2text(REALTIMEOFDAY, "DD/MM/[game_year]")]")
+ t = replacetext(t, "\[date\]", "[time2text(REALTIMEOFDAY, "Day DD Month [GLOB.game_year]")]")
+ t = replacetext(t, "\[shortdate\]", "[time2text(REALTIMEOFDAY, "DD/MM/[GLOB.game_year]")]")
t = replacetext(t, "\[time\]", "[worldtime2text("hh:mm")]")
- t = replacetext(t, "\[date+time\]", "[worldtime2text("hh:mm")], [time2text(REALTIMEOFDAY, "Day DD Month [game_year]")]")
+ t = replacetext(t, "\[date+time\]", "[worldtime2text("hh:mm")], [time2text(REALTIMEOFDAY, "Day DD Month [GLOB.game_year]")]")
t = replacetext(t, "\[field\]", "")
t = replacetext(t, "\[h1\]", "
")
@@ -382,9 +381,6 @@
/obj/item/paper/attackby(obj/item/P, mob/user)
..()
- var/clown = 0
- if(user.mind && (user.job == "Clown"))
- clown = 1
if(istype(P, /obj/item/paper) || istype(P, /obj/item/photo))
if (istype(P, /obj/item/paper/carbon))
@@ -424,6 +420,7 @@
return
stamps += (stamps=="" ? "" : " ") + "This paper has been stamped with the [P.name]."
+ playsound(src, 'sound/effects/alien_footstep_medium3.ogg', 20, TRUE, 6)
var/image/stampoverlay = image('icons/obj/items/paper.dmi')
var/x
@@ -439,11 +436,6 @@
stampoverlay.pixel_x = x
stampoverlay.pixel_y = y
- if(istype(P, /obj/item/tool/stamp/clown))
- if(!clown)
- to_chat(user, SPAN_NOTICE("You are totally unable to use the stamp. HONK!"))
- return
-
if(!ico)
ico = new
ico += "paper_[P.icon_state]"
@@ -576,6 +568,10 @@
name = "crumpled note"
info = "there is cotten candy in the walls"
+/obj/item/paper/bigred/lambda
+ name = "ripped diary entry"
+ info = "Director Smith's Diary\nEntry Date: 15 December 2181\nToday, I've felt true progress! The XX-121 reproduction program is in full effect, and Administrator Cooper have given us the all clear to continue producing specimens. To think that all this is coming from just that first specimen, a single 'Queen' form... It's grown to almost 5 meters tall and shows no signs of ceasing egg production! These creatures will be the next Synthetic of our time, we'll show those Seegson bastards."
+
/obj/item/paper/bigred/union
name = "Shaft miners union"
info = "Today we have had enough of being underpaid and treated like shit for not reaching the higher up's unreasonable quotas of ore. They say this place has a \"sea of valuable ores,\" yet we have been mining for years and are yet to find a single diamond. We have had it, enough is enough. They think they can control everything we do, they thought wrong! We, the oppressed workers, shall rise up against the capitalist dogs in a mutiny and take back our pay by force. \n If they send their dogs here to bust us, we will kill each and every single one of them."
@@ -673,34 +669,34 @@
if(!C)
var/random_chem
if(tier)
- random_chem = pick(chemical_gen_classes_list[tier])
+ random_chem = pick(GLOB.chemical_gen_classes_list[tier])
else
if(note_type == "test")
- random_chem = pick(chemical_gen_classes_list["T4"])
+ random_chem = pick(GLOB.chemical_gen_classes_list["T4"])
else
- random_chem = pick( prob(55);pick(chemical_gen_classes_list["T2"]),
- prob(30);pick(chemical_gen_classes_list["T3"]),
- prob(15);pick(chemical_gen_classes_list["T4"]))
+ random_chem = pick( prob(55);pick(GLOB.chemical_gen_classes_list["T2"]),
+ prob(30);pick(GLOB.chemical_gen_classes_list["T3"]),
+ prob(15);pick(GLOB.chemical_gen_classes_list["T4"]))
if(!random_chem)
- random_chem = pick(chemical_gen_classes_list["T1"])
- C = chemical_reagents_list["[random_chem]"]
+ random_chem = pick(GLOB.chemical_gen_classes_list["T1"])
+ C = GLOB.chemical_reagents_list["[random_chem]"]
var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper)
var/txt = "
"
txt += "During experiment [pick("C","Q","V","W","X","Y","Z")][rand(100,999)][pick("a","b","c")] the theorized compound identified as [C.name], was successfully synthesized using the following formula: \n \n"
for(var/I in G.required_reagents)
- var/datum/reagent/R = chemical_reagents_list["[I]"]
+ var/datum/reagent/R = GLOB.chemical_reagents_list["[I]"]
var/U = G.required_reagents[I]
txt += " - [U] [R.name] \n"
if(G.required_catalysts && G.required_catalysts.len)
txt += " \nWhile using the following catalysts: \n \n"
for(var/I in G.required_catalysts)
- var/datum/reagent/R = chemical_reagents_list["[I]"]
+ var/datum/reagent/R = GLOB.chemical_reagents_list["[I]"]
var/U = G.required_catalysts[I]
txt += " - [U] [R.name] \n"
if(full_report)
@@ -777,16 +773,16 @@
/obj/item/paper/research_notes/unique/Initialize()
//Each one of these get a new unique chem
var/datum/reagent/generated/C = new /datum/reagent/generated
- C.id = "tau-[length(chemical_gen_classes_list["tau"])]"
+ C.id = "tau-[length(GLOB.chemical_gen_classes_list["tau"])]"
C.generate_name()
C.chemclass = CHEM_CLASS_RARE
if(gen_tier)
C.gen_tier = gen_tier
else
- C.gen_tier = chemical_data.clearance_level
+ C.gen_tier = GLOB.chemical_data.clearance_level
C.generate_stats()
- chemical_gen_classes_list["tau"] += C.id //Because each unique_vended should be unique, we do not save the chemclass anywhere but in the tau list
- chemical_reagents_list[C.id] = C
+ GLOB.chemical_gen_classes_list["tau"] += C.id //Because each unique_vended should be unique, we do not save the chemclass anywhere but in the tau list
+ GLOB.chemical_reagents_list[C.id] = C
C.generate_assoc_recipe()
data = C
msg_admin_niche("New reagent with id [C.id], name [C.name], level [C.gen_tier], generated and printed at [loc] [ADMIN_JMP(loc)].")
@@ -810,7 +806,7 @@
info += "ID:[S.name]
\n"
info += "Database Details: \n"
if(S.chemclass >= CHEM_CLASS_ULTRA)
- if(chemical_data.clearance_level >= S.gen_tier || info_only)
+ if(GLOB.chemical_data.clearance_level >= S.gen_tier || info_only)
info += "The following information relating to [S.name] is restricted with a level [S.gen_tier] clearance classification. "
info += "[S.description]\n"
info += " Overdoses at: [S.overdose] units\n"
@@ -820,7 +816,7 @@
else
info += "CLASSIFIED: Clearance level [S.gen_tier] required to read the database entry. \n"
icon_state = "paper_wy_partial_report"
- else if(S.chemclass == CHEM_CLASS_SPECIAL && !chemical_data.clearance_x_access && !info_only)
+ else if(S.chemclass == CHEM_CLASS_SPECIAL && !GLOB.chemical_data.clearance_x_access && !info_only)
info += "CLASSIFIED: Clearance level X required to read the database entry. \n"
icon_state = "paper_wy_partial_report"
else if(S.description)
@@ -832,14 +828,14 @@
else
info += "No details on this reagent could be found in the database. \n"
icon_state = "paper_wy_synthesis"
- if(S.chemclass >= CHEM_CLASS_SPECIAL && !chemical_data.chemical_identified_list[S.id] && !info_only)
+ if(S.chemclass >= CHEM_CLASS_SPECIAL && !GLOB.chemical_data.chemical_identified_list[S.id] && !info_only)
info += " Saved emission spectrum of [S.name] to the database. \n"
info += " Composition Details: \n"
- if(chemical_reactions_list[S.id])
- var/datum/chemical_reaction/C = chemical_reactions_list[S.id]
+ if(GLOB.chemical_reactions_list[S.id])
+ var/datum/chemical_reaction/C = GLOB.chemical_reactions_list[S.id]
for(var/I in C.required_reagents)
- var/datum/reagent/R = chemical_reagents_list["[I]"]
- if(R.chemclass >= CHEM_CLASS_SPECIAL && !chemical_data.chemical_identified_list[R.id] && !info_only)
+ var/datum/reagent/R = GLOB.chemical_reagents_list["[I]"]
+ if(R.chemclass >= CHEM_CLASS_SPECIAL && !GLOB.chemical_data.chemical_identified_list[R.id] && !info_only)
info += " - Unknown emission spectrum \n"
completed = FALSE
else
@@ -849,14 +845,14 @@
if(C.required_catalysts.len)
info += " Reaction would require the following catalysts: \n"
for(var/I in C.required_catalysts)
- var/datum/reagent/R = chemical_reagents_list["[I]"]
- if(R.chemclass >= CHEM_CLASS_SPECIAL && !chemical_data.chemical_identified_list[R.id] && !info_only)
+ var/datum/reagent/R = GLOB.chemical_reagents_list["[I]"]
+ if(R.chemclass >= CHEM_CLASS_SPECIAL && !GLOB.chemical_data.chemical_identified_list[R.id] && !info_only)
info += " - Unknown emission spectrum \n"
completed = FALSE
else
var/U = C.required_catalysts[I]
info += " - [U] [R.name] \n"
- else if(chemical_gen_classes_list["C1"].Find(S.id))
+ else if(GLOB.chemical_gen_classes_list["C1"].Find(S.id))
info += " - [S.name] \n"
else
info += "ERROR: Unable to analyze emission spectrum of sample." //A reaction to make this doesn't exist, so this is our IC excuse
@@ -867,7 +863,7 @@
else
if(!S.properties) //Safety for empty reagents
completed = FALSE
- if(S.chemclass == CHEM_CLASS_SPECIAL && chemical_data.clearance_x_access)
+ if(S.chemclass == CHEM_CLASS_SPECIAL && GLOB.chemical_data.clearance_x_access)
completed = TRUE
data = S
@@ -913,3 +909,14 @@
info = parsepencode(template, null, null, FALSE)
#undef MAX_FIELDS
+
+/obj/item/paper/colonial_grunts
+ icon = 'icons/obj/items/paper.dmi'
+ icon_state = "paper_stack_words"
+ name = "Colonial Space Grunts"
+ desc = "A tabletop game based around the USCM, easy to get into, simple to play, and most inportantly fun for the whole squad."
+
+/obj/item/paper/colonial_grunts/Initialize(mapload, ...)
+ . = ..()
+ info = "
"
+ update_icon()
diff --git a/code/modules/paperwork/paperbin.dm b/code/modules/paperwork/paperbin.dm
index 521045a56717..c094c8f32569 100644
--- a/code/modules/paperwork/paperbin.dm
+++ b/code/modules/paperwork/paperbin.dm
@@ -23,8 +23,7 @@
/obj/item/paper_bin/MouseDrop(atom/over_object)
if(over_object == usr && ishuman(usr) && !usr.is_mob_restrained() && !usr.stat && (loc == usr || in_range(src, usr)))
if(!usr.get_active_hand()) //if active hand is empty
- attack_hand(usr, 1, 1)
-
+ usr.put_in_hands(src)
return
/obj/item/paper_bin/attack_hand(mob/user)
@@ -57,7 +56,7 @@
P.forceMove(user.loc)
user.put_in_hands(P)
- to_chat(user, SPAN_NOTICE("You take [P] out of the [src]."))
+ to_chat(user, SPAN_NOTICE("You take [P] out of [src]."))
else
to_chat(user, SPAN_NOTICE("[src] is empty!"))
diff --git a/code/modules/paperwork/photocopier.dm b/code/modules/paperwork/photocopier.dm
index 70d6bf3898a6..b47f630974e6 100644
--- a/code/modules/paperwork/photocopier.dm
+++ b/code/modules/paperwork/photocopier.dm
@@ -82,8 +82,6 @@
p.update_icon()
p.icon_state = "paper_words"
p.name = bundle.name
- p.pixel_y = rand(-8, 8)
- p.pixel_x = rand(-9, 9)
sleep(15*j)
updateUsrDialog()
else if(href_list["remove"])
diff --git a/code/modules/paperwork/photography.dm b/code/modules/paperwork/photography.dm
index e004715f326a..40d88f684791 100644
--- a/code/modules/paperwork/photography.dm
+++ b/code/modules/paperwork/photography.dm
@@ -46,7 +46,7 @@
..()
/obj/item/photo/get_examine_text(mob/user)
- if(in_range(user, src))
+ if(in_range(user, src) || isobserver(user))
show(user)
return list(desc)
else
@@ -175,81 +175,110 @@
res.Scale(size*32, size*32)
// Initialize the photograph to black.
res.Blend("#000", ICON_OVERLAY)
+ CHECK_TICK
- var/atoms[] = list()
- for(var/turf/the_turf in turfs)
- // Add outselves to the list of stuff to draw
+ var/pixel_size = world.icon_size
+ var/radius = (size - 1) * 0.5
+ var/center_offset = radius * pixel_size + 1
+ var/x_min = center.x - radius
+ var/x_max = center.x + radius
+ var/y_min = center.y - radius
+ var/y_max = center.y + radius
+
+ var/list/atoms = list()
+ for(var/turf/the_turf as anything in turfs)
+ // Add ourselves to the list of stuff to draw
atoms.Add(the_turf);
+
// As well as anything that isn't invisible.
- for(var/atom/A in the_turf)
- if(A.invisibility) continue
- atoms.Add(A)
+ for(var/atom/cur_atom as anything in the_turf)
+ if(!cur_atom || cur_atom.invisibility)
+ continue
+ atoms.Add(cur_atom)
// Sort the atoms into their layers
var/list/sorted = sort_atoms_by_layer(atoms)
- var/center_offset = (size-1)/2 * 32 + 1
- for(var/i; i <= sorted.len; i++)
- var/atom/A = sorted[i]
- if(A)
- var/icon/IM = getFlatIcon(A)//build_composite_icon(A)
-
- // If what we got back is actually a picture, draw it.
- if(istype(IM, /icon))
- // Check if we're looking at a mob that's lying down
- if(istype(A, /mob/living))
- var/mob/living/L = A
- if(!istype(L, /mob/living/carbon/xenomorph)) //xenos don't use icon rotatin for lying.
- if(L.lying)
- // If they are, apply that effect to their picture.
- IM.BecomeLying()
- // Calculate where we are relative to the center of the photo
- var/xoff = (A.x - center.x) * 32 + center_offset
- var/yoff = (A.y - center.y) * 32 + center_offset
- if (istype(A,/atom/movable))
- xoff+=A:step_x
- yoff+=A:step_y
- res.Blend(IM, blendMode2iconMode(A.blend_mode), A.pixel_x + xoff, A.pixel_y + yoff)
+ for(var/atom/cur_atom as anything in sorted)
+ if(QDELETED(cur_atom))
+ continue
+
+ if(cur_atom.x < x_min || cur_atom.x > x_max || cur_atom.y < y_min || cur_atom.y > y_max)
+ // they managed to move out of frame with all this CHECK_TICK...
+ continue
+
+ var/icon/cur_icon = getFlatIcon(cur_atom)//build_composite_icon(cur_atom)
+
+ // If what we got back is actually a picture, draw it.
+ if(istype(cur_icon, /icon))
+ // Check if we're looking at a mob that's lying down
+ if(istype(cur_atom, /mob/living))
+ var/mob/living/cur_mob = cur_atom
+ if(!isxeno(cur_mob) && cur_mob.body_position == LYING_DOWN) //xenos don't use icon rotatin for lying.
+ cur_icon.BecomeLying()
+
+ // Calculate where we are relative to the center of the photo
+ var/xoff = (cur_atom.x - center.x) * pixel_size + center_offset
+ var/yoff = (cur_atom.y - center.y) * pixel_size + center_offset
+ if(istype(cur_atom, /atom/movable))
+ xoff += cur_atom:step_x
+ yoff += cur_atom:step_y
+ res.Blend(cur_icon, blendMode2iconMode(cur_atom.blend_mode), cur_atom.pixel_x + xoff, cur_atom.pixel_y + yoff)
+
+ CHECK_TICK
// Lastly, render any contained effects on top.
for(var/turf/the_turf as anything in turfs)
// Calculate where we are relative to the center of the photo
- var/xoff = (the_turf.x - center.x) * 32 + center_offset
- var/yoff = (the_turf.y - center.y) * 32 + center_offset
- var/image/IM = getFlatIcon(the_turf.loc)
- if(IM)
- res.Blend(IM, blendMode2iconMode(the_turf.blend_mode),xoff,yoff)
+ var/xoff = (the_turf.x - center.x) * pixel_size + center_offset
+ var/yoff = (the_turf.y - center.y) * pixel_size + center_offset
+ var/image/cur_icon = getFlatIcon(the_turf.loc)
+ CHECK_TICK
+
+ if(cur_icon)
+ res.Blend(cur_icon, blendMode2iconMode(the_turf.blend_mode), xoff, yoff)
+ CHECK_TICK
return res
+/obj/item/device/camera/proc/get_mob_descriptions(turf/the_turf, existing_descripion)
+ var/mob_detail = existing_descripion
+ for(var/mob/living/carbon/cur_carbon in the_turf)
+ if(cur_carbon.invisibility)
+ continue
-/obj/item/device/camera/proc/get_mobs(turf/the_turf as turf)
- var/mob_detail
- for(var/mob/living/carbon/A in the_turf)
- if(A.invisibility) continue
var/holding = null
- if(A.l_hand || A.r_hand)
- if(A.l_hand) holding = "They are holding \a [A.l_hand]"
- if(A.r_hand)
+ if(cur_carbon.l_hand || cur_carbon.r_hand)
+ if(cur_carbon.l_hand)
+ holding = "They are holding \a [cur_carbon.l_hand]"
+ if(cur_carbon.r_hand)
if(holding)
- holding += " and \a [A.r_hand]"
+ holding += " and \a [cur_carbon.r_hand]"
else
- holding = "They are holding \a [A.r_hand]"
+ holding = "They are holding \a [cur_carbon.r_hand]"
+
+ var/hurt = ""
+ if(cur_carbon.health < 75)
+ hurt = prob(25) ? " - they look hurt" : " - [cur_carbon] looks hurt"
if(!mob_detail)
- mob_detail = "You can see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]. "
+ mob_detail = "You can see [cur_carbon] in the photo[hurt].[holding ? " [holding]" : "."]."
else
- mob_detail += "You can also see [A] on the photo[A:health < 75 ? " - [A] looks hurt":""].[holding ? " [holding]":"."]."
+ mob_detail += " You [prob(50) ? "can" : "also"] see [cur_carbon] in the photo[hurt].[holding ? " [holding]" : "."]."
return mob_detail
/obj/item/device/camera/afterattack(atom/target as mob|obj|turf|area, mob/user as mob, flag)
- if(!on || !pictures_left || ismob(target.loc) || isstorage(target.loc)) return
- if(user.contains(target) || istype(target, /atom/movable/screen)) return
- captureimage(target, user, flag)
+ if(!on || !pictures_left || ismob(target.loc) || isstorage(target.loc))
+ return
+ if(user.contains(target) || istype(target, /atom/movable/screen))
+ return
playsound(loc, pick('sound/items/polaroid1.ogg', 'sound/items/polaroid2.ogg'), 15, 1)
pictures_left--
desc = "A polaroid camera. It has [pictures_left] photos left."
to_chat(user, SPAN_NOTICE("[pictures_left] photos left."))
+
+ captureimage(target, user, flag)
+
icon_state = icon_off
on = 0
spawn(64)
@@ -257,37 +286,46 @@
on = 1
/obj/item/device/camera/proc/captureimage(atom/target, mob/user, flag)
- var/mobs = ""
+ var/mob_descriptions = ""
var/radius = (size-1)*0.5
- var/list/turf/turfs = RANGE_TURFS(radius, target) & view(world_view_size + radius, user.client)
- for(var/turf/T as anything in turfs)
- mobs += get_mobs(T)
- var/datum/picture/P = createpicture(target, user, turfs, mobs, flag)
- printpicture(user, P)
+ var/list/turf/turfs = RANGE_TURFS(radius, target) & view(GLOB.world_view_size + radius, user.client)
+ for(var/turf/the_turf as anything in turfs)
+ mob_descriptions = get_mob_descriptions(the_turf, mob_descriptions)
+ var/datum/picture/the_picture = createpicture(target, user, turfs, mob_descriptions, flag)
-/obj/item/device/camera/proc/createpicture(atom/target, mob/user, list/turfs, mobs, flag)
+ if(QDELETED(user))
+ return
+
+ printpicture(user, the_picture)
+
+/obj/item/device/camera/proc/createpicture(atom/target, mob/user, list/turfs, description, flag)
var/icon/photoimage = get_icon(turfs, target)
+ if(!description)
+ description = "A very scenic photo"
+
var/icon/small_img = icon(photoimage)
var/icon/tiny_img = icon(photoimage)
- var/icon/ic = icon('icons/obj/items/items.dmi',"photo")
- var/icon/pc = icon('icons/obj/items/paper.dmi', "photo")
+ var/icon/item_icon = icon('icons/obj/items/items.dmi',"photo")
+ var/icon/paper_icon = icon('icons/obj/items/paper.dmi', "photo")
small_img.Scale(8, 8)
tiny_img.Scale(4, 4)
- ic.Blend(small_img,ICON_OVERLAY, 10, 13)
- pc.Blend(tiny_img,ICON_OVERLAY, 12, 19)
-
- var/datum/picture/P = new()
- P.fields["author"] = user
- P.fields["icon"] = ic
- P.fields["tiny"] = pc
- P.fields["img"] = photoimage
- P.fields["desc"] = mobs
- P.fields["pixel_x"] = rand(-10, 10)
- P.fields["pixel_y"] = rand(-10, 10)
- P.fields["size"] = size
-
- return P
+ item_icon.Blend(small_img, ICON_OVERLAY, 10, 13)
+ CHECK_TICK
+ paper_icon.Blend(tiny_img, ICON_OVERLAY, 12, 19)
+ CHECK_TICK
+
+ var/datum/picture/the_picture = new()
+ the_picture.fields["author"] = user
+ the_picture.fields["icon"] = item_icon
+ the_picture.fields["tiny"] = paper_icon
+ the_picture.fields["img"] = photoimage
+ the_picture.fields["desc"] = description
+ the_picture.fields["pixel_x"] = rand(-10, 10)
+ the_picture.fields["pixel_y"] = rand(-10, 10)
+ the_picture.fields["size"] = size
+
+ return the_picture
/obj/item/device/camera/proc/printpicture(mob/user, datum/picture/P)
var/obj/item/photo/Photo = new/obj/item/photo()
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index fc3f213fff35..dd0327e3821d 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -1000,7 +1000,7 @@ GLOBAL_LIST_INIT(apc_wire_descriptions, list(
SEND_SIGNAL(user, COMSIG_MOB_APC_POWER_PULSE, src)
addtimer(VARSET_CALLBACK(src, shorted, FALSE), 2 MINUTES)
-/obj/structure/machinery/power/apc/proc/can_use(mob/user as mob, loud = 0) //used by attack_hand() and Topic()
+/obj/structure/machinery/power/apc/proc/can_use(mob/living/user as mob, loud = 0) //used by attack_hand() and Topic()
if(user.client && user.client.remote_control)
return TRUE
@@ -1011,12 +1011,12 @@ GLOBAL_LIST_INIT(apc_wire_descriptions, list(
return 0
if(!(ishuman(user) || isRemoteControlling(user)))
to_chat(user, SPAN_WARNING("You don't have the dexterity to use [src]!"))
- nanomanager.close_user_uis(user, src)
+ SSnano.nanomanager.close_user_uis(user, src)
return 0
if(user.is_mob_restrained())
to_chat(user, SPAN_WARNING("You must have free hands to use [src]."))
return 0
- if(user.lying)
+ if(user.body_position == LYING_DOWN)
to_chat(user, SPAN_WARNING("You can't reach [src]!"))
return 0
autoflag = 5
@@ -1024,11 +1024,11 @@ GLOBAL_LIST_INIT(apc_wire_descriptions, list(
if(aidisabled)
if(!loud)
to_chat(user, SPAN_WARNING("[src] has AI control disabled!"))
- nanomanager.close_user_uis(user, src)
+ SSnano.nanomanager.close_user_uis(user, src)
return 0
else
if((!in_range(src, user) || !istype(src.loc, /turf)))
- nanomanager.close_user_uis(user, src)
+ SSnano.nanomanager.close_user_uis(user, src)
return 0
var/mob/living/carbon/human/H = user
@@ -1266,6 +1266,7 @@ GLOBAL_LIST_INIT(apc_wire_descriptions, list(
//Damage and destruction acts
/obj/structure/machinery/power/apc/emp_act(severity)
+ . = ..()
if(cell)
cell.emp_act(severity)
lighting = 0
@@ -1274,7 +1275,6 @@ GLOBAL_LIST_INIT(apc_wire_descriptions, list(
spawn(1 MINUTES)
equipment = 3
environ = 3
- ..()
/obj/structure/machinery/power/apc/ex_act(severity)
switch(severity)
diff --git a/code/modules/power/cell.dm b/code/modules/power/cell.dm
index 992e0f3464ff..31a096a3a2ee 100644
--- a/code/modules/power/cell.dm
+++ b/code/modules/power/cell.dm
@@ -71,12 +71,12 @@
/obj/item/cell/emp_act(severity)
+ . = ..()
charge -= 1000 / severity
if (charge < 0)
charge = 0
if(reliability != 100 && prob(50/severity))
reliability -= 10 / severity
- ..()
/obj/item/cell/ex_act(severity)
diff --git a/code/modules/power/power.dm b/code/modules/power/power.dm
index bee3e0aac8c2..00e6b92eab8f 100644
--- a/code/modules/power/power.dm
+++ b/code/modules/power/power.dm
@@ -81,13 +81,13 @@
if(has_power || !src.needs_power)
if(machine_processing)
if(stat & NOPOWER)
- addToListNoDupe(processing_machines, src) // power interupted us, start processing again
+ addToListNoDupe(GLOB.processing_machines, src) // power interupted us, start processing again
stat &= ~NOPOWER
src.update_use_power(USE_POWER_IDLE)
else
if(machine_processing)
- processing_machines -= src // no power, can't process.
+ GLOB.processing_machines -= src // no power, can't process.
stat |= NOPOWER
src.update_use_power(USE_POWER_NONE)
@@ -97,19 +97,19 @@
// rebuild all power networks from scratch
/proc/makepowernets()
- for(var/datum/powernet/PN in powernets)
+ for(var/datum/powernet/PN in GLOB.powernets)
del(PN) //not qdel on purpose, powernet is still using del.
- powernets.Cut()
+ GLOB.powernets.Cut()
- for(var/area/A in all_areas)
- if(powernets_by_name[A.powernet_name])
+ for(var/area/A in GLOB.all_areas)
+ if(GLOB.powernets_by_name[A.powernet_name])
continue
var/datum/powernet/PN = new()
PN.powernet_name = A.powernet_name
- powernets += PN
- powernets_by_name[A.powernet_name] = PN
+ GLOB.powernets += PN
+ GLOB.powernets_by_name[A.powernet_name] = PN
- for(var/obj/structure/machinery/power/M in machines)
+ for(var/obj/structure/machinery/power/M in GLOB.machines)
M.connect_to_network()
return 1
@@ -222,7 +222,7 @@
var/cdir
- for(var/card in cardinal)
+ for(var/card in GLOB.cardinals)
var/turf/T = get_step(loc,card)
cdir = get_dir(T,loc)
@@ -250,7 +250,7 @@
var/area/A = get_area(src)
if(!A)
return 0
- var/datum/powernet/PN = powernets_by_name[A.powernet_name]
+ var/datum/powernet/PN = GLOB.powernets_by_name[A.powernet_name]
if(!PN)
return 0
powernet = PN
diff --git a/code/modules/power/profiling.dm b/code/modules/power/profiling.dm
index 21c8e2a63538..b4b67b8c8543 100644
--- a/code/modules/power/profiling.dm
+++ b/code/modules/power/profiling.dm
@@ -1,29 +1,27 @@
-datum
+GLOBAL_VAR_INIT(enable_power_update_profiling, FALSE)
-var/global/enable_power_update_profiling = 0
-
-var/global/power_profiled_time = 0
-var/global/power_last_profile_time = 0
-var/global/list/power_update_requests_by_machine = list()
-var/global/list/power_update_requests_by_area = list()
+GLOBAL_VAR_INIT(power_profiled_time, 0)
+GLOBAL_VAR_INIT(power_last_profile_time, 0)
+GLOBAL_LIST_EMPTY(power_update_requests_by_machine)
+GLOBAL_LIST_EMPTY(power_update_requests_by_area)
/proc/log_power_update_request(area/A, obj/structure/machinery/M)
- if (!enable_power_update_profiling)
+ if (!GLOB.enable_power_update_profiling)
return
var/machine_type = "[M.type]"
- if (machine_type in power_update_requests_by_machine)
- power_update_requests_by_machine[machine_type]++
+ if (machine_type in GLOB.power_update_requests_by_machine)
+ GLOB.power_update_requests_by_machine[machine_type]++
else
- power_update_requests_by_machine[machine_type] = 1
+ GLOB.power_update_requests_by_machine[machine_type] = 1
- if (A.name in power_update_requests_by_area)
- power_update_requests_by_area[A.name]++
+ if (A.name in GLOB.power_update_requests_by_area)
+ GLOB.power_update_requests_by_area[A.name]++
else
- power_update_requests_by_area[A.name] = 1
+ GLOB.power_update_requests_by_area[A.name] = 1
- power_profiled_time += (world.time - power_last_profile_time)
- power_last_profile_time = world.time
+ GLOB.power_profiled_time += (world.time - GLOB.power_last_profile_time)
+ GLOB.power_last_profile_time = world.time
/client/proc/toggle_power_update_profiling()
set name = "Toggle Area Power Update Profiling"
@@ -31,14 +29,14 @@ var/global/list/power_update_requests_by_area = list()
set category = "Debug.Profiling"
if(!check_rights(R_DEBUG)) return
if(!ishost(usr) || alert("Are you sure you want to do this?",, "Yes", "No") != "Yes") return
- if(enable_power_update_profiling)
- enable_power_update_profiling = 0
+ if(GLOB.enable_power_update_profiling)
+ GLOB.enable_power_update_profiling = 0
to_chat(usr, "Area power update profiling disabled.")
message_admins("[key_name(src)] toggled area power update profiling off.")
else
- enable_power_update_profiling = 1
- power_last_profile_time = world.time
+ GLOB.enable_power_update_profiling = 1
+ GLOB.power_last_profile_time = world.time
to_chat(usr, "Area power update profiling enabled.")
message_admins("[key_name(src)] toggled area power update profiling on.")
@@ -52,9 +50,9 @@ var/global/list/power_update_requests_by_area = list()
if(!check_rights(R_DEBUG)) return
- to_chat(usr, "Total profiling time: [power_profiled_time] ticks")
- for (var/M in power_update_requests_by_machine)
- to_chat(usr, "[M] = [power_update_requests_by_machine[M]]")
+ to_chat(usr, "Total profiling time: [GLOB.power_profiled_time] ticks")
+ for (var/M in GLOB.power_update_requests_by_machine)
+ to_chat(usr, "[M] = [GLOB.power_update_requests_by_machine[M]]")
/client/proc/view_power_update_stats_area()
set name = "View Area Power Update Statistics By Area"
@@ -63,7 +61,7 @@ var/global/list/power_update_requests_by_area = list()
if(!check_rights(R_DEBUG)) return
- to_chat(usr, "Total profiling time: [power_profiled_time] ticks")
- to_chat(usr, "Total profiling time: [power_profiled_time] ticks")
- for (var/A in power_update_requests_by_area)
- to_chat(usr, "[A] = [power_update_requests_by_area[A]]")
+ to_chat(usr, "Total profiling time: [GLOB.power_profiled_time] ticks")
+ to_chat(usr, "Total profiling time: [GLOB.power_profiled_time] ticks")
+ for (var/A in GLOB.power_update_requests_by_area)
+ to_chat(usr, "[A] = [GLOB.power_update_requests_by_area[A]]")
diff --git a/code/modules/power/smes.dm b/code/modules/power/smes.dm
index ac19d1ba0c67..7cf72ce1cb81 100644
--- a/code/modules/power/smes.dm
+++ b/code/modules/power/smes.dm
@@ -46,7 +46,7 @@
connect_to_network()
dir_loop:
- for(var/d in cardinal)
+ for(var/d in GLOB.cardinals)
var/turf/T = get_step(src, d)
for(var/obj/structure/machinery/power/terminal/term in T)
if(term && term.dir == turn(d, 180))
@@ -390,6 +390,7 @@
/obj/structure/machinery/power/smes/emp_act(severity)
+ . = ..()
outputting = 0
inputting = 0
output_level = 0
@@ -400,7 +401,6 @@
output_level = initial(output_level)
inputting = initial(inputting)
outputting = initial(outputting)
- ..()
diff --git a/code/modules/power/smes_construction.dm b/code/modules/power/smes_construction.dm
index 98208069c8dd..1eb249b5ecfa 100644
--- a/code/modules/power/smes_construction.dm
+++ b/code/modules/power/smes_construction.dm
@@ -85,7 +85,7 @@
if (user_protected && prob(80))
to_chat(h_user, "Small electrical arc almost burns your hand. Luckily you had your gloves on!")
else
- to_chat(h_user, "Small electrical arc sparks and burns your hand as you touch the [src]!")
+ to_chat(h_user, "Small electrical arc sparks and burns your hand as you touch [src]!")
h_user.apply_damage(rand(5,10), BURN)
h_user.apply_effect(2, PARALYZE)
charge = 0
@@ -98,7 +98,7 @@
if (user_protected && prob(25))
to_chat(h_user, "Medium electrical arc sparks and almost burns your hand. Luckily you had your gloves on!")
else
- to_chat(h_user, "Medium electrical sparks as you touch the [src], severely burning your hand!")
+ to_chat(h_user, "Medium electrical sparks as you touch [src], severely burning your hand!")
h_user.apply_damage(rand(10,25), BURN)
h_user.apply_effect(5, PARALYZE)
spawn(0)
@@ -182,7 +182,7 @@
/obj/structure/machinery/power/smes/buildable/attackby(obj/item/W as obj, mob/user as mob)
// No more disassembling of overloaded SMESs. You broke it, now enjoy the consequences.
if (failing)
- to_chat(user, SPAN_WARNING("The [src]'s screen is flashing with alerts. It seems to be overloaded! Touching it now is probably not a good idea."))
+ to_chat(user, SPAN_WARNING("[src]'s screen is flashing with alerts. It seems to be overloaded! Touching it now is probably not a good idea."))
return
// If parent returned 1:
// - Hatch is open, so we can modify the SMES
@@ -195,7 +195,7 @@
return
if (outputting || input_attempt)
- to_chat(user, SPAN_WARNING("Turn off the [src] first!"))
+ to_chat(user, SPAN_WARNING("Turn off [src] first!"))
return
// Probability of failure if safety circuit is disabled (in %)
@@ -212,7 +212,7 @@
return
playsound(get_turf(src), 'sound/items/Crowbar.ogg', 25, 1)
- to_chat(user, SPAN_WARNING("You begin to disassemble the [src]!"))
+ to_chat(user, SPAN_WARNING("You begin to disassemble [src]!"))
if (do_after(usr, 100 * cur_coils * user.get_skill_duration_multiplier(SKILL_ENGINEER), INTERRUPT_ALL|BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD)) // More coils = takes longer to disassemble. It's complex so largest one with 5 coils will take 50s
if (failure_probability && prob(failure_probability))
diff --git a/code/modules/projectiles/ammo_boxes/ammo_boxes.dm b/code/modules/projectiles/ammo_boxes/ammo_boxes.dm
index 831923415453..df8a7d7bdd76 100644
--- a/code/modules/projectiles/ammo_boxes/ammo_boxes.dm
+++ b/code/modules/projectiles/ammo_boxes/ammo_boxes.dm
@@ -85,6 +85,8 @@
var/handful = "shells" //used for 'magazine' boxes that give handfuls to determine what kind for the sprite
can_explode = TRUE
limit_per_tile = 2
+ ground_offset_x = 5
+ ground_offset_y = 5
/obj/item/ammo_box/magazine/empty
empty = TRUE
@@ -102,8 +104,6 @@
while(i < num_of_magazines)
contents += new magazine_type(src)
i++
- pixel_x = rand(-5, 5)
- pixel_y = rand(-5, 5)
update_icon()
/obj/item/ammo_box/magazine/update_icon()
diff --git a/code/modules/projectiles/ammo_boxes/box_structures.dm b/code/modules/projectiles/ammo_boxes/box_structures.dm
index cb119e1a2190..b34c0543bb2c 100644
--- a/code/modules/projectiles/ammo_boxes/box_structures.dm
+++ b/code/modules/projectiles/ammo_boxes/box_structures.dm
@@ -134,7 +134,7 @@
if(istype(W, /obj/item/storage/box/m94))
var/obj/item/storage/box/m94/flare_pack = W
if(flare_pack.contents.len < flare_pack.max_storage_space)
- to_chat(user, SPAN_WARNING("\The [W] is not full."))
+ to_chat(user, SPAN_WARNING("[W] is not full."))
return
var/flare_type
if(istype(W, /obj/item/storage/box/m94/signal))
@@ -143,28 +143,28 @@
flare_type = /obj/item/device/flashlight/flare
for(var/obj/item/device/flashlight/flare/F in flare_pack.contents)
if(F.fuel < 1)
- to_chat(user, SPAN_WARNING("Some flares in \the [F] are used."))
+ to_chat(user, SPAN_WARNING("Some flares in [F] are used."))
return
if(F.type != flare_type)
- to_chat(user, SPAN_WARNING("Some flares in \the [W] are not of the correct type."))
+ to_chat(user, SPAN_WARNING("Some flares in [W] are not of the correct type."))
return
else if(istype(W, /obj/item/storage/box/MRE))
var/obj/item/storage/box/MRE/mre_pack = W
if(mre_pack.isopened)
- to_chat(user, SPAN_WARNING("\The [W] was already opened and isn't suitable for storing in \the [src]."))
+ to_chat(user, SPAN_WARNING("[W] was already opened and isn't suitable for storing in [src]."))
return
else if(istype(W, /obj/item/cell/high))
var/obj/item/cell/high/cell = W
if(cell.charge != cell.maxcharge)
- to_chat(user, SPAN_WARNING("\The [W] needs to be fully charged before it can be stored in \the [src]."))
+ to_chat(user, SPAN_WARNING("[W] needs to be fully charged before it can be stored in [src]."))
return
if(item_box.contents.len < item_box.num_of_magazines)
user.drop_inv_item_to_loc(W, src)
item_box.contents += W
- to_chat(user, SPAN_NOTICE("You put a [W] in to \the [src]"))
+ to_chat(user, SPAN_NOTICE("You put \a [W] into [src]"))
update_icon()
else
- to_chat(user, SPAN_WARNING("\The [src] is full."))
+ to_chat(user, SPAN_WARNING("[src] is full."))
else
to_chat(user, SPAN_WARNING("You don't want to mix different magazines in one box."))
else
@@ -175,10 +175,10 @@
return
if(O.default_ammo == AM.default_ammo)
if(O.current_rounds <= 0)
- to_chat(user, SPAN_WARNING("\The [O] is empty."))
+ to_chat(user, SPAN_WARNING("[O] is empty."))
return
if(AM.current_rounds >= AM.max_rounds)
- to_chat(user, SPAN_WARNING("\The [src] is full."))
+ to_chat(user, SPAN_WARNING("[src] is full."))
return
else
if(!do_after(user, 15, INTERRUPT_ALL, BUSY_ICON_FRIENDLY))
@@ -187,7 +187,7 @@
var/S = min(O.current_rounds, AM.max_rounds - AM.current_rounds)
AM.current_rounds += S
O.current_rounds -= S
- to_chat(user, SPAN_NOTICE("You transfer shells from [O] into \the [src]"))
+ to_chat(user, SPAN_NOTICE("You transfer shells from [O] into [src]"))
update_icon()
O.update_icon()
else
diff --git a/code/modules/projectiles/ammo_boxes/grenade_packets.dm b/code/modules/projectiles/ammo_boxes/grenade_packets.dm
index 83c222a0a128..5546fe3bc520 100644
--- a/code/modules/projectiles/ammo_boxes/grenade_packets.dm
+++ b/code/modules/projectiles/ammo_boxes/grenade_packets.dm
@@ -25,7 +25,7 @@
for(var/i in 1 to storage_slots)
new content_type(src)
-var/list/grenade_packets = list(
+GLOBAL_LIST_INIT(grenade_packets, list(
/obj/item/storage/box/packet/high_explosive,
/obj/item/storage/box/packet/baton_slug,
/obj/item/storage/box/packet/flare,
@@ -37,7 +37,7 @@ var/list/grenade_packets = list(
/obj/item/storage/box/packet/m15,
/obj/item/storage/box/packet/airburst_he,
/obj/item/storage/box/packet/airburst_incen
- )
+ ))
/obj/item/storage/box/packet/high_explosive
name = "\improper HEDP grenade packet"
diff --git a/code/modules/projectiles/ammo_boxes/handful_boxes.dm b/code/modules/projectiles/ammo_boxes/handful_boxes.dm
index 28eab8463011..9ac2aeea8870 100644
--- a/code/modules/projectiles/ammo_boxes/handful_boxes.dm
+++ b/code/modules/projectiles/ammo_boxes/handful_boxes.dm
@@ -48,6 +48,15 @@
/obj/item/ammo_box/magazine/shotgun/incendiary/empty
empty = TRUE
+/obj/item/ammo_box/magazine/shotgun/incendiarybuck
+ name = "\improper shotgun shell box (Incendiary buckshot x 100)"
+ icon_state = "base_incbuck"
+ overlay_content = "_incenbuck"
+ magazine_type = /obj/item/ammo_magazine/shotgun/incendiarybuck
+
+/obj/item/ammo_box/magazine/shotgun/incendiarybuck/empty
+ empty = TRUE
+
/obj/item/ammo_box/magazine/shotgun/beanbag
name = "\improper shotgun shell box (Beanbag x 100)"
icon_state = "base_bean"
diff --git a/code/modules/projectiles/ammo_boxes/magazine_boxes.dm b/code/modules/projectiles/ammo_boxes/magazine_boxes.dm
index ff90a6659fb2..6d20dcc75949 100644
--- a/code/modules/projectiles/ammo_boxes/magazine_boxes.dm
+++ b/code/modules/projectiles/ammo_boxes/magazine_boxes.dm
@@ -286,6 +286,15 @@
/obj/item/ammo_box/magazine/m4a3/hp/empty
empty = TRUE
+/obj/item/ammo_box/magazine/m4a3/incen
+ name = "\improper magazine box (Incen M4A3 x 16)"
+ overlay_ammo_type = "_incen"
+ overlay_content = "_incen"
+ magazine_type = /obj/item/ammo_magazine/pistol/incendiary
+
+/obj/item/ammo_box/magazine/m4a3/incen/empty
+ empty = TRUE
+
//-----------------------M44 Revolver Speed Loaders Box-----------------------
/obj/item/ammo_box/magazine/m44
@@ -410,3 +419,306 @@
/obj/item/ammo_box/magazine/nailgun/empty
empty = TRUE
+
+//-----------------------M56B Drum Box-----------------------
+
+/obj/item/ammo_box/magazine/m56b
+ name = "\improper drum box (M56B x 8)"
+ icon_state = "base_m56b"
+ overlay_ammo_type = "_reg_heavy"
+ overlay_gun_type = "_sg"
+ overlay_content = "_sg"
+ magazine_type = /obj/item/ammo_magazine/smartgun
+ num_of_magazines = 8
+
+/obj/item/ammo_box/magazine/m56b/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/m56b/dirty
+ name = "\improper drum box (M56B 'Dirty' x 8)"
+ overlay_ammo_type = "_red_heavy"
+ overlay_content = "_sgdirty"
+ magazine_type = /obj/item/ammo_magazine/smartgun/dirty
+
+/obj/item/ammo_box/magazine/m56b/dirty/empty
+ empty = TRUE
+
+//-----------------------M56D Drum Box-----------------------
+
+/obj/item/ammo_box/magazine/m56d
+ name = "\improper drum box (M56D x 8)"
+ icon_state = "base_m56d"
+ overlay_ammo_type = ""
+ overlay_gun_type = "_m56d"
+ overlay_content = "_m56d"
+ magazine_type = /obj/item/ammo_magazine/m56d
+ num_of_magazines = 8
+
+/obj/item/ammo_box/magazine/m56d/update_icon()
+ if(overlays)
+ overlays.Cut()
+ overlays += image(icon, icon_state = "[icon_state]_lid") //adding lid
+ overlays += image(text_markings_icon, icon_state = "text[overlay_gun_type]") //adding text
+
+/obj/item/ammo_box/magazine/m56d/empty
+ empty = TRUE
+
+
+//-----------------------M2C Ammo Box-----------------------
+
+/obj/item/ammo_box/magazine/m2c
+ name = "\improper ammo box (M2C x 8)"
+ icon_state = "base_m2c"
+ overlay_ammo_type = ""
+ overlay_gun_type = "_m2c"
+ overlay_content = "_m2c"
+ magazine_type = /obj/item/ammo_magazine/m2c
+ num_of_magazines = 8
+
+/obj/item/ammo_box/magazine/m2c/update_icon()
+ if(overlays)
+ overlays.Cut()
+ overlays += image(icon, icon_state = "[icon_state]_lid") //adding lid
+ overlays += image(text_markings_icon, icon_state = "text[overlay_gun_type]") //adding text
+
+/obj/item/ammo_box/magazine/m2c/empty
+ empty = TRUE
+
+//-----------------------M41AE2 Ammo Box-----------------------
+
+/obj/item/ammo_box/magazine/m41ae2
+ name = "\improper magazine (M41AE2 x 8)"
+ icon_state = "base_m41ae2"
+ overlay_ammo_type = "_reg_heavy"
+ overlay_gun_type = "_m41ae2"
+ overlay_content = "_m41ae2"
+ magazine_type = /obj/item/ammo_magazine/rifle/lmg
+ num_of_magazines = 8
+
+/obj/item/ammo_box/magazine/m41ae2/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/m41ae2/holo
+ name = "\improper magazine box (M41AE2 Holo-Target x 8)"
+ overlay_ammo_type = "_holo_heavy"
+ overlay_content = "_m41ae2_holo"
+ magazine_type = /obj/item/ammo_magazine/rifle/lmg/holo_target
+
+/obj/item/ammo_box/magazine/m41ae2/holo/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/m41ae2/heap
+ name = "\improper magazine box (M41AE2 HEAP x 8)"
+ overlay_ammo_type = "_heap_heavy"
+ overlay_content = "_m41ae2_heap"
+ magazine_type = /obj/item/ammo_magazine/rifle/lmg/heap
+
+/obj/item/ammo_box/magazine/m41ae2/heap/empty
+ empty = TRUE
+
+//-----------------------Flamer Fuel Tank Box-----------------------
+
+/obj/item/ammo_box/magazine/flamer
+ name = "\improper flamer tank box (UT-Napthal Fuel x 8)"
+ icon_state = "base_flamer"
+ overlay_ammo_type = "_flamer"
+ overlay_gun_type = "_blank"
+ overlay_content = "_flamer"
+ magazine_type = /obj/item/ammo_magazine/flamer_tank
+ num_of_magazines = 8
+
+/obj/item/ammo_box/magazine/flamer/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/flamer/bgel
+ name = "\improper flamer fuel box (Napalm B-Gel x 8)"
+ overlay_ammo_type = "_flamer_bgel"
+ overlay_content = "_flamer_bgel"
+ magazine_type = /obj/item/ammo_magazine/flamer_tank/gellied
+
+/obj/item/ammo_box/magazine/flamer/bgel/empty
+ empty = TRUE
+
+//-----------------------M41A MK1 Rifle Mag Boxes-----------------------
+
+/obj/item/ammo_box/magazine/mk1
+ name = "\improper magazine box (M41A MK1 x 8)"
+ overlay_ammo_type = "_reg_mk1"
+ overlay_gun_type = "_mk1"
+ overlay_content = "_reg"
+ magazine_type = /obj/item/ammo_magazine/rifle/m41aMK1
+ num_of_magazines = 8
+
+/obj/item/ammo_box/magazine/mk1/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/mk1/ap
+ name = "\improper magazine box (M41A MK1 AP x 8)"
+ flags_equip_slot = SLOT_BACK
+ overlay_ammo_type = "_ap_mk1"
+ overlay_content = "_ap"
+ magazine_type = /obj/item/ammo_magazine/rifle/m41aMK1/ap
+
+/obj/item/ammo_box/magazine/mk1/ap/empty
+ empty = TRUE
+
+//-----------------------NSG 23 Rifle Mag Boxes-----------------------
+
+/obj/item/ammo_box/magazine/nsg23
+ name = "\improper magazine box (NSG 23 x 16)"
+ icon_state = "base_nsg23"
+ overlay_gun_type = "_nsg23"
+ overlay_content = "_reg"
+ magazine_type = /obj/item/ammo_magazine/rifle/nsg23
+ num_of_magazines = 16
+
+/obj/item/ammo_box/magazine/nsg23/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/nsg23/ap
+ name = "\improper magazine box (NSG 23 AP x 12)"
+ overlay_ammo_type = "_ap"
+ overlay_content = "_ap"
+ magazine_type = /obj/item/ammo_magazine/rifle/nsg23/ap
+ num_of_magazines = 12
+
+/obj/item/ammo_box/magazine/nsg23/ap/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/nsg23/ex
+ name = "\improper magazine box (NSG 23 Extended x 8)"
+ overlay_ammo_type = "_ext"
+ magazine_type = /obj/item/ammo_magazine/rifle/nsg23/extended
+ num_of_magazines = 8
+
+/obj/item/ammo_box/magazine/nsg23/ex/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/nsg23/heap
+ name = "\improper magazine box (NSG 23 HEAP x 16)"
+ overlay_ammo_type = "_heap"
+ overlay_content = "_heap"
+ magazine_type = /obj/item/ammo_magazine/rifle/nsg23/heap
+
+/obj/item/ammo_box/magazine/nsg23/heap/empty
+ empty = TRUE
+
+//-----------------------Spearhead Autorevolver Speed Loaders Box-----------------------
+
+/obj/item/ammo_box/magazine/spearhead
+ name = "\improper speed loaders box (Spearhead HP x 12)"
+ icon_state = "base_cmb"
+ overlay_ammo_type = "_357_hp"
+ overlay_gun_type = "_357"
+ overlay_content = "_speed"
+ num_of_magazines = 12
+ magazine_type = /obj/item/ammo_magazine/revolver/cmb
+
+/obj/item/ammo_box/magazine/spearhead/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/spearhead/normalpoint
+ name = "\improper speed loaders box (Spearhead x 12)"
+ overlay_ammo_type = "_357_reg"
+ magazine_type = /obj/item/ammo_magazine/revolver/cmb/normalpoint
+
+/obj/item/ammo_box/magazine/spearhead/normalpoint/empty
+ empty = TRUE
+
+//-----------------------Type 73 Pistol Mag Box-----------------------
+
+/obj/item/ammo_box/magazine/type73
+ name = "\improper magazine box (Type 73 x 16)"
+ icon_state = "base_type73"
+ flags_equip_slot = SLOT_BACK
+ overlay_ammo_type = "_type71_reg"
+ overlay_gun_type = "_type73"
+ overlay_content = "_type71_reg"
+ num_of_magazines = 16
+ magazine_type = /obj/item/ammo_magazine/pistol/t73
+
+/obj/item/ammo_box/magazine/type73/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/type73/impact
+ name = "\improper magazine box (Type 73 High-Impact x 10)"
+ overlay_ammo_type = "_type73_impact"
+ overlay_content = "_type73_impact"
+ num_of_magazines = 10
+ magazine_type = /obj/item/ammo_magazine/pistol/t73_impact
+
+/obj/item/ammo_box/magazine/type73/impact/empty
+ empty = TRUE
+
+
+//-----------------------AR10 Rifle Mag Box-----------------------
+
+/obj/item/ammo_box/magazine/ar10
+ name = "\improper magazine box (AR10 x 12)"
+ icon_state = "base_ar10"
+ flags_equip_slot = SLOT_BACK
+ overlay_gun_type = "_ar10"
+ overlay_content = "_reg"
+ num_of_magazines = 12
+ magazine_type = /obj/item/ammo_magazine/rifle/ar10
+
+/obj/item/ammo_box/magazine/ar10/empty
+ empty = TRUE
+
+//-----------------------MP5 Smg Mag Box-----------------------
+
+/obj/item/ammo_box/magazine/mp5
+ name = "\improper magazine box (MP5 x 12)"
+ icon_state = "base_m16"
+ flags_equip_slot = SLOT_BACK
+ overlay_gun_type = "_mp5"
+ overlay_content = "_reg"
+ num_of_magazines = 12
+ magazine_type = /obj/item/ammo_magazine/smg/mp5
+
+/obj/item/ammo_box/magazine/mp5/empty
+ empty = TRUE
+
+
+//-----------------------Desert Eagle Pistol Mag Box-----------------------
+
+/obj/item/ammo_box/magazine/deagle
+ name = "\improper magazine box (Desert Eagle x 12)"
+ icon_state = "base_deagle"
+ flags_equip_slot = SLOT_BACK
+ overlay_ammo_type = "_reg"
+ overlay_gun_type = "_deagle"
+ overlay_content = "_reg"
+ num_of_magazines = 16
+ magazine_type = /obj/item/ammo_magazine/pistol/heavy
+
+/obj/item/ammo_box/magazine/deagle/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/deagle/super
+ name = "\improper magazine box (Heavy Desert Eagle x 8)"
+ overlay_ammo_type = "_hp"
+ overlay_content = "_hp"
+ num_of_magazines = 8
+ magazine_type = /obj/item/ammo_magazine/pistol/heavy/super
+
+/obj/item/ammo_box/magazine/deagle/super/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/deagle/super/highimpact
+ name = "\improper magazine box (High Impact Desert Eagle x 8)"
+ overlay_ammo_type = "_impact"
+ overlay_content = "_impact"
+ magazine_type = /obj/item/ammo_magazine/pistol/heavy/super/highimpact
+
+/obj/item/ammo_box/magazine/deagle/super/highimpact/empty
+ empty = TRUE
+
+/obj/item/ammo_box/magazine/deagle/super/highimpact/ap
+ name = "\improper magazine box (High Impact Armor-Piercing Desert Eagle x 8)"
+ overlay_ammo_type = "_ap"
+ overlay_content = "_ap"
+ magazine_type = /obj/item/ammo_magazine/pistol/heavy/super/highimpact/ap
+
+/obj/item/ammo_box/magazine/deagle/super/highimpact/ap/empty
+ empty = TRUE
diff --git a/code/modules/projectiles/ammo_boxes/misc_boxes.dm b/code/modules/projectiles/ammo_boxes/misc_boxes.dm
index d09a69e5bb50..7b19555f4de5 100644
--- a/code/modules/projectiles/ammo_boxes/misc_boxes.dm
+++ b/code/modules/projectiles/ammo_boxes/misc_boxes.dm
@@ -75,6 +75,15 @@
overlay_gun_type = "_m94"
overlay_content = "_flares"
+//------------------------M89 Signal Flare Packs Box--------------------------
+
+/obj/item/ammo_box/magazine/misc/flares/signal
+ name = "\improper box of M89 signal flare packs"
+ desc = "A box of M89 signal flare packs, to mark up the way."
+ magazine_type = /obj/item/storage/box/m94/signal
+ overlay_gun_type = "_m89"
+ overlay_content = "_flares_signal"
+
//---------------------FIRE HANDLING PROCS
//flare box has unique stuff
@@ -139,6 +148,9 @@
/obj/item/ammo_box/magazine/misc/flares/empty
empty = TRUE
+/obj/item/ammo_box/magazine/misc/flares/signal/empty
+ empty = TRUE
+
//------------------------Flashlight Box--------------------------
/obj/item/ammo_box/magazine/misc/flashlight
diff --git a/code/modules/projectiles/ammo_boxes/round_boxes.dm b/code/modules/projectiles/ammo_boxes/round_boxes.dm
index 95115b76df43..ab1d1667c15f 100644
--- a/code/modules/projectiles/ammo_boxes/round_boxes.dm
+++ b/code/modules/projectiles/ammo_boxes/round_boxes.dm
@@ -130,3 +130,43 @@
/obj/item/ammo_box/rounds/type71/heap/empty
empty = TRUE
+
+//----------------9mm Pistol Ammunition Boxes (for mod88, M4A3 pistols)------------------
+
+/obj/item/ammo_box/rounds/pistol
+ name = "\improper pistol ammunition box (9mm)"
+ desc = "A 9mm ammunition box. Used to refill M4A3 magazines. It comes with a leather strap allowing to wear it on the back."
+ caliber = "9mm"
+ icon_state = "base_m4a3"
+ overlay_content = "_reg"
+ default_ammo = /datum/ammo/bullet/pistol
+
+/obj/item/ammo_box/rounds/pistol/empty
+ empty = TRUE
+
+/obj/item/ammo_box/rounds/pistol/ap
+ name = "\improper pistol ammunition box (9mm AP)"
+ desc = "A 9mm armor-piercing ammunition box. Used to refill mod88 and M4A3 magazines. It comes with a leather strap allowing to wear it on the back."
+ overlay_content = "_ap"
+ default_ammo = /datum/ammo/bullet/pistol/ap
+
+/obj/item/ammo_box/rounds/pistol/ap/empty
+ empty = TRUE
+
+/obj/item/ammo_box/rounds/pistol/hp
+ name = "\improper pistol ammunition box (9mm HP)"
+ desc = "A 9mm hollow-point ammunition box. Used to refill M4A3 magazines. It comes with a leather strap allowing to wear it on the back."
+ overlay_content = "_hp"
+ default_ammo = /datum/ammo/bullet/pistol/hollow
+
+/obj/item/ammo_box/rounds/pistol/hp/empty
+ empty = TRUE
+
+/obj/item/ammo_box/rounds/pistol/incen
+ name = "\improper pistol ammunition box (9mm Incendiary)"
+ desc = "A 9mm incendiary ammunition box. Used to refill M4A3 magazines. It comes with a leather strap allowing to wear it on the back."
+ overlay_content = "_incen"
+ default_ammo = /datum/ammo/bullet/pistol/incendiary
+
+/obj/item/ammo_box/rounds/pistol/incen/empty
+ empty = TRUE
diff --git a/code/modules/projectiles/ammo_datums.dm b/code/modules/projectiles/ammo_datums.dm
deleted file mode 100644
index 1bb1083a9d4f..000000000000
--- a/code/modules/projectiles/ammo_datums.dm
+++ /dev/null
@@ -1,3450 +0,0 @@
-/datum/ammo
- var/name = "generic bullet"
- var/headshot_state = null //Icon state when a human is permanently killed with it by execution/suicide.
- var/icon = 'icons/obj/items/weapons/projectiles.dmi'
- var/icon_state = "bullet"
- var/ping = "ping_b" //The icon that is displayed when the bullet bounces off something.
- var/sound_hit //When it deals damage.
- var/sound_armor //When it's blocked by human armor.
- var/sound_miss //When it misses someone.
- var/sound_bounce //When it bounces off something.
- var/sound_shield_hit //When the bullet is absorbed by a xeno_shield
-
- var/accurate_range_min = 0 // Snipers use this to simulate poor accuracy at close ranges
- var/scatter = 0 // How much the ammo scatters when burst fired, added to gun scatter, along with other mods
- var/stamina_damage = 0
- var/damage = 0 // This is the base damage of the bullet as it is fired
- var/damage_type = BRUTE // BRUTE, BURN, TOX, OXY, CLONE are the only things that should be in here
- var/penetration = 0 // How much armor it ignores before calculations take place
- var/shrapnel_chance = 0 // The % chance it will imbed in a human
- var/shrapnel_type = 0 // The shrapnel type the ammo will embed, if the chance rolls
- var/bonus_projectiles_type // Type path of the extra projectiles
- var/bonus_projectiles_amount = 0 // How many extra projectiles it shoots out. Works kind of like firing on burst, but all of the projectiles travel together
- var/debilitate[] = null // Stun,knockdown,knockout,irradiate,stutter,eyeblur,drowsy,agony
- var/pen_armor_punch = 0.5 // how much armor breaking will be done per point of penetration. This is for weapons that penetrate with their shape (like needle bullets)
- var/damage_armor_punch = 0.5 // how much armor breaking is done by sheer weapon force. This is for big blunt weapons
- var/sound_override = null // if we should play a special sound when firing.
- var/flags_ammo_behavior = NO_FLAGS
-
- var/accuracy = HIT_ACCURACY_TIER_1 // This is added to the bullet's base accuracy.
- var/accuracy_var_low = PROJECTILE_VARIANCE_TIER_9 // How much the accuracy varies when fired. // This REDUCES the lower bound of accuracy variance by 2%, to 96%.
- var/accuracy_var_high = PROJECTILE_VARIANCE_TIER_9 // This INCREASES the upper bound of accuracy variance by 2%, to 107%.
- var/accurate_range = 6 // For most guns, this is where the bullet dramatically looses accuracy. Not for snipers though.
- var/max_range = 22 // This will de-increment a counter on the bullet.
- var/damage_var_low = PROJECTILE_VARIANCE_TIER_9 // Same as with accuracy variance.
- var/damage_var_high = PROJECTILE_VARIANCE_TIER_9 // This INCREASES the upper bound of damage variance by 2%, to 107%.
- var/damage_falloff = DAMAGE_FALLOFF_TIER_10 // How much damage the bullet loses per turf traveled after the effective range
- var/damage_buildup = DAMAGE_BUILDUP_TIER_1 // How much damage the bullet loses per turf away before the effective range
- var/effective_range_min = EFFECTIVE_RANGE_OFF //What minimum range the ammo deals full damage, builds up the closer you get. 0 for no minimum. Added onto gun range as a modifier.
- var/effective_range_max = EFFECTIVE_RANGE_OFF //What maximum range the ammo deals full damage, tapers off using damage_falloff after hitting this value. 0 for no maximum. Added onto gun range as a modifier.
- var/shell_speed = AMMO_SPEED_TIER_1 // How fast the projectile moves.
-
- var/handful_type = /obj/item/ammo_magazine/handful
- var/handful_color
- var/handful_state = "bullet" //custom handful sprite, for shotgun shells or etc.
- var/multiple_handful_name //so handfuls say 'buckshot shells' not 'shell'
-
- /// Does this apply xenomorph behaviour delegate?
- var/apply_delegate = TRUE
-
- /// An assoc list in the format list(/datum/element/bullet_trait_to_give = list(...args))
- /// that will be given to a projectile with the current ammo datum
- var/list/list/traits_to_give
-
- var/flamer_reagent_type = /datum/reagent/napalm/ut
-
- /// The flicker that plays when a bullet hits a target. Usually red. Can be nulled so it doesn't show up at all.
- var/hit_effect_color = "#FF0000"
-
-/datum/ammo/New()
- set_bullet_traits()
-
-/datum/ammo/proc/on_bullet_generation(obj/projectile/generated_projectile, mob/bullet_generator) //NOT used on New(), applied to the projectiles.
- return
-
-/// Populate traits_to_give in this proc
-/datum/ammo/proc/set_bullet_traits()
- return
-
-/datum/ammo/can_vv_modify()
- return FALSE
-
-/datum/ammo/proc/do_at_half_range(obj/projectile/P)
- SHOULD_NOT_SLEEP(TRUE)
- return
-
-/datum/ammo/proc/on_embed(mob/embedded_mob, obj/limb/target_organ)
- return
-
-/datum/ammo/proc/do_at_max_range(obj/projectile/P)
- SHOULD_NOT_SLEEP(TRUE)
- return
-
-/datum/ammo/proc/on_shield_block(mob/M, obj/projectile/P) //Does it do something special when shield blocked? Ie. a flare or grenade that still blows up.
- return
-
-/datum/ammo/proc/on_hit_turf(turf/T, obj/projectile/P) //Special effects when hitting dense turfs.
- SHOULD_NOT_SLEEP(TRUE)
- return
-
-/datum/ammo/proc/on_hit_mob(mob/M, obj/projectile/P, mob/user) //Special effects when hitting mobs.
- SHOULD_NOT_SLEEP(TRUE)
- return
-
-///Special effects when pointblanking mobs. Ultimately called from /living/attackby(). Return TRUE to end the PB attempt.
-/datum/ammo/proc/on_pointblank(mob/living/L, obj/projectile/P, mob/living/user, obj/item/weapon/gun/fired_from)
- return
-
-/datum/ammo/proc/on_hit_obj(obj/O, obj/projectile/P) //Special effects when hitting objects.
- SHOULD_NOT_SLEEP(TRUE)
- return
-
-/datum/ammo/proc/on_near_target(turf/T, obj/projectile/P) //Special effects when passing near something. Range of things that triggers it is controlled by other ammo flags.
- return 0 //return 0 means it flies even after being near something. Return 1 means it stops
-
-/datum/ammo/proc/knockback(mob/living/living_mob, obj/projectile/fired_projectile, max_range = 2)
- if(!living_mob || living_mob == fired_projectile.firer)
- return
- if(fired_projectile.distance_travelled > max_range || living_mob.lying)
- return //Two tiles away or more, basically.
-
- if(living_mob.mob_size >= MOB_SIZE_BIG)
- return //Big xenos are not affected.
-
- shake_camera(living_mob, 3, 4)
- knockback_effects(living_mob, fired_projectile)
- slam_back(living_mob, fired_projectile)
-
-/datum/ammo/proc/slam_back(mob/living/living_mob, obj/projectile/fired_projectile)
- //Either knockback or slam them into an obstacle.
- var/direction = Get_Compass_Dir(fired_projectile.z ? fired_projectile : fired_projectile.firer, living_mob) //More precise than get_dir.
- if(!direction) //Same tile.
- return
- if(!step(living_mob, direction))
- living_mob.animation_attack_on(get_step(living_mob, direction))
- playsound(living_mob.loc, "punch", 25, 1)
- living_mob.visible_message(SPAN_DANGER("[living_mob] slams into an obstacle!"),
- isxeno(living_mob) ? SPAN_XENODANGER("You slam into an obstacle!") : SPAN_HIGHDANGER("You slam into an obstacle!"), null, 4, CHAT_TYPE_TAKING_HIT)
- living_mob.apply_damage(MELEE_FORCE_TIER_2)
-
-///The applied effects for knockback(), overwrite to change slow/stun amounts for different ammo datums
-/datum/ammo/proc/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
- if(iscarbonsizexeno(living_mob))
- var/mob/living/carbon/xenomorph/target = living_mob
- target.apply_effect(0.7, WEAKEN) // 0.9 seconds of stun, per agreement from Balance Team when switched from MC stuns to exact stuns
- target.apply_effect(1, SUPERSLOW)
- target.apply_effect(2, SLOW)
- to_chat(target, SPAN_XENODANGER("You are shaken by the sudden impact!"))
- else
- living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
-
-/datum/ammo/proc/pushback(mob/target_mob, obj/projectile/fired_projectile, max_range = 2)
- if(!target_mob || target_mob == fired_projectile.firer || fired_projectile.distance_travelled > max_range || target_mob.lying)
- return
-
- if(target_mob.mob_size >= MOB_SIZE_BIG)
- return //too big to push
-
- to_chat(target_mob, isxeno(target_mob) ? SPAN_XENODANGER("You are pushed back by the sudden impact!") : SPAN_HIGHDANGER("You are pushed back by the sudden impact!"), null, 4, CHAT_TYPE_TAKING_HIT)
- slam_back(target_mob, fired_projectile, max_range)
-
-/datum/ammo/proc/burst(atom/target, obj/projectile/P, damage_type = BRUTE, range = 1, damage_div = 2, show_message = SHOW_MESSAGE_VISIBLE) //damage_div says how much we divide damage
- if(!target || !P) return
- for(var/mob/living/carbon/M in orange(range,target))
- if(P.firer == M)
- continue
- if(show_message)
- var/msg = "You are hit by backlash from \a [P.name]!"
- M.visible_message(SPAN_DANGER("[M] is hit by backlash from \a [P.name]!"),isxeno(M) ? SPAN_XENODANGER("[msg]"):SPAN_HIGHDANGER("[msg]"))
- var/damage = P.damage/damage_div
-
- var/mob/living/carbon/xenomorph/XNO = null
-
- if(isxeno(M))
- XNO = M
- var/total_explosive_resistance = XNO.caste.xeno_explosion_resistance + XNO.armor_explosive_buff
- damage = armor_damage_reduction(GLOB.xeno_explosive, damage, total_explosive_resistance , 60, 0, 0.5, XNO.armor_integrity)
- var/armor_punch = armor_break_calculation(GLOB.xeno_explosive, damage, total_explosive_resistance, 60, 0, 0.5, XNO.armor_integrity)
- XNO.apply_armorbreak(armor_punch)
-
- M.apply_damage(damage,damage_type)
-
- if(XNO && XNO.xeno_shields.len)
- P.play_shielded_hit_effect(M)
- else
- P.play_hit_effect(M)
-
-/datum/ammo/proc/fire_bonus_projectiles(obj/projectile/original_P)
- set waitfor = 0
-
- var/turf/curloc = get_turf(original_P.shot_from)
- var/initial_angle = Get_Angle(curloc, original_P.target_turf)
-
- for(var/i in 1 to bonus_projectiles_amount) //Want to run this for the number of bonus projectiles.
- var/final_angle = initial_angle
-
- var/obj/projectile/P = new /obj/projectile(curloc, original_P.weapon_cause_data)
- P.generate_bullet(GLOB.ammo_list[bonus_projectiles_type]) //No bonus damage or anything.
- P.accuracy = round(P.accuracy * original_P.accuracy/initial(original_P.accuracy)) //if the gun changes the accuracy of the main projectile, it also affects the bonus ones.
- original_P.give_bullet_traits(P)
-
- var/total_scatter_angle = P.scatter
- final_angle += rand(-total_scatter_angle, total_scatter_angle)
- var/turf/new_target = get_angle_target_turf(curloc, final_angle, 30)
-
- P.fire_at(new_target, original_P.firer, original_P.shot_from, P.ammo.max_range, P.ammo.shell_speed, original_P.original) //Fire!
-
-/datum/ammo/proc/drop_flame(turf/T, datum/cause_data/cause_data) // ~Art updated fire 20JAN17
- if(!istype(T))
- return
- if(locate(/obj/flamer_fire) in T)
- return
-
- var/datum/reagent/R = new flamer_reagent_type()
- new /obj/flamer_fire(T, cause_data, R)
-
-
-/*
-//======
- Default Ammo
-//======
-*/
-//Only when things screw up do we use this as a placeholder.
-/datum/ammo/bullet
- name = "default bullet"
- icon_state = "bullet"
- headshot_state = HEADSHOT_OVERLAY_LIGHT
- flags_ammo_behavior = AMMO_BALLISTIC
- sound_hit = "ballistic_hit"
- sound_armor = "ballistic_armor"
- sound_miss = "ballistic_miss"
- sound_bounce = "ballistic_bounce"
- sound_shield_hit = "ballistic_shield_hit"
-
- accurate_range_min = 0
- damage = 10
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_1
- shrapnel_type = /obj/item/shard/shrapnel
- shell_speed = AMMO_SPEED_TIER_4
-
-/datum/ammo/bullet/proc/handle_battlefield_execution(datum/ammo/firing_ammo, mob/living/hit_mob, obj/projectile/firing_projectile, mob/living/user, obj/item/weapon/gun/fired_from)
- SIGNAL_HANDLER
-
- if(!user || hit_mob == user || user.zone_selected != "head" || user.a_intent != INTENT_HARM || !ishuman_strict(hit_mob))
- return
-
- if(!skillcheck(user, SKILL_EXECUTION, SKILL_EXECUTION_TRAINED))
- to_chat(user, SPAN_DANGER("You don't know how to execute someone correctly."))
- return
-
- var/mob/living/carbon/human/execution_target = hit_mob
-
- if(execution_target.status_flags & PERMANENTLY_DEAD)
- to_chat(user, SPAN_DANGER("[execution_target] has already been executed!"))
- return
-
- INVOKE_ASYNC(src, PROC_REF(attempt_battlefield_execution), src, execution_target, firing_projectile, user, fired_from)
-
- return COMPONENT_CANCEL_AMMO_POINT_BLANK
-
-/datum/ammo/bullet/proc/attempt_battlefield_execution(datum/ammo/firing_ammo, mob/living/carbon/human/execution_target, obj/projectile/firing_projectile, mob/living/user, obj/item/weapon/gun/fired_from)
- user.affected_message(execution_target,
- SPAN_HIGHDANGER("You aim \the [fired_from] at [execution_target]'s head!"),
- SPAN_HIGHDANGER("[user] aims \the [fired_from] directly at your head!"),
- SPAN_DANGER("[user] aims \the [fired_from] at [execution_target]'s head!"))
-
- user.next_move += 1.1 SECONDS //PB has no click delay; readding it here to prevent people accidentally queuing up multiple executions.
-
- if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_HOSTILE) || !user.Adjacent(execution_target))
- fired_from.delete_bullet(firing_projectile, TRUE)
- return
-
- if(!(fired_from.flags_gun_features & GUN_SILENCED))
- playsound(user, fired_from.fire_sound, fired_from.firesound_volume, FALSE)
- else
- playsound(user, fired_from.fire_sound, 25, FALSE)
-
- shake_camera(user, 1, 2)
-
- execution_target.apply_damage(damage * 3, BRUTE, "head", no_limb_loss = TRUE, permanent_kill = TRUE) //Apply gobs of damage and make sure they can't be revived later...
- execution_target.apply_damage(200, OXY) //...fill out the rest of their health bar with oxyloss...
- execution_target.death(create_cause_data("execution", user)) //...make certain they're properly dead...
- shake_camera(execution_target, 3, 4)
- execution_target.update_headshot_overlay(headshot_state) //...and add a gory headshot overlay.
-
- execution_target.visible_message(SPAN_HIGHDANGER(uppertext("[execution_target] WAS EXECUTED!")), \
- SPAN_HIGHDANGER("You WERE EXECUTED!"))
-
- user.count_niche_stat(STATISTICS_NICHE_EXECUTION, 1, firing_projectile.weapon_cause_data?.cause_name)
-
- var/area/execution_area = get_area(execution_target)
-
- msg_admin_attack(FONT_SIZE_HUGE("[key_name(usr)] has battlefield executed [key_name(execution_target)] in [get_area(usr)] ([usr.loc.x],[usr.loc.y],[usr.loc.z])."), usr.loc.x, usr.loc.y, usr.loc.z)
- log_attack("[key_name(usr)] battlefield executed [key_name(execution_target)] at [execution_area.name].")
-
- if(flags_ammo_behavior & AMMO_EXPLOSIVE)
- execution_target.gib()
-
-
-/*
-//======
- Pistol Ammo
-//======
-*/
-
-// Used by M4A3, M4A3 Custom and B92FS
-/datum/ammo/bullet/pistol
- name = "pistol bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
- accuracy = -HIT_ACCURACY_TIER_3
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- damage = 40
- penetration= ARMOR_PENETRATION_TIER_2
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
-
-/datum/ammo/bullet/pistol/tiny
- name = "light pistol bullet"
-
-/datum/ammo/bullet/pistol/tranq
- name = "tranquilizer bullet"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST
- stamina_damage = 30
- damage = 15
-
-//2020 rebalance: is supposed to counter runners and lurkers, dealing high damage to the only castes with no armor.
-//Limited by its lack of versatility and lower supply, so marines finally have an answer for flanker castes that isn't just buckshot.
-
-/datum/ammo/bullet/pistol/hollow
- name = "hollowpoint pistol bullet"
-
- damage = 55 //hollowpoint is strong
- penetration = 0 //hollowpoint can't pierce armor!
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_3 //hollowpoint causes shrapnel
-
-// Used by M4A3 AP and mod88
-/datum/ammo/bullet/pistol/ap
- name = "armor-piercing pistol bullet"
-
- damage = 25
- accuracy = HIT_ACCURACY_TIER_2
- penetration= ARMOR_PENETRATION_TIER_8
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
-
-/datum/ammo/bullet/pistol/ap/penetrating
- name = "wall-penetrating pistol bullet"
- shrapnel_chance = 0
-
- damage = 30
- penetration = ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/bullet/pistol/ap/penetrating/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
- ))
-
-/datum/ammo/bullet/pistol/ap/toxin
- name = "toxic pistol bullet"
- var/acid_per_hit = 10
- var/organic_damage_mult = 3
-
-/datum/ammo/bullet/pistol/ap/toxin/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
-
-/datum/ammo/bullet/pistol/ap/toxin/on_hit_turf(turf/T, obj/projectile/P)
- . = ..()
- if(T.flags_turf & TURF_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/pistol/ap/toxin/on_hit_obj(obj/O, obj/projectile/P)
- . = ..()
- if(O.flags_obj & OBJ_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/pistol/le
- name = "armor-shredding pistol bullet"
-
- damage = 15
- penetration = ARMOR_PENETRATION_TIER_4
- pen_armor_punch = 3
-
-/datum/ammo/bullet/pistol/rubber
- name = "rubber pistol bullet"
- sound_override = 'sound/weapons/gun_c99.ogg'
-
- damage = 0
- stamina_damage = 25
- shrapnel_chance = 0
-
-// Reskinned rubber bullet used for the ES-4 CL pistol.
-/datum/ammo/bullet/pistol/rubber/stun
- name = "stun pistol bullet"
- sound_override = null
-
-// Used by M1911, Deagle and KT-42
-/datum/ammo/bullet/pistol/heavy
- name = "heavy pistol bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
- accuracy = -HIT_ACCURACY_TIER_3
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- damage = 55
- penetration = ARMOR_PENETRATION_TIER_3
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
-
-/datum/ammo/bullet/pistol/heavy/super //Commander's variant
- name = ".50 heavy pistol bullet"
- damage = 60
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_6
- penetration = ARMOR_PENETRATION_TIER_4
-
-/datum/ammo/bullet/pistol/heavy/super/highimpact
- name = ".50 high-impact pistol bullet"
- penetration = ARMOR_PENETRATION_TIER_1
- debilitate = list(0,1.5,0,0,0,1,0,0)
- flags_ammo_behavior = AMMO_BALLISTIC
-
-/datum/ammo/bullet/pistol/heavy/super/highimpact/ap
- name = ".50 high-impact armor piercing pistol bullet"
- penetration = ARMOR_PENETRATION_TIER_10
- damage = 45
-
-/datum/ammo/bullet/pistol/heavy/super/highimpact/upp
- name = "high-impact pistol bullet"
- sound_override = 'sound/weapons/gun_DE50.ogg'
- penetration = ARMOR_PENETRATION_TIER_6
- debilitate = list(0,1.5,0,0,0,1,0,0)
- flags_ammo_behavior = AMMO_BALLISTIC
-
-/datum/ammo/bullet/pistol/heavy/super/highimpact/New()
- ..()
- RegisterSignal(src, COMSIG_AMMO_POINT_BLANK, PROC_REF(handle_battlefield_execution))
-
-/datum/ammo/bullet/pistol/heavy/super/highimpact/on_hit_mob(mob/M, obj/projectile/P)
- knockback(M, P, 4)
-
-/datum/ammo/bullet/pistol/deagle
- name = ".50 heavy pistol bullet"
- damage = 45
- headshot_state = HEADSHOT_OVERLAY_HEAVY
- accuracy = -HIT_ACCURACY_TIER_3
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- penetration = ARMOR_PENETRATION_TIER_6
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_5
-
-/datum/ammo/bullet/pistol/incendiary
- name = "incendiary pistol bullet"
- damage_type = BURN
- shrapnel_chance = 0
- flags_ammo_behavior = AMMO_BALLISTIC
-
- accuracy = HIT_ACCURACY_TIER_3
- damage = 20
-
-/datum/ammo/bullet/pistol/incendiary/set_bullet_traits()
- ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-// Used by the hipower
-// I know that the 'high power' in the name is supposed to mean its 'impressive' magazine capacity
-// but this is CM, half our guns have baffling misconceptions and mistakes (how do you grab the type-71?) so it's on-brand.
-// maybe in the far flung future of 2280 someone screwed up the design.
-
-/datum/ammo/bullet/pistol/highpower
- name = "high-powered pistol bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
-
- accuracy = HIT_ACCURACY_TIER_3
- damage = 36
- penetration = ARMOR_PENETRATION_TIER_5
- damage_falloff = DAMAGE_FALLOFF_TIER_7
-
-// Used by VP78 and Auto 9
-/datum/ammo/bullet/pistol/squash
- name = "squash-head pistol bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
- debilitate = list(0,0,0,0,0,0,0,2)
-
- accuracy = HIT_ACCURACY_TIER_4
- damage = 45
- penetration= ARMOR_PENETRATION_TIER_6
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
- damage_falloff = DAMAGE_FALLOFF_TIER_6 //"VP78 - the only pistol viable as a primary."-Vampmare, probably.
-
-/datum/ammo/bullet/pistol/squash/toxin
- name = "toxic squash-head pistol bullet"
- var/acid_per_hit = 10
- var/organic_damage_mult = 3
-
-/datum/ammo/bullet/pistol/squash/toxin/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
-
-/datum/ammo/bullet/pistol/squash/toxin/on_hit_turf(turf/T, obj/projectile/P)
- . = ..()
- if(T.flags_turf & TURF_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/pistol/squash/toxin/on_hit_obj(obj/O, obj/projectile/P)
- . = ..()
- if(O.flags_obj & OBJ_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/pistol/squash/penetrating
- name = "wall-penetrating squash-head pistol bullet"
- shrapnel_chance = 0
- penetration = ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/bullet/pistol/squash/penetrating/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
- ))
-
-/datum/ammo/bullet/pistol/squash/incendiary
- name = "incendiary squash-head pistol bullet"
- damage_type = BURN
- shrapnel_chance = 0
- flags_ammo_behavior = AMMO_BALLISTIC
- accuracy = HIT_ACCURACY_TIER_3
- damage = 35
-
-/datum/ammo/bullet/pistol/squash/incendiary/set_bullet_traits()
- ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-
-/datum/ammo/bullet/pistol/mankey
- name = "live monkey"
- icon_state = "monkey1"
- ping = null //no bounce off.
- damage_type = BURN
- debilitate = list(4,4,0,0,0,0,0,0)
- flags_ammo_behavior = AMMO_IGNORE_ARMOR
-
- damage = 15
- damage_var_high = PROJECTILE_VARIANCE_TIER_5
- shell_speed = AMMO_SPEED_TIER_2
-
-/datum/ammo/bullet/pistol/mankey/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/pistol/mankey/on_hit_mob(mob/M,obj/projectile/P)
- if(P && P.loc && !M.stat && !istype(M,/mob/living/carbon/human/monkey))
- P.visible_message(SPAN_DANGER("The [src] chimpers furiously!"))
- new /mob/living/carbon/human/monkey(P.loc)
-
-/datum/ammo/bullet/pistol/smart
- name = "smartpistol bullet"
- flags_ammo_behavior = AMMO_BALLISTIC
-
- accuracy = HIT_ACCURACY_TIER_8
- damage = 30
- penetration = 20
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
-
-/*
-//======
- Revolver Ammo
-//======
-*/
-
-/datum/ammo/bullet/revolver
- name = "revolver bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
-
- damage = 55
- penetration = ARMOR_PENETRATION_TIER_1
- accuracy = HIT_ACCURACY_TIER_1
-
-/datum/ammo/bullet/revolver/marksman
- name = "marksman revolver bullet"
-
- shrapnel_chance = 0
- damage_falloff = 0
- accurate_range = 12
- penetration = ARMOR_PENETRATION_TIER_7
-
-/datum/ammo/bullet/revolver/heavy
- name = "heavy revolver bullet"
-
- damage = 35
- penetration = ARMOR_PENETRATION_TIER_4
- accuracy = HIT_ACCURACY_TIER_3
-
-/datum/ammo/bullet/revolver/heavy/on_hit_mob(mob/M, obj/projectile/P)
- knockback(M, P, 4)
-
-/datum/ammo/bullet/revolver/incendiary
- name = "incendiary revolver bullet"
- damage = 40
-
-/datum/ammo/bullet/revolver/incendiary/set_bullet_traits()
- ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/revolver/marksman/toxin
- name = "toxic revolver bullet"
- var/acid_per_hit = 10
- var/organic_damage_mult = 3
-
-/datum/ammo/bullet/revolver/marksman/toxin/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
-
-/datum/ammo/bullet/revolver/marksman/toxin/on_hit_turf(turf/T, obj/projectile/P)
- . = ..()
- if(T.flags_turf & TURF_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/revolver/marksman/toxin/on_hit_obj(obj/O, obj/projectile/P)
- . = ..()
- if(O.flags_obj & OBJ_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/revolver/penetrating
- name = "wall-penetrating revolver bullet"
- shrapnel_chance = 0
-
- penetration = ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/bullet/revolver/penetrating/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
- ))
-
-/datum/ammo/bullet/revolver/upp
- name = "heavy revolver bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
- penetration = ARMOR_PENETRATION_TIER_4
- damage = 70
-
-
-/datum/ammo/bullet/revolver/upp/shrapnel
- name = "shrapnel shot"
- headshot_state = HEADSHOT_OVERLAY_HEAVY //Gol-dang shotgun blow your fething head off.
- debilitate = list(0,0,0,0,0,0,0,0)
- icon_state = "shrapnelshot"
- handful_state = "shrapnel"
- bonus_projectiles_type = /datum/ammo/bullet/revolver/upp/shrapnel_bits
-
- max_range = 6
- damage = 40 // + TIER_4 * 3
- damage_falloff = DAMAGE_FALLOFF_TIER_7
- penetration = ARMOR_PENETRATION_TIER_8
- bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3
- shrapnel_chance = 100
- shrapnel_type = /obj/item/shard/shrapnel/upp
- //roughly 90 or so damage with the additional shrapnel, around 130 in total with primary round
-
-/datum/ammo/bullet/revolver/upp/shrapnel/on_hit_mob(mob/M, obj/projectile/P)
- pushback(M, P, 1)
-
-/datum/ammo/bullet/revolver/upp/shrapnel_bits
- name = "small shrapnel"
- icon_state = "shrapnelshot_bit"
-
- max_range = 6
- damage = 30
- penetration = ARMOR_PENETRATION_TIER_4
- scatter = SCATTER_AMOUNT_TIER_1
- bonus_projectiles_amount = 0
- shrapnel_type = /obj/item/shard/shrapnel/upp/bits
-
-/datum/ammo/bullet/revolver/small
- name = "small revolver bullet"
- headshot_state = HEADSHOT_OVERLAY_LIGHT
-
- damage = 45
-
- penetration = ARMOR_PENETRATION_TIER_3
-
-/datum/ammo/bullet/revolver/small/hollowpoint
- name = "small hollowpoint revolver bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
-
- damage = 75 // way too strong because it's hard to make a good balance between HP and normal with this system, but the damage falloff is really strong
- penetration = 0
- damage_falloff = DAMAGE_FALLOFF_TIER_6
-
-/datum/ammo/bullet/revolver/mateba
- name = ".454 heavy revolver bullet"
-
- damage = 60
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_6
- penetration = ARMOR_PENETRATION_TIER_4
-
-/datum/ammo/bullet/revolver/mateba/highimpact
- name = ".454 heavy high-impact revolver bullet"
- debilitate = list(0,2,0,0,0,1,0,0)
- penetration = ARMOR_PENETRATION_TIER_1
- flags_ammo_behavior = AMMO_BALLISTIC
-
-/datum/ammo/bullet/revolver/mateba/highimpact/ap
- name = ".454 heavy high-impact armor piercing revolver bullet"
- penetration = ARMOR_PENETRATION_TIER_10
- damage = 45
-
-/datum/ammo/bullet/revolver/mateba/highimpact/New()
- ..()
- RegisterSignal(src, COMSIG_AMMO_POINT_BLANK, PROC_REF(handle_battlefield_execution))
-
-/datum/ammo/bullet/revolver/mateba/highimpact/on_hit_mob(mob/M, obj/projectile/P)
- knockback(M, P, 4)
-
-/datum/ammo/bullet/revolver/mateba/highimpact/explosive //if you ever put this in normal gameplay, i am going to scream
- name = ".454 heavy explosive revolver bullet"
- damage = 100
- damage_var_low = PROJECTILE_VARIANCE_TIER_10
- damage_var_high = PROJECTILE_VARIANCE_TIER_1
- penetration = ARMOR_PENETRATION_TIER_10
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_BALLISTIC
-
-/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_mob(mob/M, obj/projectile/P)
- ..()
- cell_explosion(get_turf(M), 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
-
-/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_obj(obj/O, obj/projectile/P)
- ..()
- cell_explosion(get_turf(O), 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
-
-/datum/ammo/bullet/revolver/mateba/highimpact/explosive/on_hit_turf(turf/T, obj/projectile/P)
- ..()
- cell_explosion(T, 120, 30, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
-
-/datum/ammo/bullet/revolver/webley //Mateba round without the knockdown.
- name = ".455 Webley bullet"
- damage = 60
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_6
- penetration = ARMOR_PENETRATION_TIER_2
-
-/*
-//======
- SMG Ammo
-//======
-*/
-//2020 SMG/ammo rebalance. default ammo actually has penetration so it can be useful, by 4khan: should be meh against t3s, better under 15 armor. Perfectly does this right now (oct 2020)
-//has reduced falloff compared to the m39. this means it is best for kiting castes (mostly t2s and below admittedly)
-//while the m39 ap is better for shredding them at close range, but has reduced velocity, so it's better for just running in and erasing armor-centric castes (defender, crusher)
-// which i think is really interesting and good balance, giving both ammo types a reason to exist even against ravagers.
-//i feel it is necessary to reflavor the default bullet, because otherwise, people won't be able to notice it has less falloff and faster bullet speed. even with a changelog,
-//way too many people don't read the changelog, and after one or two months the changelog entry is all but archive, so there needs to be an ingame description of what the ammo does
-//in comparison to armor-piercing rounds.
-
-/datum/ammo/bullet/smg
- name = "submachinegun bullet"
- damage = 34
- accurate_range = 4
- effective_range_max = 4
- penetration = ARMOR_PENETRATION_TIER_1
- shell_speed = AMMO_SPEED_TIER_6
- damage_falloff = DAMAGE_FALLOFF_TIER_5
- scatter = SCATTER_AMOUNT_TIER_6
- accuracy = HIT_ACCURACY_TIER_3
-
-/datum/ammo/bullet/smg/m39
- name = "high-velocity submachinegun bullet" //i don't want all smgs to inherit 'high velocity'
-
-/datum/ammo/bullet/smg/ap
- name = "armor-piercing submachinegun bullet"
-
- damage = 26
- penetration = ARMOR_PENETRATION_TIER_6
- shell_speed = AMMO_SPEED_TIER_4
-
-/datum/ammo/bullet/smg/heap
- name = "high-explosive armor-piercing submachinegun bullet"
-
- damage = 45
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
- penetration = ARMOR_PENETRATION_TIER_6
- shell_speed = AMMO_SPEED_TIER_4
-
-/datum/ammo/bullet/smg/ap/toxin
- name = "toxic submachinegun bullet"
- var/acid_per_hit = 5
- var/organic_damage_mult = 3
-
-/datum/ammo/bullet/smg/ap/toxin/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
-
-/datum/ammo/bullet/smg/ap/toxin/on_hit_turf(turf/T, obj/projectile/P)
- . = ..()
- if(T.flags_turf & TURF_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/smg/ap/toxin/on_hit_obj(obj/O, obj/projectile/P)
- . = ..()
- if(O.flags_obj & OBJ_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/smg/nail
- name = "7x45mm plasteel nail"
- icon_state = "nail-projectile"
-
- damage = 25
- penetration = ARMOR_PENETRATION_TIER_5
- damage_falloff = DAMAGE_FALLOFF_TIER_6
- accurate_range = 5
- shell_speed = AMMO_SPEED_TIER_4
-
-/datum/ammo/bullet/smg/incendiary
- name = "incendiary submachinegun bullet"
- damage_type = BURN
- shrapnel_chance = 0
- flags_ammo_behavior = AMMO_BALLISTIC
-
- damage = 25
- accuracy = -HIT_ACCURACY_TIER_2
-
-/datum/ammo/bullet/smg/incendiary/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/smg/ap/penetrating
- name = "wall-penetrating submachinegun bullet"
- shrapnel_chance = 0
-
- damage = 30
- penetration = ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/bullet/smg/ap/penetrating/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
- ))
-
-/datum/ammo/bullet/smg/le
- name = "armor-shredding submachinegun bullet"
-
- scatter = SCATTER_AMOUNT_TIER_10
- damage = 20
- penetration = ARMOR_PENETRATION_TIER_4
- shell_speed = AMMO_SPEED_TIER_3
- damage_falloff = DAMAGE_FALLOFF_TIER_10
- pen_armor_punch = 4
-
-/datum/ammo/bullet/smg/rubber
- name = "rubber submachinegun bullet"
- sound_override = 'sound/weapons/gun_c99.ogg'
-
- damage = 0
- stamina_damage = 10
- shrapnel_chance = 0
-
-/datum/ammo/bullet/smg/mp27
- name = "simple submachinegun bullet"
- damage = 40
- accurate_range = 5
- effective_range_max = 7
- penetration = 0
- shell_speed = AMMO_SPEED_TIER_6
- damage_falloff = DAMAGE_FALLOFF_TIER_6
- scatter = SCATTER_AMOUNT_TIER_6
- accuracy = HIT_ACCURACY_TIER_2
-
-// less damage than the m39, but better falloff, range, and AP
-
-/datum/ammo/bullet/smg/ppsh
- name = "crude submachinegun bullet"
- damage = 26
- accurate_range = 7
- effective_range_max = 7
- penetration = ARMOR_PENETRATION_TIER_2
- damage_falloff = DAMAGE_FALLOFF_TIER_7
- scatter = SCATTER_AMOUNT_TIER_5
-
-/datum/ammo/bullet/smg/pps43
- name = "simple submachinegun bullet"
- damage = 35
- accurate_range = 7
- effective_range_max = 10
- penetration = ARMOR_PENETRATION_TIER_4
- damage_falloff = DAMAGE_FALLOFF_TIER_6
- scatter = SCATTER_AMOUNT_TIER_6
-
-/*
-//======
- Rifle Ammo
-//======
-*/
-
-/datum/ammo/bullet/rifle
- name = "rifle bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
-
- damage = 40
- penetration = ARMOR_PENETRATION_TIER_1
- accurate_range = 16
- accuracy = HIT_ACCURACY_TIER_4
- scatter = SCATTER_AMOUNT_TIER_10
- shell_speed = AMMO_SPEED_TIER_6
- effective_range_max = 7
- damage_falloff = DAMAGE_FALLOFF_TIER_7
- max_range = 24 //So S8 users don't have their bullets magically disappaer at 22 tiles (S8 can see 24 tiles)
-
-/datum/ammo/bullet/rifle/holo_target
- name = "holo-targeting rifle bullet"
- damage = 30
- var/holo_stacks = 10
-
-/datum/ammo/bullet/rifle/holo_target/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- M.AddComponent(/datum/component/bonus_damage_stack, holo_stacks, world.time)
-
-/datum/ammo/bullet/rifle/holo_target/hunting
- name = "holo-targeting hunting bullet"
- damage = 25
- holo_stacks = 15
-
-/datum/ammo/bullet/rifle/explosive
- name = "explosive rifle bullet"
-
- damage = 25
- accurate_range = 22
- accuracy = 0
- shell_speed = AMMO_SPEED_TIER_4
- damage_falloff = DAMAGE_FALLOFF_TIER_9
-
-/datum/ammo/bullet/rifle/explosive/on_hit_mob(mob/M, obj/projectile/P)
- cell_explosion(get_turf(M), 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
-
-/datum/ammo/bullet/rifle/explosive/on_hit_obj(obj/O, obj/projectile/P)
- cell_explosion(get_turf(O), 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
-
-/datum/ammo/bullet/rifle/explosive/on_hit_turf(turf/T, obj/projectile/P)
- if(T.density)
- cell_explosion(T, 80, 40, EXPLOSION_FALLOFF_SHAPE_LINEAR, P.dir, P.weapon_cause_data)
-
-/datum/ammo/bullet/rifle/ap
- name = "armor-piercing rifle bullet"
-
- damage = 30
- penetration = ARMOR_PENETRATION_TIER_8
-
-// Basically AP but better. Focused at taking out armour temporarily
-/datum/ammo/bullet/rifle/ap/toxin
- name = "toxic rifle bullet"
- var/acid_per_hit = 7
- var/organic_damage_mult = 3
-
-/datum/ammo/bullet/rifle/ap/toxin/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- M.AddComponent(/datum/component/toxic_buildup, acid_per_hit)
-
-/datum/ammo/bullet/rifle/ap/toxin/on_hit_turf(turf/T, obj/projectile/P)
- . = ..()
- if(T.flags_turf & TURF_ORGANIC)
- P.damage *= organic_damage_mult
-
-/datum/ammo/bullet/rifle/ap/toxin/on_hit_obj(obj/O, obj/projectile/P)
- . = ..()
- if(O.flags_obj & OBJ_ORGANIC)
- P.damage *= organic_damage_mult
-
-
-/datum/ammo/bullet/rifle/ap/penetrating
- name = "wall-penetrating rifle bullet"
- shrapnel_chance = 0
-
- damage = 35
- penetration = ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/bullet/rifle/ap/penetrating/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
- ))
-
-/datum/ammo/bullet/rifle/le
- name = "armor-shredding rifle bullet"
-
- damage = 20
- penetration = ARMOR_PENETRATION_TIER_4
- pen_armor_punch = 5
-
-/datum/ammo/bullet/rifle/heap
- name = "high-explosive armor-piercing rifle bullet"
-
- headshot_state = HEADSHOT_OVERLAY_HEAVY
- damage = 55//big damage, doesn't actually blow up because thats stupid.
- penetration = ARMOR_PENETRATION_TIER_8
-
-/datum/ammo/bullet/rifle/rubber
- name = "rubber rifle bullet"
- sound_override = 'sound/weapons/gun_c99.ogg'
-
- damage = 0
- stamina_damage = 15
- shrapnel_chance = 0
-
-/datum/ammo/bullet/rifle/incendiary
- name = "incendiary rifle bullet"
- damage_type = BURN
- shrapnel_chance = 0
- flags_ammo_behavior = AMMO_BALLISTIC
-
- damage = 30
- shell_speed = AMMO_SPEED_TIER_4
- accuracy = -HIT_ACCURACY_TIER_2
- damage_falloff = DAMAGE_FALLOFF_TIER_10
-
-/datum/ammo/bullet/rifle/incendiary/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/rifle/m4ra
- name = "A19 high velocity bullet"
- shrapnel_chance = 0
- damage_falloff = 0
- flags_ammo_behavior = AMMO_BALLISTIC
- accurate_range_min = 4
-
- damage = 55
- scatter = -SCATTER_AMOUNT_TIER_8
- penetration= ARMOR_PENETRATION_TIER_7
- shell_speed = AMMO_SPEED_TIER_6
-
-/datum/ammo/bullet/rifle/m4ra/incendiary
- name = "A19 high velocity incendiary bullet"
- flags_ammo_behavior = AMMO_BALLISTIC
-
- damage = 40
- accuracy = HIT_ACCURACY_TIER_4
- scatter = -SCATTER_AMOUNT_TIER_8
- penetration= ARMOR_PENETRATION_TIER_5
- shell_speed = AMMO_SPEED_TIER_6
-
-/datum/ammo/bullet/rifle/m4ra/incendiary/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/rifle/m4ra/impact
- name = "A19 high velocity impact bullet"
- flags_ammo_behavior = AMMO_BALLISTIC
-
- damage = 40
- accuracy = -HIT_ACCURACY_TIER_2
- scatter = -SCATTER_AMOUNT_TIER_8
- penetration = ARMOR_PENETRATION_TIER_10
- shell_speed = AMMO_SPEED_TIER_6
-
-/datum/ammo/bullet/rifle/m4ra/impact/on_hit_mob(mob/M, obj/projectile/P)
- knockback(M, P, 32) // Can knockback basically at max range
-
-/datum/ammo/bullet/rifle/m4ra/impact/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
- if(iscarbonsizexeno(living_mob))
- var/mob/living/carbon/xenomorph/target = living_mob
- to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!"))
- target.apply_effect(0.5, WEAKEN)
- target.apply_effect(2, SUPERSLOW)
- target.apply_effect(5, SLOW)
- else
- if(!isyautja(living_mob)) //Not predators.
- living_mob.apply_effect(1, SUPERSLOW)
- living_mob.apply_effect(2, SLOW)
- to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!"))
- living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
-
-/datum/ammo/bullet/rifle/mar40
- name = "heavy rifle bullet"
-
- damage = 55
-
-/datum/ammo/bullet/rifle/type71
- name = "heavy rifle bullet"
-
- damage = 55
- penetration = ARMOR_PENETRATION_TIER_3
-
-/datum/ammo/bullet/rifle/type71/ap
- name = "heavy armor-piercing rifle bullet"
-
- damage = 40
- penetration = ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/bullet/rifle/type71/heap
- name = "heavy high-explosive armor-piercing rifle bullet"
-
- headshot_state = HEADSHOT_OVERLAY_HEAVY
- damage = 65
- penetration = ARMOR_PENETRATION_TIER_10
-
-/*
-//======
- Shotgun Ammo
-//======
-*/
-
-/datum/ammo/bullet/shotgun
- headshot_state = HEADSHOT_OVERLAY_HEAVY
-
-/datum/ammo/bullet/shotgun/slug
- name = "shotgun slug"
- handful_state = "slug_shell"
-
- accurate_range = 6
- max_range = 8
- damage = 70
- penetration = ARMOR_PENETRATION_TIER_4
- damage_armor_punch = 2
- handful_state = "slug_shell"
-
-/datum/ammo/bullet/shotgun/slug/on_hit_mob(mob/M,obj/projectile/P)
- knockback(M, P, 6)
-
-/datum/ammo/bullet/shotgun/slug/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
- if(iscarbonsizexeno(living_mob))
- var/mob/living/carbon/xenomorph/target = living_mob
- to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!"))
- target.apply_effect(0.5, WEAKEN)
- target.apply_effect(1, SUPERSLOW)
- target.apply_effect(3, SLOW)
- else
- if(!isyautja(living_mob)) //Not predators.
- living_mob.apply_effect(1, SUPERSLOW)
- living_mob.apply_effect(2, SLOW)
- to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!"))
- living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
-
-/datum/ammo/bullet/shotgun/beanbag
- name = "beanbag slug"
- headshot_state = HEADSHOT_OVERLAY_LIGHT //It's not meant to kill people... but if you put it in your mouth, it will.
- handful_state = "beanbag_slug"
- icon_state = "beanbag"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST
- sound_override = 'sound/weapons/gun_shotgun_riot.ogg'
-
- max_range = 12
- shrapnel_chance = 0
- damage = 0
- stamina_damage = 45
- accuracy = HIT_ACCURACY_TIER_3
- shell_speed = AMMO_SPEED_TIER_3
- handful_state = "beanbag_slug"
-
-/datum/ammo/bullet/shotgun/beanbag/on_hit_mob(mob/M, obj/projectile/P)
- if(!M || M == P.firer) return
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- shake_camera(H, 2, 1)
-
-
-/datum/ammo/bullet/shotgun/incendiary
- name = "incendiary slug"
- handful_state = "incendiary_slug"
- damage_type = BURN
- flags_ammo_behavior = AMMO_BALLISTIC
-
- accuracy = -HIT_ACCURACY_TIER_2
- max_range = 12
- damage = 55
- penetration= ARMOR_PENETRATION_TIER_1
- handful_state = "incendiary_slug"
-
-/datum/ammo/bullet/shotgun/incendiary/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/shotgun/incendiary/on_hit_mob(mob/M,obj/projectile/P)
- burst(get_turf(M),P,damage_type)
- knockback(M,P)
-
-/datum/ammo/bullet/shotgun/incendiary/on_hit_obj(obj/O,obj/projectile/P)
- burst(get_turf(P),P,damage_type)
-
-/datum/ammo/bullet/shotgun/incendiary/on_hit_turf(turf/T,obj/projectile/P)
- burst(get_turf(T),P,damage_type)
-
-
-/datum/ammo/bullet/shotgun/flechette
- name = "flechette shell"
- icon_state = "flechette"
- handful_state = "flechette_shell"
- bonus_projectiles_type = /datum/ammo/bullet/shotgun/flechette_spread
-
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
- max_range = 12
- damage = 30
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_8
- penetration = ARMOR_PENETRATION_TIER_7
- bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3
- handful_state = "flechette_shell"
- multiple_handful_name = TRUE
-
-/datum/ammo/bullet/shotgun/flechette_spread
- name = "additional flechette"
- icon_state = "flechette"
-
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
- max_range = 12
- damage = 30
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_8
- penetration = ARMOR_PENETRATION_TIER_7
- scatter = SCATTER_AMOUNT_TIER_5
-
-/datum/ammo/bullet/shotgun/buckshot
- name = "buckshot shell"
- icon_state = "buckshot"
- handful_state = "buckshot_shell"
- multiple_handful_name = TRUE
- bonus_projectiles_type = /datum/ammo/bullet/shotgun/spread
-
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_5
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_5
- accurate_range = 4
- max_range = 4
- damage = 65
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_8
- penetration = ARMOR_PENETRATION_TIER_1
- bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3
- shell_speed = AMMO_SPEED_TIER_2
- damage_armor_punch = 0
- pen_armor_punch = 0
- handful_state = "buckshot_shell"
- multiple_handful_name = TRUE
-
-/datum/ammo/bullet/shotgun/buckshot/incendiary
- name = "incendiary buckshot shell"
- handful_state = "incen_buckshot"
- handful_type = /obj/item/ammo_magazine/handful/shotgun/buckshot/incendiary
-
-/datum/ammo/bullet/shotgun/buckshot/incendiary/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/shotgun/buckshot/on_hit_mob(mob/M,obj/projectile/P)
- knockback(M,P)
-
-//buckshot variant only used by the masterkey shotgun attachment.
-/datum/ammo/bullet/shotgun/buckshot/masterkey
- bonus_projectiles_type = /datum/ammo/bullet/shotgun/spread/masterkey
-
- damage = 55
-
-/datum/ammo/bullet/shotgun/spread
- name = "additional buckshot"
- icon_state = "buckshot"
-
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
- accurate_range = 4
- max_range = 6
- damage = 65
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_8
- penetration = ARMOR_PENETRATION_TIER_1
- shell_speed = AMMO_SPEED_TIER_2
- scatter = SCATTER_AMOUNT_TIER_1
- damage_armor_punch = 0
- pen_armor_punch = 0
-
-/datum/ammo/bullet/shotgun/spread/masterkey
- damage = 20
-
-/*
- 8 GAUGE SHOTGUN AMMO
-*/
-
-/datum/ammo/bullet/shotgun/heavy/buckshot
- name = "heavy buckshot shell"
- icon_state = "buckshot"
- handful_state = "heavy_buckshot"
- multiple_handful_name = TRUE
- bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/buckshot/spread
- bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_3
- accurate_range = 3
- max_range = 3
- damage = 75
- penetration = 0
- shell_speed = AMMO_SPEED_TIER_2
- damage_armor_punch = 0
- pen_armor_punch = 0
-
-/datum/ammo/bullet/shotgun/heavy/buckshot/on_hit_mob(mob/M,obj/projectile/P)
- knockback(M,P)
-
-/datum/ammo/bullet/shotgun/heavy/buckshot/spread
- name = "additional heavy buckshot"
- max_range = 4
- scatter = SCATTER_AMOUNT_TIER_1
- bonus_projectiles_amount = 0
-
-//basically the same
-/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath
- name = "dragon's breath shell"
- handful_state = "heavy_dragonsbreath"
- multiple_handful_name = TRUE
- damage_type = BURN
- damage = 60
- accurate_range = 3
- max_range = 4
- bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/spread
-
-/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/shotgun/heavy/buckshot/dragonsbreath/spread
- name = "additional dragon's breath"
- bonus_projectiles_amount = 0
- accurate_range = 4
- max_range = 5 //make use of the ablaze property
- shell_speed = AMMO_SPEED_TIER_4 // so they hit before the main shell stuns
-
-
-/datum/ammo/bullet/shotgun/heavy/slug
- name = "heavy shotgun slug"
- handful_state = "heavy_slug"
-
- accurate_range = 7
- max_range = 8
- damage = 90 //ouch.
- penetration = ARMOR_PENETRATION_TIER_6
- damage_armor_punch = 2
-
-/datum/ammo/bullet/shotgun/heavy/slug/on_hit_mob(mob/M,obj/projectile/P)
- knockback(M, P, 7)
-
-/datum/ammo/bullet/shotgun/heavy/slug/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
- if(iscarbonsizexeno(living_mob))
- var/mob/living/carbon/xenomorph/target = living_mob
- to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!"))
- target.apply_effect(0.5, WEAKEN)
- target.apply_effect(2, SUPERSLOW)
- target.apply_effect(5, SLOW)
- else
- if(!isyautja(living_mob)) //Not predators.
- living_mob.apply_effect(1, SUPERSLOW)
- living_mob.apply_effect(2, SLOW)
- to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!"))
- living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
-
-/datum/ammo/bullet/shotgun/heavy/beanbag
- name = "heavy beanbag slug"
- icon_state = "beanbag"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
- handful_state = "heavy_beanbag"
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_RESIST
- sound_override = 'sound/weapons/gun_shotgun_riot.ogg'
-
- max_range = 7
- shrapnel_chance = 0
- damage = 0
- stamina_damage = 100
- accuracy = HIT_ACCURACY_TIER_2
- shell_speed = AMMO_SPEED_TIER_2
-
-/datum/ammo/bullet/shotgun/heavy/beanbag/on_hit_mob(mob/M, obj/projectile/P)
- if(!M || M == P.firer)
- return
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- shake_camera(H, 2, 1)
-
-/datum/ammo/bullet/shotgun/heavy/flechette
- name = "heavy flechette shell"
- icon_state = "flechette"
- handful_state = "heavy_flechette"
- multiple_handful_name = TRUE
- bonus_projectiles_type = /datum/ammo/bullet/shotgun/heavy/flechette_spread
-
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_3
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_3
- max_range = 12
- damage = 45
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_8
- penetration = ARMOR_PENETRATION_TIER_10
- bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_2
-
-/datum/ammo/bullet/shotgun/heavy/flechette_spread
- name = "additional heavy flechette"
- icon_state = "flechette"
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
- max_range = 12
- damage = 45
- damage_var_low = PROJECTILE_VARIANCE_TIER_8
- damage_var_high = PROJECTILE_VARIANCE_TIER_8
- penetration = ARMOR_PENETRATION_TIER_10
- scatter = SCATTER_AMOUNT_TIER_4
-
-//Enormous shell for Van Bandolier's superheavy double-barreled hunting gun.
-/datum/ammo/bullet/shotgun/twobore
- name = "two bore bullet"
- icon_state = "autocannon"
- handful_state = "twobore"
-
- accurate_range = 8 //Big low-velocity projectile; this is for blasting dangerous game at close range.
- max_range = 14 //At this range, it's lost all its damage anyway.
- damage = 300 //Hits like a buckshot PB.
- penetration = ARMOR_PENETRATION_TIER_3
- damage_falloff = DAMAGE_FALLOFF_TIER_1 * 3 //It has a lot of energy, but the 26mm bullet drops off fast.
- effective_range_max = EFFECTIVE_RANGE_MAX_TIER_2 //Full damage up to this distance, then falloff for each tile beyond.
- var/hit_messages = list()
-
-/datum/ammo/bullet/shotgun/twobore/on_hit_mob(mob/living/M, obj/projectile/P)
- var/mob/shooter = P.firer
- if(shooter && ismob(shooter) && HAS_TRAIT(shooter, TRAIT_TWOBORE_TRAINING) && M.stat != DEAD && prob(40)) //Death is handled by periodic life() checks so this should have a chance to fire on a killshot.
- if(!length(hit_messages)) //Pick and remove lines, refill on exhaustion.
- hit_messages = list("Got you!", "Aha!", "Bullseye!", "It's curtains for you, Sonny Jim!", "Your head will look fantastic on my wall!", "I have you now!", "You miserable coward! Come and fight me like a man!", "Tally ho!")
- var/message = pick_n_take(hit_messages)
- shooter.say(message)
-
- if(P.distance_travelled > 8)
- knockback(M, P, 12)
-
- else if(!M || M == P.firer || M.lying) //These checks are included in knockback and would be redundant above.
- return
-
- shake_camera(M, 3, 4)
- M.apply_effect(2, WEAKEN)
- M.apply_effect(4, SLOW)
- if(iscarbonsizexeno(M))
- to_chat(M, SPAN_XENODANGER("The impact knocks you off your feet!"))
- else //This will hammer a Yautja as hard as a human.
- to_chat(M, SPAN_HIGHDANGER("The impact knocks you off your feet!"))
-
- step(M, get_dir(P.firer, M))
-
-/datum/ammo/bullet/shotgun/twobore/knockback_effects(mob/living/living_mob, obj/projectile/fired_projectile)
- if(iscarbonsizexeno(living_mob))
- var/mob/living/carbon/xenomorph/target = living_mob
- to_chat(target, SPAN_XENODANGER("You are shaken and slowed by the sudden impact!"))
- target.apply_effect(0.5, WEAKEN)
- target.apply_effect(2, SUPERSLOW)
- target.apply_effect(5, SLOW)
- else
- if(!isyautja(living_mob)) //Not predators.
- living_mob.apply_effect(1, SUPERSLOW)
- living_mob.apply_effect(2, SLOW)
- to_chat(living_mob, SPAN_HIGHDANGER("The impact knocks you off-balance!"))
- living_mob.apply_stamina_damage(fired_projectile.ammo.damage, fired_projectile.def_zone, ARMOR_BULLET)
-
-/datum/ammo/bullet/lever_action
- name = "lever-action bullet"
-
- damage = 80
- penetration = 0
- accuracy = HIT_ACCURACY_TIER_1
- shell_speed = AMMO_SPEED_TIER_6
- accurate_range = 14
- handful_state = "lever_action_bullet"
-
-//unused and not working. need to refactor MD code. Unobtainable.
-//intended mechanic is to have xenos hit with it show up very frequently on any MDs around
-/datum/ammo/bullet/lever_action/tracker
- name = "tracking lever-action bullet"
- icon_state = "redbullet"
- damage = 70
- penetration = ARMOR_PENETRATION_TIER_3
- accuracy = HIT_ACCURACY_TIER_1
- handful_state = "tracking_lever_action_bullet"
-
-/datum/ammo/bullet/lever_action/tracker/on_hit_mob(mob/M, obj/projectile/P, mob/user)
- //SEND_SIGNAL(user, COMSIG_BULLET_TRACKING, user, M)
- M.visible_message(SPAN_DANGER("You hear a faint beep under [M]'s [M.mob_size > MOB_SIZE_HUMAN ? "chitin" : "skin"]."))
-
-/datum/ammo/bullet/lever_action/training
- name = "lever-action blank"
- icon_state = "blank"
- damage = 70 //blanks CAN hurt you if shot very close
- penetration = 0
- accuracy = HIT_ACCURACY_TIER_1
- damage_falloff = DAMAGE_FALLOFF_BLANK //not much, though (comparatively)
- shell_speed = AMMO_SPEED_TIER_5
- handful_state = "training_lever_action_bullet"
-
-//unused, and unobtainable... for now
-/datum/ammo/bullet/lever_action/marksman
- name = "marksman lever-action bullet"
- shrapnel_chance = 0
- damage_falloff = 0
- accurate_range = 12
- damage = 70
- penetration = ARMOR_PENETRATION_TIER_6
- shell_speed = AMMO_SPEED_TIER_6
- handful_state = "marksman_lever_action_bullet"
-
-/datum/ammo/bullet/lever_action/xm88
- name = ".458 SOCOM round"
-
- damage = 80
- penetration = ARMOR_PENETRATION_TIER_2
- accuracy = HIT_ACCURACY_TIER_1
- shell_speed = AMMO_SPEED_TIER_6
- accurate_range = 14
- handful_state = "boomslang_bullet"
-
-/datum/ammo/bullet/lever_action/xm88/pen20
- penetration = ARMOR_PENETRATION_TIER_4
-
-/datum/ammo/bullet/lever_action/xm88/pen30
- penetration = ARMOR_PENETRATION_TIER_6
-
-/datum/ammo/bullet/lever_action/xm88/pen40
- penetration = ARMOR_PENETRATION_TIER_8
-
-/datum/ammo/bullet/lever_action/xm88/pen50
- penetration = ARMOR_PENETRATION_TIER_10
-
-/*
-//======
- Sniper Ammo
-//======
-*/
-
-/datum/ammo/bullet/sniper
- name = "sniper bullet"
- headshot_state = HEADSHOT_OVERLAY_HEAVY
- damage_falloff = 0
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER
- accurate_range_min = 4
-
- accuracy = HIT_ACCURACY_TIER_8
- accurate_range = 32
- max_range = 32
- scatter = 0
- damage = 70
- penetration= ARMOR_PENETRATION_TIER_10
- shell_speed = AMMO_SPEED_TIER_6
- damage_falloff = 0
-
-/datum/ammo/bullet/sniper/on_hit_mob(mob/M,obj/projectile/P)
- if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
- var/mob/living/L = M
- L.apply_armoured_damage(damage*2, ARMOR_BULLET, BRUTE, null, penetration)
- to_chat(P.firer, SPAN_WARNING("Bullseye!"))
-
-/datum/ammo/bullet/sniper/incendiary
- name = "incendiary sniper bullet"
- damage_type = BRUTE
- shrapnel_chance = 0
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER
-
- //Removed accuracy = 0, accuracy_var_high = Variance Tier 6, and scatter = 0. -Kaga
- damage = 60
- penetration = ARMOR_PENETRATION_TIER_4
-
-/datum/ammo/bullet/sniper/incendiary/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/sniper/incendiary/on_hit_mob(mob/M,obj/projectile/P)
- if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
- var/mob/living/L = M
- var/blind_duration = 5
- if(isxeno(M))
- var/mob/living/carbon/xenomorph/target = M
- if(target.mob_size >= MOB_SIZE_BIG)
- blind_duration = 2
- L.AdjustEyeBlur(blind_duration)
- L.adjust_fire_stacks(10)
- to_chat(P.firer, SPAN_WARNING("Bullseye!"))
-
-/datum/ammo/bullet/sniper/flak
- name = "flak sniper bullet"
- damage_type = BRUTE
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER
-
- accuracy = HIT_ACCURACY_TIER_8
- scatter = SCATTER_AMOUNT_TIER_8
- damage = 55
- damage_var_high = PROJECTILE_VARIANCE_TIER_8 //Documenting old code: This converts to a variance of 96-109% damage. -Kaga
- penetration = 0
-
-/datum/ammo/bullet/sniper/flak/on_hit_mob(mob/M,obj/projectile/P)
- if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
- var/slow_duration = 7
- var/mob/living/L = M
- if(isxeno(M))
- var/mob/living/carbon/xenomorph/target = M
- if(target.mob_size >= MOB_SIZE_BIG)
- slow_duration = 4
- M.adjust_effect(slow_duration, SUPERSLOW)
- L.apply_armoured_damage(damage, ARMOR_BULLET, BRUTE, null, penetration)
- to_chat(P.firer, SPAN_WARNING("Bullseye!"))
- else
- burst(get_turf(M),P,damage_type, 2 , 2)
- burst(get_turf(M),P,damage_type, 1 , 2 , 0)
-
-/datum/ammo/bullet/sniper/flak/on_near_target(turf/T, obj/projectile/P)
- burst(T,P,damage_type, 2 , 2)
- burst(T,P,damage_type, 1 , 2, 0)
- return 1
-
-/datum/ammo/bullet/sniper/crude
- name = "crude sniper bullet"
- damage = 42
- penetration = ARMOR_PENETRATION_TIER_6
-
-/datum/ammo/bullet/sniper/crude/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- pushback(M, P, 3)
-
-/datum/ammo/bullet/sniper/upp
- name = "armor-piercing sniper bullet"
- damage = 80
- penetration = ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/bullet/sniper/anti_materiel
- name = "anti-materiel sniper bullet"
-
- shrapnel_chance = 0 // This isn't leaving any shrapnel.
- accuracy = HIT_ACCURACY_TIER_8
- damage = 125
- shell_speed = AMMO_SPEED_TIER_6
-
-/datum/ammo/bullet/sniper/anti_materiel/on_hit_mob(mob/M,obj/projectile/P)
- if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
- var/mob/living/L = M
- var/size_damage_mod = 0.8
- if(isxeno(M))
- var/mob/living/carbon/xenomorph/target = M
- if(target.mob_size >= MOB_SIZE_XENO)
- size_damage_mod += 0.6
- if(target.mob_size >= MOB_SIZE_BIG)
- size_damage_mod += 0.6
- L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration)
- // 180% damage to all targets (225), 240% (300) against non-Runner xenos, and 300% against Big xenos (375). -Kaga
- to_chat(P.firer, SPAN_WARNING("Bullseye!"))
-
-/datum/ammo/bullet/sniper/anti_materiel/vulture
- damage = 400 // Fully intended to vaporize anything smaller than a mini cooper
- accurate_range_min = 10
- handful_state = "vulture_bullet"
- sound_hit = 'sound/bullets/bullet_vulture_impact.ogg'
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_SNIPER|AMMO_IGNORE_COVER|AMMO_ANTIVEHICLE
-
-/datum/ammo/bullet/sniper/anti_materiel/vulture/on_hit_mob(mob/hit_mob, obj/projectile/bullet)
- . = ..()
- knockback(hit_mob, bullet, 30)
- hit_mob.apply_effect(3, SLOW)
-
-/datum/ammo/bullet/sniper/anti_materiel/vulture/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating/heavy)
- ))
-
-/datum/ammo/bullet/sniper/elite
- name = "supersonic sniper bullet"
-
- shrapnel_chance = 0 // This isn't leaving any shrapnel.
- accuracy = HIT_ACCURACY_TIER_8
- damage = 150
- shell_speed = AMMO_SPEED_TIER_6 + AMMO_SPEED_TIER_2
-
-/datum/ammo/bullet/sniper/elite/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating)
- ))
-
-/datum/ammo/bullet/sniper/elite/on_hit_mob(mob/M,obj/projectile/P)
- if((P.projectile_flags & PROJECTILE_BULLSEYE) && M == P.original)
- var/mob/living/L = M
- var/size_damage_mod = 0.5
- if(isxeno(M))
- var/mob/living/carbon/xenomorph/target = M
- if(target.mob_size >= MOB_SIZE_XENO)
- size_damage_mod += 0.5
- if(target.mob_size >= MOB_SIZE_BIG)
- size_damage_mod += 1
- L.apply_armoured_damage(damage*size_damage_mod, ARMOR_BULLET, BRUTE, null, penetration)
- else
- L.apply_armoured_damage(damage, ARMOR_BULLET, BRUTE, null, penetration)
- // 150% damage to runners (225), 300% against Big xenos (450), and 200% against all others (300). -Kaga
- to_chat(P.firer, SPAN_WARNING("Bullseye!"))
-
-/datum/ammo/bullet/tank/flak
- name = "flak autocannon bullet"
- icon_state = "autocannon"
- damage_falloff = 0
- flags_ammo_behavior = AMMO_BALLISTIC
- accurate_range_min = 4
-
- accuracy = HIT_ACCURACY_TIER_8
- scatter = 0
- damage = 60
- damage_var_high = PROJECTILE_VARIANCE_TIER_8
- penetration = ARMOR_PENETRATION_TIER_6
- accurate_range = 32
- max_range = 32
- shell_speed = AMMO_SPEED_TIER_6
-
-/datum/ammo/bullet/tank/flak/on_hit_mob(mob/M,obj/projectile/P)
- burst(get_turf(M),P,damage_type, 2 , 3)
- burst(get_turf(M),P,damage_type, 1 , 3 , 0)
-
-/datum/ammo/bullet/tank/flak/on_near_target(turf/T, obj/projectile/P)
- burst(get_turf(T),P,damage_type, 2 , 3)
- burst(get_turf(T),P,damage_type, 1 , 3, 0)
- return 1
-
-/datum/ammo/bullet/tank/flak/on_hit_obj(obj/O,obj/projectile/P)
- burst(get_turf(P),P,damage_type, 2 , 3)
- burst(get_turf(P),P,damage_type, 1 , 3 , 0)
-
-/datum/ammo/bullet/tank/flak/on_hit_turf(turf/T,obj/projectile/P)
- burst(get_turf(T),P,damage_type, 2 , 3)
- burst(get_turf(T),P,damage_type, 1 , 3 , 0)
-
-/datum/ammo/bullet/tank/dualcannon
- name = "dualcannon bullet"
- icon_state = "autocannon"
- damage_falloff = 0
- flags_ammo_behavior = AMMO_BALLISTIC
-
- accuracy = HIT_ACCURACY_TIER_8
- scatter = 0
- damage = 50
- damage_var_high = PROJECTILE_VARIANCE_TIER_8
- penetration = ARMOR_PENETRATION_TIER_3
- accurate_range = 10
- max_range = 12
- shell_speed = AMMO_SPEED_TIER_5
-
-/datum/ammo/bullet/tank/dualcannon/on_hit_mob(mob/M,obj/projectile/P)
- for(var/mob/living/carbon/L in get_turf(M))
- if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO)
- shake_camera(L, 1, 1)
-
-/datum/ammo/bullet/tank/dualcannon/on_near_target(turf/T, obj/projectile/P)
- for(var/mob/living/carbon/L in T)
- if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO)
- shake_camera(L, 1, 1)
- return 1
-
-/datum/ammo/bullet/tank/dualcannon/on_hit_obj(obj/O,obj/projectile/P)
- for(var/mob/living/carbon/L in get_turf(O))
- if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO)
- shake_camera(L, 1, 1)
-
-/datum/ammo/bullet/tank/dualcannon/on_hit_turf(turf/T,obj/projectile/P)
- for(var/mob/living/carbon/L in T)
- if(L.stat == CONSCIOUS && L.mob_size <= MOB_SIZE_XENO)
- shake_camera(L, 1, 1)
-
-/*
-//======
- Special Ammo
-//======
-*/
-
-/datum/ammo/bullet/smartgun
- name = "smartgun bullet"
- icon_state = "redbullet"
- flags_ammo_behavior = AMMO_BALLISTIC
-
- max_range = 12
- accuracy = HIT_ACCURACY_TIER_4
- damage = 30
- penetration = 0
-
-/datum/ammo/bullet/smartgun/armor_piercing
- name = "armor-piercing smartgun bullet"
- icon_state = "bullet"
-
- accurate_range = 12
- accuracy = HIT_ACCURACY_TIER_2
- damage = 20
- penetration = ARMOR_PENETRATION_TIER_8
- damage_armor_punch = 1
-
-/datum/ammo/bullet/smartgun/dirty
- name = "irradiated smartgun bullet"
- debilitate = list(0,0,0,3,0,0,0,1)
-
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_7
- accurate_range = 32
- accuracy = HIT_ACCURACY_TIER_3
- damage = 40
- penetration = 0
-
-/datum/ammo/bullet/smartgun/dirty/armor_piercing
- debilitate = list(0,0,0,3,0,0,0,1)
-
- accurate_range = 22
- accuracy = HIT_ACCURACY_TIER_3
- damage = 30
- penetration = ARMOR_PENETRATION_TIER_7
- damage_armor_punch = 3
-
-/datum/ammo/bullet/smartgun/holo_target //Royal marines smartgun bullet has only diff between regular ammo is this one does holostacks
- name = "holo-targeting smartgun bullet"
- damage = 30
-///Stuff for the HRP holotargetting stacks
- var/holo_stacks = 15
-
-/datum/ammo/bullet/smartgun/holo_target/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- M.AddComponent(/datum/component/bonus_damage_stack, holo_stacks, world.time)
-
-/datum/ammo/bullet/smartgun/holo_target/ap
- name = "armor-piercing smartgun bullet"
- icon_state = "bullet"
-
- accurate_range = 12
- accuracy = HIT_ACCURACY_TIER_2
- damage = 20
- penetration = ARMOR_PENETRATION_TIER_8
- damage_armor_punch = 1
-
-/datum/ammo/bullet/smartgun/m56_fpw
- name = "\improper M56 FPW bullet"
- icon_state = "redbullet"
- flags_ammo_behavior = AMMO_BALLISTIC
-
- max_range = 7
- accuracy = HIT_ACCURACY_TIER_7
- damage = 35
- penetration = ARMOR_PENETRATION_TIER_1
-
-/datum/ammo/bullet/turret
- name = "autocannon bullet"
- icon_state = "redbullet" //Red bullets to indicate friendly fire restriction
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_IGNORE_COVER
-
- accurate_range = 22
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_8
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_8
- max_range = 22
- damage = 30
- penetration = ARMOR_PENETRATION_TIER_7
- damage_armor_punch = 0
- pen_armor_punch = 0
- shell_speed = 2*AMMO_SPEED_TIER_6
- accuracy = HIT_ACCURACY_TIER_5
-
-/datum/ammo/bullet/turret/dumb
- icon_state = "bullet"
- flags_ammo_behavior = AMMO_BALLISTIC
-
-/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
-
- accurate_range = 12
- damage = 35
- penetration= ARMOR_PENETRATION_TIER_10 //Bumped the penetration to serve a different role from sentries, MGs are a bit more offensive
- accuracy = HIT_ACCURACY_TIER_3
-
-/datum/ammo/bullet/machinegun/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff)
- ))
-
-/datum/ammo/bullet/machinegun/auto // for M2C, automatic variant for M56D, stats for bullet should always be moderately overtuned to fulfill its ultra-offense + flank-push purpose
- name = "heavy machinegun bullet"
-
- accurate_range = 10
- damage = 50
- penetration = ARMOR_PENETRATION_TIER_6
- accuracy = -HIT_ACCURACY_TIER_2 // 75 accuracy
- shell_speed = AMMO_SPEED_TIER_2
- max_range = 15
- effective_range_max = 7
- damage_falloff = DAMAGE_FALLOFF_TIER_8
-
-/datum/ammo/bullet/machinegun/auto/set_bullet_traits()
- return
-
-/datum/ammo/bullet/minigun
- name = "minigun bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
-
- accuracy = -HIT_ACCURACY_TIER_3
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
- accurate_range = 12
- damage = 35
- penetration = ARMOR_PENETRATION_TIER_6
-
-/datum/ammo/bullet/minigun/New()
- ..()
- if(SSticker.mode && MODE_HAS_FLAG(MODE_FACTION_CLASH))
- damage = 15
- else if(SSticker.current_state < GAME_STATE_PLAYING)
- RegisterSignal(SSdcs, COMSIG_GLOB_MODE_PRESETUP, PROC_REF(setup_hvh_damage))
-
-/datum/ammo/bullet/minigun/proc/setup_hvh_damage()
- if(MODE_HAS_FLAG(MODE_FACTION_CLASH))
- damage = 15
-
-/datum/ammo/bullet/minigun/tank
- accuracy = -HIT_ACCURACY_TIER_1
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_8
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_8
- accurate_range = 12
-
-/datum/ammo/bullet/m60
- name = "M60 bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
-
- accuracy = HIT_ACCURACY_TIER_2
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_8
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
- accurate_range = 12
- damage = 45 //7.62x51 is scary
- penetration= ARMOR_PENETRATION_TIER_6
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
-
-/datum/ammo/bullet/pkp
- name = "machinegun bullet"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
-
- accuracy = HIT_ACCURACY_TIER_1
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_8
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
- accurate_range = 14
- damage = 35
- penetration= ARMOR_PENETRATION_TIER_6
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
-
-/*
-//======
- Rocket Ammo
-//======
-*/
-
-/datum/ammo/rocket
- name = "high explosive rocket"
- icon_state = "missile"
- ping = null //no bounce off.
- sound_bounce = "rocket_bounce"
- damage_falloff = 0
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_STRIKES_SURFACE
- var/datum/effect_system/smoke_spread/smoke
-
- accuracy = HIT_ACCURACY_TIER_2
- accurate_range = 7
- max_range = 7
- damage = 15
- shell_speed = AMMO_SPEED_TIER_2
-
-/datum/ammo/rocket/New()
- ..()
- smoke = new()
-
-/datum/ammo/rocket/Destroy()
- qdel(smoke)
- smoke = null
- . = ..()
-
-/datum/ammo/rocket/on_hit_mob(mob/M, obj/projectile/P)
- cell_explosion(get_turf(M), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- smoke.set_up(1, get_turf(M))
- if(ishuman_strict(M)) // No yautya or synths. Makes humans gib on direct hit.
- M.ex_act(350, P.dir, P.weapon_cause_data, 100)
- smoke.start()
-
-/datum/ammo/rocket/on_hit_obj(obj/O, obj/projectile/P)
- cell_explosion(get_turf(O), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- smoke.set_up(1, get_turf(O))
- smoke.start()
-
-/datum/ammo/rocket/on_hit_turf(turf/T, obj/projectile/P)
- cell_explosion(T, 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- smoke.set_up(1, T)
- smoke.start()
-
-/datum/ammo/rocket/do_at_max_range(obj/projectile/P)
- cell_explosion(get_turf(P), 150, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- smoke.set_up(1, get_turf(P))
- smoke.start()
-
-/datum/ammo/rocket/ap
- name = "anti-armor rocket"
- damage_falloff = 0
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET
-
- accuracy = HIT_ACCURACY_TIER_8
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_9
- accurate_range = 6
- max_range = 6
- damage = 10
- penetration= ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/rocket/ap/on_hit_mob(mob/M, obj/projectile/P)
- var/turf/T = get_turf(M)
- M.ex_act(150, P.dir, P.weapon_cause_data, 100)
- M.apply_effect(2, WEAKEN)
- M.apply_effect(2, PARALYZE)
- if(ishuman_strict(M)) // No yautya or synths. Makes humans gib on direct hit.
- M.ex_act(300, P.dir, P.weapon_cause_data, 100)
- cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- smoke.set_up(1, T)
- smoke.start()
-
-/datum/ammo/rocket/ap/on_hit_obj(obj/O, obj/projectile/P)
- var/turf/T = get_turf(O)
- O.ex_act(150, P.dir, P.weapon_cause_data, 100)
- cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- smoke.set_up(1, T)
- smoke.start()
-
-/datum/ammo/rocket/ap/on_hit_turf(turf/T, obj/projectile/P)
- var/hit_something = 0
- for(var/mob/M in T)
- M.ex_act(150, P.dir, P.weapon_cause_data, 100)
- M.apply_effect(4, WEAKEN)
- M.apply_effect(4, PARALYZE)
- hit_something = 1
- continue
- if(!hit_something)
- for(var/obj/O in T)
- if(O.density)
- O.ex_act(150, P.dir, P.weapon_cause_data, 100)
- hit_something = 1
- continue
- if(!hit_something)
- T.ex_act(150, P.dir, P.weapon_cause_data, 200)
-
- cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- smoke.set_up(1, T)
- smoke.start()
-
-/datum/ammo/rocket/ap/do_at_max_range(obj/projectile/P)
- var/turf/T = get_turf(P)
- var/hit_something = 0
- for(var/mob/M in T)
- M.ex_act(250, P.dir, P.weapon_cause_data, 100)
- M.apply_effect(2, WEAKEN)
- M.apply_effect(2, PARALYZE)
- hit_something = 1
- continue
- if(!hit_something)
- for(var/obj/O in T)
- if(O.density)
- O.ex_act(250, P.dir, P.weapon_cause_data, 100)
- hit_something = 1
- continue
- if(!hit_something)
- T.ex_act(250, P.dir, P.weapon_cause_data)
- cell_explosion(T, 100, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- smoke.set_up(1, T)
- smoke.start()
-
-/datum/ammo/rocket/ap/anti_tank
- name = "anti-tank rocket"
- damage = 100
- var/vehicle_slowdown_time = 5 SECONDS
- shrapnel_chance = 5
- shrapnel_type = /obj/item/large_shrapnel/at_rocket_dud
-
-/datum/ammo/rocket/ap/anti_tank/on_hit_obj(obj/O, obj/projectile/P)
- if(istype(O, /obj/vehicle/multitile))
- var/obj/vehicle/multitile/M = O
- M.next_move = world.time + vehicle_slowdown_time
- playsound(M, 'sound/effects/meteorimpact.ogg', 35)
- M.at_munition_interior_explosion_effect(cause_data = create_cause_data("Anti-Tank Rocket"))
- M.interior_crash_effect()
- var/turf/T = get_turf(M.loc)
- M.ex_act(150, P.dir, P.weapon_cause_data, 100)
- smoke.set_up(1, T)
- smoke.start()
- return
- return ..()
-
-
-/datum/ammo/rocket/ltb
- name = "cannon round"
- icon_state = "ltb"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_ROCKET|AMMO_STRIKES_SURFACE
-
- accuracy = HIT_ACCURACY_TIER_3
- accurate_range = 32
- max_range = 32
- damage = 25
- shell_speed = AMMO_SPEED_TIER_3
-
-/datum/ammo/rocket/ltb/on_hit_mob(mob/M, obj/projectile/P)
- cell_explosion(get_turf(M), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- cell_explosion(get_turf(M), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
-
-/datum/ammo/rocket/ltb/on_hit_obj(obj/O, obj/projectile/P)
- cell_explosion(get_turf(O), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- cell_explosion(get_turf(O), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
-
-/datum/ammo/rocket/ltb/on_hit_turf(turf/T, obj/projectile/P)
- cell_explosion(get_turf(T), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- cell_explosion(get_turf(T), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
-
-/datum/ammo/rocket/ltb/do_at_max_range(obj/projectile/P)
- cell_explosion(get_turf(P), 220, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
- cell_explosion(get_turf(P), 200, 100, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
-
-/datum/ammo/rocket/wp
- name = "white phosphorous rocket"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE|AMMO_STRIKES_SURFACE
- damage_type = BURN
-
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- accurate_range = 8
- damage = 90
- max_range = 8
-
-/datum/ammo/rocket/wp/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/rocket/wp/drop_flame(turf/T, datum/cause_data/cause_data)
- playsound(T, 'sound/weapons/gun_flamethrower3.ogg', 75, 1, 7)
- if(!istype(T)) return
- smoke.set_up(1, T)
- smoke.start()
- var/datum/reagent/napalm/blue/R = new()
- new /obj/flamer_fire(T, cause_data, R, 3)
-
- var/datum/effect_system/smoke_spread/phosphorus/landingSmoke = new /datum/effect_system/smoke_spread/phosphorus
- landingSmoke.set_up(3, 0, T, null, 6, cause_data)
- landingSmoke.start()
- landingSmoke = null
-
-/datum/ammo/rocket/wp/on_hit_mob(mob/M, obj/projectile/P)
- drop_flame(get_turf(M), P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/on_hit_obj(obj/O, obj/projectile/P)
- drop_flame(get_turf(O), P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/on_hit_turf(turf/T, obj/projectile/P)
- drop_flame(T, P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/do_at_max_range(obj/projectile/P)
- drop_flame(get_turf(P), P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/upp
- name = "extreme-intensity incendiary rocket"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_EXPLOSIVE|AMMO_STRIKES_SURFACE
- damage_type = BURN
-
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- accurate_range = 8
- damage = 150
- max_range = 10
-
-/datum/ammo/rocket/wp/upp/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/rocket/wp/upp/drop_flame(turf/T, datum/cause_data/cause_data)
- playsound(T, 'sound/weapons/gun_flamethrower3.ogg', 75, 1, 7)
- if(!istype(T)) return
- smoke.set_up(1, T)
- smoke.start()
- var/datum/reagent/napalm/upp/R = new()
- new /obj/flamer_fire(T, cause_data, R, 3)
-
-/datum/ammo/rocket/wp/upp/on_hit_mob(mob/M, obj/projectile/P)
- drop_flame(get_turf(M), P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/upp/on_hit_obj(obj/O, obj/projectile/P)
- drop_flame(get_turf(O), P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/upp/on_hit_turf(turf/T, obj/projectile/P)
- drop_flame(T, P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/upp/do_at_max_range(obj/projectile/P)
- drop_flame(get_turf(P), P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/quad
- name = "thermobaric rocket"
- flags_ammo_behavior = AMMO_ROCKET|AMMO_STRIKES_SURFACE
-
- damage = 100
- max_range = 32
- shell_speed = AMMO_SPEED_TIER_3
-
-/datum/ammo/rocket/wp/quad/on_hit_mob(mob/M, obj/projectile/P)
- drop_flame(get_turf(M), P.weapon_cause_data)
- explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/quad/on_hit_obj(obj/O, obj/projectile/P)
- drop_flame(get_turf(O), P.weapon_cause_data)
- explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/quad/on_hit_turf(turf/T, obj/projectile/P)
- drop_flame(T, P.weapon_cause_data)
- explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data)
-
-/datum/ammo/rocket/wp/quad/do_at_max_range(obj/projectile/P)
- drop_flame(get_turf(P), P.weapon_cause_data)
- explosion(P.loc, -1, 2, 4, 5, , , ,P.weapon_cause_data)
-
-/datum/ammo/rocket/custom
- name = "custom rocket"
-
-/datum/ammo/rocket/custom/proc/prime(atom/A, obj/projectile/P)
- var/obj/item/weapon/gun/launcher/rocket/launcher = P.shot_from
- var/obj/item/ammo_magazine/rocket/custom/rocket = launcher.current_mag
- if(rocket.locked && rocket.warhead && rocket.warhead.detonator)
- if(rocket.fuel && rocket.fuel.reagents.get_reagent_amount(rocket.fuel_type) >= rocket.fuel_requirement)
- rocket.forceMove(P.loc)
- rocket.warhead.cause_data = P.weapon_cause_data
- rocket.warhead.prime()
- qdel(rocket)
- smoke.set_up(1, get_turf(A))
- smoke.start()
-
-/datum/ammo/rocket/custom/on_hit_mob(mob/M, obj/projectile/P)
- prime(M, P)
-
-/datum/ammo/rocket/custom/on_hit_obj(obj/O, obj/projectile/P)
- prime(O, P)
-
-/datum/ammo/rocket/custom/on_hit_turf(turf/T, obj/projectile/P)
- prime(T, P)
-
-/datum/ammo/rocket/custom/do_at_max_range(obj/projectile/P)
- prime(null, P)
-
-/*
-//======
- Energy Ammo
-//======
-*/
-
-/datum/ammo/energy
- ping = null //no bounce off. We can have one later.
- sound_hit = "energy_hit"
- sound_miss = "energy_miss"
- sound_bounce = "energy_bounce"
-
- damage_type = BURN
- flags_ammo_behavior = AMMO_ENERGY
-
- accuracy = HIT_ACCURACY_TIER_4
-
-/datum/ammo/energy/emitter //Damage is determined in emitter.dm
- name = "emitter bolt"
- icon_state = "emitter"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_ARMOR
-
- accurate_range = 6
- max_range = 6
-
-/datum/ammo/energy/taser
- name = "taser bolt"
- icon_state = "stun"
- damage_type = OXY
- flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST|AMMO_ALWAYS_FF //Not that ignoring will do much right now.
-
- stamina_damage = 45
- accuracy = HIT_ACCURACY_TIER_8
- shell_speed = AMMO_SPEED_TIER_1 // Slightly faster
- hit_effect_color = "#FFFF00"
-
-/datum/ammo/energy/taser/on_hit_mob(mob/M, obj/projectile/P)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- H.disable_special_items() // Disables scout cloak
-
-/datum/ammo/energy/taser/precise
- name = "precise taser bolt"
- flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST|AMMO_MP
-
-/datum/ammo/energy/rxfm_eva
- name = "laser blast"
- icon_state = "laser_new"
- flags_ammo_behavior = AMMO_LASER
- accurate_range = 14
- max_range = 22
- damage = 45
- stamina_damage = 25 //why not
- shell_speed = AMMO_SPEED_TIER_3
-
-/datum/ammo/energy/rxfm_eva/on_hit_mob(mob/living/M, obj/projectile/P)
- ..()
- if(prob(10)) //small chance for one to ignite on hit
- M.fire_act()
-
-/datum/ammo/energy/laz_uzi
- name = "laser bolt"
- icon_state = "laser_new"
- flags_ammo_behavior = AMMO_ENERGY
- damage = 40
- accurate_range = 5
- effective_range_max = 7
- max_range = 10
- shell_speed = AMMO_SPEED_TIER_4
- scatter = SCATTER_AMOUNT_TIER_6
- accuracy = HIT_ACCURACY_TIER_3
- damage_falloff = DAMAGE_FALLOFF_TIER_8
-
-/datum/ammo/energy/yautja
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
- accurate_range = 12
- shell_speed = AMMO_SPEED_TIER_3
- damage_type = BURN
- flags_ammo_behavior = AMMO_IGNORE_RESIST
-
-/datum/ammo/energy/yautja/pistol
- name = "plasma pistol bolt"
- icon_state = "ion"
-
- damage = 40
- shell_speed = AMMO_SPEED_TIER_2
-
-/datum/ammo/energy/yautja/pistol/incendiary
- damage = 10
-
-/datum/ammo/energy/yautja/pistol/incendiary/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/shrapnel/plasma
- name = "plasma wave"
- shrapnel_chance = 0
- penetration = ARMOR_PENETRATION_TIER_10
- accuracy = HIT_ACCURACY_TIER_MAX
- damage = 15
- icon_state = "shrapnel_plasma"
- damage_type = BURN
-
-/datum/ammo/bullet/shrapnel/plasma/on_hit_mob(mob/hit_mob, obj/projectile/hit_projectile)
- hit_mob.apply_effect(2, WEAKEN)
-
-/datum/ammo/energy/yautja/caster
- name = "root caster bolt"
- icon_state = "ion"
-
-/datum/ammo/energy/yautja/caster/stun
- name = "low power stun bolt"
- debilitate = list(2,2,0,0,0,1,0,0)
-
- damage = 0
- flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST
-
-/datum/ammo/energy/yautja/caster/bolt
- name = "plasma bolt"
- icon_state = "pulse1"
- flags_ammo_behavior = AMMO_IGNORE_RESIST
- shell_speed = AMMO_SPEED_TIER_6
- damage = 35
-
-/datum/ammo/energy/yautja/caster/bolt/stun
- name = "high power stun bolt"
- var/stun_time = 2
-
- damage = 0
- flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST
-
-/datum/ammo/energy/yautja/caster/bolt/stun/on_hit_mob(mob/M, obj/projectile/P)
- var/mob/living/carbon/C = M
- var/stun_time = src.stun_time
- if(istype(C))
- if(isyautja(C) || ispredalien(C))
- return
- to_chat(C, SPAN_DANGER("An electric shock ripples through your body, freezing you in place!"))
- log_attack("[key_name(C)] was stunned by a high power stun bolt from [key_name(P.firer)] at [get_area(P)]")
-
- if(ishuman(C))
- var/mob/living/carbon/human/H = C
- stun_time++
- H.apply_effect(stun_time, WEAKEN)
- else
- M.apply_effect(stun_time, WEAKEN)
-
- C.apply_effect(stun_time, STUN)
- ..()
-
-/datum/ammo/energy/yautja/caster/sphere
- name = "plasma eradicator"
- icon_state = "bluespace"
- flags_ammo_behavior = AMMO_EXPLOSIVE|AMMO_HITS_TARGET_TURF
- shell_speed = AMMO_SPEED_TIER_4
- accuracy = HIT_ACCURACY_TIER_8
-
- damage = 55
-
- accurate_range = 8
- max_range = 8
-
- var/vehicle_slowdown_time = 5 SECONDS
-
-/datum/ammo/energy/yautja/caster/sphere/on_hit_mob(mob/M, obj/projectile/P)
- cell_explosion(P, 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
-
-/datum/ammo/energy/yautja/caster/sphere/on_hit_turf(turf/T, obj/projectile/P)
- cell_explosion(P, 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
-
-/datum/ammo/energy/yautja/caster/sphere/on_hit_obj(obj/O, obj/projectile/P)
- if(istype(O, /obj/vehicle/multitile))
- var/obj/vehicle/multitile/multitile_vehicle = O
- multitile_vehicle.next_move = world.time + vehicle_slowdown_time
- playsound(multitile_vehicle, 'sound/effects/meteorimpact.ogg', 35)
- multitile_vehicle.at_munition_interior_explosion_effect(cause_data = create_cause_data("Plasma Eradicator", P.firer))
- multitile_vehicle.interior_crash_effect()
- multitile_vehicle.ex_act(150, P.dir, P.weapon_cause_data, 100)
- cell_explosion(get_turf(P), 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
-
-/datum/ammo/energy/yautja/caster/sphere/do_at_max_range(obj/projectile/P)
- cell_explosion(get_turf(P), 170, 50, EXPLOSION_FALLOFF_SHAPE_LINEAR, null, P.weapon_cause_data)
-
-
-/datum/ammo/energy/yautja/caster/sphere/stun
- name = "plasma immobilizer"
- damage = 0
- flags_ammo_behavior = AMMO_ENERGY|AMMO_IGNORE_RESIST
- accurate_range = 20
- max_range = 20
-
- var/stun_range = 4 // Big
- var/stun_time = 6
-
-/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_mob(mob/M, obj/projectile/P)
- do_area_stun(P)
-
-/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_turf(turf/T,obj/projectile/P)
- do_area_stun(P)
-
-/datum/ammo/energy/yautja/caster/sphere/stun/on_hit_obj(obj/O,obj/projectile/P)
- do_area_stun(P)
-
-/datum/ammo/energy/yautja/caster/sphere/stun/do_at_max_range(obj/projectile/P)
- do_area_stun(P)
-
-/datum/ammo/energy/yautja/caster/sphere/stun/proc/do_area_stun(obj/projectile/P)
- playsound(P, 'sound/weapons/wave.ogg', 75, 1, 25)
- for (var/mob/living/carbon/M in view(src.stun_range, get_turf(P)))
- var/stun_time = src.stun_time
- log_attack("[key_name(M)] was stunned by a plasma immobilizer from [key_name(P.firer)] at [get_area(P)]")
- if (isyautja(M))
- stun_time -= 2
- if(ispredalien(M))
- continue
- to_chat(M, SPAN_DANGER("A powerful electric shock ripples through your body, freezing you in place!"))
- M.apply_effect(stun_time, STUN)
-
- if (ishuman(M))
- var/mob/living/carbon/human/H = M
- H.apply_effect(stun_time, WEAKEN)
- else
- M.apply_effect(stun_time, WEAKEN)
-
-
-
-
-/datum/ammo/energy/yautja/rifle/bolt
- name = "plasma rifle bolt"
- icon_state = "ion"
- damage_type = BURN
- debilitate = list(0,2,0,0,0,0,0,0)
- flags_ammo_behavior = AMMO_IGNORE_RESIST
-
- damage = 55
- penetration = ARMOR_PENETRATION_TIER_10
-
-/datum/ammo/energy/yautja/rifle/bolt/on_hit_mob(mob/hit_mob, obj/projectile/hit_projectile)
- if(isxeno(hit_mob))
- var/mob/living/carbon/xenomorph/xeno = hit_mob
- xeno.apply_damage(damage * 0.75, BURN)
- xeno.interference = 30
-
-/*
-//======
- Xeno Spits
-//======
-*/
-/datum/ammo/xeno
- icon_state = "neurotoxin"
- ping = "ping_x"
- damage_type = TOX
- flags_ammo_behavior = AMMO_XENO
-
- ///used to make cooldown of the different spits vary.
- var/added_spit_delay = 0
- var/spit_cost
-
- /// Should there be a windup for this spit?
- var/spit_windup = FALSE
-
- /// Should there be an additional warning while winding up? (do not put to true if there is not a windup)
- var/pre_spit_warn = FALSE
- accuracy = HIT_ACCURACY_TIER_8*2
- max_range = 12
-
-/datum/ammo/xeno/toxin
- name = "neurotoxic spit"
- damage_falloff = 0
- flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST
- spit_cost = 25
- var/effect_power = XENO_NEURO_TIER_4
- var/datum/callback/neuro_callback
-
- shell_speed = AMMO_SPEED_TIER_3
- max_range = 7
-
-/datum/ammo/xeno/toxin/New()
- ..()
-
- neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_neuro))
-
-/proc/apply_neuro(mob/M, power, insta_neuro)
- if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX) && !insta_neuro)
- M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!"))
- return //endurance 5 makes you immune to weak neurotoxin
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || H.species.flags & NO_NEURO)
- H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!"))
- return //species like zombies or synths are immune to neurotoxin
-
- if(!isxeno(M))
- if(insta_neuro)
- if(M.knocked_down < 3)
- M.adjust_effect(1 * power, WEAKEN)
- return
-
- if(ishuman(M))
- M.apply_effect(2.5, SUPERSLOW)
- M.visible_message(SPAN_DANGER("[M]'s movements are slowed."))
-
- var/no_clothes_neuro = FALSE
-
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(!H.wear_suit || H.wear_suit.slowdown == 0)
- no_clothes_neuro = TRUE
-
- if(no_clothes_neuro)
- if(M.knocked_down < 5)
- M.adjust_effect(1 * power, WEAKEN) // KD them a bit more
- M.visible_message(SPAN_DANGER("[M] falls prone."))
-
-/proc/apply_scatter_neuro(mob/M)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(skillcheck(M, SKILL_ENDURANCE, SKILL_ENDURANCE_MAX))
- M.visible_message(SPAN_DANGER("[M] withstands the neurotoxin!"))
- return //endurance 5 makes you immune to weak neuro
- if(H.chem_effect_flags & CHEM_EFFECT_RESIST_NEURO || H.species.flags & NO_NEURO)
- H.visible_message(SPAN_DANGER("[M] shrugs off the neurotoxin!"))
- return
-
- if(M.knocked_down < 0.7) // apply knockdown only if current knockdown is less than 0.7 second
- M.apply_effect(0.7, WEAKEN)
- M.visible_message(SPAN_DANGER("[M] falls prone."))
-
-/datum/ammo/xeno/toxin/on_hit_mob(mob/M,obj/projectile/P)
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.status_flags & XENO_HOST)
- neuro_callback.Invoke(H, effect_power, TRUE)
- return
-
- neuro_callback.Invoke(M, effect_power, FALSE)
-
-/datum/ammo/xeno/toxin/medium //Spitter
- name = "neurotoxic spatter"
- spit_cost = 50
- effect_power = 1
-
- shell_speed = AMMO_SPEED_TIER_3
-
-/datum/ammo/xeno/toxin/queen
- name = "neurotoxic spit"
- spit_cost = 50
- effect_power = 2
-
- accuracy = HIT_ACCURACY_TIER_5*2
- max_range = 6 - 1
-
-/datum/ammo/xeno/toxin/queen/on_hit_mob(mob/M,obj/projectile/P)
- neuro_callback.Invoke(M, effect_power, TRUE)
-
-/datum/ammo/xeno/toxin/shotgun
- name = "neurotoxic droplet"
- flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST
- bonus_projectiles_type = /datum/ammo/xeno/toxin/shotgun/additional
-
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_6
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_6
- accurate_range = 5
- max_range = 5
- scatter = SCATTER_AMOUNT_NEURO
- bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_4
-
-/datum/ammo/xeno/toxin/shotgun/New()
- ..()
-
- neuro_callback = CALLBACK(GLOBAL_PROC, GLOBAL_PROC_REF(apply_scatter_neuro))
-
-/datum/ammo/xeno/toxin/shotgun/additional
- name = "additional neurotoxic droplets"
-
- bonus_projectiles_amount = 0
-
-/*proc/neuro_flak(turf/T, obj/projectile/P, datum/callback/CB, power, insta_neuro, radius)
- if(!T) return FALSE
- var/firer = P.firer
- var/hit_someone = FALSE
- for(var/mob/living/carbon/M in orange(radius,T))
- if(isxeno(M) && isxeno(firer) && M:hivenumber == firer:hivenumber)
- continue
-
- if(HAS_TRAIT(M, TRAIT_NESTED))
- continue
-
- hit_someone = TRUE
- CB.Invoke(M, power, insta_neuro)
-
- P.play_hit_effect(M)
-
- return hit_someone
-
-/datum/ammo/xeno/toxin/burst //sentinel burst
- name = "neurotoxic air splash"
- effect_power = XENO_NEURO_TIER_1
- spit_cost = 50
- flags_ammo_behavior = AMMO_XENO|AMMO_IGNORE_RESIST
-
-/datum/ammo/xeno/toxin/burst/on_hit_mob(mob/M, obj/projectile/P)
- if(isxeno(M) && isxeno(P.firer) && M:hivenumber == P.firer:hivenumber)
- neuro_callback.Invoke(M, effect_power*1.5, TRUE)
-
- neuro_flak(get_turf(M), P, neuro_callback, effect_power, FALSE, 1)
-
-/datum/ammo/xeno/toxin/burst/on_near_target(turf/T, obj/projectile/P)
- return neuro_flak(T, P, neuro_callback, effect_power, FALSE, 1)
-
-/datum/ammo/xeno/sticky
- name = "sticky resin spit"
- icon_state = "sticky"
- ping = null
- flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE
- added_spit_delay = 5
- spit_cost = 40
-
- shell_speed = AMMO_SPEED_TIER_3
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_4
- max_range = 32
-
-/datum/ammo/xeno/sticky/on_hit_mob(mob/M,obj/projectile/P)
- drop_resin(get_turf(P))
-
-/datum/ammo/xeno/sticky/on_hit_obj(obj/O,obj/projectile/P)
- drop_resin(get_turf(P))
-
-/datum/ammo/xeno/sticky/on_hit_turf(turf/T,obj/projectile/P)
- drop_resin(T)
-
-/datum/ammo/xeno/sticky/do_at_max_range(obj/projectile/P)
- drop_resin(get_turf(P))
-
-/datum/ammo/xeno/sticky/proc/drop_resin(turf/T)
- if(T.density)
- return
-
- for(var/obj/O in T.contents)
- if(istype(O, /obj/item/clothing/mask/facehugger))
- return
- if(istype(O, /obj/effect/alien/egg))
- return
- if(istype(O, /obj/structure/mineral_door) || istype(O, /obj/effect/alien/resin) || istype(O, /obj/structure/bed))
- return
- if(O.density && !(O.flags_atom & ON_BORDER))
- return
-
- new /obj/effect/alien/resin/sticky/thin(T) */
-
-/datum/ammo/xeno/acid
- name = "acid spit"
- icon_state = "xeno_acid"
- sound_hit = "acid_hit"
- sound_bounce = "acid_bounce"
- damage_type = BURN
- spit_cost = 25
- flags_ammo_behavior = AMMO_ACIDIC|AMMO_XENO
- accuracy = HIT_ACCURACY_TIER_5
- damage = 20
- max_range = 8 // 7 will disappear on diagonals. i love shitcode
- penetration = ARMOR_PENETRATION_TIER_2
- shell_speed = AMMO_SPEED_TIER_3
-
-/datum/ammo/xeno/acid/on_shield_block(mob/M, obj/projectile/P)
- burst(M,P,damage_type)
-
-/datum/ammo/xeno/acid/on_hit_mob(mob/M, obj/projectile/P)
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- if(C.status_flags & XENO_HOST && HAS_TRAIT(C, TRAIT_NESTED) || C.stat == DEAD)
- return FALSE
- ..()
-
-/datum/ammo/xeno/acid/spatter
- name = "acid spatter"
-
- damage = 30
- max_range = 6
-
-/datum/ammo/xeno/acid/spatter/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- if(. == FALSE)
- return
-
- new /datum/effects/acid(M, P.firer)
-
-/datum/ammo/xeno/acid/praetorian
- name = "acid splash"
-
- accuracy = HIT_ACCURACY_TIER_10 + HIT_ACCURACY_TIER_5
- max_range = 8
- damage = 30
- shell_speed = AMMO_SPEED_TIER_2
- added_spit_delay = 0
-
-/datum/ammo/xeno/acid/dot
- name = "acid spit"
-
-/datum/ammo/xeno/acid/prae_nade // Used by base prae's acid nade
- name = "acid scatter"
-
- flags_ammo_behavior = AMMO_STOPPED_BY_COVER
- accuracy = HIT_ACCURACY_TIER_5
- accurate_range = 32
- max_range = 4
- damage = 25
- shell_speed = AMMO_SPEED_TIER_1
- scatter = SCATTER_AMOUNT_TIER_6
-
- apply_delegate = FALSE
-
-/datum/ammo/xeno/acid/prae_nade/on_hit_mob(mob/M, obj/projectile/P)
- if (!ishuman(M))
- return
-
- var/mob/living/carbon/human/H = M
-
- var/datum/effects/prae_acid_stacks/PAS = null
- for (var/datum/effects/prae_acid_stacks/prae_acid_stacks in H.effects_list)
- PAS = prae_acid_stacks
- break
-
- if (PAS == null)
- PAS = new /datum/effects/prae_acid_stacks(H)
- else
- PAS.increment_stack_count()
-
-/*datum/ammo/xeno/prae_skillshot
- name = "blob of acid"
- icon_state = "boiler_gas2"
- ping = "ping_x"
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE|AMMO_IGNORE_RESIST
-
- accuracy = HIT_ACCURACY_TIER_5
- accurate_range = 32
- max_range = 8
- damage = 20
- damage_falloff = DAMAGE_FALLOFF_TIER_10
- shell_speed = AMMO_SPEED_TIER_1
- scatter = SCATTER_AMOUNT_TIER_10
-
-/datum/ammo/xeno/prae_skillshot/on_hit_mob(mob/M, obj/projectile/P)
- acid_stacks_aoe(get_turf(P))
-
-/datum/ammo/xeno/prae_skillshot/on_hit_obj(obj/O, obj/projectile/P)
- acid_stacks_aoe(get_turf(P))
-
-/datum/ammo/xeno/prae_skillshot/on_hit_turf(turf/T, obj/projectile/P)
- acid_stacks_aoe(get_turf(P))
-
-/datum/ammo/xeno/prae_skillshot/do_at_max_range(obj/projectile/P)
- acid_stacks_aoe(get_turf(P))
-
-/datum/ammo/xeno/prae_skillshot/proc/acid_stacks_aoe(turf/T)
-
- if (!istype(T))
- return
-
- for (var/mob/living/carbon/human/H in orange(1, T))
- to_chat(H, SPAN_XENODANGER("You are spattered with acid!"))
- animation_flash_color(H)
- var/datum/effects/prae_acid_stacks/PAS = null
- for (var/datum/effects/prae_acid_stacks/prae_acid_stacks in H.effects_list)
- PAS = prae_acid_stacks
- break
-
- if (PAS == null)
- PAS = new /datum/effects/prae_acid_stacks(H)
- PAS.increment_stack_count()
- else
- PAS.increment_stack_count()
- PAS.increment_stack_count() */
-
-/datum/ammo/xeno/boiler_gas
- name = "glob of neuro gas"
- icon_state = "neuro_glob"
- ping = "ping_x"
- debilitate = list(2,2,0,1,11,12,1,10) // Stun,knockdown,knockout,irradiate,stutter,eyeblur,drowsy,agony
- flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_EXPLOSIVE|AMMO_IGNORE_RESIST|AMMO_HITS_TARGET_TURF|AMMO_ACIDIC
- var/datum/effect_system/smoke_spread/smoke_system
- spit_cost = 200
- pre_spit_warn = TRUE
- spit_windup = 5 SECONDS
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_4
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_4
- accuracy = HIT_ACCURACY_TIER_2
- scatter = SCATTER_AMOUNT_TIER_4
- shell_speed = 0.75
- max_range = 16
- /// range on the smoke in tiles from center
- var/smokerange = 4
- var/lifetime_mult = 1.0
-
-/datum/ammo/xeno/boiler_gas/New()
- ..()
- set_xeno_smoke()
-
-/datum/ammo/xeno/boiler_gas/Destroy()
- qdel(smoke_system)
- smoke_system = null
- . = ..()
-
-/datum/ammo/xeno/boiler_gas/on_hit_mob(mob/moob, obj/projectile/proj)
- if(iscarbon(moob))
- var/mob/living/carbon/carbon = moob
- if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD)
- return
- var/datum/effects/neurotoxin/neuro_effect = locate() in moob.effects_list
- if(!neuro_effect)
- neuro_effect = new /datum/effects/neurotoxin(moob, proj.firer)
- neuro_effect.duration += 5
- moob.apply_effect(3, DAZE)
- to_chat(moob, SPAN_HIGHDANGER("Neurotoxic liquid spreads all over you and immediately soaks into your pores and orifices! Oh fuck!")) // Fucked up but have a chance to escape rather than being game-ended
- drop_nade(get_turf(proj), proj,TRUE)
-
-/datum/ammo/xeno/boiler_gas/on_hit_obj(obj/outbacksteakhouse, obj/projectile/proj)
- drop_nade(get_turf(proj), proj)
-
-/datum/ammo/xeno/boiler_gas/on_hit_turf(turf/Turf, obj/projectile/proj)
- if(Turf.density && isturf(proj.loc))
- drop_nade(proj.loc, proj) //we don't want the gas globs to land on dense turfs, they block smoke expansion.
- else
- drop_nade(Turf, proj)
-
-/datum/ammo/xeno/boiler_gas/do_at_max_range(obj/projectile/proj)
- drop_nade(get_turf(proj), proj)
-
-/datum/ammo/xeno/boiler_gas/proc/set_xeno_smoke(obj/projectile/proj)
- smoke_system = new /datum/effect_system/smoke_spread/xeno_weaken()
-
-/datum/ammo/xeno/boiler_gas/proc/drop_nade(turf/turf, obj/projectile/proj)
- var/lifetime_mult = 1.0
- var/datum/cause_data
- if(isboiler(proj.firer))
- cause_data = proj.weapon_cause_data
- smoke_system.set_up(smokerange, 0, turf, new_cause_data = cause_data)
- smoke_system.lifetime = 12 * lifetime_mult
- smoke_system.start()
- turf.visible_message(SPAN_DANGER("A glob of acid lands with a splat and explodes into noxious fumes!"))
-
-
-/datum/ammo/xeno/boiler_gas/acid
- name = "glob of acid gas"
- icon_state = "acid_glob"
- ping = "ping_x"
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_4
- smokerange = 3
-
-
-/datum/ammo/xeno/boiler_gas/acid/set_xeno_smoke(obj/projectile/proj)
- smoke_system = new /datum/effect_system/smoke_spread/xeno_acid()
-
-/datum/ammo/xeno/boiler_gas/acid/on_hit_mob(mob/moob, obj/projectile/proj)
- if(iscarbon(moob))
- var/mob/living/carbon/carbon = moob
- if(carbon.status_flags & XENO_HOST && HAS_TRAIT(carbon, TRAIT_NESTED) || carbon.stat == DEAD)
- return
- to_chat(moob,SPAN_HIGHDANGER("Acid covers your body! Oh fuck!"))
- playsound(moob,"acid_strike",75,1)
- INVOKE_ASYNC(moob, TYPE_PROC_REF(/mob, emote), "pain") // why do I need this bullshit
- new /datum/effects/acid(moob, proj.firer)
- drop_nade(get_turf(proj), proj,TRUE)
-
-/datum/ammo/xeno/bone_chips
- name = "bone chips"
- icon_state = "shrapnel_light"
- ping = null
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_STOPPED_BY_COVER|AMMO_IGNORE_ARMOR
- damage_type = BRUTE
- bonus_projectiles_type = /datum/ammo/xeno/bone_chips/spread
-
- damage = 8
- max_range = 6
- accuracy = HIT_ACCURACY_TIER_8
- accuracy_var_low = PROJECTILE_VARIANCE_TIER_7
- accuracy_var_high = PROJECTILE_VARIANCE_TIER_7
- bonus_projectiles_amount = EXTRA_PROJECTILES_TIER_7
- shrapnel_type = /obj/item/shard/shrapnel/bone_chips
- shrapnel_chance = 60
-
-/datum/ammo/xeno/bone_chips/on_hit_mob(mob/M, obj/projectile/P)
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD)
- return
- if(ishuman_strict(M) || isxeno(M))
- playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1)
- if(M.slowed < 3)
- M.apply_effect(3, SLOW)
-
-/datum/ammo/xeno/bone_chips/spread
- name = "small bone chips"
-
- scatter = 30 // We want a wild scatter angle
- max_range = 5
- bonus_projectiles_amount = 0
-
-/datum/ammo/xeno/bone_chips/spread/short_range
- name = "small bone chips"
-
- max_range = 3 // Very short range
-
-/datum/ammo/xeno/bone_chips/spread/runner_skillshot
- name = "bone chips"
-
- scatter = 0
- max_range = 5
- damage = 10
- shrapnel_chance = 0
-
-/datum/ammo/xeno/bone_chips/spread/runner/on_hit_mob(mob/M, obj/projectile/P)
- if(iscarbon(M))
- var/mob/living/carbon/C = M
- if((HAS_FLAG(C.status_flags, XENO_HOST) && HAS_TRAIT(C, TRAIT_NESTED)) || C.stat == DEAD)
- return
- if(ishuman_strict(M) || isxeno(M))
- playsound(M, 'sound/effects/spike_hit.ogg', 25, 1, 1)
- if(M.slowed < 6)
- M.apply_effect(6, SLOW)
-
-/datum/ammo/xeno/oppressor_tail
- name = "tail hook"
- icon_state = "none"
- ping = null
- flags_ammo_behavior = AMMO_XENO|AMMO_SKIPS_ALIENS|AMMO_STOPPED_BY_COVER|AMMO_IGNORE_ARMOR
- damage_type = BRUTE
-
- damage = XENO_DAMAGE_TIER_5
- max_range = 4
- accuracy = HIT_ACCURACY_TIER_MAX
-
-/datum/ammo/xeno/oppressor_tail/on_bullet_generation(obj/projectile/generated_projectile, mob/bullet_generator)
- //The projectile has no icon, so the overlay shows up in FRONT of the projectile, and the beam connects to it in the middle.
- var/image/hook_overlay = new(icon = 'icons/effects/beam.dmi', icon_state = "oppressor_tail_hook", layer = BELOW_MOB_LAYER)
- generated_projectile.overlays += hook_overlay
-
-/datum/ammo/xeno/oppressor_tail/on_hit_mob(mob/target, obj/projectile/fired_proj)
- var/mob/living/carbon/xenomorph/xeno_firer = fired_proj.firer
- if(xeno_firer.can_not_harm(target))
- return
-
- shake_camera(target, 5, 0.1 SECONDS)
- var/obj/effect/beam/tail_beam = fired_proj.firer.beam(target, "oppressor_tail", 'icons/effects/beam.dmi', 0.5 SECONDS, 5)
- var/image/tail_image = image('icons/effects/status_effects.dmi', "hooked")
- target.overlays += tail_image
-
- new /datum/effects/xeno_slow(target, fired_proj.firer, ttl = 0.5 SECONDS)
- target.apply_effect(0.5, STUN)
- INVOKE_ASYNC(target, TYPE_PROC_REF(/atom/movable, throw_atom), fired_proj.firer, get_dist(fired_proj.firer, target)-1, SPEED_VERY_FAST)
-
- qdel(tail_beam)
- addtimer(CALLBACK(src, TYPE_PROC_REF(/datum/ammo/xeno/oppressor_tail, remove_tail_overlay), target, tail_image), 0.5 SECONDS) //needed so it can actually be seen as it gets deleted too quickly otherwise.
-
-/datum/ammo/xeno/oppressor_tail/proc/remove_tail_overlay(mob/overlayed_mob, image/tail_image)
- overlayed_mob.overlays -= tail_image
-
-/*
-//======
- Shrapnel
-//======
-*/
-/datum/ammo/bullet/shrapnel
- name = "shrapnel"
- icon_state = "buckshot"
- accurate_range_min = 5
- flags_ammo_behavior = AMMO_BALLISTIC|AMMO_STOPPED_BY_COVER
-
- accuracy = HIT_ACCURACY_TIER_3
- accurate_range = 32
- max_range = 8
- damage = 25
- damage_var_low = -PROJECTILE_VARIANCE_TIER_6
- damage_var_high = PROJECTILE_VARIANCE_TIER_6
- penetration = ARMOR_PENETRATION_TIER_4
- shell_speed = AMMO_SPEED_TIER_2
- shrapnel_chance = 5
-
-/datum/ammo/bullet/shrapnel/on_hit_obj(obj/O, obj/projectile/P)
- if(istype(O, /obj/structure/barricade))
- var/obj/structure/barricade/B = O
- B.health -= rand(2, 5)
- B.update_health(1)
-
-/datum/ammo/bullet/shrapnel/rubber
- name = "rubber pellets"
- icon_state = "rubber_pellets"
- flags_ammo_behavior = AMMO_STOPPED_BY_COVER
-
- damage = 0
- stamina_damage = 25
- shrapnel_chance = 0
-
-
-/datum/ammo/bullet/shrapnel/hornet_rounds
- name = ".22 hornet round"
- icon_state = "hornet_round"
- flags_ammo_behavior = AMMO_BALLISTIC
- damage = 20
- shrapnel_chance = 0
- shell_speed = AMMO_SPEED_TIER_3//she fast af boi
- penetration = ARMOR_PENETRATION_TIER_5
-
-/datum/ammo/bullet/shrapnel/hornet_rounds/on_hit_mob(mob/M, obj/projectile/P)
- . = ..()
- M.AddComponent(/datum/component/bonus_damage_stack, 10, world.time)
-
-/datum/ammo/bullet/shrapnel/incendiary
- name = "flaming shrapnel"
- icon_state = "beanbag" // looks suprisingly a lot like flaming shrapnel chunks
- flags_ammo_behavior = AMMO_STOPPED_BY_COVER
-
- shell_speed = AMMO_SPEED_TIER_1
- damage = 20
- penetration = ARMOR_PENETRATION_TIER_4
-
-/datum/ammo/bullet/shrapnel/incendiary/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/bullet/shrapnel/metal
- name = "metal shrapnel"
- icon_state = "shrapnelshot_bit"
- flags_ammo_behavior = AMMO_STOPPED_BY_COVER|AMMO_BALLISTIC
- shell_speed = AMMO_SPEED_TIER_1
- damage = 30
- shrapnel_chance = 15
- accuracy = HIT_ACCURACY_TIER_8
- penetration = ARMOR_PENETRATION_TIER_4
-
-/datum/ammo/bullet/shrapnel/light // weak shrapnel
- name = "light shrapnel"
- icon_state = "shrapnel_light"
-
- damage = 10
- penetration = ARMOR_PENETRATION_TIER_1
- shell_speed = AMMO_SPEED_TIER_1
- shrapnel_chance = 0
-
-/datum/ammo/bullet/shrapnel/light/human
- name = "human bone fragments"
- icon_state = "shrapnel_human"
-
- shrapnel_chance = 50
- shrapnel_type = /obj/item/shard/shrapnel/bone_chips/human
-
-/datum/ammo/bullet/shrapnel/light/human/var1 // sprite variants
- icon_state = "shrapnel_human1"
-
-/datum/ammo/bullet/shrapnel/light/human/var2 // sprite variants
- icon_state = "shrapnel_human2"
-
-/datum/ammo/bullet/shrapnel/light/xeno
- name = "alien bone fragments"
- icon_state = "shrapnel_xeno"
-
- shrapnel_chance = 50
- shrapnel_type = /obj/item/shard/shrapnel/bone_chips/xeno
-
-/datum/ammo/bullet/shrapnel/spall // weak shrapnel
- name = "spall"
- icon_state = "shrapnel_light"
-
- damage = 10
- penetration = ARMOR_PENETRATION_TIER_1
- shell_speed = AMMO_SPEED_TIER_1
- shrapnel_chance = 0
-
-/datum/ammo/bullet/shrapnel/light/glass
- name = "glass shrapnel"
- icon_state = "shrapnel_glass"
-
-/datum/ammo/bullet/shrapnel/light/effect/ // no damage, but looks bright and neat
- name = "sparks"
-
- damage = 1 // Tickle tickle
-
-/datum/ammo/bullet/shrapnel/light/effect/ver1
- icon_state = "shrapnel_bright1"
-
-/datum/ammo/bullet/shrapnel/light/effect/ver2
- icon_state = "shrapnel_bright2"
-
-/datum/ammo/bullet/shrapnel/jagged
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_2
- accuracy = HIT_ACCURACY_TIER_MAX
-
-/datum/ammo/bullet/shrapnel/jagged/on_hit_mob(mob/M, obj/projectile/P)
- if(isxeno(M))
- M.apply_effect(0.4, SLOW)
-
-/*
-//========
- CAS 30mm impacters
-//========
-*/
-/datum/ammo/bullet/shrapnel/gau //for the GAU to have a impact bullet instead of firecrackers
- name = "30mm Multi-Purpose shell"
-
- damage = 1 // ALL DAMAGE IS IN dropship_ammo SO WE CAN DEAL DAMAGE TO RESTING MOBS, these will still remain however so that we can get cause_data and status effects.
- damage_type = BRUTE
- penetration = ARMOR_PENETRATION_TIER_2
- accuracy = HIT_ACCURACY_TIER_MAX
- max_range = 0
- shrapnel_chance = 100 //the least of your problems
-
-/datum/ammo/bullet/shrapnel/gau/at
- name = "30mm Anti-Tank shell"
-
- damage = 1 // ALL DAMAGE IS IN dropship_ammo SO WE CAN DEAL DAMAGE TO RESTING MOBS, these will still remain however so that we can get cause_data and status effects.
- penetration = ARMOR_PENETRATION_TIER_8
- accuracy = HIT_ACCURACY_TIER_MAX
-/*
-//======
- Misc Ammo
-//======
-*/
-
-/datum/ammo/alloy_spike
- name = "alloy spike"
- headshot_state = HEADSHOT_OVERLAY_MEDIUM
- ping = "ping_s"
- icon_state = "MSpearFlight"
- sound_hit = "alloy_hit"
- sound_armor = "alloy_armor"
- sound_bounce = "alloy_bounce"
-
- accuracy = HIT_ACCURACY_TIER_8
- accurate_range = 12
- max_range = 12
- damage = 30
- penetration= ARMOR_PENETRATION_TIER_10
- shrapnel_chance = SHRAPNEL_CHANCE_TIER_7
- shrapnel_type = /obj/item/shard/shrapnel
-
-/datum/ammo/flamethrower
- name = "flame"
- icon_state = "pulse0"
- damage_type = BURN
- flags_ammo_behavior = AMMO_IGNORE_ARMOR|AMMO_HITS_TARGET_TURF
-
- max_range = 6
- damage = 35
-
-/datum/ammo/flamethrower/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/flamethrower/on_hit_mob(mob/M, obj/projectile/P)
- drop_flame(get_turf(M), P.weapon_cause_data)
-
-/datum/ammo/flamethrower/on_hit_obj(obj/O, obj/projectile/P)
- drop_flame(get_turf(O), P.weapon_cause_data)
-
-/datum/ammo/flamethrower/on_hit_turf(turf/T, obj/projectile/P)
- drop_flame(T, P.weapon_cause_data)
-
-/datum/ammo/flamethrower/do_at_max_range(obj/projectile/P)
- drop_flame(get_turf(P), P.weapon_cause_data)
-
-/datum/ammo/flamethrower/tank_flamer
- flamer_reagent_type = /datum/reagent/napalm/blue
-
-/datum/ammo/flamethrower/sentry_flamer
- flags_ammo_behavior = AMMO_IGNORE_ARMOR|AMMO_IGNORE_COVER|AMMO_FLAME
- flamer_reagent_type = /datum/reagent/napalm/blue
-
- accuracy = HIT_ACCURACY_TIER_8
- accurate_range = 6
- max_range = 12
- shell_speed = AMMO_SPEED_TIER_3
-
-/datum/ammo/flamethrower/sentry_flamer/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/flamethrower/sentry_flamer/glob
- max_range = 14
- accurate_range = 10
- var/datum/effect_system/smoke_spread/phosphorus/smoke
-
-/datum/ammo/flamethrower/sentry_flamer/glob/New()
- . = ..()
- smoke = new()
-
-/datum/ammo/flamethrower/sentry_flamer/glob/drop_flame(turf/T, datum/cause_data/cause_data)
- if(!istype(T))
- return
- smoke.set_up(1, 0, T, new_cause_data = cause_data)
- smoke.start()
-
-/datum/ammo/flamethrower/sentry_flamer/glob/Destroy()
- qdel(smoke)
- return ..()
-
-/datum/ammo/flamethrower/sentry_flamer/mini
- name = "normal fire"
-
-/datum/ammo/flamethrower/sentry_flamer/mini/drop_flame(turf/T, datum/cause_data/cause_data)
- if(!istype(T))
- return
- var/datum/reagent/napalm/ut/R = new()
- R.durationfire = BURN_TIME_INSTANT
- new /obj/flamer_fire(T, cause_data, R, 0)
-
-/datum/ammo/flare
- name = "flare"
- ping = null //no bounce off.
- damage_type = BURN
- flags_ammo_behavior = AMMO_HITS_TARGET_TURF
- icon_state = "flare"
-
- damage = 15
- accuracy = HIT_ACCURACY_TIER_3
- max_range = 14
- shell_speed = AMMO_SPEED_TIER_3
-
- var/flare_type = /obj/item/device/flashlight/flare/on/gun
- handful_type = /obj/item/device/flashlight/flare
-
-/datum/ammo/flare/set_bullet_traits()
- . = ..()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/flare/on_hit_mob(mob/M,obj/projectile/P)
- drop_flare(get_turf(M), P, P.firer)
-
-/datum/ammo/flare/on_hit_obj(obj/O,obj/projectile/P)
- drop_flare(get_turf(P), P, P.firer)
-
-/datum/ammo/flare/on_hit_turf(turf/T, obj/projectile/P)
- if(T.density && isturf(P.loc))
- drop_flare(P.loc, P, P.firer)
- else
- drop_flare(T, P, P.firer)
-
-/datum/ammo/flare/do_at_max_range(obj/projectile/P, mob/firer)
- drop_flare(get_turf(P), P, P.firer)
-
-/datum/ammo/flare/proc/drop_flare(turf/T, obj/projectile/fired_projectile, mob/firer)
- var/obj/item/device/flashlight/flare/G = new flare_type(T)
- var/matrix/rotation = matrix()
- rotation.Turn(fired_projectile.angle - 90)
- G.apply_transform(rotation)
- G.visible_message(SPAN_WARNING("\A [G] bursts into brilliant light nearby!"))
- return G
-
-/datum/ammo/flare/signal
- name = "signal flare"
- icon_state = "flare_signal"
- flare_type = /obj/item/device/flashlight/flare/signal/gun
- handful_type = /obj/item/device/flashlight/flare/signal
-
-/datum/ammo/flare/signal/drop_flare(turf/T, obj/projectile/fired_projectile, mob/firer)
- var/obj/item/device/flashlight/flare/signal/gun/signal_flare = ..()
- signal_flare.activate_signal(firer)
- if(istype(fired_projectile.shot_from, /obj/item/weapon/gun/flare))
- var/obj/item/weapon/gun/flare/flare_gun_fired_from = fired_projectile.shot_from
- flare_gun_fired_from.last_signal_flare_name = signal_flare.name
-
-/datum/ammo/flare/starshell
- name = "starshell ash"
- icon_state = "starshell_bullet"
- max_range = 5
- flare_type = /obj/item/device/flashlight/flare/on/starshell_ash
-
-/datum/ammo/flare/starshell/set_bullet_traits()
- LAZYADD(traits_to_give, list(
- BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff, /datum/element/bullet_trait_incendiary)
- ))
-
-/datum/ammo/souto
- name = "Souto Can"
- ping = null //no bounce off.
- damage_type = BRUTE
- shrapnel_type = /obj/item/reagent_container/food/drinks/cans/souto/classic
- flags_ammo_behavior = AMMO_SKIPS_ALIENS|AMMO_IGNORE_ARMOR|AMMO_IGNORE_RESIST|AMMO_BALLISTIC|AMMO_STOPPED_BY_COVER|AMMO_SPECIAL_EMBED
- var/obj/item/reagent_container/food/drinks/cans/souto/can_type
- icon_state = "souto_classic"
-
- max_range = 12
- shrapnel_chance = 10
- accuracy = HIT_ACCURACY_TIER_8 + HIT_ACCURACY_TIER_8
- accurate_range = 12
- shell_speed = AMMO_SPEED_TIER_1
-
-/datum/ammo/souto/on_embed(mob/embedded_mob, obj/limb/target_organ)
- if(ishuman(embedded_mob) && !isyautja(embedded_mob))
- if(istype(target_organ))
- target_organ.embed(new can_type)
-
-/datum/ammo/souto/on_hit_mob(mob/M, obj/projectile/P)
- if(!M || M == P.firer) return
- if(M.throw_mode && !M.get_active_hand()) //empty active hand and we're in throw mode. If so we catch the can.
- if(!M.is_mob_incapacitated()) // People who are not able to catch cannot catch.
- if(P.contents.len == 1)
- for(var/obj/item/reagent_container/food/drinks/cans/souto/S in P.contents)
- M.put_in_active_hand(S)
- for(var/mob/O in viewers(world_view_size, P)) //find all people in view.
- O.show_message(SPAN_DANGER("[M] catches the [S]!"), SHOW_MESSAGE_VISIBLE) //Tell them the can was caught.
- return //Can was caught.
- if(ishuman(M))
- var/mob/living/carbon/human/H = M
- if(H.species.name == "Human") //no effect on synths or preds.
- H.apply_effect(6, STUN)
- H.apply_effect(8, WEAKEN)
- H.apply_effect(15, DAZE)
- H.apply_effect(15, SLOW)
- shake_camera(H, 2, 1)
- if(P.contents.len)
- drop_can(P.loc, P) //We make a can at the location.
-
-/datum/ammo/souto/on_hit_obj(obj/O,obj/projectile/P)
- drop_can(P.loc, P) //We make a can at the location.
-
-/datum/ammo/souto/on_hit_turf(turf/T, obj/projectile/P)
- drop_can(P.loc, P) //We make a can at the location.
-
-/datum/ammo/souto/do_at_max_range(obj/projectile/P)
- drop_can(P.loc, P) //We make a can at the location.
-
-/datum/ammo/souto/on_shield_block(mob/M, obj/projectile/P)
- drop_can(P.loc, P) //We make a can at the location.
-
-/datum/ammo/souto/proc/drop_can(loc, obj/projectile/P)
- if(P.contents.len)
- for(var/obj/item/I in P.contents)
- I.forceMove(loc)
- randomize_projectile(P)
-
-/datum/ammo/souto/proc/randomize_projectile(obj/projectile/P)
- shrapnel_type = pick(typesof(/obj/item/reagent_container/food/drinks/cans/souto)-/obj/item/reagent_container/food/drinks/cans/souto)
-
-/datum/ammo/grenade_container
- name = "grenade shell"
- ping = null
- damage_type = BRUTE
- var/nade_type = /obj/item/explosive/grenade/high_explosive
- icon_state = "grenade"
- flags_ammo_behavior = AMMO_IGNORE_COVER|AMMO_SKIPS_ALIENS
-
- damage = 15
- accuracy = HIT_ACCURACY_TIER_3
- max_range = 6
-
-/datum/ammo/grenade_container/on_hit_mob(mob/M,obj/projectile/P)
- drop_nade(P)
-
-/datum/ammo/grenade_container/on_hit_obj(obj/O,obj/projectile/P)
- drop_nade(P)
-
-/datum/ammo/grenade_container/on_hit_turf(turf/T,obj/projectile/P)
- drop_nade(P)
-
-/datum/ammo/grenade_container/do_at_max_range(obj/projectile/P)
- drop_nade(P)
-
-/datum/ammo/grenade_container/proc/drop_nade(obj/projectile/P)
- var/turf/T = get_turf(P)
- var/obj/item/explosive/grenade/G = new nade_type(T)
- G.visible_message(SPAN_WARNING("\A [G] lands on [T]!"))
- G.det_time = 10
- G.cause_data = P.weapon_cause_data
- G.activate()
-
-/datum/ammo/grenade_container/rifle
- flags_ammo_behavior = NO_FLAGS
-
-/datum/ammo/grenade_container/smoke
- name = "smoke grenade shell"
- nade_type = /obj/item/explosive/grenade/smokebomb
- icon_state = "smoke_shell"
-
-/datum/ammo/hugger_container
- name = "hugger shell"
- ping = null
- damage_type = BRUTE
- var/hugger_hive = XENO_HIVE_NORMAL
- icon_state = "smoke_shell"
-
- damage = 15
- accuracy = HIT_ACCURACY_TIER_3
- max_range = 6
-
-/datum/ammo/hugger_container/on_hit_mob(mob/M,obj/projectile/P)
- spawn_hugger(get_turf(P))
-
-/datum/ammo/hugger_container/on_hit_obj(obj/O,obj/projectile/P)
- spawn_hugger(get_turf(P))
-
-/datum/ammo/hugger_container/on_hit_turf(turf/T,obj/projectile/P)
- spawn_hugger(get_turf(P))
-
-/datum/ammo/hugger_container/do_at_max_range(obj/projectile/P)
- spawn_hugger(get_turf(P))
-
-/datum/ammo/hugger_container/proc/spawn_hugger(turf/T)
- var/obj/item/clothing/mask/facehugger/child = new(T)
- child.hivenumber = hugger_hive
- INVOKE_ASYNC(child, TYPE_PROC_REF(/obj/item/clothing/mask/facehugger, leap_at_nearest_target))
diff --git a/code/modules/projectiles/ammunition.dm b/code/modules/projectiles/ammunition.dm
index d747525f3feb..594ad6b69dce 100644
--- a/code/modules/projectiles/ammunition.dm
+++ b/code/modules/projectiles/ammunition.dm
@@ -18,6 +18,8 @@ They're all essentially identical when it comes to getting the job done.
w_class = SIZE_SMALL
throw_speed = SPEED_SLOW
throw_range = 6
+ ground_offset_x = 7
+ ground_offset_y = 6
var/default_ammo = /datum/ammo/bullet
var/caliber = null // This is used for matching handfuls to each other or whatever the mag is. Examples are" "12g" ".44" ".357" etc.
var/current_rounds = -1 //Set this to something else for it not to start with different initial counts.
@@ -50,8 +52,7 @@ They're all essentially identical when it comes to getting the job done.
if(0)
icon_state += "_e" //In case it spawns empty instead.
item_state += "_e"
- pixel_y = rand(-6, 6)
- pixel_x = rand(-7, 7)
+
if(ammo_band_color && ammo_band_icon)
update_ammo_band()
diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm
index 6fd5d4b0d834..131b19c5d81e 100644
--- a/code/modules/projectiles/gun.dm
+++ b/code/modules/projectiles/gun.dm
@@ -288,16 +288,11 @@
/obj/item/weapon/gun/Destroy()
in_chamber = null
ammo = null
- current_mag = null
+ QDEL_NULL(current_mag)
target = null
last_moved_mob = null
if(flags_gun_features & GUN_FLASHLIGHT_ON)//Handle flashlight.
flags_gun_features &= ~GUN_FLASHLIGHT_ON
- if(ismob(loc))
- for(var/slot in attachments)
- var/obj/item/attachable/potential_attachment = attachments[slot]
- if(!potential_attachment)
- continue
attachments = null
attachable_overlays = null
QDEL_NULL(active_attachable)
@@ -486,6 +481,7 @@
/obj/item/weapon/gun/emp_act(severity)
+ . = ..()
for(var/obj/O in contents)
O.emp_act(severity)
@@ -493,12 +489,12 @@
Note: pickup and dropped on weapons must have both the ..() to update zoom AND twohanded,
As sniper rifles have both and weapon mods can change them as well. ..() deals with zoom only.
*/
-/obj/item/weapon/gun/equipped(mob/user, slot)
+/obj/item/weapon/gun/equipped(mob/living/user, slot)
if(flags_item & NODROP) return
unwield(user)
pull_time = world.time + wield_delay
- if(user.dazed)
+ if(HAS_TRAIT(user, TRAIT_DAZED))
pull_time += 3
guaranteed_delay_time = world.time + WEAPON_GUARANTEED_DELAY
@@ -525,6 +521,10 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
if(fire_delay_group && delay_left > 0)
LAZYSET(user.fire_delay_next_fire, src, world.time + delay_left)
+ for(var/obj/item/attachable/stock/smg/collapsible/brace/current_stock in contents) //SMG armbrace folds to stop it getting stuck on people
+ if(current_stock.stock_activated)
+ current_stock.activate_attachment(src, user, turn_off = TRUE)
+
unwield(user)
set_gun_user(null)
@@ -733,7 +733,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
// END TGUI \\
-/obj/item/weapon/gun/wield(mob/user)
+/obj/item/weapon/gun/wield(mob/living/user)
if(!(flags_item & TWOHANDED) || flags_item & WIELDED)
return
@@ -760,7 +760,7 @@ As sniper rifles have both and weapon mods can change them as well. ..() deals w
slowdown = initial(slowdown) + aim_slowdown
place_offhand(user, initial(name))
wield_time = world.time + wield_delay
- if(user.dazed)
+ if(HAS_TRAIT(user, TRAIT_DAZED))
wield_time += 5
guaranteed_delay_time = world.time + WEAPON_GUARANTEED_DELAY
//slower or faster wield delay depending on skill.
@@ -844,6 +844,7 @@ User can be passed as null, (a gun reloading itself for instance), so we need to
to_chat(user, SPAN_WARNING("Your reload was interrupted!"))
return
replace_magazine(user, magazine)
+ SEND_SIGNAL(user, COMSIG_MOB_RELOADED_GUN, src)
else
current_mag = magazine
magazine.forceMove(src)
@@ -1049,6 +1050,7 @@ and you're good to go.
user.swap_hand()
unload(user, TRUE, drop_to_ground) // We want to quickly autoeject the magazine. This proc does the rest based on magazine type. User can be passed as null.
playsound(src, empty_sound, 25, 1)
+ SEND_SIGNAL(user, COMSIG_MOB_GUN_EMPTY, src)
else // Just fired a chambered bullet with no magazine in the gun
update_icon()
@@ -1401,7 +1403,7 @@ and you're good to go.
var/damage_buff = BASE_BULLET_DAMAGE_MULT
//if target is lying or unconscious - add damage bonus
- if(attacked_mob.lying == TRUE || attacked_mob.stat == UNCONSCIOUS)
+ if(!(attacked_mob.mobility_flags & MOBILITY_STAND) || attacked_mob.stat == UNCONSCIOUS)
damage_buff += BULLET_DAMAGE_MULT_TIER_4
projectile_to_fire.damage *= damage_buff //Multiply the damage for point blank.
if(bullets_fired == 1) //First shot gives the PB message.
@@ -1425,7 +1427,7 @@ and you're good to go.
projectile_to_fire.give_bullet_traits(BP)
if(bullets_fired > 1)
BP.original = attacked_mob //original == the original target of the projectile. If the target is downed and this isn't set, the projectile will try to fly over it. Of course, it isn't going anywhere, but it's the principle of the thing. Very embarrassing.
- if(!BP.handle_mob(attacked_mob) && attacked_mob.lying) //This is the 'handle impact' proc for a flying projectile, including hit RNG, on_hit_mob and bullet_act. If it misses, it doesn't go anywhere. We'll pretend it slams into the ground or punches a hole in the ceiling, because trying to make it bypass the xeno or shoot from the tile beyond it is probably more spaghet than my life is worth.
+ if(!BP.handle_mob(attacked_mob) && attacked_mob.body_position == LYING_DOWN) //This is the 'handle impact' proc for a flying projectile, including hit RNG, on_hit_mob and bullet_act. If it misses, it doesn't go anywhere. We'll pretend it slams into the ground or punches a hole in the ceiling, because trying to make it bypass the xeno or shoot from the tile beyond it is probably more spaghet than my life is worth.
if(BP.ammo.sound_bounce)
playsound(attacked_mob.loc, BP.ammo.sound_bounce, 35, 1)
attacked_mob.visible_message(SPAN_AVOIDHARM("[BP] slams into [get_turf(attacked_mob)]!"), //Managing to miss an immobile target flat on the ground deserves some recognition, don't you think?
@@ -1438,7 +1440,7 @@ and you're good to go.
if(bullets_fired > 1)
projectile_to_fire.original = attacked_mob
- if(!projectile_to_fire.handle_mob(attacked_mob) && attacked_mob.lying)
+ if(!projectile_to_fire.handle_mob(attacked_mob) && attacked_mob.body_position == LYING_DOWN)
if(projectile_to_fire.ammo.sound_bounce)
playsound(attacked_mob.loc, projectile_to_fire.ammo.sound_bounce, 35, 1)
attacked_mob.visible_message(SPAN_AVOIDHARM("[projectile_to_fire] slams into [get_turf(attacked_mob)]!"),
@@ -1539,6 +1541,7 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed
if(flags_gun_features & GUN_TRIGGER_SAFETY)
to_chat(user, SPAN_WARNING("The safety is on!"))
+ gun_user.balloon_alert(gun_user, "safety on")
return
if(active_attachable)
if(active_attachable.flags_attach_features & ATTACH_PROJECTILE)
@@ -1934,8 +1937,8 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed
if(gun_user.client?.prefs?.toggle_prefs & TOGGLE_HELP_INTENT_SAFETY && (gun_user.a_intent == INTENT_HELP))
if(world.time % 3) // Limits how often this message pops up, saw this somewhere else and thought it was clever
- //Absolutely SCREAM this at people so they don't get killed by it
- to_chat(gun_user, SPAN_HIGHDANGER("Help intent safety is on! Switch to another intent to fire your weapon."))
+ to_chat(gun_user, SPAN_DANGER("Help intent safety is on! Switch to another intent to fire your weapon."))
+ gun_user.balloon_alert(gun_user, "help intent safety")
click_empty(gun_user)
return FALSE
@@ -1960,6 +1963,7 @@ not all weapons use normal magazines etc. load_into_chamber() itself is designed
/// Setter proc for fa_firing
/obj/item/weapon/gun/proc/set_auto_firing(auto = FALSE)
+ SIGNAL_HANDLER
fa_firing = auto
/// Getter for gun_user
diff --git a/code/modules/projectiles/gun_attachables.dm b/code/modules/projectiles/gun_attachables.dm
index 2438947ef254..0f3fde8f3c9b 100644
--- a/code/modules/projectiles/gun_attachables.dm
+++ b/code/modules/projectiles/gun_attachables.dm
@@ -342,6 +342,10 @@ Defined in conflicts.dm of the #defines folder.
throw_range = 7
pry_delay = 1 SECONDS
+/obj/item/attachable/bayonet/van_bandolier
+ name = "\improper Fairbairn-Sykes fighting knife"
+ desc = "This isn't for dressing game or performing camp chores. It's almost certainly not an original. Almost."
+
/obj/item/attachable/bayonet/co2/update_icon()
icon_state = "co2_knife[filled ? "-f" : ""]"
attach_icon = "co2_bayonet[filled ? "-f" : ""]_a"
@@ -350,16 +354,16 @@ Defined in conflicts.dm of the #defines folder.
if(istype(W, /obj/item/co2_cartridge))
if(!filled)
filled = TRUE
- user.visible_message(SPAN_NOTICE("[user] slots a CO2 cartridge into [src]. A second later, \he apparently looks dismayed."), SPAN_WARNING("You slot a fresh CO2 cartridge into [src] and snap the slot cover into place. Only then do you realize \the [W]'s valve broke inside \the [src]. Fuck."))
+ user.visible_message(SPAN_NOTICE("[user] slots a CO2 cartridge into [src]. A second later, \he apparently looks dismayed."), SPAN_WARNING("You slot a fresh CO2 cartridge into [src] and snap the slot cover into place. Only then do you realize [W]'s valve broke inside [src]. Fuck."))
playsound(src, 'sound/machines/click.ogg')
qdel(W)
update_icon()
return
else
- user.visible_message(SPAN_WARNING("[user] fiddles with \the [src]. \He looks frustrated."), SPAN_NOTICE("No way man! You can't seem to pry the existing container out of \the [src]... try a screwdriver?"))
+ user.visible_message(SPAN_WARNING("[user] fiddles with [src]. \He looks frustrated."), SPAN_NOTICE("No way man! You can't seem to pry the existing container out of [src]... try a screwdriver?"))
return
if(HAS_TRAIT(W, TRAIT_TOOL_SCREWDRIVER) && do_after(user, 2 SECONDS, INTERRUPT_ALL, BUSY_ICON_BUILD))
- user.visible_message(SPAN_WARNING("[user] screws with \the [src], using \a [W]. \He looks very frustrated."), SPAN_NOTICE("You try to pry the cartridge out of the [src], but it's stuck damn deep. Piece of junk..."))
+ user.visible_message(SPAN_WARNING("[user] screws with [src], using \a [W]. \He looks very frustrated."), SPAN_NOTICE("You try to pry the cartridge out of [src], but it's stuck damn deep. Piece of junk..."))
return
..()
@@ -495,6 +499,20 @@ Defined in conflicts.dm of the #defines folder.
accuracy_mod = HIT_ACCURACY_MULT_TIER_3
scatter_mod = -SCATTER_AMOUNT_TIER_8
+/obj/item/attachable/pmc_sniperbarrel
+ name = "sniper barrel"
+ icon = 'icons/obj/items/weapons/guns/attachments/barrel.dmi'
+ icon_state = "pmc_sniperbarrel"
+ desc = "A heavy barrel. CANNOT BE REMOVED."
+ slot = "muzzle"
+ flags_attach_features = NO_FLAGS
+ hud_offset_mod = -3
+
+/obj/item/attachable/pmc_sniperbarrel/New()
+ ..()
+ accuracy_mod = HIT_ACCURACY_MULT_TIER_3
+ scatter_mod = -SCATTER_AMOUNT_TIER_8
+
/obj/item/attachable/sniperbarrel/vulture
name = "\improper M707 barrel"
icon_state = "vulture_barrel"
@@ -1283,7 +1301,7 @@ Defined in conflicts.dm of the #defines folder.
switch(action)
if("adjust_dir")
var/direction = params["offset_dir"]
- if(!(direction in alldirs) || !scoping || !scope_user)
+ if(!(direction in GLOB.alldirs) || !scoping || !scope_user)
return
var/mob/scoper = scope_user.resolve()
@@ -1300,7 +1318,7 @@ Defined in conflicts.dm of the #defines folder.
if("adjust_position")
var/direction = params["position_dir"]
- if(!(direction in alldirs) || !scoping || !scope_user)
+ if(!(direction in GLOB.alldirs) || !scoping || !scope_user)
return
var/mob/scoper = scope_user.resolve()
@@ -1367,7 +1385,7 @@ Defined in conflicts.dm of the #defines folder.
return TRUE
/obj/item/attachable/vulture_scope/proc/get_offset_dirs()
- var/list/possible_dirs = alldirs.Copy()
+ var/list/possible_dirs = GLOB.alldirs.Copy()
if(scope_offset_x >= scope_drift_max)
possible_dirs -= list(NORTHEAST, EAST, SOUTHEAST)
else if(scope_offset_x <= -scope_drift_max)
@@ -1384,7 +1402,7 @@ Defined in conflicts.dm of the #defines folder.
/obj/item/attachable/vulture_scope/proc/get_adjust_dirs()
if(!scoping)
return list()
- var/list/possible_dirs = alldirs.Copy()
+ var/list/possible_dirs = GLOB.alldirs.Copy()
var/turf/current_turf = get_turf(src)
var/turf/scope_tile = locate(scope_x, scope_y, current_turf.z)
var/mob/scoper = scope_user.resolve()
@@ -1568,7 +1586,7 @@ Defined in conflicts.dm of the #defines folder.
scoper.clear_fullscreen("vulture")
scoper.client.remove_from_screen(scope_element)
scoper.see_in_dark -= darkness_view
- scoper.lighting_alpha = 127
+ scoper.lighting_alpha = LIGHTING_PLANE_ALPHA_VISIBLE
scoper.sync_lighting_plane_alpha()
QDEL_NULL(scope_element)
recalculate_scope_pos()
@@ -2671,7 +2689,7 @@ Defined in conflicts.dm of the #defines folder.
/obj/item/attachable/attached_gun/grenade/unique_action(mob/user)
if(!ishuman(usr))
return
- if(!user.canmove || user.stat || user.is_mob_restrained() || !user.loc || !isturf(usr.loc))
+ if(user.is_mob_incapacitated() || !isturf(usr.loc))
to_chat(user, SPAN_WARNING("Not right now."))
return
@@ -3058,9 +3076,6 @@ Defined in conflicts.dm of the #defines folder.
/obj/item/attachable/attached_gun/extinguisher/fire_attachment(atom/target, obj/item/weapon/gun/gun, mob/living/user)
if(!internal_extinguisher)
return
- if(!(gun.flags_item & WIELDED))
- to_chat(user, SPAN_WARNING("You must wield [gun] to fire [src]!"))
- return
if(..())
return internal_extinguisher.afterattack(target, user)
@@ -3436,4 +3451,3 @@ Defined in conflicts.dm of the #defines folder.
accuracy_mod = HIT_ACCURACY_MULT_TIER_5
accuracy_unwielded_mod = HIT_ACCURACY_MULT_TIER_5
damage_mod -= BULLET_DAMAGE_MULT_TIER_4
-
diff --git a/code/modules/projectiles/gun_helpers.dm b/code/modules/projectiles/gun_helpers.dm
index be46fdb15ed0..f73b5550b297 100644
--- a/code/modules/projectiles/gun_helpers.dm
+++ b/code/modules/projectiles/gun_helpers.dm
@@ -462,7 +462,7 @@ DEFINES in setup.dm, referenced here.
/obj/item/weapon/gun/proc/get_active_firearm(mob/user, restrictive = TRUE)
if(!ishuman(usr))
return
- if(!user.canmove || user.stat || user.is_mob_restrained() || !user.loc || !isturf(usr.loc))
+ if(user.is_mob_incapacitated() || !isturf(usr.loc))
to_chat(user, SPAN_WARNING("Not right now."))
return
diff --git a/code/modules/projectiles/guns/boltaction.dm b/code/modules/projectiles/guns/boltaction.dm
index c18e45e38d3e..d21cb5b87254 100644
--- a/code/modules/projectiles/guns/boltaction.dm
+++ b/code/modules/projectiles/guns/boltaction.dm
@@ -214,7 +214,7 @@
return .
for(var/mob/current_mob as anything in get_mobs_in_z_level_range(get_turf(user), fire_message_range) - user)
- var/relative_dir = get_dir(current_mob, user)
+ var/relative_dir = Get_Compass_Dir(current_mob, user)
var/final_dir = dir2text(relative_dir)
to_chat(current_mob, SPAN_HIGHDANGER("You hear a massive boom coming from [final_dir ? "the [final_dir]" : "nearby"]!"))
if(current_mob.client)
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index adca6a7cce6f..ee122d8f8edd 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -66,9 +66,9 @@
overlays += charge_icon + "_0"
/obj/item/weapon/gun/energy/emp_act(severity)
+ . = ..()
cell.use(round(cell.maxcharge / severity))
update_icon()
- ..()
/obj/item/weapon/gun/energy/load_into_chamber()
if(!cell || cell.charge < charge_cost)
diff --git a/code/modules/projectiles/guns/flamer/flamer.dm b/code/modules/projectiles/guns/flamer/flamer.dm
index 13ccd03c3e82..282edcab9fd6 100644
--- a/code/modules/projectiles/guns/flamer/flamer.dm
+++ b/code/modules/projectiles/guns/flamer/flamer.dm
@@ -250,6 +250,9 @@
/obj/item/weapon/gun/flamer/deathsquad/nolock
flags_gun_features = GUN_WIELDED_FIRING_ONLY
+/obj/item/weapon/gun/flamer/deathsquad/standard
+ current_mag = /obj/item/ammo_magazine/flamer_tank
+
/obj/item/weapon/gun/flamer/M240T
name = "\improper M240-T incinerator unit"
desc = "An improved version of the M240A1 incinerator unit, the M240-T model is capable of dispersing a larger variety of fuel types."
@@ -372,29 +375,6 @@
. = ..()
set_fire_delay(FIRE_DELAY_TIER_7)
-GLOBAL_LIST_EMPTY(flamer_particles)
-/particles/flamer_fire
- icon = 'icons/effects/particles/fire.dmi'
- icon_state = "bonfire"
- width = 100
- height = 100
- count = 1000
- spawning = 8
- lifespan = 0.7 SECONDS
- fade = 1 SECONDS
- grow = -0.01
- velocity = list(0, 0)
- position = generator("box", list(-16, -16), list(16, 16), NORMAL_RAND)
- drift = generator("vector", list(0, -0.2), list(0, 0.2))
- gravity = list(0, 0.95)
- scale = generator("vector", list(0.3, 0.3), list(1,1), NORMAL_RAND)
- rotation = 30
- spin = generator("num", -20, 20)
-
-/particles/flamer_fire/New(set_color)
- ..()
- color = set_color
-
/obj/flamer_fire
name = "fire"
desc = "Ouch!"
@@ -451,14 +431,11 @@ GLOBAL_LIST_EMPTY(flamer_particles)
set_light(l_color = R.burncolor)
- if(!GLOB.flamer_particles[R.burncolor])
- GLOB.flamer_particles[R.burncolor] = new /particles/flamer_fire(R.burncolor)
- particles = GLOB.flamer_particles[R.burncolor]
-
tied_reagent = new R.type() // Can't get deleted this way
tied_reagent.make_alike(R)
- tied_reagents = obj_reagents
+ if(obj_reagents)
+ tied_reagents = obj_reagents
target_clicked = target
@@ -644,7 +621,7 @@ GLOBAL_LIST_EMPTY(flamer_particles)
burn_damage = 0
if(!burn_damage)
- to_chat(M, SPAN_DANGER("You step over the flames."))
+ to_chat(M, SPAN_DANGER("[isxeno(M) ? "We" : "You"] step over the flames."))
return
M.last_damage_data = weapon_cause_data
@@ -655,7 +632,7 @@ GLOBAL_LIST_EMPTY(flamer_particles)
if(FIRE_VARIANT_TYPE_B)
if(isxeno(M))
var/mob/living/carbon/xenomorph/X = M
- X.armor_deflection?(variant_burn_msg=" You feel the flames weakening your exoskeleton!"):(variant_burn_msg=" You feel the flaming chemicals eating into your body!")
+ X.armor_deflection?(variant_burn_msg=" We feel the flames weakening our exoskeleton!"):(variant_burn_msg=" You feel the flaming chemicals eating into your body!")
to_chat(M, SPAN_DANGER("You are burned![variant_burn_msg?"[variant_burn_msg]":""]"))
M.updatehealth()
@@ -719,16 +696,16 @@ GLOBAL_LIST_EMPTY(flamer_particles)
var/direction_angle = dir2angle(direction)
var/obj/flamer_fire/foundflame = locate() in target
if(!foundflame)
- var/datum/reagent/R = new()
- R.intensityfire = burn_lvl
- R.durationfire = fire_lvl
- R.burn_sprite = burn_sprite
- R.burncolor = f_color
- new/obj/flamer_fire(target, cause_data, R)
+ var/datum/reagent/fire_reag = new()
+ fire_reag.intensityfire = burn_lvl
+ fire_reag.durationfire = fire_lvl
+ fire_reag.burn_sprite = burn_sprite
+ fire_reag.burncolor = f_color
+ new/obj/flamer_fire(target, cause_data, fire_reag)
if(target.density)
return
- for(var/spread_direction in alldirs)
+ for(var/spread_direction in GLOB.alldirs)
var/spread_power = remaining_distance
@@ -737,11 +714,9 @@ GLOBAL_LIST_EMPTY(flamer_particles)
var/angle = 180 - abs( abs( direction_angle - spread_direction_angle ) - 180 ) // the angle difference between the spread direction and initial direction
switch(angle) //this reduces power when the explosion is going around corners
- if (0)
- //no change
if (45)
spread_power *= 0.75
- else //turns out angles greater than 90 degrees almost never happen. This bit also prevents trying to spread backwards
+ if (90 to 180) //turns out angles greater than 90 degrees almost never happen. This bit also prevents trying to spread backwards
continue
switch(spread_direction)
@@ -753,33 +728,41 @@ GLOBAL_LIST_EMPTY(flamer_particles)
if (spread_power < 1)
continue
- var/turf/T = get_step(target, spread_direction)
+ var/turf/picked_turf = get_step(target, spread_direction)
- if(!T) //prevents trying to spread into "null" (edge of the map?)
+ if(!picked_turf) //prevents trying to spread into "null" (edge of the map?)
continue
- if(aerial_flame_level && (T.get_pylon_protection_level() >= aerial_flame_level))
- break
+ if(aerial_flame_level)
+ if(picked_turf.get_pylon_protection_level() >= aerial_flame_level)
+ break
+ var/area/picked_area = get_area(picked_turf)
+ if(CEILING_IS_PROTECTED(picked_area?.ceiling, get_ceiling_protection_level(aerial_flame_level)))
+ break
spawn(0)
- fire_spread_recur(T, cause_data, spread_power, spread_direction, fire_lvl, burn_lvl, f_color, burn_sprite, aerial_flame_level)
+ fire_spread_recur(picked_turf, cause_data, spread_power, spread_direction, fire_lvl, burn_lvl, f_color, burn_sprite, aerial_flame_level)
/proc/fire_spread(turf/target, datum/cause_data/cause_data, range, fire_lvl, burn_lvl, f_color, burn_sprite = "dynamic", aerial_flame_level = TURF_PROTECTION_NONE)
- var/datum/reagent/R = new()
- R.intensityfire = burn_lvl
- R.durationfire = fire_lvl
- R.burn_sprite = burn_sprite
- R.burncolor = f_color
-
- new/obj/flamer_fire(target, cause_data, R)
- for(var/direction in alldirs)
+ var/datum/reagent/fire_reag = new()
+ fire_reag.intensityfire = burn_lvl
+ fire_reag.durationfire = fire_lvl
+ fire_reag.burn_sprite = burn_sprite
+ fire_reag.burncolor = f_color
+
+ new/obj/flamer_fire(target, cause_data, fire_reag)
+ for(var/direction in GLOB.alldirs)
var/spread_power = range
switch(direction)
if(NORTH,SOUTH,EAST,WEST)
spread_power--
else
spread_power -= 1.414 //diagonal spreading
- var/turf/T = get_step(target, direction)
- if(aerial_flame_level && (T.get_pylon_protection_level() >= aerial_flame_level))
- continue
- fire_spread_recur(T, cause_data, spread_power, direction, fire_lvl, burn_lvl, f_color, burn_sprite, aerial_flame_level)
+ var/turf/picked_turf = get_step(target, direction)
+ if(aerial_flame_level)
+ if(picked_turf.get_pylon_protection_level() >= aerial_flame_level)
+ continue
+ var/area/picked_area = get_area(picked_turf)
+ if(CEILING_IS_PROTECTED(picked_area?.ceiling, get_ceiling_protection_level(aerial_flame_level)))
+ continue
+ fire_spread_recur(picked_turf, cause_data, spread_power, direction, fire_lvl, burn_lvl, f_color, burn_sprite, aerial_flame_level)
diff --git a/code/modules/projectiles/guns/flamer/flameshape.dm b/code/modules/projectiles/guns/flamer/flameshape.dm
index f5a0699067e4..ae6c2dec0a67 100644
--- a/code/modules/projectiles/guns/flamer/flameshape.dm
+++ b/code/modules/projectiles/guns/flamer/flameshape.dm
@@ -28,7 +28,7 @@
/datum/flameshape/default/handle_fire_spread(obj/flamer_fire/F, fire_spread_amount, burn_dam, fuel_pressure = 1)
var/turf/T
var/turf/source_turf = get_turf(F.loc)
- for(var/dirn in cardinal)
+ for(var/dirn in GLOB.cardinals)
T = get_step(source_turf, dirn)
if(istype(T, /turf/open/space))
continue
@@ -64,7 +64,7 @@
id = FLAMESHAPE_STAR
/datum/flameshape/star/proc/dirs_to_use()
- return alldirs
+ return GLOB.alldirs
/datum/flameshape/star/handle_fire_spread(obj/flamer_fire/F, fire_spread_amount, burn_dam, fuel_pressure = 1)
fire_spread_amount = Floor(fire_spread_amount * 1.5) // branch 'length'
@@ -102,9 +102,9 @@
/datum/flameshape/star/minor/dirs_to_use()
if(prob(50))
- return cardinal
+ return GLOB.cardinals
else
- return diagonals
+ return GLOB.diagonals
/datum/flameshape/line
name = "Line"
diff --git a/code/modules/projectiles/guns/lever_action.dm b/code/modules/projectiles/guns/lever_action.dm
index 81d7dc166cd3..849844f4f044 100644
--- a/code/modules/projectiles/guns/lever_action.dm
+++ b/code/modules/projectiles/guns/lever_action.dm
@@ -373,6 +373,7 @@ their unique feature is that a direct hit will buff your damage and firerate
hit_buff_reset_cooldown = 2 SECONDS //how much time after a direct hit until streaks reset
var/floating_penetration = FLOATING_PENETRATION_TIER_0 //holder var
var/floating_penetration_upper_limit = FLOATING_PENETRATION_TIER_4
+ var/direct_hit_sound = 'sound/weapons/gun_xm88_directhit_low.ogg'
attachable_allowed = list(
/obj/item/attachable/bayonet/upp, // Barrel
/obj/item/attachable/bayonet,
@@ -405,9 +406,9 @@ their unique feature is that a direct hit will buff your damage and firerate
/obj/item/weapon/gun/lever_action/xm88/wield(mob/user)
. = ..()
-
- RegisterSignal(src, COMSIG_ITEM_ZOOM, PROC_REF(scope_on))
- RegisterSignal(src, COMSIG_ITEM_UNZOOM, PROC_REF(scope_off))
+ if(.)
+ RegisterSignal(src, COMSIG_ITEM_ZOOM, PROC_REF(scope_on))
+ RegisterSignal(src, COMSIG_ITEM_UNZOOM, PROC_REF(scope_off))
/obj/item/weapon/gun/lever_action/xm88/proc/scope_on(atom/source, mob/current_user)
SIGNAL_HANDLER
@@ -499,12 +500,16 @@ their unique feature is that a direct hit will buff your damage and firerate
switch(floating_penetration)
if(FLOATING_PENETRATION_TIER_1)
P.ammo = GLOB.ammo_list[/datum/ammo/bullet/lever_action/xm88/pen20]
+ direct_hit_sound = "sound/weapons/gun_xm88_directhit_low.ogg"
if(FLOATING_PENETRATION_TIER_2)
P.ammo = GLOB.ammo_list[/datum/ammo/bullet/lever_action/xm88/pen30]
+ direct_hit_sound = "sound/weapons/gun_xm88_directhit_medium.ogg"
if(FLOATING_PENETRATION_TIER_3)
P.ammo = GLOB.ammo_list[/datum/ammo/bullet/lever_action/xm88/pen40]
+ direct_hit_sound = "sound/weapons/gun_xm88_directhit_medium.ogg"
if(FLOATING_PENETRATION_TIER_4)
P.ammo = GLOB.ammo_list[/datum/ammo/bullet/lever_action/xm88/pen50]
+ direct_hit_sound = "sound/weapons/gun_xm88_directhit_high.ogg"
return ..()
/obj/item/weapon/gun/lever_action/xm88/unload(mob/user)
@@ -524,6 +529,7 @@ their unique feature is that a direct hit will buff your damage and firerate
lever_message = initial(lever_message)
wield_delay = initial(wield_delay)
cur_onehand_chance = initial(cur_onehand_chance)
+ direct_hit_sound = "sound/weapons/gun_xm88_directhit_low.ogg"
if(in_chamber)
var/obj/projectile/P = in_chamber
P.ammo = GLOB.ammo_list[/datum/ammo/bullet/lever_action/xm88]
@@ -536,6 +542,10 @@ their unique feature is that a direct hit will buff your damage and firerate
if(one_hand_lever)
addtimer(VARSET_CALLBACK(src, cur_onehand_chance, reset_onehand_chance), 4 SECONDS, TIMER_OVERRIDE|TIMER_UNIQUE)
+/obj/item/weapon/gun/lever_action/xm88/direct_hit_buff(mob/user, mob/target, one_hand_lever = FALSE)
+ . = ..()
+ playsound(target, direct_hit_sound, 75)
+
#undef FLOATING_PENETRATION_TIER_0
#undef FLOATING_PENETRATION_TIER_1
#undef FLOATING_PENETRATION_TIER_2
diff --git a/code/modules/projectiles/guns/rifles.dm b/code/modules/projectiles/guns/rifles.dm
index 65e4a6f2b7b3..1ee8aa189ed3 100644
--- a/code/modules/projectiles/guns/rifles.dm
+++ b/code/modules/projectiles/guns/rifles.dm
@@ -357,6 +357,8 @@
burst_scatter_mult = SCATTER_AMOUNT_TIER_10
scatter_unwielded = SCATTER_AMOUNT_TIER_4
+/obj/item/weapon/gun/rifle/m41a/elite/xm40/ap
+ current_mag = /obj/item/ammo_magazine/rifle/xm40
//-------------------------------------------------------
//M41A TRUE AND ORIGINAL
diff --git a/code/modules/projectiles/guns/shotguns.dm b/code/modules/projectiles/guns/shotguns.dm
index 9a4b1551736c..c3b4906c1b29 100644
--- a/code/modules/projectiles/guns/shotguns.dm
+++ b/code/modules/projectiles/guns/shotguns.dm
@@ -266,14 +266,18 @@ can cause issues with ammo types getting mixed up during the burst.
/obj/item/weapon/gun/shotgun/combat/handle_starting_attachment()
..()
- var/obj/item/attachable/attached_gun/grenade/G = new(src)
- G.flags_attach_features &= ~ATTACH_REMOVABLE
- G.hidden = TRUE
- G.Attach(src)
- update_attachable(G.slot)
+ var/obj/item/attachable/attached_gun/grenade/ugl = new(src)
+ var/obj/item/attachable/stock/tactical/stock = new(src)
+ ugl.flags_attach_features &= ~ATTACH_REMOVABLE
+ ugl.hidden = TRUE
+ ugl.Attach(src)
+ update_attachable(ugl.slot)
+ stock.hidden = FALSE
+ stock.Attach(src)
+ update_attachable(stock.slot)
/obj/item/weapon/gun/shotgun/combat/set_gun_attachment_offsets()
- attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 19,"rail_x" = 10, "rail_y" = 21, "under_x" = 14, "under_y" = 16, "stock_x" = 14, "stock_y" = 16)
+ attachable_offset = list("muzzle_x" = 33, "muzzle_y" = 19,"rail_x" = 10, "rail_y" = 21, "under_x" = 14, "under_y" = 16, "stock_x" = 11, "stock_y" = 13.)
@@ -1274,7 +1278,7 @@ can cause issues with ammo types getting mixed up during the burst.
/obj/item/weapon/gun/shotgun/pump/dual_tube/cmb/m3717
name = "\improper M37-17 pump shotgun"
- desc = "A military version of the iconic HG 37-12, this design can fit one extra shell in each of its dual-tube internal magazines, and fires shells with increased velocity, resulting in more damage. Issued to select USCM vessels out on the rim. You can switch the active internal magazine by toggling the shotgun tube."
+ desc = "A military version of the iconic HG 37-12, this design can fit one extra shell in each of its dual-tube internal magazines, and fires shells with increased velocity, resulting in more damage. Issued to select USCM vessels and stations in the outer veil. A button on the side toggles the internal tubes."
icon = 'icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi'
icon_state = "m3717"
item_state = "m3717"
diff --git a/code/modules/projectiles/guns/smartgun.dm b/code/modules/projectiles/guns/smartgun.dm
index 22f10cafb35b..8ac629310132 100644
--- a/code/modules/projectiles/guns/smartgun.dm
+++ b/code/modules/projectiles/guns/smartgun.dm
@@ -144,7 +144,8 @@
/obj/item/weapon/gun/smartgun/attackby(obj/item/attacking_object, mob/user)
if(istype(attacking_object, /obj/item/smartgun_battery))
var/obj/item/smartgun_battery/new_cell = attacking_object
- visible_message("[user] swaps out the power cell in the [src].","You swap out the power cell in the [src] and drop the old one.")
+ visible_message(SPAN_NOTICE("[user] swaps out the power cell in [src]."),
+ SPAN_NOTICE("You swap out the power cell in [src] and drop the old one."))
to_chat(user, SPAN_NOTICE("The new cell contains: [new_cell.power_cell.charge] power."))
battery.update_icon()
battery.forceMove(get_turf(user))
diff --git a/code/modules/projectiles/guns/smgs.dm b/code/modules/projectiles/guns/smgs.dm
index 89e6594c64e7..24eddf31597d 100644
--- a/code/modules/projectiles/guns/smgs.dm
+++ b/code/modules/projectiles/guns/smgs.dm
@@ -11,7 +11,7 @@
aim_slowdown = SLOWDOWN_ADS_QUICK
wield_delay = WIELD_DELAY_VERY_FAST
attachable_allowed = list(
- /obj/item/attachable/suppressor,
+ /obj/item/attachable/suppressor,
/obj/item/attachable/reddot,
/obj/item/attachable/reflex,
/obj/item/attachable/flashlight,
@@ -50,7 +50,8 @@
/obj/item/attachable/suppressor,
/obj/item/attachable/reddot,
/obj/item/attachable/reflex,
- /obj/item/attachable/angledgrip,
+ /obj/item/attachable/angledgrip,
+ /obj/item/attachable/verticalgrip,
/obj/item/attachable/flashlight/grip,
/obj/item/attachable/stock/smg,
/obj/item/attachable/stock/smg/collapsible,
diff --git a/code/modules/projectiles/guns/souto.dm b/code/modules/projectiles/guns/souto.dm
index 6f45f57e1d61..1e9669dd0b7b 100644
--- a/code/modules/projectiles/guns/souto.dm
+++ b/code/modules/projectiles/guns/souto.dm
@@ -39,11 +39,11 @@
return ..()
/obj/item/weapon/gun/souto/reload(mob/user, obj/item/ammo_magazine/magazine)
- to_chat(user, SPAN_WARNING("The [src] feed system cannot be reloaded manually."))
+ to_chat(user, SPAN_WARNING("[src]'s feed system cannot be reloaded manually."))
return
/obj/item/weapon/gun/souto/unload(mob/user, reload_override = 0, drop_override = 0, loc_override = 0)
- to_chat(user, SPAN_WARNING("You cannot unload the [src]."))
+ to_chat(user, SPAN_WARNING("You cannot unload [src]."))
return
/obj/item/weapon/gun/souto/able_to_fire(mob/user)
diff --git a/code/modules/projectiles/guns/specialist/launcher/rocket_launcher.dm b/code/modules/projectiles/guns/specialist/launcher/rocket_launcher.dm
index 6d998002134c..356d0e6c3b48 100644
--- a/code/modules/projectiles/guns/specialist/launcher/rocket_launcher.dm
+++ b/code/modules/projectiles/guns/specialist/launcher/rocket_launcher.dm
@@ -190,7 +190,7 @@
smoke.start()
playsound(src, 'sound/weapons/gun_rocketlauncher.ogg', 100, TRUE, 10)
for(var/mob/living/carbon/C in backblast_loc)
- if(!C.lying && !HAS_TRAIT(C, TRAIT_EAR_PROTECTION)) //Have to be standing up to get the fun stuff
+ if(C.body_position == STANDING_UP && !HAS_TRAIT(C, TRAIT_EAR_PROTECTION)) //Have to be standing up to get the fun stuff
C.apply_damage(15, BRUTE) //The shockwave hurts, quite a bit. It can knock unarmored targets unconscious in real life
C.apply_effect(4, STUN) //For good measure
C.apply_effect(6, STUTTER)
@@ -362,7 +362,7 @@
smoke.start()
playsound(src, 'sound/weapons/gun_rocketlauncher.ogg', 100, TRUE, 10)
for(var/mob/living/carbon/C in backblast_loc)
- if(!C.lying && !HAS_TRAIT(C, TRAIT_EAR_PROTECTION)) //Have to be standing up to get the fun stuff
+ if(C.body_position == STANDING_UP && !HAS_TRAIT(C, TRAIT_EAR_PROTECTION)) //Have to be standing up to get the fun stuff
C.apply_damage(15, BRUTE) //The shockwave hurts, quite a bit. It can knock unarmored targets unconscious in real life
C.apply_effect(4, STUN) //For good measure
C.apply_effect(6, STUTTER)
diff --git a/code/modules/projectiles/guns/specialist/sniper.dm b/code/modules/projectiles/guns/specialist/sniper.dm
index 17a2c0f26887..673de1a59602 100644
--- a/code/modules/projectiles/guns/specialist/sniper.dm
+++ b/code/modules/projectiles/guns/specialist/sniper.dm
@@ -75,7 +75,7 @@
/datum/action/item_action/specialist/aimed_shot/can_use_action()
var/mob/living/carbon/human/H = owner
- if(istype(H) && !H.is_mob_incapacitated() && !H.lying && (holder_item == H.r_hand || holder_item || H.l_hand))
+ if(istype(H) && !H.is_mob_incapacitated() && (holder_item == H.r_hand || holder_item || H.l_hand))
return TRUE
/datum/action/item_action/specialist/aimed_shot/proc/use_ability(atom/A)
@@ -154,7 +154,7 @@
target.overlays -= lockon_direction_icon
qdel(laser_beam)
- if(!check_can_use(target, TRUE))
+ if(!check_can_use(target, TRUE) || target.is_dead())
return
var/obj/projectile/aimed_proj = sniper_rifle.in_chamber
@@ -337,12 +337,12 @@
damage_mult = BASE_BULLET_DAMAGE_MULT
recoil = RECOIL_AMOUNT_TIER_5
-/obj/item/weapon/gun/rifle/sniper/xm43e1
+/obj/item/weapon/gun/rifle/sniper/XM43E1
name = "\improper XM43E1 experimental anti-materiel rifle"
desc = "An experimental anti-materiel rifle produced by Armat Systems, recently reacquired from the deep storage of an abandoned prototyping facility. This one in particular is currently undergoing field testing. Chambered in 10x99mm Caseless."
icon = 'icons/obj/items/weapons/guns/guns_by_faction/uscm.dmi'
- icon_state = "xm42b"
- item_state = "xm42b"
+ icon_state = "xm43e1"
+ item_state = "xm43e1"
unacidable = TRUE
indestructible = 1
@@ -353,12 +353,12 @@
zoomdevicename = "scope"
attachable_allowed = list(/obj/item/attachable/bipod)
flags_gun_features = GUN_AUTO_EJECTOR|GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER
- starting_attachment_types = list(/obj/item/attachable/sniperbarrel)
+ starting_attachment_types = list(/obj/item/attachable/pmc_sniperbarrel)
sniper_beam_type = /obj/effect/ebeam/laser/intense
sniper_beam_icon = "laser_beam_intense"
sniper_lockon_icon = "sniper_lockon_intense"
-/obj/item/weapon/gun/rifle/sniper/XM42B/handle_starting_attachment()
+/obj/item/weapon/gun/rifle/sniper/XM43E1/handle_starting_attachment()
..()
var/obj/item/attachable/scope/variable_zoom/S = new(src)
S.icon_state = "pmcscope"
@@ -368,11 +368,11 @@
update_attachable(S.slot)
-/obj/item/weapon/gun/rifle/sniper/XM42B/set_gun_attachment_offsets()
+/obj/item/weapon/gun/rifle/sniper/XM43E1/set_gun_attachment_offsets()
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)
-/obj/item/weapon/gun/rifle/sniper/XM42B/set_gun_config_values()
+/obj/item/weapon/gun/rifle/sniper/XM43E1/set_gun_config_values()
..()
set_fire_delay(FIRE_DELAY_TIER_6 * 6 )//Big boy damage, but it takes a lot of time to fire a shot.
//Kaga: Adjusted from 56 (Tier 4, 7*8) -> 30 (Tier 6, 5*6) ticks. 95 really wasn't big-boy damage anymore, although I updated it to 125 to remain consistent with the other 10x99mm caliber weapon (M42C). Now takes only twice as long as the M42A.
@@ -382,7 +382,7 @@
damage_mult = BASE_BULLET_DAMAGE_MULT
recoil = RECOIL_AMOUNT_TIER_1
-/obj/item/weapon/gun/rifle/sniper/XM42B/set_bullet_traits()
+/obj/item/weapon/gun/rifle/sniper/XM43E1/set_bullet_traits()
LAZYADD(traits_to_give, list(
BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff),
BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_penetrating),
@@ -415,7 +415,7 @@
force = 17
zoomdevicename = "scope"
flags_gun_features = GUN_AUTO_EJECTOR|GUN_WY_RESTRICTED|GUN_SPECIALIST|GUN_WIELDED_FIRING_ONLY|GUN_AMMO_COUNTER
- starting_attachment_types = list(/obj/item/attachable/sniperbarrel)
+ starting_attachment_types = list(/obj/item/attachable/pmc_sniperbarrel)
sniper_beam_type = /obj/effect/ebeam/laser/intense
sniper_beam_icon = "laser_beam_intense"
sniper_lockon_icon = "sniper_lockon_intense"
@@ -450,10 +450,11 @@
. = ..()
if(.)
var/mob/living/carbon/human/PMC_sniper = user
- if(PMC_sniper.lying == 0 && !istype(PMC_sniper.wear_suit,/obj/item/clothing/suit/storage/marine/smartgunner/veteran/pmc) && !istype(PMC_sniper.wear_suit,/obj/item/clothing/suit/storage/marine/veteran))
+ if(PMC_sniper.body_position == STANDING_UP && !istype(PMC_sniper.wear_suit,/obj/item/clothing/suit/storage/marine/smartgunner/veteran/pmc) && !istype(PMC_sniper.wear_suit,/obj/item/clothing/suit/storage/marine/veteran))
PMC_sniper.visible_message(SPAN_WARNING("[PMC_sniper] is blown backwards from the recoil of the [src.name]!"),SPAN_HIGHDANGER("You are knocked prone by the blowback!"))
step(PMC_sniper,turn(PMC_sniper.dir,180))
- PMC_sniper.apply_effect(5, WEAKEN)
+ PMC_sniper.KnockDown(5)
+ PMC_sniper.Stun(5)
//Type 88 //Based on the actual Dragunov DMR rifle.
diff --git a/code/modules/projectiles/magazines/shotguns.dm b/code/modules/projectiles/magazines/shotguns.dm
index 24e482549dac..6c103aaa9677 100644
--- a/code/modules/projectiles/magazines/shotguns.dm
+++ b/code/modules/projectiles/magazines/shotguns.dm
@@ -8,11 +8,11 @@ you're looking back on the different shotgun projectiles available. In short of
one type of shotgun ammo, but I think it helps in referencing it. ~N
*/
-var/list/shotgun_boxes_12g = list(
+GLOBAL_LIST_INIT(shotgun_boxes_12g, list(
/obj/item/ammo_magazine/shotgun/buckshot,
/obj/item/ammo_magazine/shotgun/flechette,
/obj/item/ammo_magazine/shotgun/slugs
- )
+ ))
/obj/item/ammo_magazine/shotgun
name = "box of shotgun slugs"
@@ -46,6 +46,14 @@ var/list/shotgun_boxes_12g = list(
default_ammo = /datum/ammo/bullet/shotgun/incendiary
handful_state = "incendiary_slug"
+/obj/item/ammo_magazine/shotgun/incendiarybuck
+ name = "box of incendiary buckshots"
+ desc = "A box filled with self-detonating buckshot incendiary shotgun rounds. 12 Gauge."
+ icon_state = "incendiarybuck"
+ item_state = "incendiarybuck"
+ default_ammo = /datum/ammo/bullet/shotgun/buckshot/incendiary
+ handful_state = "incen_buckshot"
+
/obj/item/ammo_magazine/shotgun/buckshot
name = "box of buckshot shells"
desc = "A box filled with buckshot spread shotgun shells. 12 Gauge."
@@ -151,21 +159,21 @@ also doesn't really matter. You can only reload them with handfuls.
Handfuls of shotgun rounds. For spawning directly on mobs in roundstart, ERTs, etc
*/
-var/list/shotgun_handfuls_8g = list(
+GLOBAL_LIST_INIT(shotgun_handfuls_8g, list(
/obj/item/ammo_magazine/handful/shotgun/heavy/slug,
/obj/item/ammo_magazine/handful/shotgun/heavy/buckshot,
/obj/item/ammo_magazine/handful/shotgun/heavy/flechette,
/obj/item/ammo_magazine/handful/shotgun/heavy/dragonsbreath
- )
+ ))
-var/list/shotgun_handfuls_12g = list(
+GLOBAL_LIST_INIT(shotgun_handfuls_12g, list(
/obj/item/ammo_magazine/handful/shotgun/slug,
/obj/item/ammo_magazine/handful/shotgun/buckshot,
/obj/item/ammo_magazine/handful/shotgun/flechette,
/obj/item/ammo_magazine/handful/shotgun/incendiary,
/obj/item/ammo_magazine/handful/shotgun/buckshot/incendiary,
/obj/item/ammo_magazine/handful/shotgun/beanbag
- )
+ ))
/obj/item/ammo_magazine/handful/shotgun
name = "handful of shotgun slugs (12g)"
diff --git a/code/modules/projectiles/magazines/specialist.dm b/code/modules/projectiles/magazines/specialist.dm
index 821273247f66..761e77305254 100644
--- a/code/modules/projectiles/magazines/specialist.dm
+++ b/code/modules/projectiles/magazines/specialist.dm
@@ -27,14 +27,14 @@
default_ammo = /datum/ammo/bullet/sniper/flak
ammo_band_color = AMMO_BAND_COLOR_IMPACT
-//M42B Magazine
+//XM43E1 Magazine
/obj/item/ammo_magazine/sniper/anti_materiel
- name = "\improper XM42B marksman magazine (10x99mm)"
+ name = "\improper XM43E1 marksman magazine (10x99mm)"
desc = "A magazine of caseless 10x99mm anti-materiel rounds."
max_rounds = 8
caliber = "10x99mm"
default_ammo = /datum/ammo/bullet/sniper/anti_materiel
- gun_type = /obj/item/weapon/gun/rifle/sniper/XM42B
+ gun_type = /obj/item/weapon/gun/rifle/sniper/XM43E1
//M42C magazine
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index b01203d0f4d8..ee9caa61d7a7 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -13,8 +13,9 @@
anchored = TRUE //You will not have me, space wind!
flags_atom = NOINTERACT //No real need for this, but whatever. Maybe this flag will do something useful in the future.
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- invisibility = 100 // 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.
+ alpha = 0 // We want this thing to be transparent when it drops on a turf because it will be on the user's turf. We then want to make it opaque as it travels.
layer = FLY_LAYER
+ animate_movement = NO_STEPS //disables gliding because it fights against what animate() is doing
var/datum/ammo/ammo //The ammo data which holds most of the actual info.
@@ -48,6 +49,13 @@
var/vis_travelled = 0
/// Origin point for tracing and visual updates
var/turf/vis_source
+ var/vis_source_pixel_x = 0
+ var/vis_source_pixel_y = 0
+
+ /// Starting point of projectile before each flight.
+ var/turf/process_start_turf
+ var/process_start_pixel_x = 0
+ var/process_start_pixel_y = 0
var/damage = 0
var/accuracy = 85 //Base projectile accuracy. Can maybe be later taken from the mob if desired.
@@ -88,7 +96,10 @@
starting = null
permutated = null
path = null
+ vis_source = null
+ process_start_turf = null
weapon_cause_data = null
+ bullet_traits = null
firer = null
QDEL_NULL(bound_beam)
SSprojectiles.stop_projectile(src)
@@ -193,10 +204,10 @@
setDir(get_dir(loc, target_turf))
var/ammo_flags = ammo.flags_ammo_behavior | projectile_override_flags
- if(round_statistics && ammo_flags & AMMO_BALLISTIC)
- round_statistics.total_projectiles_fired++
+ if(GLOB.round_statistics && ammo_flags & AMMO_BALLISTIC)
+ GLOB.round_statistics.total_projectiles_fired++
if(ammo.bonus_projectiles_amount)
- round_statistics.total_projectiles_fired += ammo.bonus_projectiles_amount
+ GLOB.round_statistics.total_projectiles_fired += ammo.bonus_projectiles_amount
if(firer && ismob(firer) && weapon_cause_data)
var/mob/M = firer
M.track_shot(weapon_cause_data.cause_name)
@@ -229,32 +240,24 @@
p_x = Clamp(p_x, -16, 16)
p_y = Clamp(p_y, -16, 16)
- if(source_turf != vis_source)
+ if(process_start_turf != vis_source)
vis_travelled = 0
- vis_source = source_turf
+ vis_source = process_start_turf || source_turf
+ vis_source_pixel_x = process_start_pixel_x
+ vis_source_pixel_y = process_start_pixel_y
- angle = 0 // Stolen from Get_Angle() basically
var/dx = p_x + aim_turf.x * 32 - source_turf.x * 32 // todo account for firer offsets
var/dy = p_y + aim_turf.y * 32 - source_turf.y * 32
- if(!dy)
- if(dx >= 0)
- angle = 90
- else
- angle = 280
- else
- angle = arctan(dx/dy)
- if(dy < 0)
- angle += 180
- else if(dx < 0)
- angle += 360
-
- var/matrix/rotate = matrix() //Change the bullet angle.
- rotate.Turn(angle)
- apply_transform(rotate)
+ angle = delta_to_angle(dx, dy)
/obj/projectile/process(delta_time)
. = PROC_RETURN_SLEEP
+ var/process_start_delta_time = delta_time //easier to take it unaltered than to recalculate it later
+ process_start_turf = get_turf(src) //obj-level vars so update_angle() can use it without passing it through a ton of procs
+ process_start_pixel_x = pixel_x
+ process_start_pixel_y = pixel_y
+
// Keep going as long as we got speed and time
while(speed > 0 && (speed * ((delta_time + time_carry)/10) >= 1))
time_carry -= 1/speed*10
@@ -266,8 +269,72 @@
return PROCESS_KILL
time_carry += delta_time
+
+ animate_flight(process_start_turf, process_start_pixel_x, process_start_pixel_y, process_start_delta_time)
+
return FALSE
+//#define LERP(a, b, t) (a + (b - a) * CLAMP01(t))
+#define LERP_UNCLAMPED(a, b, t) (a + (b - a) * t)
+
+/// Animates the projectile across the process'ed flight.
+/obj/projectile/proc/animate_flight(turf/start_turf, start_pixel_x, start_pixel_y, delta_time)
+ //Get pixelspace coordinates of start and end of visual path
+
+ var/pixel_x_source = vis_source.x * world.icon_size + vis_source_pixel_x
+ var/pixel_y_source = vis_source.y * world.icon_size + vis_source_pixel_y
+
+ var/turf/vis_target = path[path.len]
+ var/pixel_x_target = vis_target.x * world.icon_size + p_x
+ var/pixel_y_target = vis_target.y * world.icon_size + p_y
+
+ //Change the bullet angle to its visual path
+
+ var/vis_angle = delta_to_angle(pixel_x_target - pixel_x_source, pixel_y_target - pixel_y_source)
+ var/matrix/rotate = matrix()
+ rotate.Turn(vis_angle)
+ apply_transform(rotate)
+
+ //Determine apparent position along visual path, then lerp between start and end positions
+
+ var/vis_length = vis_travelled + path.len
+ var/vis_current = vis_travelled + speed * (time_carry * 0.1) //speed * (time_carry * 0.1) for remainder time movement, visually "catching up" to where it should be
+ var/vis_interpolant = vis_current / vis_length
+
+ var/pixel_x_lerped = LERP_UNCLAMPED(pixel_x_source, pixel_x_target, vis_interpolant)
+ var/pixel_y_lerped = LERP_UNCLAMPED(pixel_y_source, pixel_y_target, vis_interpolant)
+
+ //Convert pixelspace to pixel offset relative to current loc
+
+ var/turf/current_turf = get_turf(src)
+ var/pixel_x_rel_new = pixel_x_lerped - current_turf.x * world.icon_size
+ var/pixel_y_rel_new = pixel_y_lerped - current_turf.y * world.icon_size
+
+ //Set pixel offset as from current loc to old position, so it appears to start in the old position
+
+ pixel_x = (start_turf.x - current_turf.x) * world.icon_size + start_pixel_x
+ pixel_y = (start_turf.y - current_turf.y) * world.icon_size + start_pixel_y
+
+ //Determine apparent distance travelled, then lerp for projectile fade-in
+
+ var/dist_current = distance_travelled + speed * (time_carry * 0.1) //speed * (time_carry * 0.1) for remainder time fade-in
+ var/alpha_interpolant = dist_current - 1 //-1 so it transitions from transparent to opaque between dist 1-2
+ var/alpha_new = LERP_UNCLAMPED(0, 255, alpha_interpolant)
+
+ //Animate the visuals from starting position to new position
+
+ if(projectile_flags & PROJECTILE_SHRAPNEL) //there can be a LOT of shrapnel especially from a cluster OB, not important enough for the expense of an animate()
+ alpha = alpha_new
+ pixel_x = pixel_x_rel_new
+ pixel_y = pixel_y_rel_new
+ return
+
+ var/anim_time = delta_time * 0.1
+ animate(src, pixel_x = pixel_x_rel_new, pixel_y = pixel_y_rel_new, alpha = alpha_new, time = anim_time, flags = ANIMATION_END_NOW)
+
+//#undef LERP
+#undef LERP_UNCLAMPED
+
/// Flies the projectile forward one single turf
/obj/projectile/proc/fly()
SHOULD_NOT_SLEEP(TRUE)
@@ -294,8 +361,6 @@
forceMove(next_turf)
distance_travelled++
vis_travelled++
- if(distance_travelled > 1)
- invisibility = 0
// Check we're still flying - in the highly unlikely but apparently possible case
// we hit something through forceMove callbacks that we didn't pick up in scan_a_turf
@@ -320,20 +385,6 @@
p_y *= 2
retarget(aim_turf, keep_angle = TRUE)
- // Nowe we update visual offset by tracing the bullet predicted location against real one
- //
- // Travelled real distance so far
- var/dist = vis_travelled * 32 + speed * (time_carry*10)
- // Compute where we should be
- var/vis_x = vis_source.x * 32 + sin(angle) * dist
- var/vis_y = vis_source.y * 32 + cos(angle) * dist
- // Get the difference with where we actually are
- var/dx = vis_x - loc.x * 32
- var/dy = vis_y - loc.y * 32
- // Clamp and set this as pixel offsets
- pixel_x = Clamp(dx, -16, 16)
- pixel_y = Clamp(dy, -16, 16)
-
/obj/projectile/proc/retarget(atom/new_target, keep_angle = FALSE)
var/turf/current_turf = get_turf(src)
path = getline2(current_turf, new_target)
@@ -455,12 +506,31 @@
if(hit_chance) // Calculated from combination of both ammo accuracy and gun accuracy
var/hit_roll = rand(1,100)
+ var/direct_hit = FALSE
+
+ // Wasn't the clicked target
+ if(original != L)
+ def_zone = rand_zone()
+
+ // Xenos get a RNG limb miss chance regardless of being clicked target or not, see below
+ else if(isxeno(L) && hit_roll > hit_chance - 20)
+ def_zone = rand_zone()
- if(original != L || hit_roll > hit_chance-base_miss_chance[def_zone]-20) // If hit roll is high or the firer wasn't aiming at this mob, we still hit but now we might hit the wrong body part
+ // Other targets do the same roll with penalty - a near hit will hit but redirected to another limb
+ else if(!isxeno(L) && hit_roll > hit_chance - 20 - GLOB.base_miss_chance[def_zone])
def_zone = rand_zone()
+
else
+ direct_hit = TRUE
SEND_SIGNAL(firer, COMSIG_BULLET_DIRECT_HIT, L)
- hit_chance -= base_miss_chance[def_zone] // Reduce accuracy based on spot.
+
+ // At present, Xenos have no inherent effects or localized damage stemming from limb targeting
+ // Therefore we exempt the shooter from direct hit accuracy penalties as well,
+ // simply to avoid them from resetting target to chest every time they want to shoot a xeno
+
+ if(!direct_hit || !isxeno(L)) // For normal people or direct hits we apply the limb accuracy penalty
+ hit_chance -= GLOB.base_miss_chance[def_zone]
+ // else for direct hits on xenos, we skip it, pretending it's a chest shot with zero penalty
#if DEBUG_HIT_CHANCE
to_world(SPAN_DEBUG("([L]) Hit chance: [hit_chance] | Roll: [hit_roll]"))
@@ -498,7 +568,7 @@
X.behavior_delegate.on_hitby_projectile(ammo)
. = TRUE
- else if(!L.lying)
+ else if(L.body_position != LYING_DOWN)
animatation_displace_reset(L)
if(ammo.sound_miss) playsound_client(L.client, ammo.sound_miss, get_turf(L), 75, TRUE)
L.visible_message(SPAN_AVOIDHARM("[src] misses [L]!"),
@@ -747,8 +817,8 @@
//mobs use get_projectile_hit_chance instead of get_projectile_hit_boolean
/mob/living/proc/get_projectile_hit_chance(obj/projectile/P)
- if(lying && src != P.original)
- return FALSE
+ if((body_position == LYING_DOWN || HAS_TRAIT(src, TRAIT_NESTED)) && src != P.original)
+ return FALSE // Snowflake check for xeno nests, because we want bullets to fly through even though they're standing in it
var/ammo_flags = P.ammo.flags_ammo_behavior | P.projectile_override_flags
if(ammo_flags & AMMO_XENO)
if((status_flags & XENO_HOST) && HAS_TRAIT(src, TRAIT_NESTED))
@@ -756,7 +826,7 @@
. = P.get_effective_accuracy()
- if(lying && stat)
+ if(body_position == LYING_DOWN && stat)
. += 15 //Bonus hit against unconscious people.
if(isliving(P.firer))
@@ -1157,16 +1227,17 @@
return
if(COOLDOWN_FINISHED(src, shot_cooldown))
visible_message(SPAN_DANGER("[src] is hit by the [P.name] in the [parse_zone(P.def_zone)]!"), \
- SPAN_HIGHDANGER("You are hit by the [P.name] in the [parse_zone(P.def_zone)]!"), null, 4, CHAT_TYPE_TAKING_HIT)
+ SPAN_HIGHDANGER("[isxeno(src) ? "We" : "You"] are hit by the [P.name] in the [parse_zone(P.def_zone)]!"), null, 4, CHAT_TYPE_TAKING_HIT)
COOLDOWN_START(src, shot_cooldown, 1 SECONDS)
+
last_damage_data = P.weapon_cause_data
if(P.firer && ismob(P.firer))
var/mob/firingMob = P.firer
var/area/A = get_area(src)
if(ishuman(firingMob) && ishuman(src) && faction == firingMob.faction && !A?.statistic_exempt) //One human shot another, be worried about it but do everything basically the same //special_role should be null or an empty string if done correctly
if(!istype(P.ammo, /datum/ammo/energy/taser))
- round_statistics.total_friendly_fire_instances++
+ GLOB.round_statistics.total_friendly_fire_instances++
var/ff_msg = "[key_name(firingMob)] shot [key_name(src)] with \a [P.name] in [get_area(firingMob)] [ADMIN_JMP(firingMob)] [ADMIN_PM(firingMob)]"
var/ff_living = TRUE
if(src.stat == DEAD)
@@ -1184,7 +1255,7 @@
return
attack_log += "\[[time_stamp()]\] SOMETHING?? shot [key_name(src)] with a [P]"
- msg_admin_attack("SOMETHING?? shot [key_name(src)] with a [P] in [get_area(src)] ([loc.x],[loc.y],[loc.z]).", loc.x, loc.y, loc.z)
+ msg_admin_attack("SOMETHING?? shot [key_name(src)] with \a [P] in [get_area(src)] ([loc.x],[loc.y],[loc.z]).", loc.x, loc.y, loc.z)
//Abby -- Just check if they're 1 tile horizontal or vertical, no diagonals
/proc/get_adj_simple(atom/Loc1,atom/Loc2)
diff --git a/code/modules/reagents/Chemistry-Generator.dm b/code/modules/reagents/Chemistry-Generator.dm
index bb8f69b714b2..b2e6402d4b06 100644
--- a/code/modules/reagents/Chemistry-Generator.dm
+++ b/code/modules/reagents/Chemistry-Generator.dm
@@ -75,56 +75,56 @@
if(my_chemid) //Do we want a specific chem?
chem_id = my_chemid
else if(class) //do we want a specific class?
- chem_id = pick(chemical_gen_classes_list["C[class]"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C[class]"])
else
var/roll = rand(0,100)
switch(tier)
if(0)
- chem_id = pick(chemical_gen_classes_list["C"])//If tier is 0, we can add any classed chemical
+ chem_id = pick(GLOB.chemical_gen_classes_list["C"])//If tier is 0, we can add any classed chemical
if(1)
if(roll<=35)
- chem_id = pick(chemical_gen_classes_list["C1"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C1"])
else if(roll<=65)
- chem_id = pick(chemical_gen_classes_list["C2"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C2"])
else if(roll<=85)
- chem_id = pick(chemical_gen_classes_list["C3"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C3"])
else
- chem_id = pick(chemical_gen_classes_list["C4"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C4"])
if(2)
if(roll<=30)
- chem_id = pick(chemical_gen_classes_list["C1"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C1"])
else if(roll<=55)
- chem_id = pick(chemical_gen_classes_list["C2"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C2"])
else if(roll<=70)
- chem_id = pick(chemical_gen_classes_list["C3"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C3"])
else
- chem_id = pick(chemical_gen_classes_list["C4"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C4"])
if(3)
if(roll<=10)
- chem_id = pick(chemical_gen_classes_list["C1"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C1"])
else if(roll<=30)
- chem_id = pick(chemical_gen_classes_list["C2"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C2"])
else if(roll<=50)
- chem_id = pick(chemical_gen_classes_list["C3"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C3"])
else if(roll<=70)
- chem_id = pick(chemical_gen_classes_list["C4"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C4"])
else
- chem_id = pick(chemical_gen_classes_list["C5"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C5"])
else
if(!required_reagents || is_catalyst)//first component is more likely to be special in chems tier 4 or higher, catalysts are always special in tier 4 or higher
if (prob(50))
- chem_id = pick(chemical_gen_classes_list["C5"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C5"])
else
- chem_id = pick(chemical_gen_classes_list["C4"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C4"])
else if(roll<=15)
- chem_id = pick(chemical_gen_classes_list["C2"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C2"])
else if(roll<=40)
- chem_id = pick(chemical_gen_classes_list["C3"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C3"])
else if(roll<=65)
- chem_id = pick(chemical_gen_classes_list["C4"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C4"])
else
- chem_id = pick(chemical_gen_classes_list["C5"])
+ chem_id = pick(GLOB.chemical_gen_classes_list["C5"])
//if we are already using this reagent, try again
if(required_reagents && required_reagents.Find(chem_id))
@@ -169,7 +169,7 @@
while(!gen_name)
gen_name = addtext(pick(prefix),pick(wordroot),pick(suffix))
//Make sure this name is not already used
- for(var/datum/reagent/R in chemical_reagents_list)
+ for(var/datum/reagent/R in GLOB.chemical_reagents_list)
if(R.name == gen_name)//if we are already using this name, try again
gen_name = ""
//set name
@@ -249,58 +249,58 @@
var/property
var/roll = rand(1,100)
if(make_rare)
- property = pick(chemical_properties_list["rare"])
+ property = pick(GLOB.chemical_properties_list["rare"])
//Pick the property by value and roll
else if(value_offset > 0) //Balance the value of our chemical
- property = pick(chemical_properties_list["positive"])
+ property = pick(GLOB.chemical_properties_list["positive"])
else if(value_offset < 0)
if(roll <= gen_tier*10)
- property = pick(chemical_properties_list["negative"])
+ property = pick(GLOB.chemical_properties_list["negative"])
else
- property = pick(chemical_properties_list["neutral"])
+ property = pick(GLOB.chemical_properties_list["neutral"])
else
switch(gen_tier)
if(1)
if(roll<=20)
- property = pick(chemical_properties_list["negative"])
+ property = pick(GLOB.chemical_properties_list["negative"])
else if (roll<=50)
- property = pick(chemical_properties_list["neutral"])
+ property = pick(GLOB.chemical_properties_list["neutral"])
else
- property = pick(chemical_properties_list["positive"])
+ property = pick(GLOB.chemical_properties_list["positive"])
if(2)
if(roll<=25)
- property = pick(chemical_properties_list["negative"])
+ property = pick(GLOB.chemical_properties_list["negative"])
else if (roll<=45)
- property = pick(chemical_properties_list["neutral"])
+ property = pick(GLOB.chemical_properties_list["neutral"])
else
- property = pick(chemical_properties_list["positive"])
+ property = pick(GLOB.chemical_properties_list["positive"])
if(3)
if(roll<=15)
- property = pick(chemical_properties_list["negative"])
+ property = pick(GLOB.chemical_properties_list["negative"])
else if (roll<=40)
- property = pick(chemical_properties_list["neutral"])
+ property = pick(GLOB.chemical_properties_list["neutral"])
else
- property = pick(chemical_properties_list["positive"])
+ property = pick(GLOB.chemical_properties_list["positive"])
else
if(roll<=15)
- property = pick(chemical_properties_list["negative"])
+ property = pick(GLOB.chemical_properties_list["negative"])
else if (roll<=40)
- property = pick(chemical_properties_list["neutral"])
+ property = pick(GLOB.chemical_properties_list["neutral"])
else
- property = pick(chemical_properties_list["positive"])
+ property = pick(GLOB.chemical_properties_list["positive"])
if(track_added_properties) //Generated effects are more unique for lower-tier chemicals, but not higher-tier ones
var/property_checks = 0
while(!check_generated_properties(property) && property_checks < 4)
property_checks++
- if(LAZYISIN(chemical_properties_list["negative"], property))
- property = pick(chemical_properties_list["negative"])
- else if(LAZYISIN(chemical_properties_list["neutral"], property))
- property = pick(chemical_properties_list["neutral"])
+ if(LAZYISIN(GLOB.chemical_properties_list["negative"], property))
+ property = pick(GLOB.chemical_properties_list["negative"])
+ else if(LAZYISIN(GLOB.chemical_properties_list["neutral"], property))
+ property = pick(GLOB.chemical_properties_list["neutral"])
else
- property = pick(chemical_properties_list["positive"])
+ property = pick(GLOB.chemical_properties_list["positive"])
- var/datum/chem_property/P = chemical_properties_list[property]
+ var/datum/chem_property/P = GLOB.chemical_properties_list[property]
//Calculate what our chemical value is with our level
var/new_value
@@ -389,7 +389,7 @@
return FALSE
break
//Insert the property
- var/datum/chem_property/P = chemical_properties_list[property]
+ var/datum/chem_property/P = GLOB.chemical_properties_list[property]
P = new P.type()
P.level = level
P.holder = src
@@ -397,7 +397,7 @@
//Special case: If it's a catalyst property, add it nonetheless.
if(initial_property && initial_property != property)
- P = chemical_properties_list[initial_property]
+ P = GLOB.chemical_properties_list[initial_property]
if(P.category & PROPERTY_TYPE_CATALYST)
P = new P.type()
P.level = level
@@ -425,22 +425,22 @@
C.gen_tier = gen_tier
if(!C.generate_recipe(complexity))
return //Generating a recipe failed, so return null
- chemical_reactions_list[C.id] = C
+ GLOB.chemical_reactions_list[C.id] = C
C.add_to_filtered_list()
return C
//Returns false if a property has been generated in a previous reagent and all properties of that category haven't been generated yet.
/datum/reagent/proc/check_generated_properties(datum/chem_property/P)
- if(LAZYISIN(chemical_properties_list["positive"], P))
- if(LAZYISIN(GLOB.generated_properties["positive"], P) && LAZYLEN(GLOB.generated_properties["positive"]) < LAZYLEN(chemical_properties_list["positive"]))
+ if(LAZYISIN(GLOB.chemical_properties_list["positive"], P))
+ if(LAZYISIN(GLOB.generated_properties["positive"], P) && LAZYLEN(GLOB.generated_properties["positive"]) < LAZYLEN(GLOB.chemical_properties_list["positive"]))
return FALSE
GLOB.generated_properties["positive"] += P
- else if(LAZYISIN(chemical_properties_list["negative"], P))
- if(LAZYISIN(GLOB.generated_properties["negative"], P) && LAZYLEN(GLOB.generated_properties["negative"]) < LAZYLEN(chemical_properties_list["negative"]))
+ else if(LAZYISIN(GLOB.chemical_properties_list["negative"], P))
+ if(LAZYISIN(GLOB.generated_properties["negative"], P) && LAZYLEN(GLOB.generated_properties["negative"]) < LAZYLEN(GLOB.chemical_properties_list["negative"]))
return FALSE
GLOB.generated_properties["negative"] += P
- else if(LAZYISIN(chemical_properties_list["neutral"], P))
- if(LAZYISIN(GLOB.generated_properties["neutral"], P) && LAZYLEN(GLOB.generated_properties["neutral"]) < LAZYLEN(chemical_properties_list["neutral"]))
+ else if(LAZYISIN(GLOB.chemical_properties_list["neutral"], P))
+ if(LAZYISIN(GLOB.generated_properties["neutral"], P) && LAZYLEN(GLOB.generated_properties["neutral"]) < LAZYLEN(GLOB.chemical_properties_list["neutral"]))
return FALSE
GLOB.generated_properties["neutral"] += P
return TRUE
diff --git a/code/modules/reagents/Chemistry-Holder.dm b/code/modules/reagents/Chemistry-Holder.dm
index 643130559e94..dcb949424bdf 100644
--- a/code/modules/reagents/Chemistry-Holder.dm
+++ b/code/modules/reagents/Chemistry-Holder.dm
@@ -25,7 +25,7 @@
maximum_volume = maximum
#ifdef UNIT_TESTS
- if(!chemical_reagents_list || !chemical_reactions_filtered_list || !chemical_properties_list)
+ if(!GLOB.chemical_reagents_list || !GLOB.chemical_reactions_filtered_list || !GLOB.chemical_properties_list)
CRASH("Chemistry reagents are not set up!")
#endif
@@ -240,7 +240,7 @@
O.volume += R.volume
qdel(R)
break
- for(var/reaction in chemical_reactions_filtered_list[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id
+ for(var/reaction in GLOB.chemical_reactions_filtered_list[R.id]) // Was a big list but now it should be smaller since we filtered it with our reagent id
if(!reaction)
continue
@@ -417,10 +417,10 @@
handle_reactions()
return FALSE
- var/datum/reagent/D = chemical_reagents_list[reagent]
+ var/datum/reagent/D = GLOB.chemical_reagents_list[reagent]
if(D)
if(!istype(D, /datum/reagent))
- CRASH("Not REAGENT - [reagent] - chemical_reagents_list[reagent]")
+ CRASH("Not REAGENT - [reagent] - GLOB.chemical_reagents_list[reagent]")
var/datum/reagent/R = new D.type()
if(D.type == /datum/reagent/generated)
@@ -713,5 +713,6 @@
// Convenience proc to create a reagents holder for an atom
// Max vol is maximum volume of holder
/atom/proc/create_reagents(max_vol)
+ QDEL_NULL(reagents)
reagents = new/datum/reagents(max_vol)
reagents.my_atom = src
diff --git a/code/modules/reagents/Chemistry-Reactions.dm b/code/modules/reagents/Chemistry-Reactions.dm
index 1d9c03f9e923..7a8f0b21158a 100644
--- a/code/modules/reagents/Chemistry-Reactions.dm
+++ b/code/modules/reagents/Chemistry-Reactions.dm
@@ -22,15 +22,15 @@
/datum/chemical_reaction/proc/add_to_filtered_list(reset = FALSE)
if(reset)
- for(var/R in chemical_reactions_filtered_list)
- LAZYREMOVE(chemical_reactions_filtered_list[R], src)
+ for(var/R in GLOB.chemical_reactions_filtered_list)
+ LAZYREMOVE(GLOB.chemical_reactions_filtered_list[R], src)
for(var/R in required_reagents)
- LAZYADD(chemical_reactions_filtered_list[R], src)
+ LAZYADD(GLOB.chemical_reactions_filtered_list[R], src)
/datum/chemical_reaction/proc/check_duplicate()
for(var/R in required_reagents)
- if(chemical_reactions_filtered_list[R])
- for(var/reaction in chemical_reactions_filtered_list[R])//We filter the chemical_reactions_filtered_list so we don't have to search through as much
+ if(GLOB.chemical_reactions_filtered_list[R])
+ for(var/reaction in GLOB.chemical_reactions_filtered_list[R])//We filter the GLOB.chemical_reactions_filtered_list so we don't have to search through as much
var/datum/chemical_reaction/C = reaction
var/matches = 0
for(var/B in required_reagents)
@@ -43,7 +43,7 @@
// To prevent such a situation, if ALL reagent inside a reaction are medical chemicals, the recipe is considered flawed.
/datum/chemical_reaction/proc/check_reaction_uses_all_default_medical()
for(var/R in required_reagents)
- var/datum/reagent/M = chemical_reagents_list[R]
+ var/datum/reagent/M = GLOB.chemical_reagents_list[R]
if(!(initial(M.flags) & REAGENT_TYPE_MEDICAL))
return FALSE
return TRUE
diff --git a/code/modules/reagents/Chemistry-Reagents.dm b/code/modules/reagents/Chemistry-Reagents.dm
index 7f659c54c40d..4e3f3a91449d 100644
--- a/code/modules/reagents/Chemistry-Reagents.dm
+++ b/code/modules/reagents/Chemistry-Reagents.dm
@@ -152,6 +152,9 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
handle_processing(M, mods, delta_time)
holder.remove_reagent(id, custom_metabolism * delta_time)
+ if(!holder)
+ return FALSE
+
return TRUE
//Pre-processing
@@ -267,37 +270,37 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
if(chemclass && !(flags & REAGENT_NO_GENERATION))
switch(chemclass)
if(CHEM_CLASS_BASIC)
- chemical_gen_classes_list["C1"] += id
+ GLOB.chemical_gen_classes_list["C1"] += id
if(CHEM_CLASS_COMMON)
- chemical_gen_classes_list["C2"] += id
+ GLOB.chemical_gen_classes_list["C2"] += id
if(CHEM_CLASS_UNCOMMON)
- chemical_gen_classes_list["C3"] += id
+ GLOB.chemical_gen_classes_list["C3"] += id
if(CHEM_CLASS_RARE)
- chemical_gen_classes_list["C4"] += id
+ GLOB.chemical_gen_classes_list["C4"] += id
if(CHEM_CLASS_SPECIAL)
- chemical_gen_classes_list["C5"] += id
- chemical_data.add_chemical_objective(src)
+ GLOB.chemical_gen_classes_list["C5"] += id
+ GLOB.chemical_data.add_chemical_objective(src)
if(CHEM_CLASS_ULTRA)
- chemical_gen_classes_list["C6"] += id
- chemical_data.add_chemical_objective(src)
- chemical_gen_classes_list["C"] += id
+ GLOB.chemical_gen_classes_list["C6"] += id
+ GLOB.chemical_data.add_chemical_objective(src)
+ GLOB.chemical_gen_classes_list["C"] += id
if(gen_tier)
switch(gen_tier)
if(1)
- chemical_gen_classes_list["T1"] += id
+ GLOB.chemical_gen_classes_list["T1"] += id
if(2)
- chemical_gen_classes_list["T2"] += id
+ GLOB.chemical_gen_classes_list["T2"] += id
if(3)
- chemical_gen_classes_list["T3"] += id
+ GLOB.chemical_gen_classes_list["T3"] += id
if(4)
- chemical_gen_classes_list["T4"] += id
+ GLOB.chemical_gen_classes_list["T4"] += id
if(5)
- chemical_gen_classes_list["T5"] += id
+ GLOB.chemical_gen_classes_list["T5"] += id
/datum/reagent/proc/properties_to_datums()
#ifdef UNIT_TESTS
- if(!chemical_properties_list)
+ if(!GLOB.chemical_properties_list)
CRASH("Chemistry reagents are not set up!")
#endif
@@ -306,7 +309,7 @@ GLOBAL_LIST_INIT(name2reagent, build_name2reagent())
if(istype(prop, /datum/chem_property))
new_properties += prop
continue
- var/datum/chem_property/chem = chemical_properties_list[prop]
+ var/datum/chem_property/chem = GLOB.chemical_properties_list[prop]
if(chem)
chem = new chem.type()
chem.level = properties[prop]
diff --git a/code/modules/reagents/chemical_research/Chemical-Research.dm b/code/modules/reagents/chemical_research/Chemical-Research.dm
index 0b1152154dc3..e66cb474df50 100644
--- a/code/modules/reagents/chemical_research/Chemical-Research.dm
+++ b/code/modules/reagents/chemical_research/Chemical-Research.dm
@@ -1,4 +1,4 @@
-var/global/datum/chemical_data/chemical_data = new /datum/chemical_data
+GLOBAL_DATUM_INIT(chemical_data, /datum/chemical_data, new)
/datum/chemical_data
var/rsc_credits = 0
@@ -38,7 +38,7 @@ var/global/datum/chemical_data/chemical_data = new /datum/chemical_data
/datum/chemical_data/proc/get_report(doc_type, doc_title)
var/obj/item/paper/research_report/report = null
- for(var/document_data in chemical_data.research_documents[doc_type])
+ for(var/document_data in GLOB.chemical_data.research_documents[doc_type])
if(document_data["document_title"] == doc_title)
report = document_data["document"]
break
@@ -92,7 +92,7 @@ var/global/datum/chemical_data/chemical_data = new /datum/chemical_data
if(LAZYLEN(property_names))
has_new_properties = TRUE
for(var/name in property_names)
- var/datum/chem_property/ref = chemical_properties_list[name]
+ var/datum/chem_property/ref = GLOB.chemical_properties_list[name]
var/datum/chem_property/P = new ref.type
P.level = 0
research_property_data += P
@@ -146,7 +146,7 @@ var/global/datum/chemical_data/chemical_data = new /datum/chemical_data
chemical_not_completed_objective_list[chem.id] = chem.objective_value
/datum/chemical_data/proc/get_tgui_data(chemid)
- var/datum/reagent/chem = chemical_reagents_list[chemid]
+ var/datum/reagent/chem = GLOB.chemical_reagents_list[chemid]
if(!chem)
error("Invalid chemid [chemid]")
return
diff --git a/code/modules/reagents/chemical_research/generated_reagents.dm b/code/modules/reagents/chemical_research/generated_reagents.dm
index 6eaa664b6d7e..a21d74e26f8a 100644
--- a/code/modules/reagents/chemical_research/generated_reagents.dm
+++ b/code/modules/reagents/chemical_research/generated_reagents.dm
@@ -16,21 +16,21 @@
//Generate stats
if(!id) //So we can initiate a new datum without generating it
return
- if(!chemical_reagents_list[id])
+ if(!GLOB.chemical_reagents_list[id])
generate_name()
generate_stats()
- chemical_reagents_list[id] = src
- make_alike(chemical_reagents_list[id])
+ GLOB.chemical_reagents_list[id] = src
+ make_alike(GLOB.chemical_reagents_list[id])
recalculate_variables()
/datum/chemical_reaction/generated/New()
//Generate recipe
if(!id) //So we can initiate a new datum without generating it
return
- if(!chemical_reactions_list[id])
+ if(!GLOB.chemical_reactions_list[id])
generate_recipe()
- chemical_reactions_list[id] = src
- make_alike(chemical_reactions_list[id])
+ GLOB.chemical_reactions_list[id] = src
+ make_alike(GLOB.chemical_reactions_list[id])
/////////Tier 1
/datum/chemical_reaction/generated/alpha
diff --git a/code/modules/reagents/chemistry_machinery/acid_harness.dm b/code/modules/reagents/chemistry_machinery/acid_harness.dm
index ae54474c3aed..b349b3224d1a 100644
--- a/code/modules/reagents/chemistry_machinery/acid_harness.dm
+++ b/code/modules/reagents/chemistry_machinery/acid_harness.dm
@@ -443,10 +443,10 @@
else if(inject_conditions & ACID_SCAN_CONDITION_DEFIB && vitals_scan < ACID_VITALS_DEAD && last_vitals_scan & ACID_SCAN_CONDITION_DEATH)
condition_scan |= ACID_SCAN_CONDITION_DEFIB //If we were previously dead and are now alive, we assume we got defibbed
- if(inject_conditions & ACID_SCAN_CONDITION_CONCUSSION && (user.knocked_down || user.knocked_out))
+ if(inject_conditions & ACID_SCAN_CONDITION_CONCUSSION && (HAS_TRAIT(src, TRAIT_KNOCKEDOUT) || HAS_TRAIT(src, TRAIT_FLOORED)))
condition_scan |= ACID_SCAN_CONDITION_CONCUSSION
- if(inject_conditions & ACID_SCAN_CONDITION_INTOXICATION && (user.dazed || user.slowed || user.confused || user.drowsyness || user.dizziness || user.druggy))
+ if(inject_conditions & ACID_SCAN_CONDITION_INTOXICATION && (HAS_TRAIT(src, TRAIT_DAZED) || user.slowed || user.confused || user.drowsyness || user.dizziness || user.druggy))
condition_scan |= ACID_SCAN_CONDITION_INTOXICATION
//Compare
diff --git a/code/modules/reagents/chemistry_machinery/autodispenser.dm b/code/modules/reagents/chemistry_machinery/autodispenser.dm
index 3486e97524b8..eed96564da71 100644
--- a/code/modules/reagents/chemistry_machinery/autodispenser.dm
+++ b/code/modules/reagents/chemistry_machinery/autodispenser.dm
@@ -154,8 +154,7 @@
data["multiplier"] = multiplier
data["cycle_limit"] = cycle_limit
data["automode"] = automode
- data["linked_storage"] = linked_storage
- data["networked_storage"] = linked_storage.is_in_network()
+ data["networked_storage"] = linked_storage?.is_in_network()
data["smartlink"] = smartlink
data["outputmode"] = outputmode
data["buffervolume"] = reagents.total_volume
@@ -347,8 +346,7 @@
C.reagents.trans_to(container, amount)
//We don't care about keeping empty bottles stored
if(C.reagents.total_volume <= 0 && istypestrict(C,/obj/item/reagent_container/glass/bottle))
- linked_storage.item_quants[C.name]--
- qdel(C) //Might want to connect it to a disposal system later instead
+ linked_storage.delete_contents(C)
if(stage_missing)
amount = stage_missing
diff --git a/code/modules/reagents/chemistry_machinery/centrifuge.dm b/code/modules/reagents/chemistry_machinery/centrifuge.dm
index b21c52112d0f..6143313377a0 100644
--- a/code/modules/reagents/chemistry_machinery/centrifuge.dm
+++ b/code/modules/reagents/chemistry_machinery/centrifuge.dm
@@ -89,7 +89,7 @@
tgui_interact(user)
return
if(output_container)
- to_chat(user, SPAN_NOTICE("You remove the [output_container] from the [src]."))
+ to_chat(user, SPAN_NOTICE("You remove [output_container] from the [src]."))
user.put_in_active_hand(output_container)
output_container = null
if(input_container)
@@ -97,7 +97,7 @@
else
icon_state = "centrifuge_empty_open"
else if(input_container)
- to_chat(user, SPAN_NOTICE("You remove the [input_container] from the [src]."))
+ to_chat(user, SPAN_NOTICE("You remove [input_container] from the [src]."))
user.put_in_active_hand(input_container)
input_container = null
icon_state = "centrifuge_empty_open"
diff --git a/code/modules/reagents/chemistry_machinery/chem_dispenser.dm b/code/modules/reagents/chemistry_machinery/chem_dispenser.dm
index 6778bdd3c72b..85ed21543127 100644
--- a/code/modules/reagents/chemistry_machinery/chem_dispenser.dm
+++ b/code/modules/reagents/chemistry_machinery/chem_dispenser.dm
@@ -59,7 +59,7 @@
/obj/structure/machinery/chem_dispenser/process()
if(!chem_storage)
- chem_storage = chemical_data.connect_chem_storage(network)
+ chem_storage = GLOB.chemical_data.connect_chem_storage(network)
/obj/structure/machinery/chem_dispenser/Initialize()
. = ..()
@@ -68,7 +68,7 @@
/obj/structure/machinery/chem_dispenser/Destroy()
if(!chem_storage)
- chem_storage = chemical_data.disconnect_chem_storage(network)
+ chem_storage = GLOB.chemical_data.disconnect_chem_storage(network)
return ..()
/obj/structure/machinery/chem_dispenser/ex_act(severity)
@@ -155,7 +155,7 @@
var/list/chemicals = list()
for(var/re in dispensable_reagents)
- var/datum/reagent/temp = chemical_reagents_list[re]
+ var/datum/reagent/temp = GLOB.chemical_reagents_list[re]
if(temp)
var/chemname = temp.name
chemicals.Add(list(list("title" = chemname, "id" = temp.id)))
diff --git a/code/modules/reagents/chemistry_machinery/chem_master.dm b/code/modules/reagents/chemistry_machinery/chem_master.dm
index 9d2d1ff10a0c..1e7e3bb08384 100644
--- a/code/modules/reagents/chemistry_machinery/chem_master.dm
+++ b/code/modules/reagents/chemistry_machinery/chem_master.dm
@@ -237,8 +237,6 @@
while (count--)
var/obj/item/reagent_container/pill/P = new/obj/item/reagent_container/pill(loc)
P.pill_desc = "A custom pill."
- P.pixel_x = rand(-7, 7) //random position
- P.pixel_y = rand(-7, 7)
P.icon_state = "pill"+pillsprite
reagents.trans_to(P,amount_per_pill)
if(loaded_pill_bottle)
@@ -271,8 +269,6 @@
P.name = "[name] vial"
reagents.trans_to(P, 30)
- P.pixel_x = rand(-7, 7) //random position
- P.pixel_y = rand(-7, 7)
P.update_icon()
if(href_list["store"])
diff --git a/code/modules/reagents/chemistry_machinery/chem_simulator.dm b/code/modules/reagents/chemistry_machinery/chem_simulator.dm
index 2c8602b0dab7..8dc34f208549 100644
--- a/code/modules/reagents/chemistry_machinery/chem_simulator.dm
+++ b/code/modules/reagents/chemistry_machinery/chem_simulator.dm
@@ -13,7 +13,7 @@
#define SIMULATION_STAGE_BEGIN 6
/obj/structure/machinery/chem_simulator
- name = "Synthesis Simulator"
+ name = "synthesis simulator"
desc = "This computer uses advanced algorithms to perform simulations of reagent properties, for the purpose of calculating the synthesis required to make a new variant."
icon = 'icons/obj/structures/machinery/science_machines_64x32.dmi'
icon_state = "modifier"
@@ -62,7 +62,7 @@
..()
if(inoperable())
icon_state = "modifier_off"
- nanomanager.update_uis(src) // update all UIs attached to src
+ SSnano.nanomanager.update_uis(src) // update all UIs attached to src
/obj/structure/machinery/chem_simulator/attackby(obj/item/B, mob/living/user)
if(!skillcheck(user, SKILL_RESEARCH, SKILL_RESEARCH_TRAINED))
@@ -87,13 +87,13 @@
to_chat(user, SPAN_WARNING("Chemical data already inserted."))
return
else
- to_chat(user, SPAN_WARNING("The [src] refuses the [B]."))
+ to_chat(user, SPAN_WARNING("[src] refuses [B]."))
return
user.drop_inv_item_to_loc(B, src)
- to_chat(user, SPAN_NOTICE("You insert [B] into the [src]."))
+ to_chat(user, SPAN_NOTICE("You insert [B] into [src]."))
flick("[icon_state]_reading",src)
update_costs()
- nanomanager.update_uis(src) // update all UIs attached to src
+ SSnano.nanomanager.update_uis(src) // update all UIs attached to src
/obj/structure/machinery/chem_simulator/attack_hand(mob/user as mob)
if(inoperable())
@@ -105,7 +105,7 @@
/obj/structure/machinery/chem_simulator/ui_interact(mob/user, ui_key = "main", datum/nanoui/ui = null, force_open = 0)
var/list/data = list(
- "rsc_credits" = chemical_data.rsc_credits,
+ "rsc_credits" = GLOB.chemical_data.rsc_credits,
"target" = target,
"reference" = reference,
"mode" = mode,
@@ -122,7 +122,7 @@
if(simulating == SIMULATION_STAGE_FINAL)
for(var/reagent_id in recipe_targets)
- var/datum/reagent/R = chemical_reagents_list[reagent_id]
+ var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
var/list/id_name[0]
id_name["[R.id]"] = R.name
data["recipe_targets"] += id_name
@@ -134,7 +134,7 @@
//List of all available properties
data["property_data_list"] = list()
- for(var/datum/chem_property/P in chemical_data.research_property_data)
+ for(var/datum/chem_property/P in GLOB.chemical_data.research_property_data)
data["property_codings"][P.name] = P.code
if(template_filter && !check_bitflag(P.category, template_filter))
continue
@@ -182,7 +182,7 @@
else
data["reference_info"] = ""
- ui = nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
+ ui = SSnano.nanomanager.try_update_ui(user, src, ui_key, ui, data, force_open)
if(!ui)
ui = new(user, src, ui_key, "chem_simulator.tmpl", "Synthesis Simulator", 800, 550)
ui.set_initial_data(data)
@@ -198,7 +198,7 @@
if(user.stat || user.is_mob_restrained() || !in_range(src, user))
return
- if(mode == MODE_CREATE && chemical_data.has_new_properties)
+ if(mode == MODE_CREATE && GLOB.chemical_data.has_new_properties)
update_costs()
if(href_list["simulate"] && ready)
@@ -252,7 +252,7 @@
return
if(mode == MODE_CREATE)
var/target_name = href_list["set_target"]
- for(var/datum/chem_property/P in chemical_data.research_property_data)
+ for(var/datum/chem_property/P in GLOB.chemical_data.research_property_data)
if(P.name == target_name)
if(target_property && target_property.name == target_name)
//Toggle the property
@@ -294,15 +294,15 @@
newname = reject_bad_name(newname, TRUE, 20, FALSE)
if(isnull(newname))
to_chat(user, "Bad name.")
- else if(chemical_reagents_list[newname])
+ else if(GLOB.chemical_reagents_list[newname])
to_chat(user, "Name already taken.")
else
creation_name = newname
else if(href_list["set_level"] && target_property)
var/level_to_set = 1
- if(chemical_data.clearance_level <= 2)
+ if(GLOB.chemical_data.clearance_level <= 2)
level_to_set = tgui_input_list(usr, "Set target level for [target_property.name]:","[src]", list(1,2,3,4))
- else if(chemical_data.clearance_level <= 4)
+ else if(GLOB.chemical_data.clearance_level <= 4)
level_to_set = tgui_input_list(usr, "Set target level for [target_property.name]:","[src]", list(1,2,3,4,5,6,7,8))
else
level_to_set = tgui_input_list(usr, "Set target level for [target_property.name]:","[src]", list(1,2,3,4,5,6,7,8,9,10))
@@ -350,7 +350,7 @@
calculate_creation_cost()
ready = check_ready()
playsound(loc, pick('sound/machines/computer_typing1.ogg','sound/machines/computer_typing2.ogg','sound/machines/computer_typing3.ogg'), 5, 1)
- nanomanager.update_uis(src)
+ SSnano.nanomanager.update_uis(src)
/obj/structure/machinery/chem_simulator/process()
if(inoperable())
@@ -384,7 +384,7 @@
C.name = C.id
if(C.id in simulations)
//We've already simulated this before, so we don't need to continue
- C = chemical_reagents_list[C.id]
+ C = GLOB.chemical_reagents_list[C.id]
print(C.id)
status_bar = "SIMULATION COMPLETE"
simulating = SIMULATION_STAGE_OFF
@@ -398,13 +398,13 @@
else
ready = check_ready()
stop_processing()
- nanomanager.update_uis(src)
+ SSnano.nanomanager.update_uis(src)
/obj/structure/machinery/chem_simulator/proc/update_costs()
property_costs = list()
var/only_positive = TRUE
if(mode == MODE_CREATE)
- for(var/datum/chem_property/P in chemical_data.research_property_data)
+ for(var/datum/chem_property/P in GLOB.chemical_data.research_property_data)
property_costs[P.name] = max(abs(P.value), 1)
else if(target && target.data && target.completed)
for(var/datum/chem_property/P in target.data.properties)
@@ -431,7 +431,7 @@
if(only_positive)
for(var/P in property_costs)
property_costs[P] = property_costs[P] + 1
- chemical_data.has_new_properties = FALSE
+ GLOB.chemical_data.has_new_properties = FALSE
//Here the cost for creating a chemical is calculated. If you're looking to rebalance create mode, this is where you do it
/obj/structure/machinery/chem_simulator/proc/calculate_creation_cost()
@@ -468,7 +468,7 @@
new_od_level = max(new_od_level - 5, 5)
/obj/structure/machinery/chem_simulator/proc/prepare_recipe_options()
- var/datum/chemical_reaction/generated/O = chemical_reactions_list[target.data.id]
+ var/datum/chemical_reaction/generated/O = GLOB.chemical_reactions_list[target.data.id]
if(!O) //If it doesn't have a recipe, go immediately to finalizing, which will then generate a new associated recipe
return FALSE
recipe_targets = list() //reset
@@ -481,7 +481,7 @@
if(LAZYLEN(R.required_reagents) > 2)
LAZYREMOVE(R.required_reagents, pick(R.required_reagents))
var/new_component_id = R.add_component(tier = max(min(target.data.chemclass, CHEM_CLASS_COMMON), target.data.gen_tier, 1))
- var/datum/reagent/new_component = chemical_reagents_list[new_component_id]
+ var/datum/reagent/new_component = GLOB.chemical_reagents_list[new_component_id]
//Make sure we don't have an identical reaction and that the component is identified
if(R.check_duplicate() || R.check_reaction_uses_all_default_medical() || new_component.chemclass >= CHEM_CLASS_SPECIAL)
R.required_reagents = old_reaction.Copy()
@@ -512,27 +512,27 @@
status_bar = "TARGET CAN NOT BE ALTERED"
return FALSE
//Safety check in case of irregular papers
- var/datum/chemical_reaction/C = chemical_reactions_list[target.data.id]
+ var/datum/chemical_reaction/C = GLOB.chemical_reactions_list[target.data.id]
if(C)
for(var/component in C.required_reagents)
- var/datum/reagent/R = chemical_reagents_list[component]
- if(R && R.chemclass >= CHEM_CLASS_SPECIAL && !chemical_data.chemical_identified_list[R.id])
+ var/datum/reagent/R = GLOB.chemical_reagents_list[component]
+ if(R && R.chemclass >= CHEM_CLASS_SPECIAL && !GLOB.chemical_data.chemical_identified_list[R.id])
status_bar = "UNREGISTERED COMPONENTS DETECTED"
return FALSE
for(var/catalyst in C.required_catalysts)
- var/datum/reagent/R = chemical_reagents_list[catalyst]
- if(R && R.chemclass >= CHEM_CLASS_SPECIAL && !chemical_data.chemical_identified_list[R.id])
+ var/datum/reagent/R = GLOB.chemical_reagents_list[catalyst]
+ if(R && R.chemclass >= CHEM_CLASS_SPECIAL && !GLOB.chemical_data.chemical_identified_list[R.id])
status_bar = "UNREGISTERED CATALYSTS DETECTED"
return FALSE
if(target_property)
- if(property_costs[target_property.name] > chemical_data.rsc_credits)
+ if(property_costs[target_property.name] > GLOB.chemical_data.rsc_credits)
status_bar = "INSUFFICIENT FUNDS"
return FALSE
if(target_property.category & PROPERTY_TYPE_UNADJUSTABLE)
status_bar = "TARGET PROPERTY CAN NOT BE SIMULATED"
return FALSE
if(mode == MODE_AMPLIFY)
- if(target_property.level >= chemical_data.clearance_level*TECHTREE_LEVEL_MULTIPLIER + 2 && chemical_data.clearance_level < 5)
+ if(target_property.level >= GLOB.chemical_data.clearance_level*TECHTREE_LEVEL_MULTIPLIER + 2 && GLOB.chemical_data.clearance_level < 5)
status_bar = "CLEARANCE INSUFFICIENT FOR AMPLIFICATION"
return FALSE
if(target && length(target.data.properties) < 2)
@@ -560,7 +560,7 @@
if(LAZYLEN(creation_name) < 2)
status_bar = "NAME NOT SET"
return FALSE
- if(creation_cost > chemical_data.rsc_credits)
+ if(creation_cost > GLOB.chemical_data.rsc_credits)
status_bar = "INSUFFICIENT FUNDS"
return FALSE
else if(!target)
@@ -575,18 +575,18 @@
flick("[icon_state]_printing",src)
sleep(10)
var/obj/item/paper/research_report/report = new /obj/item/paper/research_report/(loc)
- var/datum/reagent/D = chemical_reagents_list[id]
+ var/datum/reagent/D = GLOB.chemical_reagents_list[id]
var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper)
report.name = "Simulation result for [D.name]"
report.info += "
Official Company Document Simulated Synthesis Report
Result for [D.name]
"
report.generate(D)
- report.info += " This report was automatically printed by the Synthesis Simulator. The [MAIN_SHIP_NAME], [time2text(world.timeofday, "MM/DD")]/[game_year], [worldtime2text()] \n"
+ report.info += " This report was automatically printed by the Synthesis Simulator. The [MAIN_SHIP_NAME], [time2text(world.timeofday, "MM/DD")]/[GLOB.game_year], [worldtime2text()] \n"
playsound(loc, 'sound/machines/twobeep.ogg', 15, 1)
if(is_new)
- chemical_data.save_document(report, "Synthesis Simulations", report.name)
+ GLOB.chemical_data.save_document(report, "Synthesis Simulations", report.name)
/obj/structure/machinery/chem_simulator/proc/encode_reagent(datum/reagent/C)
- var/datum/reagent/O = chemical_reagents_list[C.original_id] //So make the new name based on the Original
+ var/datum/reagent/O = GLOB.chemical_reagents_list[C.original_id] //So make the new name based on the Original
var/suffix = " "
for(var/datum/chem_property/P in C.properties)
suffix += P.code+"[P.level]"
@@ -661,7 +661,7 @@
R.gen_tier = C.gen_tier
if(mode != MODE_CREATE)
- assoc_R = chemical_reactions_list[target.data.id]
+ assoc_R = GLOB.chemical_reactions_list[target.data.id]
if(!assoc_R) //no associated recipe found
if(mode == MODE_CREATE)
assoc_R = C.generate_assoc_recipe(creation_complexity)
@@ -690,25 +690,25 @@
//Pay
if(mode == MODE_CREATE)
- chemical_data.update_credits(creation_cost * -1)
+ GLOB.chemical_data.update_credits(creation_cost * -1)
else
- chemical_data.update_credits(property_costs[target_property.name] * -1)
+ GLOB.chemical_data.update_credits(property_costs[target_property.name] * -1)
//Refund 1 credit if a rare or rarer target was added
- var/datum/reagent/component = chemical_reagents_list[recipe_target]
+ var/datum/reagent/component = GLOB.chemical_reagents_list[recipe_target]
if(component && component.chemclass >= CHEM_CLASS_RARE)
- chemical_data.update_credits(1)
+ GLOB.chemical_data.update_credits(1)
//Save the reagent
C.generate_description()
C.chemclass = CHEM_CLASS_RARE //So that we can always scan this in the future, don't generate defcon, and don't get a loop of making credits
- chemical_reagents_list[C.id] = C
+ GLOB.chemical_reagents_list[C.id] = C
LAZYADD(simulations, C.id) //Remember we've simulated this
//Save the reaction
R.id = C.id
R.result = C.id
- chemical_reactions_list[R.id] = R
+ GLOB.chemical_reactions_list[R.id] = R
R.add_to_filtered_list()
status_bar = "SIMULATION COMPLETE"
print(C.id, TRUE)
diff --git a/code/modules/reagents/chemistry_machinery/chem_storage.dm b/code/modules/reagents/chemistry_machinery/chem_storage.dm
index 3a05201dea25..692daef7864f 100644
--- a/code/modules/reagents/chemistry_machinery/chem_storage.dm
+++ b/code/modules/reagents/chemistry_machinery/chem_storage.dm
@@ -31,11 +31,11 @@
/obj/structure/machinery/chem_storage/Initialize()
. = ..()
- chemical_data.add_chem_storage(src)
+ GLOB.chemical_data.add_chem_storage(src)
start_processing()
/obj/structure/machinery/chem_storage/Destroy()
- chemical_data.remove_chem_storage(src)
+ GLOB.chemical_data.remove_chem_storage(src)
return ..()
/obj/structure/machinery/chem_storage/get_examine_text(mob/user)
diff --git a/code/modules/reagents/chemistry_machinery/pandemic.dm b/code/modules/reagents/chemistry_machinery/pandemic.dm
index aef4823effda..5cd7f6584705 100644
--- a/code/modules/reagents/chemistry_machinery/pandemic.dm
+++ b/code/modules/reagents/chemistry_machinery/pandemic.dm
@@ -59,10 +59,10 @@
if(B)
var/datum/disease/D = null
if(!vaccine_type)
- D = archive_diseases[path]
+ D = GLOB.archive_diseases[path]
vaccine_type = path
else
- if(vaccine_type in diseases)
+ if(vaccine_type in GLOB.diseases)
D = new vaccine_type(0, null)
if(D)
@@ -90,11 +90,11 @@
B.icon_state = "bottle3"
var/datum/disease/D = null
if(!virus_type)
- var/datum/disease/advance/A = archive_diseases[href_list["create_virus_culture"]]
+ var/datum/disease/advance/A = GLOB.archive_diseases[href_list["create_virus_culture"]]
if(A)
D = new A.type(0, A)
else
- if(virus_type in diseases) // Make sure this is a disease
+ if(virus_type in GLOB.diseases) // Make sure this is a disease
D = new virus_type(0, null)
var/list/data = list("viruses"=list(D))
var/name = strip_html(input(user,"Name:","Name the culture",D.name))
@@ -129,10 +129,10 @@
if(user.stat || user.is_mob_restrained()) return
if(!in_range(src, user)) return
var/id = href_list["name_disease"]
- if(archive_diseases[id])
- var/datum/disease/advance/A = archive_diseases[id]
+ if(GLOB.archive_diseases[id])
+ var/datum/disease/advance/A = GLOB.archive_diseases[id]
A.AssignName(new_name)
- for(var/datum/disease/advance/AD in active_diseases)
+ for(var/datum/disease/advance/AD in SSdisease.all_diseases)
AD.Refresh()
updateUsrDialog()
@@ -184,7 +184,7 @@
if(istype(D, /datum/disease/advance))
var/datum/disease/advance/A = D
- D = archive_diseases[A.GetDiseaseID()]
+ D = GLOB.archive_diseases[A.GetDiseaseID()]
disease_creation = A.GetDiseaseID()
if(D.name == "Unknown")
dat += "Name Disease "
@@ -216,7 +216,7 @@
var/disease_name = "Unknown"
if(!ispath(type))
- var/datum/disease/advance/A = archive_diseases[type]
+ var/datum/disease/advance/A = GLOB.archive_diseases[type]
if(A)
disease_name = A.name
else
diff --git a/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm b/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm
index dc1f72ec41c7..51db188826b8 100644
--- a/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm
+++ b/code/modules/reagents/chemistry_machinery/reagent_analyzer.dm
@@ -13,22 +13,25 @@
/obj/structure/machinery/reagent_analyzer/attackby(obj/item/B, mob/living/user)
if(processing)
- to_chat(user, SPAN_WARNING("The [src] is still processing!"))
+ to_chat(user, SPAN_WARNING("[src] is still processing!"))
return
if(!skillcheck(usr, SKILL_RESEARCH, SKILL_RESEARCH_TRAINED))
to_chat(user, SPAN_WARNING("You have no idea how to use this."))
return
if(istype(B, /obj/item/reagent_container/glass/beaker/vial))
if(sample || status)
- to_chat(user, SPAN_WARNING("Something is already loaded into the [src]."))
+ to_chat(user, SPAN_WARNING("Something is already loaded into [src]."))
return
if(user.drop_inv_item_to_loc(B, src))
sample = B
icon_state = "reagent_analyzer_sample"
- to_chat(user, SPAN_NOTICE("You insert [B] and start configuring the [src]."))
+ to_chat(user, SPAN_NOTICE("You insert [B] and start configuring [src]."))
updateUsrDialog()
if(!do_after(user, 1 SECONDS, INTERRUPT_ALL, BUSY_ICON_GENERIC))
return
+ if(!sample)
+ to_chat(user, SPAN_WARNING("Someone else removed the sample. Make up your mind!"))
+ return
processing = TRUE
if(sample.reagents.total_volume < 30 || sample.reagents.reagent_list.len > 1)
icon_state = "reagent_analyzer_error"
@@ -72,12 +75,12 @@
/obj/structure/machinery/reagent_analyzer/attack_hand(mob/user as mob)
if(processing)
- to_chat(user, SPAN_WARNING("The [src] is still processing!"))
+ to_chat(user, SPAN_WARNING("[src] is still processing!"))
return
if(!sample)
- to_chat(user, SPAN_WARNING("The [src] is empty."))
+ to_chat(user, SPAN_WARNING("[src] is empty."))
return
- to_chat(user, SPAN_NOTICE("You remove the [sample] from the [src]."))
+ to_chat(user, SPAN_NOTICE("You remove [sample] from [src]."))
user.put_in_active_hand(sample)
sample = null
icon_state = "reagent_analyzer"
@@ -89,27 +92,27 @@
var/datum/reagent/S = sample.reagents.reagent_list[1]
S.print_report(report = report, sample_number = sample_number)
sample.name = "vial ([S.name])"
- chemical_data.save_document(report, "XRF Scans", "[sample_number] - [report.name]")
+ GLOB.chemical_data.save_document(report, "XRF Scans", "[sample_number] - [report.name]")
if(S.chemclass < CHEM_CLASS_SPECIAL || (S.chemclass >= CHEM_CLASS_SPECIAL && report.completed))
- chemical_data.save_new_properties(S.properties)
- if(S.chemclass >= CHEM_CLASS_SPECIAL && !chemical_data.chemical_identified_list[S.id])
+ GLOB.chemical_data.save_new_properties(S.properties)
+ if(S.chemclass >= CHEM_CLASS_SPECIAL && !GLOB.chemical_data.chemical_identified_list[S.id])
if(last_used)
last_used.count_niche_stat(STATISTICS_NICHE_CHEMS)
var/datum/chem_property/P = S.get_property(PROPERTY_DNA_DISINTEGRATING)
if(P)
- if(chemical_data.clearance_level >= S.gen_tier)
+ if(GLOB.chemical_data.clearance_level >= S.gen_tier)
P.trigger()
else
return
- chemical_data.complete_chemical(S)
+ GLOB.chemical_data.complete_chemical(S)
else
var/datum/asset/asset = get_asset_datum(/datum/asset/simple/paper)
report.name = "Analysis of ERROR"
report.info += "
Official Weyland-Yutani Document Reagent Analysis Print
Analysis ERROR
"
report.info += "Result: Analysis failed for sample #[sample_number].
\n"
report.info += "Reason for error: [reason] \n"
- report.info += " This report was automatically printed by the A-XRF Scanner. The [MAIN_SHIP_NAME], [time2text(world.timeofday, "MM/DD")]/[game_year], [worldtime2text()] \n"
+ report.info += " This report was automatically printed by the A-XRF Scanner. The [MAIN_SHIP_NAME], [time2text(world.timeofday, "MM/DD")]/[GLOB.game_year], [worldtime2text()] \n"
/datum/reagent/proc/print_report(turf/loc, obj/item/paper/research_report/report, admin_spawned = FALSE, sample_number = 0)
if(!report)
diff --git a/code/modules/reagents/chemistry_properties/prop_neutral.dm b/code/modules/reagents/chemistry_properties/prop_neutral.dm
index d420623879ce..3048b12ee296 100644
--- a/code/modules/reagents/chemistry_properties/prop_neutral.dm
+++ b/code/modules/reagents/chemistry_properties/prop_neutral.dm
@@ -199,8 +199,8 @@
M.druggy = min(M.druggy + 0.5 * potency * delta_time, potency * 10)
/datum/chem_property/neutral/hallucinogenic/process_overdose(mob/living/M, potency = 1, delta_time)
- if(isturf(M.loc) && !istype(M.loc, /turf/open/space) && M.canmove && !M.is_mob_restrained())
- step(M, pick(cardinal))
+ if(isturf(M.loc) && !istype(M.loc, /turf/open/space) && (M.mobility_flags & MOBILITY_MOVE) && !M.is_mob_restrained())
+ step(M, pick(GLOB.cardinals))
M.hallucination += 10
M.make_jittery(5)
diff --git a/code/modules/reagents/chemistry_properties/prop_positive.dm b/code/modules/reagents/chemistry_properties/prop_positive.dm
index 7f476cecf2c5..a8a11fc299ad 100644
--- a/code/modules/reagents/chemistry_properties/prop_positive.dm
+++ b/code/modules/reagents/chemistry_properties/prop_positive.dm
@@ -455,7 +455,7 @@
if(prob(10 * delta_time))
to_chat(M, SPAN_WARNING("You feel like you have the worst brain freeze ever!"))
M.apply_effect(20, PARALYZE)
- M.stunned = max(M.stunned,21)
+ M.apply_effect(20, STUN)
/datum/chem_property/positive/neurocryogenic/process_overdose(mob/living/M, potency = 1, delta_time)
M.bodytemperature = max(M.bodytemperature - 2.5 * potency * delta_time,0)
@@ -548,7 +548,7 @@
rarity = PROPERTY_RARE
category = PROPERTY_TYPE_REACTANT
value = 3
- max_level = 1
+ COOLDOWN_DECLARE(ghost_notif)
/datum/chem_property/positive/defibrillating/on_delete(mob/living/M)
..()
@@ -574,19 +574,33 @@
/datum/chem_property/positive/defibrillating/process_dead(mob/living/M, potency = 1, delta_time)
if(!ishuman(M))
return
- var/mob/living/carbon/human/H = M
- H.apply_damage(-H.getOxyLoss(), OXY)
- if(H.check_tod() && H.is_revivable() && H.health > HEALTH_THRESHOLD_DEAD)
- to_chat(H, SPAN_NOTICE("You feel your heart struggling as you suddenly feel a spark, making it desperately try to continue pumping."))
- playsound_client(H.client, 'sound/effects/Heart Beat Short.ogg', 35)
- addtimer(CALLBACK(H, TYPE_PROC_REF(/mob/living/carbon/human, handle_revive)), 50, TIMER_UNIQUE)
- else if (potency > POTENCY_MAX_TIER_1 && H.check_tod() && H.is_revivable() && H.health < HEALTH_THRESHOLD_DEAD) //Will heal if level is 7 or greater
- to_chat(H, SPAN_NOTICE("You feel a faint spark in your chest."))
- H.apply_damage(-potency * POTENCY_MULTIPLIER_LOW, BRUTE)
- H.apply_damage(-potency * POTENCY_MULTIPLIER_LOW, BURN)
- H.apply_damage(-potency * POTENCY_MULTIPLIER_LOW, TOX)
- H.apply_damage(-potency * POTENCY_MULTIPLIER_LOW, CLONE)
- H.apply_damage(-H.getOxyLoss(), OXY)
+ var/mob/living/carbon/human/dead = M
+ var/revivable = dead.check_tod() && dead.is_revivable()
+ if(revivable && (dead.health > HEALTH_THRESHOLD_DEAD))
+ addtimer(CALLBACK(dead, TYPE_PROC_REF(/mob/living/carbon/human, handle_revive)), 5 SECONDS)
+ to_chat(dead, SPAN_NOTICE("You feel your heart struggling as you suddenly feel a spark, making it desperately try to continue pumping."))
+ playsound_client(dead.client, 'sound/effects/heart_beat_short.ogg', 35)
+ else if ((potency >= 1) && revivable && dead.health <= HEALTH_THRESHOLD_DEAD) //heals on all level above 1. This is however, minimal.
+ to_chat(dead, SPAN_NOTICE("You feel a faint spark in your chest."))
+ dead.apply_damage(-potency * POTENCY_MULTIPLIER_VLOW, BRUTE)
+ dead.apply_damage(-potency * POTENCY_MULTIPLIER_VLOW, BURN)
+ dead.apply_damage(-potency * POTENCY_MULTIPLIER_VLOW, TOX)
+ dead.apply_damage(-potency * POTENCY_MULTIPLIER_VLOW, CLONE)
+ dead.apply_damage(-dead.getOxyLoss(), OXY)
+ if(potency > CREATE_MAX_TIER_1) //heal more if higher levels
+ dead.apply_damage(-potency * POTENCY_MULTIPLIER_LOW, BRUTE)
+ dead.apply_damage(-potency * POTENCY_MULTIPLIER_LOW, BURN)
+ dead.apply_damage(-potency * POTENCY_MULTIPLIER_LOW, TOX)
+ dead.apply_damage(-potency * POTENCY_MULTIPLIER_LOW, CLONE)
+ if(dead.health < HEALTH_THRESHOLD_DEAD)
+ return
+ if(!COOLDOWN_FINISHED(src, ghost_notif))
+ return
+ var/mob/dead/observer/ghost = dead.get_ghost()
+ if(ghost?.client)
+ COOLDOWN_START(src, ghost_notif, 30 SECONDS)
+ playsound_client(ghost.client, 'sound/effects/adminhelp_new.ogg')
+ to_chat(ghost, SPAN_BOLDNOTICE("Your heart is struggling to pump! There is a chance you might get up!(Verbs -> Ghost -> Re-enter corpse, or click here!)"))
return TRUE
/datum/chem_property/positive/hyperdensificating
@@ -633,7 +647,7 @@
return
H.chem_effect_flags |= CHEM_EFFECT_RESIST_NEURO
to_chat(M, SPAN_NOTICE("Your skull feels incredibly thick."))
- M.dazed = 0
+ M.SetDaze(0)
/datum/chem_property/positive/neuroshielding/process_overdose(mob/living/M, potency = 1, delta_time)
if(!ishuman(M))
diff --git a/code/modules/reagents/chemistry_properties/prop_special.dm b/code/modules/reagents/chemistry_properties/prop_special.dm
index 640e18426311..52354f0d6b01 100644
--- a/code/modules/reagents/chemistry_properties/prop_special.dm
+++ b/code/modules/reagents/chemistry_properties/prop_special.dm
@@ -96,8 +96,8 @@
H.contract_disease(new /datum/disease/xeno_transformation(0),1) //This is the real reason PMCs are being sent to retrieve it.
/datum/chem_property/special/DNA_Disintegrating/trigger()
- SSticker.mode.get_specific_call("Weyland-Yutani Goon (Chemical Investigation Squad)", TRUE, FALSE, FALSE, holder.name, TRUE)
- chemical_data.update_credits(10)
+ SSticker.mode.get_specific_call("Weyland-Yutani Goon (Chemical Investigation Squad)", TRUE, FALSE, holder.name)
+ GLOB.chemical_data.update_credits(10)
message_admins("The research department has discovered DNA_Disintegrating in [holder.name] adding 10 bonus tech points.")
var/datum/techtree/tree = GET_TREE(TREE_MARINE)
tree.add_points(10)
diff --git a/code/modules/reagents/chemistry_reagents/drink.dm b/code/modules/reagents/chemistry_reagents/drink.dm
index 468243a0cc8d..3a49429d664e 100644
--- a/code/modules/reagents/chemistry_reagents/drink.dm
+++ b/code/modules/reagents/chemistry_reagents/drink.dm
@@ -85,13 +85,13 @@
/datum/reagent/drink/carrotjuice/on_mob_life(mob/living/M)
. = ..()
- if(!.) return
+ if(!.)
+ return
M.ReduceEyeBlur(1)
M.ReduceEyeBlind(1)
- if(!data) data = 1
+ if(!data)
+ data = 1
switch(data)
- if(1 to 20)
- //nothing
if(21 to INFINITY)
if(prob(data-10))
M.disabilities &= ~NEARSIGHTED
@@ -163,8 +163,10 @@
/datum/reagent/drink/milk/on_mob_life(mob/living/M)
. = ..()
- if(!.) return
- if(M.getBruteLoss() && prob(20)) M.heal_limb_damage(1,0)
+ if(!.)
+ return
+ if(M.getBruteLoss() && prob(20))
+ M.heal_limb_damage(1,0)
holder.remove_reagent("capsaicin", 10*REAGENTS_METABOLISM)
holder.remove_reagent("hotsauce", 10*REAGENTS_METABOLISM)
@@ -555,7 +557,7 @@
/datum/reagent/neurotoxin/on_mob_life(mob/living/carbon/M)
. = ..()
if(!.) return
- M.knocked_down = max(M.knocked_down, 3)
+ M.KnockDown(5)
if(!data) data = 1
data++
M.dizziness +=6
diff --git a/code/modules/reagents/chemistry_reagents/toxin.dm b/code/modules/reagents/chemistry_reagents/toxin.dm
index 458424a5db11..445918ef284d 100644
--- a/code/modules/reagents/chemistry_reagents/toxin.dm
+++ b/code/modules/reagents/chemistry_reagents/toxin.dm
@@ -113,8 +113,10 @@
if(!. || deleted)
return
M.status_flags |= FAKEDEATH
+ ADD_TRAIT(M, TRAIT_IMMOBILIZED, FAKEDEATH_TRAIT)
M.apply_damage(0.5*REM, OXY)
- M.apply_effect(2, WEAKEN)
+ M.KnockDown(2)
+ M.Stun(2)
M.silent = max(M.silent, 10)
/datum/reagent/toxin/zombiepowder/on_delete()
@@ -125,6 +127,7 @@
var/mob/living/holder_mob = .
holder_mob.status_flags &= ~FAKEDEATH
+ REMOVE_TRAIT(holder_mob, TRAIT_IMMOBILIZED, FAKEDEATH_TRAIT)
/datum/reagent/toxin/mindbreaker
name = "Mindbreaker Toxin"
@@ -279,4 +282,4 @@
color = "#669900"
reagent_state = LIQUID
chemclass = CHEM_CLASS_NONE
- properties = list(PROPERTY_CORROSIVE = 2, PROPERTY_TOXIC = 1)
+ properties = list(PROPERTY_CORROSIVE = 2, PROPERTY_TOXIC = 1, PROPERTY_CROSSMETABOLIZING = 3)
diff --git a/code/modules/recycling/conveyor2.dm b/code/modules/recycling/conveyor2.dm
index b4b4f68ed99d..4c60a9e345e0 100644
--- a/code/modules/recycling/conveyor2.dm
+++ b/code/modules/recycling/conveyor2.dm
@@ -112,7 +112,7 @@
// attack with hand, move pulled object onto conveyor
/obj/structure/machinery/conveyor/attack_hand(mob/user as mob)
- if ((!( user.canmove ) || user.is_mob_restrained() || !( user.pulling )))
+ if (( user.is_mob_incapacitated() || !( user.pulling )))
return
if (user.pulling.anchored)
return
@@ -197,7 +197,7 @@
/obj/structure/machinery/conveyor_switch/LateInitialize()
. = ..()
conveyors = list()
- for(var/obj/structure/machinery/conveyor/C in machines)
+ for(var/obj/structure/machinery/conveyor/C in GLOB.machines)
if(C.id == id)
conveyors += C
start_processing()
@@ -246,7 +246,7 @@
update()
// find any switches with same id as this one, and set their positions to match us
- for(var/obj/structure/machinery/conveyor_switch/S in machines)
+ for(var/obj/structure/machinery/conveyor_switch/S in GLOB.machines)
if(S.id == src.id)
S.position = position
S.update()
@@ -266,7 +266,7 @@
update()
// find any switches with same id as this one, and set their positions to match us
- for(var/obj/structure/machinery/conveyor_switch/S in machines)
+ for(var/obj/structure/machinery/conveyor_switch/S in GLOB.machines)
if(S.id == src.id)
S.position = position
S.update()
diff --git a/code/modules/recycling/disposal.dm b/code/modules/recycling/disposal.dm
index 2c7401ac278c..88efcf7a37ba 100644
--- a/code/modules/recycling/disposal.dm
+++ b/code/modules/recycling/disposal.dm
@@ -195,7 +195,7 @@
return FALSE //Need a firm grip to put someone else in there.
if(!istype(target) || target.anchored || target.buckled || get_dist(user, src) > 1 || user.is_mob_incapacitated(TRUE) || isRemoteControlling(user) || target.mob_size >= MOB_SIZE_BIG)
- to_chat(user, SPAN_WARNING("You cannot get into the [src]!"))
+ to_chat(user, SPAN_WARNING("You cannot get into [src]!"))
return FALSE
add_fingerprint(user)
var/target_loc = target.loc
@@ -221,22 +221,21 @@
update()
///Attempt to move while inside
-/obj/structure/machinery/disposal/relaymove(mob/user)
- if(user.stat || user.stunned || user.knocked_down || flushing)
+/obj/structure/machinery/disposal/relaymove(mob/living/user)
+ if(user.is_mob_incapacitated(TRUE) || flushing)
return FALSE
if(user.loc == src)
go_out(user)
return TRUE
///Leave the disposal
-/obj/structure/machinery/disposal/proc/go_out(mob/user)
+/obj/structure/machinery/disposal/proc/go_out(mob/living/user)
if(user.client)
user.client.eye = user.client.mob
user.client.perspective = MOB_PERSPECTIVE
user.forceMove(loc)
- user.stunned = max(user.stunned, 2) //Action delay when going out of a bin
- user.update_canmove() //Force the delay to go in action immediately
- if(!user.lying)
+ user.apply_effect(2, STUN)
+ if(user.mobility_flags & MOBILITY_MOVE)
user.visible_message(SPAN_WARNING("[user] suddenly climbs out of [src]!"),
SPAN_WARNING("You climb out of [src] and get your bearings!"))
update()
@@ -302,12 +301,11 @@
for(var/atom/movable/AM in src)
AM.forceMove(loc)
AM.pipe_eject(0)
- if(ismob(AM))
- var/mob/M = AM
- M.stunned = max(M.stunned, 2) //Action delay when going out of a bin
- M.update_canmove() //Force the delay to go in action immediately
- if(!M.lying)
- M.visible_message(SPAN_WARNING("[M] is suddenly pushed out of [src]!"),
+ if(isliving(AM))
+ var/mob/living/living = AM
+ living.Stun(2)
+ if(living.body_position == STANDING_UP)
+ living.visible_message(SPAN_WARNING("[living] is suddenly pushed out of [src]!"),
SPAN_WARNING("You get pushed out of [src] and get your bearings!"))
update()
@@ -746,7 +744,7 @@
//Remains : set to leave broken pipe pieces in place
/obj/structure/disposalpipe/deconstruct(disassembled = TRUE)
if(disassembled)
- for(var/D in cardinal)
+ for(var/D in GLOB.cardinals)
if(D & dpdir)
var/obj/structure/disposalpipe/broken/P = new(loc)
P.setDir(D)
@@ -1096,7 +1094,8 @@
/obj/structure/disposalpipe/tagger/Initialize(mapload, ...)
. = ..()
dpdir = dir|turn(dir, 180)
- if(sort_tag) tagger_locations |= sort_tag
+ if(sort_tag)
+ GLOB.tagger_locations |= sort_tag
updatename()
updatedesc()
update()
@@ -1152,7 +1151,8 @@
/obj/structure/disposalpipe/sortjunction/Initialize(mapload, ...)
. = ..()
- if(sortType) tagger_locations |= sortType
+ if(sortType)
+ GLOB.tagger_locations |= sortType
updatedir()
updatename()
@@ -1457,7 +1457,7 @@
if(direction)
dirs = list( direction, turn(direction, -45), turn(direction, 45))
else
- dirs = alldirs.Copy()
+ dirs = GLOB.alldirs.Copy()
INVOKE_ASYNC(streak(dirs))
@@ -1466,7 +1466,7 @@
if(direction)
dirs = list( direction, turn(direction, -45), turn(direction, 45))
else
- dirs = alldirs.Copy()
+ dirs = GLOB.alldirs.Copy()
INVOKE_ASYNC(streak(dirs))
diff --git a/code/modules/recycling/recycler.dm b/code/modules/recycling/recycler.dm
index 73d00b763f68..abbf010bf4cc 100644
--- a/code/modules/recycling/recycler.dm
+++ b/code/modules/recycling/recycler.dm
@@ -9,32 +9,39 @@
density = TRUE
var/recycle_dir = NORTH
var/list/stored_matter = list("metal" = 0, "glass" = 0)
+ /// Amount of metal refunded per crate, by default about 2 metal sheets (building one takes 5)
+ var/crate_reward = 7500
+ /// Amount of sheets to stack before outputting a stack
+ var/sheets_per_batch = 10
var/last_recycle_sound //for sound cooldown
var/ignored_items = list(/obj/item/limb)
-/obj/structure/machinery/recycler/New()
- ..()
- update_icon()
+/obj/structure/machinery/recycler/whiskey
+ crate_reward = 15000 // Boosted reward (4 sheets) to make up for workload and the fact you can't sell them
+/obj/structure/machinery/recycler/Initialize(mapload, ...)
+ . = ..()
+ update_icon()
/obj/structure/machinery/recycler/power_change()
..()
update_icon()
-
/obj/structure/machinery/recycler/update_icon()
+ . = ..()
icon_state = "separator-AO[(inoperable()) ? "0":"1"]"
-
-/obj/structure/machinery/recycler/Collided(atom/movable/AM)
+/obj/structure/machinery/recycler/Collided(atom/movable/movable)
if(inoperable())
return
- var/move_dir = get_dir(loc, AM.loc)
- if(!AM.anchored && move_dir == recycle_dir)
- if(istype(AM, /obj/item))
- recycle(AM)
+ var/move_dir = get_dir(loc, movable.loc)
+ if(!movable.anchored && move_dir == recycle_dir)
+ if(istype(movable, /obj/item))
+ recycle(movable)
+ else if(istype(movable, /obj/structure/closet/crate))
+ recycle_crate(movable)
else
- AM.forceMove(loc)
+ movable.forceMove(loc)
/obj/structure/machinery/recycler/proc/recycle(obj/item/I)
@@ -63,7 +70,32 @@
stored_matter[material] += total_material
qdel(I)
+ play_recycle_sound()
+ output_materials()
+
+/obj/structure/machinery/recycler/proc/recycle_crate(obj/structure/closet/crate)
+ for(var/atom/movable/movable in crate)
+ movable.forceMove(loc)
+ recycle(movable)
+ stored_matter["metal"] += crate_reward
+ qdel(crate)
+ play_recycle_sound()
+ output_materials()
+
+/obj/structure/machinery/recycler/proc/play_recycle_sound()
if(last_recycle_sound < world.time)
playsound(loc, 'sound/items/Welder.ogg', 30, 1)
last_recycle_sound = world.time + 50
+/obj/structure/machinery/recycler/proc/output_materials()
+ for(var/material in stored_matter)
+ if(stored_matter[material] >= sheets_per_batch * 3750)
+ var/sheets = round(stored_matter[material] / 3750)
+ stored_matter[material] -= sheets * 3750
+ var/obj/item/stack/sheet/sheet_stack
+ switch(material)
+ if("metal") sheet_stack = new /obj/item/stack/sheet/metal(loc)
+ if("glass") sheet_stack = new /obj/item/stack/sheet/glass(loc)
+ if(sheet_stack)
+ sheet_stack.amount = sheets
+ sheet_stack.update_icon()
diff --git a/code/modules/recycling/sortingmachinery.dm b/code/modules/recycling/sortingmachinery.dm
index e61357188ad6..ec1c8c245f2b 100644
--- a/code/modules/recycling/sortingmachinery.dm
+++ b/code/modules/recycling/sortingmachinery.dm
@@ -215,7 +215,7 @@
icon = 'icons/obj/items/items.dmi'
icon_state = "deliveryPaper"
w_class = SIZE_MEDIUM
- var/amount = 25
+ var/amount = 50
/obj/item/packageWrap/afterattack(obj/target as obj, mob/user as mob, proximity)
@@ -263,39 +263,55 @@
O.add_fingerprint(usr)
src.add_fingerprint(usr)
src.amount--
- user.visible_message("\The [user] wraps \a [target] with \a [src].",\
- SPAN_NOTICE("You wrap \the [target], leaving [amount] units of paper on \the [src]."),\
+ user.visible_message("[user] wraps [target] with [src].",\
+ SPAN_NOTICE("You wrap [target], leaving [amount] units of paper on [src]."),\
"You hear someone taping paper around a small object.")
else if (istype(target, /obj/structure/closet/crate))
- var/obj/structure/closet/crate/O = target
- if (src.amount > 3 && !O.opened)
- var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
- P.icon_state = "deliverycrate"
- P.wrapped = O
- O.forceMove(P)
- src.amount -= 3
- user.visible_message("\The [user] wraps \a [target] with \a [src].",\
- SPAN_NOTICE("You wrap \the [target], leaving [amount] units of paper on \the [src]."),\
- "You hear someone taping paper around a large object.")
- else if(src.amount < 3)
- to_chat(user, SPAN_WARNING("You need more paper."))
+ var/obj/structure/closet/crate/crate = target
+ var/answer = tgui_alert(user, "Wrap the crate for delivery or customize it?", "Crate wrapping", list("Customize", "Wrap"))
+ if(!answer || !user.Adjacent(target) || !target.z)
+ return
+ if(answer == "Customize")
+ if(!length(crate.crate_customizing_types))
+ to_chat(user, SPAN_WARNING("You cannot customize this kind of crate."))
+ return
+ var/label = tgui_input_text(user, "Give the crate a new logistic tag:", "Customizing")
+ if(!label || !user.Adjacent(target) || !target.z)
+ return
+ var/chosen_type = tgui_input_list(user, "Select the kind of crate to make this into:", "Customizing", crate.crate_customizing_types)
+ if(!chosen_type || !ispath(crate.crate_customizing_types[chosen_type]) || !user.Adjacent(target) || !target.z)
+ return
+ target.AddComponent(/datum/component/crate_tag, label, crate.crate_customizing_types[chosen_type])
+ amount -= 3
+ else
+ if (amount > 3 && !crate.opened)
+ var/obj/structure/bigDelivery/package = new /obj/structure/bigDelivery(get_turf(crate.loc))
+ package.icon_state = "deliverycrate"
+ package.wrapped = crate
+ crate.forceMove(package)
+ amount -= 3
+ user.visible_message("[user] wraps [target] with [src].",\
+ SPAN_NOTICE("You wrap [target], leaving [amount] units of paper on [src]."),\
+ "You hear someone taping paper around a large object.")
+ else if(amount < 3)
+ to_chat(user, SPAN_WARNING("You need more paper."))
else if (istype (target, /obj/structure/closet))
- var/obj/structure/closet/O = target
- if (src.amount > 3 && !O.opened)
- var/obj/structure/bigDelivery/P = new /obj/structure/bigDelivery(get_turf(O.loc))
- P.wrapped = O
- O.welded = 1
- O.forceMove(P)
- src.amount -= 3
- user.visible_message("\The [user] wraps \a [target] with \a [src].",\
- SPAN_NOTICE("You wrap \the [target], leaving [amount] units of paper on \the [src]."),\
+ var/obj/structure/closet/object = target
+ if (amount > 3 && !object.opened)
+ var/obj/structure/bigDelivery/package = new /obj/structure/bigDelivery(get_turf(object.loc))
+ package.wrapped = object
+ object.welded = 1
+ object.forceMove(package)
+ amount -= 3
+ user.visible_message("[user] wraps [target] with [src].",\
+ SPAN_NOTICE("You wrap [target], leaving [amount] units of paper on [src]."),\
"You hear someone taping paper around a large object.")
- else if(src.amount < 3)
+ else if(amount < 3)
to_chat(user, SPAN_WARNING("You need more paper."))
else
to_chat(user, SPAN_NOTICE(" The object you are trying to wrap is unsuitable for the sorting machinery!"))
- if (src.amount <= 0)
- new /obj/item/trash/c_tube( src.loc )
+ if (amount <= 0)
+ new /obj/item/trash/c_tube( loc )
qdel(src)
return
return
@@ -321,8 +337,8 @@
var/dat = "
TagMaster 2.3
"
dat += "
"
- for(var/i = 1, i <= tagger_locations.len, i++)
- dat += "
- {{for data.targets_data}}
- {{:helper.link(value.target_name, null, {'select_laser_firemission' : value.target_tag}, (data.shuttle_state == "in_transit") ? null : 'disabled' , 'fixedLeftLongText')}}
- {{empty}}
- No CAS signal detected.
- {{/for}}
-
-
-{{/if}}
diff --git a/sound/effects/creak1.ogg b/sound/effects/creak1.ogg
new file mode 100644
index 000000000000..0cad4802ffa9
Binary files /dev/null and b/sound/effects/creak1.ogg differ
diff --git a/sound/effects/creak2.ogg b/sound/effects/creak2.ogg
new file mode 100644
index 000000000000..707bf39e338e
Binary files /dev/null and b/sound/effects/creak2.ogg differ
diff --git a/sound/effects/creak3.ogg b/sound/effects/creak3.ogg
new file mode 100644
index 000000000000..88ff37a339ed
Binary files /dev/null and b/sound/effects/creak3.ogg differ
diff --git a/sound/effects/Heart Beat Short.ogg b/sound/effects/heart_beat_short.ogg
similarity index 100%
rename from sound/effects/Heart Beat Short.ogg
rename to sound/effects/heart_beat_short.ogg
diff --git a/sound/items/whistle.ogg b/sound/items/whistle.ogg
index 8e276d522669..3223f52cae36 100644
Binary files a/sound/items/whistle.ogg and b/sound/items/whistle.ogg differ
diff --git a/sound/piano/A#1.ogg b/sound/piano/A#1.ogg
deleted file mode 100644
index ae41c0a189b1..000000000000
Binary files a/sound/piano/A#1.ogg and /dev/null differ
diff --git a/sound/piano/A#2.ogg b/sound/piano/A#2.ogg
deleted file mode 100644
index c35ce012b3ee..000000000000
Binary files a/sound/piano/A#2.ogg and /dev/null differ
diff --git a/sound/piano/A#3.ogg b/sound/piano/A#3.ogg
deleted file mode 100644
index 9ea8795bcf31..000000000000
Binary files a/sound/piano/A#3.ogg and /dev/null differ
diff --git a/sound/piano/A#4.ogg b/sound/piano/A#4.ogg
deleted file mode 100644
index aeb41ce1a722..000000000000
Binary files a/sound/piano/A#4.ogg and /dev/null differ
diff --git a/sound/piano/A#5.ogg b/sound/piano/A#5.ogg
deleted file mode 100644
index eca721384308..000000000000
Binary files a/sound/piano/A#5.ogg and /dev/null differ
diff --git a/sound/piano/A#6.ogg b/sound/piano/A#6.ogg
deleted file mode 100644
index 0ae9e89b0c28..000000000000
Binary files a/sound/piano/A#6.ogg and /dev/null differ
diff --git a/sound/piano/A#7.ogg b/sound/piano/A#7.ogg
deleted file mode 100644
index e1b469da8164..000000000000
Binary files a/sound/piano/A#7.ogg and /dev/null differ
diff --git a/sound/piano/A#8.ogg b/sound/piano/A#8.ogg
deleted file mode 100644
index 83bd263e9804..000000000000
Binary files a/sound/piano/A#8.ogg and /dev/null differ
diff --git a/sound/piano/Ab1.ogg b/sound/piano/Ab1.ogg
deleted file mode 100644
index 1f67015756c2..000000000000
Binary files a/sound/piano/Ab1.ogg and /dev/null differ
diff --git a/sound/piano/Ab2.ogg b/sound/piano/Ab2.ogg
deleted file mode 100644
index 985bfd608212..000000000000
Binary files a/sound/piano/Ab2.ogg and /dev/null differ
diff --git a/sound/piano/Ab3.ogg b/sound/piano/Ab3.ogg
deleted file mode 100644
index 5dbcb2d7c634..000000000000
Binary files a/sound/piano/Ab3.ogg and /dev/null differ
diff --git a/sound/piano/Ab4.ogg b/sound/piano/Ab4.ogg
deleted file mode 100644
index 01add48a44ad..000000000000
Binary files a/sound/piano/Ab4.ogg and /dev/null differ
diff --git a/sound/piano/Ab5.ogg b/sound/piano/Ab5.ogg
deleted file mode 100644
index 6fbe70844dc3..000000000000
Binary files a/sound/piano/Ab5.ogg and /dev/null differ
diff --git a/sound/piano/Ab6.ogg b/sound/piano/Ab6.ogg
deleted file mode 100644
index 82b5a84e6824..000000000000
Binary files a/sound/piano/Ab6.ogg and /dev/null differ
diff --git a/sound/piano/Ab7.ogg b/sound/piano/Ab7.ogg
deleted file mode 100644
index 391b1c1185af..000000000000
Binary files a/sound/piano/Ab7.ogg and /dev/null differ
diff --git a/sound/piano/Ab8.ogg b/sound/piano/Ab8.ogg
deleted file mode 100644
index aa83b7aaab90..000000000000
Binary files a/sound/piano/Ab8.ogg and /dev/null differ
diff --git a/sound/piano/An1.ogg b/sound/piano/An1.ogg
deleted file mode 100644
index 4a87d59adac5..000000000000
Binary files a/sound/piano/An1.ogg and /dev/null differ
diff --git a/sound/piano/An2.ogg b/sound/piano/An2.ogg
deleted file mode 100644
index f5327d0d7cf1..000000000000
Binary files a/sound/piano/An2.ogg and /dev/null differ
diff --git a/sound/piano/An3.ogg b/sound/piano/An3.ogg
deleted file mode 100644
index 7c3e8a031e80..000000000000
Binary files a/sound/piano/An3.ogg and /dev/null differ
diff --git a/sound/piano/An4.ogg b/sound/piano/An4.ogg
deleted file mode 100644
index 2ba84a58a6e3..000000000000
Binary files a/sound/piano/An4.ogg and /dev/null differ
diff --git a/sound/piano/An5.ogg b/sound/piano/An5.ogg
deleted file mode 100644
index 5e04fc8c7fbc..000000000000
Binary files a/sound/piano/An5.ogg and /dev/null differ
diff --git a/sound/piano/An6.ogg b/sound/piano/An6.ogg
deleted file mode 100644
index 48b639d77f2d..000000000000
Binary files a/sound/piano/An6.ogg and /dev/null differ
diff --git a/sound/piano/An7.ogg b/sound/piano/An7.ogg
deleted file mode 100644
index 5d93800f28a6..000000000000
Binary files a/sound/piano/An7.ogg and /dev/null differ
diff --git a/sound/piano/An8.ogg b/sound/piano/An8.ogg
deleted file mode 100644
index e01acd4e7e13..000000000000
Binary files a/sound/piano/An8.ogg and /dev/null differ
diff --git a/sound/piano/B#1.ogg b/sound/piano/B#1.ogg
deleted file mode 100644
index bcdd2bfd4a1c..000000000000
Binary files a/sound/piano/B#1.ogg and /dev/null differ
diff --git a/sound/piano/B#2.ogg b/sound/piano/B#2.ogg
deleted file mode 100644
index 0effb061b460..000000000000
Binary files a/sound/piano/B#2.ogg and /dev/null differ
diff --git a/sound/piano/B#3.ogg b/sound/piano/B#3.ogg
deleted file mode 100644
index 64f390516fc3..000000000000
Binary files a/sound/piano/B#3.ogg and /dev/null differ
diff --git a/sound/piano/B#4.ogg b/sound/piano/B#4.ogg
deleted file mode 100644
index a423bbb83d21..000000000000
Binary files a/sound/piano/B#4.ogg and /dev/null differ
diff --git a/sound/piano/B#5.ogg b/sound/piano/B#5.ogg
deleted file mode 100644
index 9a63a927fd08..000000000000
Binary files a/sound/piano/B#5.ogg and /dev/null differ
diff --git a/sound/piano/B#6.ogg b/sound/piano/B#6.ogg
deleted file mode 100644
index be35faabf563..000000000000
Binary files a/sound/piano/B#6.ogg and /dev/null differ
diff --git a/sound/piano/B#7.ogg b/sound/piano/B#7.ogg
deleted file mode 100644
index cbb2ad3bc152..000000000000
Binary files a/sound/piano/B#7.ogg and /dev/null differ
diff --git a/sound/piano/B#8.ogg b/sound/piano/B#8.ogg
deleted file mode 100644
index 5297b755a356..000000000000
Binary files a/sound/piano/B#8.ogg and /dev/null differ
diff --git a/sound/piano/Bb1.ogg b/sound/piano/Bb1.ogg
deleted file mode 100644
index 617f36454115..000000000000
Binary files a/sound/piano/Bb1.ogg and /dev/null differ
diff --git a/sound/piano/Bb2.ogg b/sound/piano/Bb2.ogg
deleted file mode 100644
index eb4215daa4c1..000000000000
Binary files a/sound/piano/Bb2.ogg and /dev/null differ
diff --git a/sound/piano/Bb3.ogg b/sound/piano/Bb3.ogg
deleted file mode 100644
index 35f7eb53d47c..000000000000
Binary files a/sound/piano/Bb3.ogg and /dev/null differ
diff --git a/sound/piano/Bb4.ogg b/sound/piano/Bb4.ogg
deleted file mode 100644
index 1eef7b921392..000000000000
Binary files a/sound/piano/Bb4.ogg and /dev/null differ
diff --git a/sound/piano/Bb5.ogg b/sound/piano/Bb5.ogg
deleted file mode 100644
index 118867fd1468..000000000000
Binary files a/sound/piano/Bb5.ogg and /dev/null differ
diff --git a/sound/piano/Bb6.ogg b/sound/piano/Bb6.ogg
deleted file mode 100644
index 700b2c5abd7f..000000000000
Binary files a/sound/piano/Bb6.ogg and /dev/null differ
diff --git a/sound/piano/Bb7.ogg b/sound/piano/Bb7.ogg
deleted file mode 100644
index c50955bf01c3..000000000000
Binary files a/sound/piano/Bb7.ogg and /dev/null differ
diff --git a/sound/piano/Bb8.ogg b/sound/piano/Bb8.ogg
deleted file mode 100644
index b076c4b4e2be..000000000000
Binary files a/sound/piano/Bb8.ogg and /dev/null differ
diff --git a/sound/piano/Bn1.ogg b/sound/piano/Bn1.ogg
deleted file mode 100644
index 256534881c18..000000000000
Binary files a/sound/piano/Bn1.ogg and /dev/null differ
diff --git a/sound/piano/Bn2.ogg b/sound/piano/Bn2.ogg
deleted file mode 100644
index 8ed87aa49e77..000000000000
Binary files a/sound/piano/Bn2.ogg and /dev/null differ
diff --git a/sound/piano/Bn3.ogg b/sound/piano/Bn3.ogg
deleted file mode 100644
index 19788aad716c..000000000000
Binary files a/sound/piano/Bn3.ogg and /dev/null differ
diff --git a/sound/piano/Bn4.ogg b/sound/piano/Bn4.ogg
deleted file mode 100644
index 773f5b3bd3bf..000000000000
Binary files a/sound/piano/Bn4.ogg and /dev/null differ
diff --git a/sound/piano/Bn5.ogg b/sound/piano/Bn5.ogg
deleted file mode 100644
index 3297fab1d597..000000000000
Binary files a/sound/piano/Bn5.ogg and /dev/null differ
diff --git a/sound/piano/Bn6.ogg b/sound/piano/Bn6.ogg
deleted file mode 100644
index 35a39b20f66a..000000000000
Binary files a/sound/piano/Bn6.ogg and /dev/null differ
diff --git a/sound/piano/Bn7.ogg b/sound/piano/Bn7.ogg
deleted file mode 100644
index e7a8ba403430..000000000000
Binary files a/sound/piano/Bn7.ogg and /dev/null differ
diff --git a/sound/piano/Bn8.ogg b/sound/piano/Bn8.ogg
deleted file mode 100644
index 2c821e818539..000000000000
Binary files a/sound/piano/Bn8.ogg and /dev/null differ
diff --git a/sound/piano/C#1.ogg b/sound/piano/C#1.ogg
deleted file mode 100644
index be3d7e3e3081..000000000000
Binary files a/sound/piano/C#1.ogg and /dev/null differ
diff --git a/sound/piano/C#2.ogg b/sound/piano/C#2.ogg
deleted file mode 100644
index cefe3a745dc0..000000000000
Binary files a/sound/piano/C#2.ogg and /dev/null differ
diff --git a/sound/piano/C#3.ogg b/sound/piano/C#3.ogg
deleted file mode 100644
index dc3d0878475f..000000000000
Binary files a/sound/piano/C#3.ogg and /dev/null differ
diff --git a/sound/piano/C#4.ogg b/sound/piano/C#4.ogg
deleted file mode 100644
index c31a44bdf6dd..000000000000
Binary files a/sound/piano/C#4.ogg and /dev/null differ
diff --git a/sound/piano/C#5.ogg b/sound/piano/C#5.ogg
deleted file mode 100644
index c5d10d13764d..000000000000
Binary files a/sound/piano/C#5.ogg and /dev/null differ
diff --git a/sound/piano/C#6.ogg b/sound/piano/C#6.ogg
deleted file mode 100644
index a084a04de146..000000000000
Binary files a/sound/piano/C#6.ogg and /dev/null differ
diff --git a/sound/piano/C#7.ogg b/sound/piano/C#7.ogg
deleted file mode 100644
index 6da255f5aea0..000000000000
Binary files a/sound/piano/C#7.ogg and /dev/null differ
diff --git a/sound/piano/C#8.ogg b/sound/piano/C#8.ogg
deleted file mode 100644
index b4d4cbe41579..000000000000
Binary files a/sound/piano/C#8.ogg and /dev/null differ
diff --git a/sound/piano/Cb2.ogg b/sound/piano/Cb2.ogg
deleted file mode 100644
index cefff94c1465..000000000000
Binary files a/sound/piano/Cb2.ogg and /dev/null differ
diff --git a/sound/piano/Cb3.ogg b/sound/piano/Cb3.ogg
deleted file mode 100644
index 0425228ee726..000000000000
Binary files a/sound/piano/Cb3.ogg and /dev/null differ
diff --git a/sound/piano/Cb4.ogg b/sound/piano/Cb4.ogg
deleted file mode 100644
index e9c8ad22e94b..000000000000
Binary files a/sound/piano/Cb4.ogg and /dev/null differ
diff --git a/sound/piano/Cb5.ogg b/sound/piano/Cb5.ogg
deleted file mode 100644
index 611c8ef9e42e..000000000000
Binary files a/sound/piano/Cb5.ogg and /dev/null differ
diff --git a/sound/piano/Cb6.ogg b/sound/piano/Cb6.ogg
deleted file mode 100644
index 3fe79c61ef92..000000000000
Binary files a/sound/piano/Cb6.ogg and /dev/null differ
diff --git a/sound/piano/Cb7.ogg b/sound/piano/Cb7.ogg
deleted file mode 100644
index ff6a3fb00726..000000000000
Binary files a/sound/piano/Cb7.ogg and /dev/null differ
diff --git a/sound/piano/Cb8.ogg b/sound/piano/Cb8.ogg
deleted file mode 100644
index 8ff3d57fe907..000000000000
Binary files a/sound/piano/Cb8.ogg and /dev/null differ
diff --git a/sound/piano/Cb9.ogg b/sound/piano/Cb9.ogg
deleted file mode 100644
index fa2a3de7a777..000000000000
Binary files a/sound/piano/Cb9.ogg and /dev/null differ
diff --git a/sound/piano/Cn1.ogg b/sound/piano/Cn1.ogg
deleted file mode 100644
index 86fba1381012..000000000000
Binary files a/sound/piano/Cn1.ogg and /dev/null differ
diff --git a/sound/piano/Cn2.ogg b/sound/piano/Cn2.ogg
deleted file mode 100644
index e069259e8507..000000000000
Binary files a/sound/piano/Cn2.ogg and /dev/null differ
diff --git a/sound/piano/Cn3.ogg b/sound/piano/Cn3.ogg
deleted file mode 100644
index 01f5bcde7c5d..000000000000
Binary files a/sound/piano/Cn3.ogg and /dev/null differ
diff --git a/sound/piano/Cn4.ogg b/sound/piano/Cn4.ogg
deleted file mode 100644
index 2545ccb996b9..000000000000
Binary files a/sound/piano/Cn4.ogg and /dev/null differ
diff --git a/sound/piano/Cn5.ogg b/sound/piano/Cn5.ogg
deleted file mode 100644
index 601fd5340b37..000000000000
Binary files a/sound/piano/Cn5.ogg and /dev/null differ
diff --git a/sound/piano/Cn6.ogg b/sound/piano/Cn6.ogg
deleted file mode 100644
index f89c2c78f3af..000000000000
Binary files a/sound/piano/Cn6.ogg and /dev/null differ
diff --git a/sound/piano/Cn7.ogg b/sound/piano/Cn7.ogg
deleted file mode 100644
index 09723616a74c..000000000000
Binary files a/sound/piano/Cn7.ogg and /dev/null differ
diff --git a/sound/piano/Cn8.ogg b/sound/piano/Cn8.ogg
deleted file mode 100644
index 4c7e2b44c6fc..000000000000
Binary files a/sound/piano/Cn8.ogg and /dev/null differ
diff --git a/sound/piano/Cn9.ogg b/sound/piano/Cn9.ogg
deleted file mode 100644
index 2b6812d62b24..000000000000
Binary files a/sound/piano/Cn9.ogg and /dev/null differ
diff --git a/sound/piano/D#1.ogg b/sound/piano/D#1.ogg
deleted file mode 100644
index d772320b150d..000000000000
Binary files a/sound/piano/D#1.ogg and /dev/null differ
diff --git a/sound/piano/D#2.ogg b/sound/piano/D#2.ogg
deleted file mode 100644
index ae9d529e907c..000000000000
Binary files a/sound/piano/D#2.ogg and /dev/null differ
diff --git a/sound/piano/D#3.ogg b/sound/piano/D#3.ogg
deleted file mode 100644
index 63fc4fdd5953..000000000000
Binary files a/sound/piano/D#3.ogg and /dev/null differ
diff --git a/sound/piano/D#4.ogg b/sound/piano/D#4.ogg
deleted file mode 100644
index 39cf1adbca97..000000000000
Binary files a/sound/piano/D#4.ogg and /dev/null differ
diff --git a/sound/piano/D#5.ogg b/sound/piano/D#5.ogg
deleted file mode 100644
index 071a57544aee..000000000000
Binary files a/sound/piano/D#5.ogg and /dev/null differ
diff --git a/sound/piano/D#6.ogg b/sound/piano/D#6.ogg
deleted file mode 100644
index 7ee1bd4bfa07..000000000000
Binary files a/sound/piano/D#6.ogg and /dev/null differ
diff --git a/sound/piano/D#7.ogg b/sound/piano/D#7.ogg
deleted file mode 100644
index 19f72532dde6..000000000000
Binary files a/sound/piano/D#7.ogg and /dev/null differ
diff --git a/sound/piano/D#8.ogg b/sound/piano/D#8.ogg
deleted file mode 100644
index ee87d875bd40..000000000000
Binary files a/sound/piano/D#8.ogg and /dev/null differ
diff --git a/sound/piano/Db1.ogg b/sound/piano/Db1.ogg
deleted file mode 100644
index 9166b7335552..000000000000
Binary files a/sound/piano/Db1.ogg and /dev/null differ
diff --git a/sound/piano/Db2.ogg b/sound/piano/Db2.ogg
deleted file mode 100644
index 623acd0ec54f..000000000000
Binary files a/sound/piano/Db2.ogg and /dev/null differ
diff --git a/sound/piano/Db3.ogg b/sound/piano/Db3.ogg
deleted file mode 100644
index 5c8943b4da9f..000000000000
Binary files a/sound/piano/Db3.ogg and /dev/null differ
diff --git a/sound/piano/Db4.ogg b/sound/piano/Db4.ogg
deleted file mode 100644
index 2deb5b8d9173..000000000000
Binary files a/sound/piano/Db4.ogg and /dev/null differ
diff --git a/sound/piano/Db5.ogg b/sound/piano/Db5.ogg
deleted file mode 100644
index 9c77ee37a7d8..000000000000
Binary files a/sound/piano/Db5.ogg and /dev/null differ
diff --git a/sound/piano/Db6.ogg b/sound/piano/Db6.ogg
deleted file mode 100644
index 49e1e04dff84..000000000000
Binary files a/sound/piano/Db6.ogg and /dev/null differ
diff --git a/sound/piano/Db7.ogg b/sound/piano/Db7.ogg
deleted file mode 100644
index b53fd2f27e03..000000000000
Binary files a/sound/piano/Db7.ogg and /dev/null differ
diff --git a/sound/piano/Db8.ogg b/sound/piano/Db8.ogg
deleted file mode 100644
index af6cfdffad62..000000000000
Binary files a/sound/piano/Db8.ogg and /dev/null differ
diff --git a/sound/piano/Dn1.ogg b/sound/piano/Dn1.ogg
deleted file mode 100644
index c6dd20cb65b4..000000000000
Binary files a/sound/piano/Dn1.ogg and /dev/null differ
diff --git a/sound/piano/Dn2.ogg b/sound/piano/Dn2.ogg
deleted file mode 100644
index 0783087dc658..000000000000
Binary files a/sound/piano/Dn2.ogg and /dev/null differ
diff --git a/sound/piano/Dn3.ogg b/sound/piano/Dn3.ogg
deleted file mode 100644
index bf7bd97ad137..000000000000
Binary files a/sound/piano/Dn3.ogg and /dev/null differ
diff --git a/sound/piano/Dn4.ogg b/sound/piano/Dn4.ogg
deleted file mode 100644
index e35a6af447e8..000000000000
Binary files a/sound/piano/Dn4.ogg and /dev/null differ
diff --git a/sound/piano/Dn5.ogg b/sound/piano/Dn5.ogg
deleted file mode 100644
index 7e355266c0f5..000000000000
Binary files a/sound/piano/Dn5.ogg and /dev/null differ
diff --git a/sound/piano/Dn6.ogg b/sound/piano/Dn6.ogg
deleted file mode 100644
index 5da94c15adf2..000000000000
Binary files a/sound/piano/Dn6.ogg and /dev/null differ
diff --git a/sound/piano/Dn7.ogg b/sound/piano/Dn7.ogg
deleted file mode 100644
index ac43398ece62..000000000000
Binary files a/sound/piano/Dn7.ogg and /dev/null differ
diff --git a/sound/piano/Dn8.ogg b/sound/piano/Dn8.ogg
deleted file mode 100644
index 534e51e72013..000000000000
Binary files a/sound/piano/Dn8.ogg and /dev/null differ
diff --git a/sound/piano/E#1.ogg b/sound/piano/E#1.ogg
deleted file mode 100644
index 46fd3d50c91b..000000000000
Binary files a/sound/piano/E#1.ogg and /dev/null differ
diff --git a/sound/piano/E#2.ogg b/sound/piano/E#2.ogg
deleted file mode 100644
index eece0448208d..000000000000
Binary files a/sound/piano/E#2.ogg and /dev/null differ
diff --git a/sound/piano/E#3.ogg b/sound/piano/E#3.ogg
deleted file mode 100644
index d5acee8dfa7f..000000000000
Binary files a/sound/piano/E#3.ogg and /dev/null differ
diff --git a/sound/piano/E#4.ogg b/sound/piano/E#4.ogg
deleted file mode 100644
index 3e75fccc91b9..000000000000
Binary files a/sound/piano/E#4.ogg and /dev/null differ
diff --git a/sound/piano/E#5.ogg b/sound/piano/E#5.ogg
deleted file mode 100644
index cc91527d0ea0..000000000000
Binary files a/sound/piano/E#5.ogg and /dev/null differ
diff --git a/sound/piano/E#6.ogg b/sound/piano/E#6.ogg
deleted file mode 100644
index 476edd68e22a..000000000000
Binary files a/sound/piano/E#6.ogg and /dev/null differ
diff --git a/sound/piano/E#7.ogg b/sound/piano/E#7.ogg
deleted file mode 100644
index 7c77c6971ee2..000000000000
Binary files a/sound/piano/E#7.ogg and /dev/null differ
diff --git a/sound/piano/E#8.ogg b/sound/piano/E#8.ogg
deleted file mode 100644
index 61a55478dc95..000000000000
Binary files a/sound/piano/E#8.ogg and /dev/null differ
diff --git a/sound/piano/Eb1.ogg b/sound/piano/Eb1.ogg
deleted file mode 100644
index 745c448a4f1f..000000000000
Binary files a/sound/piano/Eb1.ogg and /dev/null differ
diff --git a/sound/piano/Eb2.ogg b/sound/piano/Eb2.ogg
deleted file mode 100644
index 85fc213e8214..000000000000
Binary files a/sound/piano/Eb2.ogg and /dev/null differ
diff --git a/sound/piano/Eb3.ogg b/sound/piano/Eb3.ogg
deleted file mode 100644
index 66c673310bb6..000000000000
Binary files a/sound/piano/Eb3.ogg and /dev/null differ
diff --git a/sound/piano/Eb4.ogg b/sound/piano/Eb4.ogg
deleted file mode 100644
index bff7248310b8..000000000000
Binary files a/sound/piano/Eb4.ogg and /dev/null differ
diff --git a/sound/piano/Eb5.ogg b/sound/piano/Eb5.ogg
deleted file mode 100644
index 8ecb263ee720..000000000000
Binary files a/sound/piano/Eb5.ogg and /dev/null differ
diff --git a/sound/piano/Eb6.ogg b/sound/piano/Eb6.ogg
deleted file mode 100644
index 29e62c7a16d8..000000000000
Binary files a/sound/piano/Eb6.ogg and /dev/null differ
diff --git a/sound/piano/Eb7.ogg b/sound/piano/Eb7.ogg
deleted file mode 100644
index 95e70c0b8cba..000000000000
Binary files a/sound/piano/Eb7.ogg and /dev/null differ
diff --git a/sound/piano/Eb8.ogg b/sound/piano/Eb8.ogg
deleted file mode 100644
index e421154b62e3..000000000000
Binary files a/sound/piano/Eb8.ogg and /dev/null differ
diff --git a/sound/piano/En1.ogg b/sound/piano/En1.ogg
deleted file mode 100644
index 32819af46ba5..000000000000
Binary files a/sound/piano/En1.ogg and /dev/null differ
diff --git a/sound/piano/En2.ogg b/sound/piano/En2.ogg
deleted file mode 100644
index f1931e091425..000000000000
Binary files a/sound/piano/En2.ogg and /dev/null differ
diff --git a/sound/piano/En3.ogg b/sound/piano/En3.ogg
deleted file mode 100644
index fd9d54a6d03f..000000000000
Binary files a/sound/piano/En3.ogg and /dev/null differ
diff --git a/sound/piano/En4.ogg b/sound/piano/En4.ogg
deleted file mode 100644
index 41dcf10ff57e..000000000000
Binary files a/sound/piano/En4.ogg and /dev/null differ
diff --git a/sound/piano/En5.ogg b/sound/piano/En5.ogg
deleted file mode 100644
index 571bb0768e56..000000000000
Binary files a/sound/piano/En5.ogg and /dev/null differ
diff --git a/sound/piano/En6.ogg b/sound/piano/En6.ogg
deleted file mode 100644
index 7dbf990b1864..000000000000
Binary files a/sound/piano/En6.ogg and /dev/null differ
diff --git a/sound/piano/En7.ogg b/sound/piano/En7.ogg
deleted file mode 100644
index 0793106be1f4..000000000000
Binary files a/sound/piano/En7.ogg and /dev/null differ
diff --git a/sound/piano/En8.ogg b/sound/piano/En8.ogg
deleted file mode 100644
index 2989d16d1ded..000000000000
Binary files a/sound/piano/En8.ogg and /dev/null differ
diff --git a/sound/piano/F#1.ogg b/sound/piano/F#1.ogg
deleted file mode 100644
index f646e20a3385..000000000000
Binary files a/sound/piano/F#1.ogg and /dev/null differ
diff --git a/sound/piano/F#2.ogg b/sound/piano/F#2.ogg
deleted file mode 100644
index 140c0ab01750..000000000000
Binary files a/sound/piano/F#2.ogg and /dev/null differ
diff --git a/sound/piano/F#3.ogg b/sound/piano/F#3.ogg
deleted file mode 100644
index 03f74deae5e7..000000000000
Binary files a/sound/piano/F#3.ogg and /dev/null differ
diff --git a/sound/piano/F#4.ogg b/sound/piano/F#4.ogg
deleted file mode 100644
index 8b6be4a8e83e..000000000000
Binary files a/sound/piano/F#4.ogg and /dev/null differ
diff --git a/sound/piano/F#5.ogg b/sound/piano/F#5.ogg
deleted file mode 100644
index 2ada429e53c6..000000000000
Binary files a/sound/piano/F#5.ogg and /dev/null differ
diff --git a/sound/piano/F#6.ogg b/sound/piano/F#6.ogg
deleted file mode 100644
index a3c41995a142..000000000000
Binary files a/sound/piano/F#6.ogg and /dev/null differ
diff --git a/sound/piano/F#7.ogg b/sound/piano/F#7.ogg
deleted file mode 100644
index 8c87e9c8b7bd..000000000000
Binary files a/sound/piano/F#7.ogg and /dev/null differ
diff --git a/sound/piano/F#8.ogg b/sound/piano/F#8.ogg
deleted file mode 100644
index 7a20d3cd3d4a..000000000000
Binary files a/sound/piano/F#8.ogg and /dev/null differ
diff --git a/sound/piano/Fb1.ogg b/sound/piano/Fb1.ogg
deleted file mode 100644
index ba3f5bde8ca0..000000000000
Binary files a/sound/piano/Fb1.ogg and /dev/null differ
diff --git a/sound/piano/Fb2.ogg b/sound/piano/Fb2.ogg
deleted file mode 100644
index d601261c9218..000000000000
Binary files a/sound/piano/Fb2.ogg and /dev/null differ
diff --git a/sound/piano/Fb3.ogg b/sound/piano/Fb3.ogg
deleted file mode 100644
index 0c67f09c6e71..000000000000
Binary files a/sound/piano/Fb3.ogg and /dev/null differ
diff --git a/sound/piano/Fb4.ogg b/sound/piano/Fb4.ogg
deleted file mode 100644
index 6b23e1dca8bc..000000000000
Binary files a/sound/piano/Fb4.ogg and /dev/null differ
diff --git a/sound/piano/Fb5.ogg b/sound/piano/Fb5.ogg
deleted file mode 100644
index 992fbef3c832..000000000000
Binary files a/sound/piano/Fb5.ogg and /dev/null differ
diff --git a/sound/piano/Fb6.ogg b/sound/piano/Fb6.ogg
deleted file mode 100644
index 622859f44d54..000000000000
Binary files a/sound/piano/Fb6.ogg and /dev/null differ
diff --git a/sound/piano/Fb7.ogg b/sound/piano/Fb7.ogg
deleted file mode 100644
index bb44482880ca..000000000000
Binary files a/sound/piano/Fb7.ogg and /dev/null differ
diff --git a/sound/piano/Fb8.ogg b/sound/piano/Fb8.ogg
deleted file mode 100644
index 940c92efafa5..000000000000
Binary files a/sound/piano/Fb8.ogg and /dev/null differ
diff --git a/sound/piano/Fn1.ogg b/sound/piano/Fn1.ogg
deleted file mode 100644
index 52a717014860..000000000000
Binary files a/sound/piano/Fn1.ogg and /dev/null differ
diff --git a/sound/piano/Fn2.ogg b/sound/piano/Fn2.ogg
deleted file mode 100644
index 28770a787229..000000000000
Binary files a/sound/piano/Fn2.ogg and /dev/null differ
diff --git a/sound/piano/Fn3.ogg b/sound/piano/Fn3.ogg
deleted file mode 100644
index 5db839ab9cbb..000000000000
Binary files a/sound/piano/Fn3.ogg and /dev/null differ
diff --git a/sound/piano/Fn4.ogg b/sound/piano/Fn4.ogg
deleted file mode 100644
index 5a4437102ae4..000000000000
Binary files a/sound/piano/Fn4.ogg and /dev/null differ
diff --git a/sound/piano/Fn5.ogg b/sound/piano/Fn5.ogg
deleted file mode 100644
index fb748454480c..000000000000
Binary files a/sound/piano/Fn5.ogg and /dev/null differ
diff --git a/sound/piano/Fn6.ogg b/sound/piano/Fn6.ogg
deleted file mode 100644
index 3e23b71b1ef5..000000000000
Binary files a/sound/piano/Fn6.ogg and /dev/null differ
diff --git a/sound/piano/Fn7.ogg b/sound/piano/Fn7.ogg
deleted file mode 100644
index d897ab7c3c8f..000000000000
Binary files a/sound/piano/Fn7.ogg and /dev/null differ
diff --git a/sound/piano/Fn8.ogg b/sound/piano/Fn8.ogg
deleted file mode 100644
index 3ebf0e9bbc49..000000000000
Binary files a/sound/piano/Fn8.ogg and /dev/null differ
diff --git a/sound/piano/G#1.ogg b/sound/piano/G#1.ogg
deleted file mode 100644
index 4b559e5583ac..000000000000
Binary files a/sound/piano/G#1.ogg and /dev/null differ
diff --git a/sound/piano/G#2.ogg b/sound/piano/G#2.ogg
deleted file mode 100644
index d70745db3e76..000000000000
Binary files a/sound/piano/G#2.ogg and /dev/null differ
diff --git a/sound/piano/G#3.ogg b/sound/piano/G#3.ogg
deleted file mode 100644
index cb69b23a17af..000000000000
Binary files a/sound/piano/G#3.ogg and /dev/null differ
diff --git a/sound/piano/G#4.ogg b/sound/piano/G#4.ogg
deleted file mode 100644
index fc0965821fc5..000000000000
Binary files a/sound/piano/G#4.ogg and /dev/null differ
diff --git a/sound/piano/G#5.ogg b/sound/piano/G#5.ogg
deleted file mode 100644
index 845c02160cc9..000000000000
Binary files a/sound/piano/G#5.ogg and /dev/null differ
diff --git a/sound/piano/G#6.ogg b/sound/piano/G#6.ogg
deleted file mode 100644
index 934f281311c1..000000000000
Binary files a/sound/piano/G#6.ogg and /dev/null differ
diff --git a/sound/piano/G#7.ogg b/sound/piano/G#7.ogg
deleted file mode 100644
index 0366b7a74b33..000000000000
Binary files a/sound/piano/G#7.ogg and /dev/null differ
diff --git a/sound/piano/G#8.ogg b/sound/piano/G#8.ogg
deleted file mode 100644
index 5c7f1b3fa57c..000000000000
Binary files a/sound/piano/G#8.ogg and /dev/null differ
diff --git a/sound/piano/Gb1.ogg b/sound/piano/Gb1.ogg
deleted file mode 100644
index 229e2e5d477e..000000000000
Binary files a/sound/piano/Gb1.ogg and /dev/null differ
diff --git a/sound/piano/Gb2.ogg b/sound/piano/Gb2.ogg
deleted file mode 100644
index c22963c95b67..000000000000
Binary files a/sound/piano/Gb2.ogg and /dev/null differ
diff --git a/sound/piano/Gb3.ogg b/sound/piano/Gb3.ogg
deleted file mode 100644
index de273ab8d200..000000000000
Binary files a/sound/piano/Gb3.ogg and /dev/null differ
diff --git a/sound/piano/Gb4.ogg b/sound/piano/Gb4.ogg
deleted file mode 100644
index 383d7a9212bf..000000000000
Binary files a/sound/piano/Gb4.ogg and /dev/null differ
diff --git a/sound/piano/Gb5.ogg b/sound/piano/Gb5.ogg
deleted file mode 100644
index e84ca674898a..000000000000
Binary files a/sound/piano/Gb5.ogg and /dev/null differ
diff --git a/sound/piano/Gb6.ogg b/sound/piano/Gb6.ogg
deleted file mode 100644
index d6171c668f75..000000000000
Binary files a/sound/piano/Gb6.ogg and /dev/null differ
diff --git a/sound/piano/Gb7.ogg b/sound/piano/Gb7.ogg
deleted file mode 100644
index c47bff993c11..000000000000
Binary files a/sound/piano/Gb7.ogg and /dev/null differ
diff --git a/sound/piano/Gb8.ogg b/sound/piano/Gb8.ogg
deleted file mode 100644
index bdd5e3396642..000000000000
Binary files a/sound/piano/Gb8.ogg and /dev/null differ
diff --git a/sound/piano/Gn1.ogg b/sound/piano/Gn1.ogg
deleted file mode 100644
index b78d3f44faa5..000000000000
Binary files a/sound/piano/Gn1.ogg and /dev/null differ
diff --git a/sound/piano/Gn2.ogg b/sound/piano/Gn2.ogg
deleted file mode 100644
index 4cc8e85d33fd..000000000000
Binary files a/sound/piano/Gn2.ogg and /dev/null differ
diff --git a/sound/piano/Gn3.ogg b/sound/piano/Gn3.ogg
deleted file mode 100644
index 65a0a83b7e9c..000000000000
Binary files a/sound/piano/Gn3.ogg and /dev/null differ
diff --git a/sound/piano/Gn4.ogg b/sound/piano/Gn4.ogg
deleted file mode 100644
index ac88f21a5168..000000000000
Binary files a/sound/piano/Gn4.ogg and /dev/null differ
diff --git a/sound/piano/Gn5.ogg b/sound/piano/Gn5.ogg
deleted file mode 100644
index a2cd6b032cf9..000000000000
Binary files a/sound/piano/Gn5.ogg and /dev/null differ
diff --git a/sound/piano/Gn6.ogg b/sound/piano/Gn6.ogg
deleted file mode 100644
index 6e22bdeae80c..000000000000
Binary files a/sound/piano/Gn6.ogg and /dev/null differ
diff --git a/sound/piano/Gn7.ogg b/sound/piano/Gn7.ogg
deleted file mode 100644
index 3c2af2907da7..000000000000
Binary files a/sound/piano/Gn7.ogg and /dev/null differ
diff --git a/sound/piano/Gn8.ogg b/sound/piano/Gn8.ogg
deleted file mode 100644
index f27b35f10abd..000000000000
Binary files a/sound/piano/Gn8.ogg and /dev/null differ
diff --git a/sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg b/sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg
new file mode 100644
index 000000000000..9fe0b4c11da1
Binary files /dev/null and b/sound/vehicles/Dropships/single_alarm_brr_dropship_1.ogg differ
diff --git a/sound/violin/A#1.mid b/sound/violin/A#1.mid
deleted file mode 100644
index 693b73f5420f..000000000000
Binary files a/sound/violin/A#1.mid and /dev/null differ
diff --git a/sound/violin/A#2.mid b/sound/violin/A#2.mid
deleted file mode 100644
index 40da5f3da152..000000000000
Binary files a/sound/violin/A#2.mid and /dev/null differ
diff --git a/sound/violin/A#3.mid b/sound/violin/A#3.mid
deleted file mode 100644
index 5bab6ccd6362..000000000000
Binary files a/sound/violin/A#3.mid and /dev/null differ
diff --git a/sound/violin/A#4.mid b/sound/violin/A#4.mid
deleted file mode 100644
index dce830448ef8..000000000000
Binary files a/sound/violin/A#4.mid and /dev/null differ
diff --git a/sound/violin/A#5.mid b/sound/violin/A#5.mid
deleted file mode 100644
index fda796e27b90..000000000000
Binary files a/sound/violin/A#5.mid and /dev/null differ
diff --git a/sound/violin/A#6.mid b/sound/violin/A#6.mid
deleted file mode 100644
index 9e5da684f43c..000000000000
Binary files a/sound/violin/A#6.mid and /dev/null differ
diff --git a/sound/violin/A#7.mid b/sound/violin/A#7.mid
deleted file mode 100644
index 215c56cbe7ee..000000000000
Binary files a/sound/violin/A#7.mid and /dev/null differ
diff --git a/sound/violin/A#8.mid b/sound/violin/A#8.mid
deleted file mode 100644
index 4b55c34691f7..000000000000
Binary files a/sound/violin/A#8.mid and /dev/null differ
diff --git a/sound/violin/Ab1.mid b/sound/violin/Ab1.mid
deleted file mode 100644
index b8253364b4e8..000000000000
Binary files a/sound/violin/Ab1.mid and /dev/null differ
diff --git a/sound/violin/Ab2.mid b/sound/violin/Ab2.mid
deleted file mode 100644
index 4cd7f9b55a7c..000000000000
Binary files a/sound/violin/Ab2.mid and /dev/null differ
diff --git a/sound/violin/Ab3.mid b/sound/violin/Ab3.mid
deleted file mode 100644
index e827cfc635ee..000000000000
Binary files a/sound/violin/Ab3.mid and /dev/null differ
diff --git a/sound/violin/Ab4.mid b/sound/violin/Ab4.mid
deleted file mode 100644
index 57e1f76c9761..000000000000
Binary files a/sound/violin/Ab4.mid and /dev/null differ
diff --git a/sound/violin/Ab5.mid b/sound/violin/Ab5.mid
deleted file mode 100644
index 59e95a6d9974..000000000000
Binary files a/sound/violin/Ab5.mid and /dev/null differ
diff --git a/sound/violin/Ab6.mid b/sound/violin/Ab6.mid
deleted file mode 100644
index 9bd3436287b9..000000000000
Binary files a/sound/violin/Ab6.mid and /dev/null differ
diff --git a/sound/violin/Ab7.mid b/sound/violin/Ab7.mid
deleted file mode 100644
index 3c90af807e27..000000000000
Binary files a/sound/violin/Ab7.mid and /dev/null differ
diff --git a/sound/violin/Ab8.mid b/sound/violin/Ab8.mid
deleted file mode 100644
index 873d771f2aea..000000000000
Binary files a/sound/violin/Ab8.mid and /dev/null differ
diff --git a/sound/violin/An1.mid b/sound/violin/An1.mid
deleted file mode 100644
index d7f8a001d93f..000000000000
Binary files a/sound/violin/An1.mid and /dev/null differ
diff --git a/sound/violin/An2.mid b/sound/violin/An2.mid
deleted file mode 100644
index 2f01800a0754..000000000000
Binary files a/sound/violin/An2.mid and /dev/null differ
diff --git a/sound/violin/An3.mid b/sound/violin/An3.mid
deleted file mode 100644
index c8ed3cdfa6cb..000000000000
Binary files a/sound/violin/An3.mid and /dev/null differ
diff --git a/sound/violin/An4.mid b/sound/violin/An4.mid
deleted file mode 100644
index e7984ca7e62b..000000000000
Binary files a/sound/violin/An4.mid and /dev/null differ
diff --git a/sound/violin/An5.mid b/sound/violin/An5.mid
deleted file mode 100644
index e1fd228f7a9e..000000000000
Binary files a/sound/violin/An5.mid and /dev/null differ
diff --git a/sound/violin/An6.mid b/sound/violin/An6.mid
deleted file mode 100644
index 1c8df6c98e5c..000000000000
Binary files a/sound/violin/An6.mid and /dev/null differ
diff --git a/sound/violin/An7.mid b/sound/violin/An7.mid
deleted file mode 100644
index 2784428daf9e..000000000000
Binary files a/sound/violin/An7.mid and /dev/null differ
diff --git a/sound/violin/An8.mid b/sound/violin/An8.mid
deleted file mode 100644
index 2db2ab70a7d9..000000000000
Binary files a/sound/violin/An8.mid and /dev/null differ
diff --git a/sound/violin/B#1.mid b/sound/violin/B#1.mid
deleted file mode 100644
index d83b176edd8b..000000000000
Binary files a/sound/violin/B#1.mid and /dev/null differ
diff --git a/sound/violin/B#2.mid b/sound/violin/B#2.mid
deleted file mode 100644
index cddff75625f0..000000000000
Binary files a/sound/violin/B#2.mid and /dev/null differ
diff --git a/sound/violin/B#3.mid b/sound/violin/B#3.mid
deleted file mode 100644
index 8bd7ec2fa9d6..000000000000
Binary files a/sound/violin/B#3.mid and /dev/null differ
diff --git a/sound/violin/B#4.mid b/sound/violin/B#4.mid
deleted file mode 100644
index 4c7ab84b57be..000000000000
Binary files a/sound/violin/B#4.mid and /dev/null differ
diff --git a/sound/violin/B#5.mid b/sound/violin/B#5.mid
deleted file mode 100644
index d7f990b2d6c3..000000000000
Binary files a/sound/violin/B#5.mid and /dev/null differ
diff --git a/sound/violin/B#6.mid b/sound/violin/B#6.mid
deleted file mode 100644
index e124ccb8e2b0..000000000000
Binary files a/sound/violin/B#6.mid and /dev/null differ
diff --git a/sound/violin/B#7.mid b/sound/violin/B#7.mid
deleted file mode 100644
index 231c9e428db5..000000000000
Binary files a/sound/violin/B#7.mid and /dev/null differ
diff --git a/sound/violin/B#8.mid b/sound/violin/B#8.mid
deleted file mode 100644
index 981943c08f0c..000000000000
Binary files a/sound/violin/B#8.mid and /dev/null differ
diff --git a/sound/violin/Bb1.mid b/sound/violin/Bb1.mid
deleted file mode 100644
index 693b73f5420f..000000000000
Binary files a/sound/violin/Bb1.mid and /dev/null differ
diff --git a/sound/violin/Bb2.mid b/sound/violin/Bb2.mid
deleted file mode 100644
index 40da5f3da152..000000000000
Binary files a/sound/violin/Bb2.mid and /dev/null differ
diff --git a/sound/violin/Bb3.mid b/sound/violin/Bb3.mid
deleted file mode 100644
index 5bab6ccd6362..000000000000
Binary files a/sound/violin/Bb3.mid and /dev/null differ
diff --git a/sound/violin/Bb4.mid b/sound/violin/Bb4.mid
deleted file mode 100644
index dce830448ef8..000000000000
Binary files a/sound/violin/Bb4.mid and /dev/null differ
diff --git a/sound/violin/Bb5.mid b/sound/violin/Bb5.mid
deleted file mode 100644
index fda796e27b90..000000000000
Binary files a/sound/violin/Bb5.mid and /dev/null differ
diff --git a/sound/violin/Bb6.mid b/sound/violin/Bb6.mid
deleted file mode 100644
index 9e5da684f43c..000000000000
Binary files a/sound/violin/Bb6.mid and /dev/null differ
diff --git a/sound/violin/Bb7.mid b/sound/violin/Bb7.mid
deleted file mode 100644
index 215c56cbe7ee..000000000000
Binary files a/sound/violin/Bb7.mid and /dev/null differ
diff --git a/sound/violin/Bb8.mid b/sound/violin/Bb8.mid
deleted file mode 100644
index 4b55c34691f7..000000000000
Binary files a/sound/violin/Bb8.mid and /dev/null differ
diff --git a/sound/violin/Bn1.mid b/sound/violin/Bn1.mid
deleted file mode 100644
index 27968b5f9e7d..000000000000
Binary files a/sound/violin/Bn1.mid and /dev/null differ
diff --git a/sound/violin/Bn2.mid b/sound/violin/Bn2.mid
deleted file mode 100644
index 54c9b99d03fe..000000000000
Binary files a/sound/violin/Bn2.mid and /dev/null differ
diff --git a/sound/violin/Bn3.mid b/sound/violin/Bn3.mid
deleted file mode 100644
index f73476fb7bb1..000000000000
Binary files a/sound/violin/Bn3.mid and /dev/null differ
diff --git a/sound/violin/Bn4.mid b/sound/violin/Bn4.mid
deleted file mode 100644
index 2aa30708a6cb..000000000000
Binary files a/sound/violin/Bn4.mid and /dev/null differ
diff --git a/sound/violin/Bn5.mid b/sound/violin/Bn5.mid
deleted file mode 100644
index 0ebe636b7145..000000000000
Binary files a/sound/violin/Bn5.mid and /dev/null differ
diff --git a/sound/violin/Bn6.mid b/sound/violin/Bn6.mid
deleted file mode 100644
index 3b8e1c217f7b..000000000000
Binary files a/sound/violin/Bn6.mid and /dev/null differ
diff --git a/sound/violin/Bn7.mid b/sound/violin/Bn7.mid
deleted file mode 100644
index afcb1982a13f..000000000000
Binary files a/sound/violin/Bn7.mid and /dev/null differ
diff --git a/sound/violin/Bn8.mid b/sound/violin/Bn8.mid
deleted file mode 100644
index 3afd469256c1..000000000000
Binary files a/sound/violin/Bn8.mid and /dev/null differ
diff --git a/sound/violin/C#1.mid b/sound/violin/C#1.mid
deleted file mode 100644
index 88dba851452e..000000000000
Binary files a/sound/violin/C#1.mid and /dev/null differ
diff --git a/sound/violin/C#2.mid b/sound/violin/C#2.mid
deleted file mode 100644
index b510926b45fa..000000000000
Binary files a/sound/violin/C#2.mid and /dev/null differ
diff --git a/sound/violin/C#3.mid b/sound/violin/C#3.mid
deleted file mode 100644
index 9954bbe478a2..000000000000
Binary files a/sound/violin/C#3.mid and /dev/null differ
diff --git a/sound/violin/C#4.mid b/sound/violin/C#4.mid
deleted file mode 100644
index 2c5ff74db0aa..000000000000
Binary files a/sound/violin/C#4.mid and /dev/null differ
diff --git a/sound/violin/C#5.mid b/sound/violin/C#5.mid
deleted file mode 100644
index e5850a3fd041..000000000000
Binary files a/sound/violin/C#5.mid and /dev/null differ
diff --git a/sound/violin/C#6.mid b/sound/violin/C#6.mid
deleted file mode 100644
index 217c0ad014c5..000000000000
Binary files a/sound/violin/C#6.mid and /dev/null differ
diff --git a/sound/violin/C#7.mid b/sound/violin/C#7.mid
deleted file mode 100644
index ec32bdbf9040..000000000000
Binary files a/sound/violin/C#7.mid and /dev/null differ
diff --git a/sound/violin/C#8.mid b/sound/violin/C#8.mid
deleted file mode 100644
index 555bce3db0d8..000000000000
Binary files a/sound/violin/C#8.mid and /dev/null differ
diff --git a/sound/violin/Cb1.mid b/sound/violin/Cb1.mid
deleted file mode 100644
index a00f09dfb088..000000000000
Binary files a/sound/violin/Cb1.mid and /dev/null differ
diff --git a/sound/violin/Cb2.mid b/sound/violin/Cb2.mid
deleted file mode 100644
index 4085711bf127..000000000000
Binary files a/sound/violin/Cb2.mid and /dev/null differ
diff --git a/sound/violin/Cb3.mid b/sound/violin/Cb3.mid
deleted file mode 100644
index f647983ef05c..000000000000
Binary files a/sound/violin/Cb3.mid and /dev/null differ
diff --git a/sound/violin/Cb4.mid b/sound/violin/Cb4.mid
deleted file mode 100644
index 24f22f09eecc..000000000000
Binary files a/sound/violin/Cb4.mid and /dev/null differ
diff --git a/sound/violin/Cb5.mid b/sound/violin/Cb5.mid
deleted file mode 100644
index 057e97c5e0d0..000000000000
Binary files a/sound/violin/Cb5.mid and /dev/null differ
diff --git a/sound/violin/Cb6.mid b/sound/violin/Cb6.mid
deleted file mode 100644
index 887e65fc13d0..000000000000
Binary files a/sound/violin/Cb6.mid and /dev/null differ
diff --git a/sound/violin/Cb7.mid b/sound/violin/Cb7.mid
deleted file mode 100644
index 99668bc192c2..000000000000
Binary files a/sound/violin/Cb7.mid and /dev/null differ
diff --git a/sound/violin/Cb8.mid b/sound/violin/Cb8.mid
deleted file mode 100644
index 53ea61d1b250..000000000000
Binary files a/sound/violin/Cb8.mid and /dev/null differ
diff --git a/sound/violin/Cb9.mid b/sound/violin/Cb9.mid
deleted file mode 100644
index 1e8c3afadf13..000000000000
Binary files a/sound/violin/Cb9.mid and /dev/null differ
diff --git a/sound/violin/Cn1.mid b/sound/violin/Cn1.mid
deleted file mode 100644
index 857120f31f4e..000000000000
Binary files a/sound/violin/Cn1.mid and /dev/null differ
diff --git a/sound/violin/Cn2.mid b/sound/violin/Cn2.mid
deleted file mode 100644
index 3ccd6670e873..000000000000
Binary files a/sound/violin/Cn2.mid and /dev/null differ
diff --git a/sound/violin/Cn3.mid b/sound/violin/Cn3.mid
deleted file mode 100644
index 1851e4f8d27d..000000000000
Binary files a/sound/violin/Cn3.mid and /dev/null differ
diff --git a/sound/violin/Cn4.mid b/sound/violin/Cn4.mid
deleted file mode 100644
index 65e8b0efe4e5..000000000000
Binary files a/sound/violin/Cn4.mid and /dev/null differ
diff --git a/sound/violin/Cn5.mid b/sound/violin/Cn5.mid
deleted file mode 100644
index 544f921e43b9..000000000000
Binary files a/sound/violin/Cn5.mid and /dev/null differ
diff --git a/sound/violin/Cn6.mid b/sound/violin/Cn6.mid
deleted file mode 100644
index 7c78dab2f076..000000000000
Binary files a/sound/violin/Cn6.mid and /dev/null differ
diff --git a/sound/violin/Cn7.mid b/sound/violin/Cn7.mid
deleted file mode 100644
index 3abe4cde0863..000000000000
Binary files a/sound/violin/Cn7.mid and /dev/null differ
diff --git a/sound/violin/Cn8.mid b/sound/violin/Cn8.mid
deleted file mode 100644
index 06f14081b3b9..000000000000
Binary files a/sound/violin/Cn8.mid and /dev/null differ
diff --git a/sound/violin/Cn9.mid b/sound/violin/Cn9.mid
deleted file mode 100644
index 62f4eef045a8..000000000000
Binary files a/sound/violin/Cn9.mid and /dev/null differ
diff --git a/sound/violin/D#1.mid b/sound/violin/D#1.mid
deleted file mode 100644
index 829e6fcf185a..000000000000
Binary files a/sound/violin/D#1.mid and /dev/null differ
diff --git a/sound/violin/D#2.mid b/sound/violin/D#2.mid
deleted file mode 100644
index 66029b340cc9..000000000000
Binary files a/sound/violin/D#2.mid and /dev/null differ
diff --git a/sound/violin/D#3.mid b/sound/violin/D#3.mid
deleted file mode 100644
index c982375941e6..000000000000
Binary files a/sound/violin/D#3.mid and /dev/null differ
diff --git a/sound/violin/D#4.mid b/sound/violin/D#4.mid
deleted file mode 100644
index 016ed4f1edf9..000000000000
Binary files a/sound/violin/D#4.mid and /dev/null differ
diff --git a/sound/violin/D#5.mid b/sound/violin/D#5.mid
deleted file mode 100644
index ddb511795df2..000000000000
Binary files a/sound/violin/D#5.mid and /dev/null differ
diff --git a/sound/violin/D#6.mid b/sound/violin/D#6.mid
deleted file mode 100644
index b7242b9ab994..000000000000
Binary files a/sound/violin/D#6.mid and /dev/null differ
diff --git a/sound/violin/D#7.mid b/sound/violin/D#7.mid
deleted file mode 100644
index 773538340a56..000000000000
Binary files a/sound/violin/D#7.mid and /dev/null differ
diff --git a/sound/violin/D#8.mid b/sound/violin/D#8.mid
deleted file mode 100644
index 4ad074e173b7..000000000000
Binary files a/sound/violin/D#8.mid and /dev/null differ
diff --git a/sound/violin/Db1.mid b/sound/violin/Db1.mid
deleted file mode 100644
index 88dba851452e..000000000000
Binary files a/sound/violin/Db1.mid and /dev/null differ
diff --git a/sound/violin/Db2.mid b/sound/violin/Db2.mid
deleted file mode 100644
index b510926b45fa..000000000000
Binary files a/sound/violin/Db2.mid and /dev/null differ
diff --git a/sound/violin/Db3.mid b/sound/violin/Db3.mid
deleted file mode 100644
index 9954bbe478a2..000000000000
Binary files a/sound/violin/Db3.mid and /dev/null differ
diff --git a/sound/violin/Db4.mid b/sound/violin/Db4.mid
deleted file mode 100644
index 2c5ff74db0aa..000000000000
Binary files a/sound/violin/Db4.mid and /dev/null differ
diff --git a/sound/violin/Db5.mid b/sound/violin/Db5.mid
deleted file mode 100644
index e5850a3fd041..000000000000
Binary files a/sound/violin/Db5.mid and /dev/null differ
diff --git a/sound/violin/Db6.mid b/sound/violin/Db6.mid
deleted file mode 100644
index 217c0ad014c5..000000000000
Binary files a/sound/violin/Db6.mid and /dev/null differ
diff --git a/sound/violin/Db7.mid b/sound/violin/Db7.mid
deleted file mode 100644
index ec32bdbf9040..000000000000
Binary files a/sound/violin/Db7.mid and /dev/null differ
diff --git a/sound/violin/Db8.mid b/sound/violin/Db8.mid
deleted file mode 100644
index 555bce3db0d8..000000000000
Binary files a/sound/violin/Db8.mid and /dev/null differ
diff --git a/sound/violin/Dn1.mid b/sound/violin/Dn1.mid
deleted file mode 100644
index 92e4e0d95816..000000000000
Binary files a/sound/violin/Dn1.mid and /dev/null differ
diff --git a/sound/violin/Dn2.mid b/sound/violin/Dn2.mid
deleted file mode 100644
index 34eb9d1db1ba..000000000000
Binary files a/sound/violin/Dn2.mid and /dev/null differ
diff --git a/sound/violin/Dn3.mid b/sound/violin/Dn3.mid
deleted file mode 100644
index fbd56085aafa..000000000000
Binary files a/sound/violin/Dn3.mid and /dev/null differ
diff --git a/sound/violin/Dn4.mid b/sound/violin/Dn4.mid
deleted file mode 100644
index e13c74482921..000000000000
Binary files a/sound/violin/Dn4.mid and /dev/null differ
diff --git a/sound/violin/Dn5.mid b/sound/violin/Dn5.mid
deleted file mode 100644
index 8fd41e5c6fe0..000000000000
Binary files a/sound/violin/Dn5.mid and /dev/null differ
diff --git a/sound/violin/Dn6.mid b/sound/violin/Dn6.mid
deleted file mode 100644
index d47329e8f9ed..000000000000
Binary files a/sound/violin/Dn6.mid and /dev/null differ
diff --git a/sound/violin/Dn7.mid b/sound/violin/Dn7.mid
deleted file mode 100644
index b24966038762..000000000000
Binary files a/sound/violin/Dn7.mid and /dev/null differ
diff --git a/sound/violin/Dn8.mid b/sound/violin/Dn8.mid
deleted file mode 100644
index 56667a1a86d0..000000000000
Binary files a/sound/violin/Dn8.mid and /dev/null differ
diff --git a/sound/violin/E#1.mid b/sound/violin/E#1.mid
deleted file mode 100644
index 3f130ee126c1..000000000000
Binary files a/sound/violin/E#1.mid and /dev/null differ
diff --git a/sound/violin/E#2.mid b/sound/violin/E#2.mid
deleted file mode 100644
index f67c2d0a2673..000000000000
Binary files a/sound/violin/E#2.mid and /dev/null differ
diff --git a/sound/violin/E#3.mid b/sound/violin/E#3.mid
deleted file mode 100644
index bb393382d6c8..000000000000
Binary files a/sound/violin/E#3.mid and /dev/null differ
diff --git a/sound/violin/E#4.mid b/sound/violin/E#4.mid
deleted file mode 100644
index a96520c595d3..000000000000
Binary files a/sound/violin/E#4.mid and /dev/null differ
diff --git a/sound/violin/E#5.mid b/sound/violin/E#5.mid
deleted file mode 100644
index d1378af1972d..000000000000
Binary files a/sound/violin/E#5.mid and /dev/null differ
diff --git a/sound/violin/E#6.mid b/sound/violin/E#6.mid
deleted file mode 100644
index 7abe40bd8242..000000000000
Binary files a/sound/violin/E#6.mid and /dev/null differ
diff --git a/sound/violin/E#7.mid b/sound/violin/E#7.mid
deleted file mode 100644
index df278c20d6b6..000000000000
Binary files a/sound/violin/E#7.mid and /dev/null differ
diff --git a/sound/violin/E#8.mid b/sound/violin/E#8.mid
deleted file mode 100644
index 35254cd5b25b..000000000000
Binary files a/sound/violin/E#8.mid and /dev/null differ
diff --git a/sound/violin/Eb1.mid b/sound/violin/Eb1.mid
deleted file mode 100644
index 829e6fcf185a..000000000000
Binary files a/sound/violin/Eb1.mid and /dev/null differ
diff --git a/sound/violin/Eb2.mid b/sound/violin/Eb2.mid
deleted file mode 100644
index 66029b340cc9..000000000000
Binary files a/sound/violin/Eb2.mid and /dev/null differ
diff --git a/sound/violin/Eb3.mid b/sound/violin/Eb3.mid
deleted file mode 100644
index c982375941e6..000000000000
Binary files a/sound/violin/Eb3.mid and /dev/null differ
diff --git a/sound/violin/Eb4.mid b/sound/violin/Eb4.mid
deleted file mode 100644
index 016ed4f1edf9..000000000000
Binary files a/sound/violin/Eb4.mid and /dev/null differ
diff --git a/sound/violin/Eb5.mid b/sound/violin/Eb5.mid
deleted file mode 100644
index ddb511795df2..000000000000
Binary files a/sound/violin/Eb5.mid and /dev/null differ
diff --git a/sound/violin/Eb6.mid b/sound/violin/Eb6.mid
deleted file mode 100644
index b7242b9ab994..000000000000
Binary files a/sound/violin/Eb6.mid and /dev/null differ
diff --git a/sound/violin/Eb7.mid b/sound/violin/Eb7.mid
deleted file mode 100644
index 773538340a56..000000000000
Binary files a/sound/violin/Eb7.mid and /dev/null differ
diff --git a/sound/violin/Eb8.mid b/sound/violin/Eb8.mid
deleted file mode 100644
index 4ad074e173b7..000000000000
Binary files a/sound/violin/Eb8.mid and /dev/null differ
diff --git a/sound/violin/En1.mid b/sound/violin/En1.mid
deleted file mode 100644
index 79ab68df9df7..000000000000
Binary files a/sound/violin/En1.mid and /dev/null differ
diff --git a/sound/violin/En2.mid b/sound/violin/En2.mid
deleted file mode 100644
index cd61c8d0de5b..000000000000
Binary files a/sound/violin/En2.mid and /dev/null differ
diff --git a/sound/violin/En3.mid b/sound/violin/En3.mid
deleted file mode 100644
index da5b703d545b..000000000000
Binary files a/sound/violin/En3.mid and /dev/null differ
diff --git a/sound/violin/En4.mid b/sound/violin/En4.mid
deleted file mode 100644
index f7d3af024ff2..000000000000
Binary files a/sound/violin/En4.mid and /dev/null differ
diff --git a/sound/violin/En5.mid b/sound/violin/En5.mid
deleted file mode 100644
index d3d353943f9d..000000000000
Binary files a/sound/violin/En5.mid and /dev/null differ
diff --git a/sound/violin/En6.mid b/sound/violin/En6.mid
deleted file mode 100644
index 73eb5b0697db..000000000000
Binary files a/sound/violin/En6.mid and /dev/null differ
diff --git a/sound/violin/En7.mid b/sound/violin/En7.mid
deleted file mode 100644
index 79a9462c844e..000000000000
Binary files a/sound/violin/En7.mid and /dev/null differ
diff --git a/sound/violin/En8.mid b/sound/violin/En8.mid
deleted file mode 100644
index 88947fc7318e..000000000000
Binary files a/sound/violin/En8.mid and /dev/null differ
diff --git a/sound/violin/F#1.mid b/sound/violin/F#1.mid
deleted file mode 100644
index d18668e89112..000000000000
Binary files a/sound/violin/F#1.mid and /dev/null differ
diff --git a/sound/violin/F#2.mid b/sound/violin/F#2.mid
deleted file mode 100644
index 302f0c6fdc15..000000000000
Binary files a/sound/violin/F#2.mid and /dev/null differ
diff --git a/sound/violin/F#3.mid b/sound/violin/F#3.mid
deleted file mode 100644
index 1f592fc90399..000000000000
Binary files a/sound/violin/F#3.mid and /dev/null differ
diff --git a/sound/violin/F#4.mid b/sound/violin/F#4.mid
deleted file mode 100644
index 45854126f988..000000000000
Binary files a/sound/violin/F#4.mid and /dev/null differ
diff --git a/sound/violin/F#5.mid b/sound/violin/F#5.mid
deleted file mode 100644
index fb1e1da339a9..000000000000
Binary files a/sound/violin/F#5.mid and /dev/null differ
diff --git a/sound/violin/F#6.mid b/sound/violin/F#6.mid
deleted file mode 100644
index bfa896bb7844..000000000000
Binary files a/sound/violin/F#6.mid and /dev/null differ
diff --git a/sound/violin/F#7.mid b/sound/violin/F#7.mid
deleted file mode 100644
index a27763c1d47d..000000000000
Binary files a/sound/violin/F#7.mid and /dev/null differ
diff --git a/sound/violin/F#8.mid b/sound/violin/F#8.mid
deleted file mode 100644
index aaab80a72762..000000000000
Binary files a/sound/violin/F#8.mid and /dev/null differ
diff --git a/sound/violin/Fb1.mid b/sound/violin/Fb1.mid
deleted file mode 100644
index c89b3f36b439..000000000000
Binary files a/sound/violin/Fb1.mid and /dev/null differ
diff --git a/sound/violin/Fb2.mid b/sound/violin/Fb2.mid
deleted file mode 100644
index 3db6af1aa459..000000000000
Binary files a/sound/violin/Fb2.mid and /dev/null differ
diff --git a/sound/violin/Fb3.mid b/sound/violin/Fb3.mid
deleted file mode 100644
index 5f601f3ac424..000000000000
Binary files a/sound/violin/Fb3.mid and /dev/null differ
diff --git a/sound/violin/Fb4.mid b/sound/violin/Fb4.mid
deleted file mode 100644
index f1abc8109d1e..000000000000
Binary files a/sound/violin/Fb4.mid and /dev/null differ
diff --git a/sound/violin/Fb5.mid b/sound/violin/Fb5.mid
deleted file mode 100644
index 2ec1b2e51283..000000000000
Binary files a/sound/violin/Fb5.mid and /dev/null differ
diff --git a/sound/violin/Fb6.mid b/sound/violin/Fb6.mid
deleted file mode 100644
index b8bdf7fee071..000000000000
Binary files a/sound/violin/Fb6.mid and /dev/null differ
diff --git a/sound/violin/Fb7.mid b/sound/violin/Fb7.mid
deleted file mode 100644
index 51f5f1bcdb48..000000000000
Binary files a/sound/violin/Fb7.mid and /dev/null differ
diff --git a/sound/violin/Fb8.mid b/sound/violin/Fb8.mid
deleted file mode 100644
index 47928f38475c..000000000000
Binary files a/sound/violin/Fb8.mid and /dev/null differ
diff --git a/sound/violin/Fn1.mid b/sound/violin/Fn1.mid
deleted file mode 100644
index abe0d4e4051b..000000000000
Binary files a/sound/violin/Fn1.mid and /dev/null differ
diff --git a/sound/violin/Fn2.mid b/sound/violin/Fn2.mid
deleted file mode 100644
index d245bef3b54c..000000000000
Binary files a/sound/violin/Fn2.mid and /dev/null differ
diff --git a/sound/violin/Fn3.mid b/sound/violin/Fn3.mid
deleted file mode 100644
index e532e30dac9c..000000000000
Binary files a/sound/violin/Fn3.mid and /dev/null differ
diff --git a/sound/violin/Fn4.mid b/sound/violin/Fn4.mid
deleted file mode 100644
index 47219c72fa2e..000000000000
Binary files a/sound/violin/Fn4.mid and /dev/null differ
diff --git a/sound/violin/Fn5.mid b/sound/violin/Fn5.mid
deleted file mode 100644
index 630d16371d9e..000000000000
Binary files a/sound/violin/Fn5.mid and /dev/null differ
diff --git a/sound/violin/Fn6.mid b/sound/violin/Fn6.mid
deleted file mode 100644
index 08cbc981bdb6..000000000000
Binary files a/sound/violin/Fn6.mid and /dev/null differ
diff --git a/sound/violin/Fn7.mid b/sound/violin/Fn7.mid
deleted file mode 100644
index 6c28c7d272e2..000000000000
Binary files a/sound/violin/Fn7.mid and /dev/null differ
diff --git a/sound/violin/Fn8.mid b/sound/violin/Fn8.mid
deleted file mode 100644
index 2d73762f269a..000000000000
Binary files a/sound/violin/Fn8.mid and /dev/null differ
diff --git a/sound/violin/G#1.mid b/sound/violin/G#1.mid
deleted file mode 100644
index b1b38856858c..000000000000
Binary files a/sound/violin/G#1.mid and /dev/null differ
diff --git a/sound/violin/G#2.mid b/sound/violin/G#2.mid
deleted file mode 100644
index e827cfc635ee..000000000000
Binary files a/sound/violin/G#2.mid and /dev/null differ
diff --git a/sound/violin/G#3.mid b/sound/violin/G#3.mid
deleted file mode 100644
index 57e1f76c9761..000000000000
Binary files a/sound/violin/G#3.mid and /dev/null differ
diff --git a/sound/violin/G#4.mid b/sound/violin/G#4.mid
deleted file mode 100644
index 59e95a6d9974..000000000000
Binary files a/sound/violin/G#4.mid and /dev/null differ
diff --git a/sound/violin/G#5.mid b/sound/violin/G#5.mid
deleted file mode 100644
index 9bd3436287b9..000000000000
Binary files a/sound/violin/G#5.mid and /dev/null differ
diff --git a/sound/violin/G#6.mid b/sound/violin/G#6.mid
deleted file mode 100644
index 3c90af807e27..000000000000
Binary files a/sound/violin/G#6.mid and /dev/null differ
diff --git a/sound/violin/G#7.mid b/sound/violin/G#7.mid
deleted file mode 100644
index b51afd323c64..000000000000
Binary files a/sound/violin/G#7.mid and /dev/null differ
diff --git a/sound/violin/G#8.mid b/sound/violin/G#8.mid
deleted file mode 100644
index d3f5c898d47d..000000000000
Binary files a/sound/violin/G#8.mid and /dev/null differ
diff --git a/sound/violin/Gb1.mid b/sound/violin/Gb1.mid
deleted file mode 100644
index d18668e89112..000000000000
Binary files a/sound/violin/Gb1.mid and /dev/null differ
diff --git a/sound/violin/Gb2.mid b/sound/violin/Gb2.mid
deleted file mode 100644
index 302f0c6fdc15..000000000000
Binary files a/sound/violin/Gb2.mid and /dev/null differ
diff --git a/sound/violin/Gb3.mid b/sound/violin/Gb3.mid
deleted file mode 100644
index 1f592fc90399..000000000000
Binary files a/sound/violin/Gb3.mid and /dev/null differ
diff --git a/sound/violin/Gb4.mid b/sound/violin/Gb4.mid
deleted file mode 100644
index 45854126f988..000000000000
Binary files a/sound/violin/Gb4.mid and /dev/null differ
diff --git a/sound/violin/Gb5.mid b/sound/violin/Gb5.mid
deleted file mode 100644
index fb1e1da339a9..000000000000
Binary files a/sound/violin/Gb5.mid and /dev/null differ
diff --git a/sound/violin/Gb6.mid b/sound/violin/Gb6.mid
deleted file mode 100644
index bfa896bb7844..000000000000
Binary files a/sound/violin/Gb6.mid and /dev/null differ
diff --git a/sound/violin/Gb7.mid b/sound/violin/Gb7.mid
deleted file mode 100644
index a27763c1d47d..000000000000
Binary files a/sound/violin/Gb7.mid and /dev/null differ
diff --git a/sound/violin/Gb8.mid b/sound/violin/Gb8.mid
deleted file mode 100644
index aaab80a72762..000000000000
Binary files a/sound/violin/Gb8.mid and /dev/null differ
diff --git a/sound/violin/Gn1.mid b/sound/violin/Gn1.mid
deleted file mode 100644
index 1df52ab07606..000000000000
Binary files a/sound/violin/Gn1.mid and /dev/null differ
diff --git a/sound/violin/Gn2.mid b/sound/violin/Gn2.mid
deleted file mode 100644
index 6e0ca3831272..000000000000
Binary files a/sound/violin/Gn2.mid and /dev/null differ
diff --git a/sound/violin/Gn3.mid b/sound/violin/Gn3.mid
deleted file mode 100644
index bb3e6dedcbf9..000000000000
Binary files a/sound/violin/Gn3.mid and /dev/null differ
diff --git a/sound/violin/Gn4.mid b/sound/violin/Gn4.mid
deleted file mode 100644
index 0c46432afee5..000000000000
Binary files a/sound/violin/Gn4.mid and /dev/null differ
diff --git a/sound/violin/Gn5.mid b/sound/violin/Gn5.mid
deleted file mode 100644
index f39dcf5e2b9f..000000000000
Binary files a/sound/violin/Gn5.mid and /dev/null differ
diff --git a/sound/violin/Gn6.mid b/sound/violin/Gn6.mid
deleted file mode 100644
index 0efa2259ca17..000000000000
Binary files a/sound/violin/Gn6.mid and /dev/null differ
diff --git a/sound/violin/Gn7.mid b/sound/violin/Gn7.mid
deleted file mode 100644
index 22fd1b6bcb00..000000000000
Binary files a/sound/violin/Gn7.mid and /dev/null differ
diff --git a/sound/violin/Gn8.mid b/sound/violin/Gn8.mid
deleted file mode 100644
index 16b7171d627c..000000000000
Binary files a/sound/violin/Gn8.mid and /dev/null differ
diff --git a/sound/voice/human_male_scream_6.ogg b/sound/voice/human_male_scream_6.ogg
new file mode 100644
index 000000000000..0005a26bf7ac
Binary files /dev/null and b/sound/voice/human_male_scream_6.ogg differ
diff --git a/sound/weapons/gun_xm88_directhit_high.ogg b/sound/weapons/gun_xm88_directhit_high.ogg
new file mode 100644
index 000000000000..6db42f73cf0e
Binary files /dev/null and b/sound/weapons/gun_xm88_directhit_high.ogg differ
diff --git a/sound/weapons/gun_xm88_directhit_low.ogg b/sound/weapons/gun_xm88_directhit_low.ogg
new file mode 100644
index 000000000000..c516f4fc2650
Binary files /dev/null and b/sound/weapons/gun_xm88_directhit_low.ogg differ
diff --git a/sound/weapons/gun_xm88_directhit_medium.ogg b/sound/weapons/gun_xm88_directhit_medium.ogg
new file mode 100644
index 000000000000..106fd23cb981
Binary files /dev/null and b/sound/weapons/gun_xm88_directhit_medium.ogg differ
diff --git a/strings/marinetips.txt b/strings/marinetips.txt
index cf808884f1e5..416c9ef0a4dd 100644
--- a/strings/marinetips.txt
+++ b/strings/marinetips.txt
@@ -53,35 +53,51 @@ A misloaded OB can deviate severely from the intended target area - ensure you l
The XO and CO are trained in Power Loader use and engineering, and can load the OB.
You can change what your SL tracker beacon is tracking by right clicking on your headset and clicking "Switch Tracker Target".
Boilers emit light - not every glow from around the corner is friendly!
+The amount of items in Requisitions and Squad Preparations depend on how many players readied up at the start of the round.
You can carry a variety of items inside your helmet - from gauze and cigarettes to flares and screwdrivers.
CIC staff can track every USCM-aligned person via the suit sensors console and overwatch console - useful for finding escaped prisoners or dead marines.
When the M7 RPG is fired, it creates a substantial shockwave behind it that can stun and harm marines standing too close. Watch your backblast!
Remember that you need to put a defibrillator's paddles away in order to store it.
-W-Y PMCs do not have marine IFF. Don't fire Smartguns through them!
-To talk on multiple radio channels at once, put a COMMA [,] before your message and add up to four prefixes. E.g, ,abcd talks on all squad channels at once.
+W-Y PMCs do not have marine IFF. Don't fire Smartguns at them!
+To talk on multiple radio channels at once, put a COMMA [,] before your message and add up to four prefixes. E.g, ,abcd talks on the main four squad channels at once.
Put .w or :w before your message to whisper. Another way to whisper is to use the verb "whisper" in the IC tab or command bar.
For Vehicle Crewmen : it is often safer to repair the parts of your APC or tank inside the vehicle than outside it.
It is almost always faster to do surgery manually than in the autodoc.
To check your skills, go to the IC tab and click "view skills".
+Minirockets pack the most punch per cost as far as CAS weaponry is concerned.
The U7 underbarrel shotgun can instantly break down both resin doors and mechanical airlocks, and it's not bad at breaking walls down either.
You can find breaching charges in Requisitions or the Squad Engineer vendor. They function like C4, but can be deployed and explode much quicker, and release powerful shrapnel on the opposite side. They require minor engineering knowledge, which can be obtained from pamphlets.
Armor piercing ammunition does less damage to unarmored targets.
+Requisitions may not grant you service if you are a 'pajamarine' : a marine in cryosleep attire. Be sure to dress up!
You can insert empty pill bottles into ChemMasters before creating pills to have them automatically inserted.
Nurses can practice a full range of surgeries on Professor DUMMY. Ask the gods to give you one if you see (or are) a nurse practicing.
Drinks from the hot drinks machine warm you up.
Be careful! Barricades block grenades, and indeed all thrown items, from the front if they're barbed up.
+CAS Fire Missions doubles the accuracy of fired weapons, which can be substantial.
Painkillers do not stack. Only the strongest has any effect.
+Don't underestimate the mortar: with ammo and proper communication it can hit surprisingly hard.
+You can shoot through tents, but they won't protect you much in return.
+Reqs doesn't have an infinite budget.
+Good Reqs can land supplies anywhere outside - given coords - and sometimes in a minimal amount of time.
+A ‘point blank’ or ‘PB’ is a type of attack with a firearm where you click directly on a mob next to you. These attacks are not effected by accuracy allowing you to quickly fire with weapons like a shotgun to great effect.
Intel Officers can be put in a squad by going to CIC and requesting it.
Any marine can perform CPR. On dead marines, this will increase the time they have until they become unrevivable.
If you've been pounced on and your squad is unloading into the target, you can hit the 'rest' button to stay down so you don't get filled with lead after getting up.
You can check the landing zone as a marine in the status panel.
+The Colonial Marshals may come to crack down on too heavy of a Black Market usage.
Functioning night vision goggles can be recharged with batteries. Broken night vision goggles can be repaired by an Engineer with a screwdriver. Not the loadout ones though, those cannot be fixed.
You can put a pistol belt on your suit slot. (Just grab a rifle instead.)
Alt-clicking the Squad Leader tracker lets you track your fireteam leader instead.
Armor has a randomized reduction in effectiveness, and does not protect the digits. Take the wiki damage values as a best-case scenario.
You can click on your Security Access Tuner (multitool) in your hand to locate the area's APC if there is one.
+Need help learning the game and these tips aren't enough? Use MentorHelp or try to get ahold of your ship's Senior Enlisted Advisor.
Clicking on your sprite with help intent will let you check your body, seeing where your fractures and other wounds are.
Armor has insulative properties - taking it off will help you cool off and take less damage faster if you've been set on fire.
Both foldable cades & plasteel cades if loosened and folded down can be transported in crates! In this way, you can use the crate as a portable breach-repair kit, or dragged (or carried via Power Loader) to an unsecure area for quick defensive set up.
The fuel tank pouch doesn't just carry fuel for an incinerator- they can also carry full-size extinguishers. Toolbelts & tool pouches also may hold miniature extinguishers.
The M2C heavy machine gunner belt rig can also carry C4, breaching charges, and most tools.
+You can always multitask as Medic, such as by using pills or healing kits at the same time as defibrillator.
+The nuclear ordnance requires BOTH communication towers to be actively held to decrypt the nuclear codes.
+ARES will periodically report the amount of available tech points on Command Channel.
+The quick wield keys generally prioritize wieldable gear going from left to right on your inventory bar.
+Orbital Bombardment warheads respect roofing and hive core protection. They won't hit inside of protected areas.
diff --git a/strings/memetips.txt b/strings/memetips.txt
index e05ac2f66bdb..abfe0872180c 100644
--- a/strings/memetips.txt
+++ b/strings/memetips.txt
@@ -12,17 +12,39 @@ Contrary to popular belief, turning off IFF as a Smartgunner does not actually i
When playing as a Xenomorph, remember to aim for the groin to inflict additional psychological damage to marines.
Never tell an officer that you're smarter than them - especially if it's true.
There is no USS Sulaco.
-There is no such thing as an Intel Officer.
+There is no such thing as a Radio-Telephone Operator.
There is no such thing as a techweb.
+There is no such thing as a tip.
+There is no such thing as a Fatty.
+Dropship update is dropping tomorrow.
+Don't forget your ceramic plates.
Echo Squad does not exist.
+Reqs should always spend all its resources on the Black Market.
Foxtrot Squad DEFINITELY does not exist.
+Intel Squad is a unicorn.
Spec rolls are not actually random.
+Watch out for Queen's charge ability.
Never, ever attempt to correct a Provost about anything.
If you die, make sure to ahelp so staff can restart the round!
+You can obtain spec tokens by climbing outside the map and into space.
There is no alcohol on Whiskey Outpost, other than in the Ground Commander's locker.
Hitting enemies with weapons damages them.
+Don't swap East and West. AGAIN.
+Don't swap Minus and Positive coordinates... AGAIN.
+OB'ing the FOB is always an option.
+OB'ing the FOB is the best way to get some recognition from the aCO.
+The sky erupts into flames right above you!
This tip is a lie.
+Stay hydrated.
+Have a good day.
+There is no tip.
+These tips suck. Please write more.
+This tip is not ready, please wait until next round.
+Someone stole this tip, ask staff for a new one.
If it's stupid but it works, it isn't stupid.
If it's stupid but it works, it's still stupid and you got lucky.
Corroders aren't real. They can't hurt you.
ARES is not sentient. It has no feelings and its only thoughts are pre-programmed subroutines.
+Remember that as Yautja HPCs are your primary weapons.
+You can always bully staff into giving you more awesome tips.
+Embrace the suck.
diff --git a/strings/metatips.txt b/strings/metatips.txt
index f694da02b5bf..a28c90239593 100644
--- a/strings/metatips.txt
+++ b/strings/metatips.txt
@@ -1,13 +1,22 @@
Remember hotkeys and macros can be customized to your liking. Hotkeys can be accessed in your preferences, and macros can be edited in the Byond macro editor, available in the top left drop down menu (click the Byond logo in the corner of the game window).
-If you're unsure about a gameplay mechanic, use the 'mentorhelp' verb in the Admin tab to ask veteran players on the subject.
+If you're unsure about a gameplay mechanic, use the 'mentorhelp' verb in the Admin tab to ask veteran players on the subject. It is also available from the pause menu, pressing ESCAPE.
Try not to get too mad about dying. We’re all here to have fun.
+You can get information on current TestMerges by pressing 'Show Server Revision' in 'OOC' tab.
After dying, ask yourself what you did wrong and make a mental note to not make the same mistake again.
Communication, be it from a marine to a marine, a drone to the queen, or command to everyone, is vital and information on flanks can change how the entire round plays out.
As an alien or marine, be careful of the flank, regardless of if the push is going well or stalling out.
Half of getting good is knowing to be aggressive. The other half is knowing when not to be aggressive.
Alt-click a storage item to draw the last item in it (last non-weapon if it's a weapon belt). Middle-click a storage item to immediately open it, and middle-click structures to attempt to vault them.
Use "North, South, West, East" when referring to locations in-game rather than "up, down, left, right".
+As a mentor, you can become the imaginary friend of a new player to teach them!
You shouldn't ignore what your allies are up to. Sometimes they can be organizing a flank in hivemind/radio, sometimes they can be walking up behind you with a slug-loaded shotgun. Either way, it pays to be alert to what they're doing, as much to as what the enemies are.
The Wiki (https://cm-ss13.com/wiki) is a very useful repository of information about the game, such as weapons, equipment, xenomorph castes and their strains. It may not be fully up to date much of the time, but the basics are usually accurate.
As an observer, you may see how much remaining hijack time is left in the status panel.
-Embrace the suck.
+You can always AdminHelp with the F1 key to question a member of staff regarding rules or game bugs.
+As ghost you are given extra tools for spectating the round: you can jump and follow specific players, get notifications about CAS and OB strikes, can see all health bars, and such.
+You can press ESC key to bring up the game pause menu. It allows you change settings, AdminHelp and MentorHelp, and even access the Web Maps of game by clicking at top right.
+Dead? You can take that moment to 'Edit Characters' from Preferences or Escape menus, to flesh out your characters or change your settings.
+Control of intelligence is important: be it for retrieving it as marine, or denying it as Xeno.
+If the lobby music is too loud or bothering you, you can disable it in Preferences tab at top right.
+Maps can and will be unpredictably modified by the Nightmare system - stay frosty while roaming around!
+You can go to GitHub to view code of the game and propose modifications of your own.
diff --git a/strings/xenotips.txt b/strings/xenotips.txt
index 2ca2964ae2d5..8674146de655 100644
--- a/strings/xenotips.txt
+++ b/strings/xenotips.txt
@@ -32,5 +32,7 @@ You can join the hive as a living Facehugger by clicking on the hive's Eggmorphe
Playable Facehuggers can leap onto targets with a one-second windup, but this will only infect them if they are adjacent to it. Otherwise, it will simply knock them down for a small duration.
As a Facehugger, you cannot talk in hivemind, but you can still open Hive Status and overwatch your sisters. This can be useful if you're locating other Facehuggers, flanker castes, or trying to learn from experienced Facehugger players.
Shift-clicking the Queen indicator will tell you what area you are in, on the map.
+As a Ravager your abilities become greatly enhanced when you empower with three or more people around you.
Resisting on a water tile will immediately put out fires. Make sure you're alone though - It's usually better to let a friendly Xenomorph pat you out than it is to expose yourself to open water.
You can filter out the Xenomorphs displayed in hive status by health, allowing you to look only for wounded sisters.
+Each xeno has their own ‘tackle counter’ on a marine. The range to successfully tackle can be anywhere from two to six tackles based on caste. If a marine gets stunned or knocked over by other means it will reset everyone's tackle counters and they may get up!
diff --git a/tgui/packages/tgui-panel/chat/constants.js b/tgui/packages/tgui-panel/chat/constants.js
index ac9346d8d5f0..020e8513dc2c 100644
--- a/tgui/packages/tgui-panel/chat/constants.js
+++ b/tgui/packages/tgui-panel/chat/constants.js
@@ -24,6 +24,7 @@ export const MESSAGE_TYPE_INTERNAL = 'internal';
export const MESSAGE_TYPE_SYSTEM = 'system';
export const MESSAGE_TYPE_LOCALCHAT = 'localchat';
export const MESSAGE_TYPE_RADIO = 'radio';
+export const MESSAGE_TYPE_HIVEMIND = 'hivemind';
export const MESSAGE_TYPE_INFO = 'info';
export const MESSAGE_TYPE_WARNING = 'warning';
export const MESSAGE_TYPE_HELPFUL = 'helpful';
@@ -62,7 +63,13 @@ export const MESSAGE_TYPES = [
type: MESSAGE_TYPE_RADIO,
name: 'Radio',
description: 'All departments of radio messages',
- selector: '.radio, .xeno, .xenoqueen, .xenoleader, .alert, .newscaster',
+ selector: '.radio, .alert, .newscaster',
+ },
+ {
+ type: MESSAGE_TYPE_HIVEMIND,
+ name: 'Hivemind',
+ description: 'Xenomorph hivemind messages',
+ selector: '.xeno, .xenoqueen, .xenoleader',
},
{
type: MESSAGE_TYPE_INFO,
diff --git a/tgui/packages/tgui-panel/chat/renderer.js b/tgui/packages/tgui-panel/chat/renderer.js
index f7ce9277cf68..fe175ee6d94e 100644
--- a/tgui/packages/tgui-panel/chat/renderer.js
+++ b/tgui/packages/tgui-panel/chat/renderer.js
@@ -193,6 +193,7 @@ class ChatRenderer {
const matchWord = setting.matchWord;
const matchCase = setting.matchCase;
const allowedRegex = /^[a-z0-9_\-$/^[\s\]\\]+$/gi;
+ const regexEscapeCharacters = /[!#$%^&*)(+=.<>{}[\]:;'"|~`_\-\\/]/g;
const lines = String(text)
.split(',')
.map((str) => str.trim())
@@ -228,19 +229,27 @@ class ChatRenderer {
if (!highlightWords) {
highlightWords = [];
}
+ // We're not going to let regex characters fuck up our RegEx operation.
+ line = line.replace(regexEscapeCharacters, '\\$&');
+
highlightWords.push(line);
}
}
- const regexStr = regexExpressions.join('|');
- const flags = 'g' + (matchCase ? '' : 'i');
- // setting regex overrides matchword
- if (regexStr) {
- highlightRegex = new RegExp('(' + regexStr + ')', flags);
- } else {
- const pattern = `${matchWord ? '\\b' : ''}(${lines.join('|')})${
- matchWord ? '\\b' : ''
- }`;
- highlightRegex = new RegExp(pattern, flags);
+ // We wrap this in a try-catch to ensure that broken regex doesn't break
+ // the entire chat.
+ try {
+ // setting regex overrides matchword
+ if (regexStr) {
+ highlightRegex = new RegExp('(' + regexStr + ')', flags);
+ } else {
+ const pattern = `${matchWord ? '\\b' : ''}(${highlightWords.join(
+ '|'
+ )})${matchWord ? '\\b' : ''}`;
+ highlightRegex = new RegExp(pattern, flags);
+ }
+ } catch {
+ // We just reset it if it's invalid.
+ highlightRegex = null;
}
// Lazy init
if (!this.highlightParsers) {
diff --git a/tgui/packages/tgui-panel/settings/reducer.js b/tgui/packages/tgui-panel/settings/reducer.js
index 42d799fd6597..0c93a5b94d4e 100644
--- a/tgui/packages/tgui-panel/settings/reducer.js
+++ b/tgui/packages/tgui-panel/settings/reducer.js
@@ -16,7 +16,7 @@ const initialState = {
fontFamily: FONTS[0],
lineHeight: 1.2,
theme: 'light',
- adminMusicVolume: 0.5,
+ adminMusicVolume: 0.2,
// Keep these two state vars for compatibility with other servers
highlightText: '',
highlightColor: '#ffdd44',
diff --git a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
index 835a94341708..9e6d604bdf82 100644
--- a/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
+++ b/tgui/packages/tgui-panel/styles/goon/chat-dark.scss
@@ -434,9 +434,9 @@ em {
font-weight: bold;
}
-.minorannounce {
+.bigannounce {
font-weight: bold;
- font-size: 185%;
+ font-size: 115%;
}
.greenannounce {
@@ -956,10 +956,6 @@ em {
color: #844300;
}
-.sentryradio {
- color: #844300;
-}
-
.medradio {
color: #008160;
}
@@ -1105,7 +1101,7 @@ em {
.xenoboldnotice {
color: #51a16c;
- font-style: italic;
+ font-weight: bold;
}
.xenowarning {
diff --git a/tgui/packages/tgui-panel/styles/goon/chat-light.scss b/tgui/packages/tgui-panel/styles/goon/chat-light.scss
index 8501d0b9526c..78613d37ae51 100644
--- a/tgui/packages/tgui-panel/styles/goon/chat-light.scss
+++ b/tgui/packages/tgui-panel/styles/goon/chat-light.scss
@@ -470,9 +470,9 @@ h2.alert {
font-weight: bold;
}
-.minorannounce {
+.bigannounce {
font-weight: bold;
- font-size: 185%;
+ font-size: 115%;
}
.greenannounce {
@@ -1133,7 +1133,7 @@ h2.alert {
.xenoboldnotice {
color: #2a623d;
- font-style: italic;
+ font-weight: bold;
}
.xenowarning {
diff --git a/tgui/packages/tgui/components/Blink.js b/tgui/packages/tgui/components/Blink.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Blink.js
rename to tgui/packages/tgui/components/Blink.jsx
diff --git a/tgui/packages/tgui/components/BlockQuote.js b/tgui/packages/tgui/components/BlockQuote.jsx
similarity index 100%
rename from tgui/packages/tgui/components/BlockQuote.js
rename to tgui/packages/tgui/components/BlockQuote.jsx
diff --git a/tgui/packages/tgui/components/Button.js b/tgui/packages/tgui/components/Button.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Button.js
rename to tgui/packages/tgui/components/Button.jsx
diff --git a/tgui/packages/tgui/components/ByondUi.js b/tgui/packages/tgui/components/ByondUi.jsx
similarity index 100%
rename from tgui/packages/tgui/components/ByondUi.js
rename to tgui/packages/tgui/components/ByondUi.jsx
diff --git a/tgui/packages/tgui/components/Chart.js b/tgui/packages/tgui/components/Chart.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Chart.js
rename to tgui/packages/tgui/components/Chart.jsx
diff --git a/tgui/packages/tgui/components/Collapsible.js b/tgui/packages/tgui/components/Collapsible.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Collapsible.js
rename to tgui/packages/tgui/components/Collapsible.jsx
diff --git a/tgui/packages/tgui/components/ColorBox.js b/tgui/packages/tgui/components/ColorBox.jsx
similarity index 100%
rename from tgui/packages/tgui/components/ColorBox.js
rename to tgui/packages/tgui/components/ColorBox.jsx
diff --git a/tgui/packages/tgui/components/Dimmer.js b/tgui/packages/tgui/components/Dimmer.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Dimmer.js
rename to tgui/packages/tgui/components/Dimmer.jsx
diff --git a/tgui/packages/tgui/components/Divider.js b/tgui/packages/tgui/components/Divider.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Divider.js
rename to tgui/packages/tgui/components/Divider.jsx
diff --git a/tgui/packages/tgui/components/DraggableControl.js b/tgui/packages/tgui/components/DraggableControl.jsx
similarity index 100%
rename from tgui/packages/tgui/components/DraggableControl.js
rename to tgui/packages/tgui/components/DraggableControl.jsx
diff --git a/tgui/packages/tgui/components/Dropdown.js b/tgui/packages/tgui/components/Dropdown.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Dropdown.js
rename to tgui/packages/tgui/components/Dropdown.jsx
diff --git a/tgui/packages/tgui/components/Grid.js b/tgui/packages/tgui/components/Grid.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Grid.js
rename to tgui/packages/tgui/components/Grid.jsx
diff --git a/tgui/packages/tgui/components/Icon.js b/tgui/packages/tgui/components/Icon.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Icon.js
rename to tgui/packages/tgui/components/Icon.jsx
diff --git a/tgui/packages/tgui/components/InfinitePlane.js b/tgui/packages/tgui/components/InfinitePlane.jsx
similarity index 100%
rename from tgui/packages/tgui/components/InfinitePlane.js
rename to tgui/packages/tgui/components/InfinitePlane.jsx
diff --git a/tgui/packages/tgui/components/Input.js b/tgui/packages/tgui/components/Input.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Input.js
rename to tgui/packages/tgui/components/Input.jsx
diff --git a/tgui/packages/tgui/components/Knob.js b/tgui/packages/tgui/components/Knob.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Knob.js
rename to tgui/packages/tgui/components/Knob.jsx
diff --git a/tgui/packages/tgui/components/LabeledControls.js b/tgui/packages/tgui/components/LabeledControls.jsx
similarity index 100%
rename from tgui/packages/tgui/components/LabeledControls.js
rename to tgui/packages/tgui/components/LabeledControls.jsx
diff --git a/tgui/packages/tgui/components/Modal.js b/tgui/packages/tgui/components/Modal.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Modal.js
rename to tgui/packages/tgui/components/Modal.jsx
diff --git a/tgui/packages/tgui/components/NoticeBox.js b/tgui/packages/tgui/components/NoticeBox.jsx
similarity index 100%
rename from tgui/packages/tgui/components/NoticeBox.js
rename to tgui/packages/tgui/components/NoticeBox.jsx
diff --git a/tgui/packages/tgui/components/NumberInput.js b/tgui/packages/tgui/components/NumberInput.jsx
similarity index 100%
rename from tgui/packages/tgui/components/NumberInput.js
rename to tgui/packages/tgui/components/NumberInput.jsx
diff --git a/tgui/packages/tgui/components/ProgressBar.js b/tgui/packages/tgui/components/ProgressBar.jsx
similarity index 100%
rename from tgui/packages/tgui/components/ProgressBar.js
rename to tgui/packages/tgui/components/ProgressBar.jsx
diff --git a/tgui/packages/tgui/components/RestrictedInput.js b/tgui/packages/tgui/components/RestrictedInput.jsx
similarity index 100%
rename from tgui/packages/tgui/components/RestrictedInput.js
rename to tgui/packages/tgui/components/RestrictedInput.jsx
diff --git a/tgui/packages/tgui/components/RoundGauge.js b/tgui/packages/tgui/components/RoundGauge.jsx
similarity index 100%
rename from tgui/packages/tgui/components/RoundGauge.js
rename to tgui/packages/tgui/components/RoundGauge.jsx
diff --git a/tgui/packages/tgui/components/Slider.js b/tgui/packages/tgui/components/Slider.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Slider.js
rename to tgui/packages/tgui/components/Slider.jsx
diff --git a/tgui/packages/tgui/components/Table.js b/tgui/packages/tgui/components/Table.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Table.js
rename to tgui/packages/tgui/components/Table.jsx
diff --git a/tgui/packages/tgui/components/Tabs.js b/tgui/packages/tgui/components/Tabs.jsx
similarity index 100%
rename from tgui/packages/tgui/components/Tabs.js
rename to tgui/packages/tgui/components/Tabs.jsx
diff --git a/tgui/packages/tgui/components/TextArea.js b/tgui/packages/tgui/components/TextArea.jsx
similarity index 100%
rename from tgui/packages/tgui/components/TextArea.js
rename to tgui/packages/tgui/components/TextArea.jsx
diff --git a/tgui/packages/tgui/components/TimeDisplay.js b/tgui/packages/tgui/components/TimeDisplay.jsx
similarity index 100%
rename from tgui/packages/tgui/components/TimeDisplay.js
rename to tgui/packages/tgui/components/TimeDisplay.jsx
diff --git a/tgui/packages/tgui/components/index.js b/tgui/packages/tgui/components/index.jsx
similarity index 100%
rename from tgui/packages/tgui/components/index.js
rename to tgui/packages/tgui/components/index.jsx
diff --git a/tgui/packages/tgui/constants.js b/tgui/packages/tgui/constants.js
index 3d7530e7ead8..0ec51380a322 100644
--- a/tgui/packages/tgui/constants.js
+++ b/tgui/packages/tgui/constants.js
@@ -80,153 +80,233 @@ export const CSS_COLORS = [
export const RADIO_CHANNELS = [
{
name: 'Yautja',
- freq: 1214,
+ freq: 1205,
color: '#1ecc43',
},
{
- name: 'PMC',
- freq: 1235,
+ name: "Dutch's Dozen",
+ freq: 1210,
color: '#1ecc43',
},
+ {
+ name: 'VAI',
+ freq: 1215,
+ color: '#e3580e',
+ },
+ {
+ name: 'CMB',
+ freq: 1220,
+ color: '#1b748c',
+ },
{
name: 'WY',
- freq: 1236,
- color: '#1ecc43',
+ freq: 1231,
+ color: '#fe9b24',
},
{
- name: "Dutch's Dozen",
- freq: 1340,
- color: '#1ecc43',
+ name: 'PMC CMD',
+ freq: 1232,
+ color: '#4dc5ce',
},
{
- name: 'VAI',
- freq: 1218,
- color: '#1ecc43',
+ name: 'PMC',
+ freq: 1233,
+ color: '#4dc5ce',
},
{
- name: 'ERT',
- freq: 1342,
- color: '#1ecc43',
+ name: 'PMC ENG',
+ freq: 1234,
+ color: '#4dc5ce',
+ },
+ {
+ name: 'PMC MED',
+ freq: 1235,
+ color: '#4dc5ce',
+ },
+ {
+ name: 'PMC CCT',
+ freq: 1236,
+ color: '#4dc5ce',
+ },
+ {
+ name: 'Deathsquad',
+ freq: 1239,
+ color: '#fe9b24',
},
{
name: 'UPP',
- freq: 1338,
- color: '#1ecc43',
+ freq: 1251,
+ color: '#8f4a4b',
+ },
+ {
+ name: 'UPP CMD',
+ freq: 1252,
+ color: '#8f4a4b',
+ },
+ {
+ name: 'UPP ENG',
+ freq: 1253,
+ color: '#8f4a4b',
+ },
+ {
+ name: 'UPP MED',
+ freq: 1254,
+ color: '#8f4a4b',
+ },
+ {
+ name: 'UPP CCT',
+ freq: 1255,
+ color: '#8f4a4b',
+ },
+ {
+ name: 'UPP KDO',
+ freq: 1259,
+ color: '#8f4a4b',
},
{
name: 'CLF',
- freq: 1339,
- color: '#1ecc43',
+ freq: 1271,
+ color: '#8e83ca',
},
{
- name: 'Deathsquad',
- freq: 1344,
+ name: 'CLF CMD',
+ freq: 1272,
+ color: '#8e83ca',
+ },
+ {
+ name: 'CLF ENG',
+ freq: 1273,
+ color: '#8e83ca',
+ },
+ {
+ name: 'CLF MED',
+ freq: 1274,
+ color: '#8e83ca',
+ },
+ {
+ name: 'CLF CCT',
+ freq: 1275,
+ color: '#8e83ca',
+ },
+ {
+ name: 'LSTN BUG A',
+ freq: 1290,
+ color: '#d65d95',
+ },
+ {
+ name: 'LSTN BUG B',
+ freq: 1291,
+ color: '#d65d95',
+ },
+ {
+ name: 'Common',
+ freq: 1461,
color: '#1ecc43',
},
{
- name: 'ARES',
- freq: 1447,
+ name: 'Colony',
+ freq: 1469,
color: '#1ecc43',
},
{
name: 'High Command',
- freq: 1240,
- color: '#1ecc43',
+ freq: 1471,
+ color: '#318779',
},
{
- name: 'CCT',
- freq: 1350,
- color: '#1ecc43',
+ name: 'SOF',
+ freq: 1472,
+ color: '#318779',
+ },
+ {
+ name: 'Provost',
+ freq: 1473,
+ color: '#9b0612',
+ },
+ {
+ name: 'Sentry',
+ freq: 1480,
+ color: '#844300',
},
{
name: 'Command',
- freq: 1353,
- color: '#1ecc43',
+ freq: 1481,
+ color: '#779cc2',
},
{
name: 'Medsci',
- freq: 1355,
- color: '#1ecc43',
+ freq: 1482,
+ color: '#008160',
},
{
name: 'Engineering',
- freq: 1357,
- color: '#1ecc43',
+ freq: 1483,
+ color: '#a66300',
},
{
name: 'MP',
- freq: 1359,
- color: '#1ecc43',
+ freq: 1484,
+ color: '#a52929',
},
{
name: 'Req',
- freq: 1354,
- color: '#1ecc43',
+ freq: 1485,
+ color: '#ba8e41',
},
{
name: 'JTAC',
- freq: 1358,
- color: '#1ecc43',
+ freq: 1486,
+ color: '#ad3b98',
},
{
name: 'Intel',
- freq: 1356,
- color: '#1ecc43',
+ freq: 1487,
+ color: '#027d02',
},
{
name: 'Alamo',
- freq: 1441,
+ freq: 1488,
color: '#1ecc43',
},
{
name: 'Normandy',
- freq: 1443,
+ freq: 1489,
color: '#1ecc43',
},
{
name: 'Alpha',
- freq: 1449,
- color: '#1ecc43',
+ freq: 1491,
+ color: '#db2626',
},
{
name: 'Bravo',
- freq: 1451,
- color: '#1ecc43',
- },
- {
- name: 'Common',
- freq: 1461,
- color: '#1ecc43',
+ freq: 1492,
+ color: '#c68610',
},
{
- name: 'Colony',
- freq: 1469,
- color: '#1ecc43',
- },
- {
- name: 'MARSOC',
- freq: 1241,
- color: '#1ecc43',
+ name: 'Charlie',
+ freq: 1493,
+ color: '#aa55aa',
},
{
- name: 'Reserves',
- freq: 1457,
- color: '#1ecc43',
+ name: 'Delta',
+ freq: 1494,
+ color: '#007fcf',
},
{
name: 'Echo',
- freq: 1456,
- color: '#1ecc43',
+ freq: 1495,
+ color: '#3eb489',
},
{
- name: 'Delta',
- freq: 1455,
- color: '#1ecc43',
+ name: 'Reserves',
+ freq: 1496,
+ color: '#ad6d48',
},
{
- name: 'Charlie',
- freq: 1453,
- color: '#1ecc43',
+ name: 'ARES',
+ freq: 1500,
+ color: '#ff00ff',
},
];
diff --git a/tgui/packages/tgui/debug/KitchenSink.js b/tgui/packages/tgui/debug/KitchenSink.jsx
similarity index 95%
rename from tgui/packages/tgui/debug/KitchenSink.js
rename to tgui/packages/tgui/debug/KitchenSink.jsx
index 246b4f50b478..e25751722c52 100644
--- a/tgui/packages/tgui/debug/KitchenSink.js
+++ b/tgui/packages/tgui/debug/KitchenSink.jsx
@@ -8,7 +8,7 @@ import { useLocalState } from '../backend';
import { Flex, Section, Tabs } from '../components';
import { Pane, Window } from '../layouts';
-const r = require.context('../stories', false, /\.stories\.js$/);
+const r = require.context('../stories', false, /\.stories\.jsx$/);
/**
* @returns {{
diff --git a/tgui/packages/tgui/interfaces/AcidVest.js b/tgui/packages/tgui/interfaces/AcidVest.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/AcidVest.js
rename to tgui/packages/tgui/interfaces/AcidVest.jsx
diff --git a/tgui/packages/tgui/interfaces/AlmayerControl.js b/tgui/packages/tgui/interfaces/AlmayerControl.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/AlmayerControl.js
rename to tgui/packages/tgui/interfaces/AlmayerControl.jsx
diff --git a/tgui/packages/tgui/interfaces/AltitudeControlConsole.js b/tgui/packages/tgui/interfaces/AltitudeControlConsole.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/AltitudeControlConsole.js
rename to tgui/packages/tgui/interfaces/AltitudeControlConsole.jsx
diff --git a/tgui/packages/tgui/interfaces/AntiAirConsole.js b/tgui/packages/tgui/interfaces/AntiAirConsole.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/AntiAirConsole.js
rename to tgui/packages/tgui/interfaces/AntiAirConsole.jsx
diff --git a/tgui/packages/tgui/interfaces/Apc.js b/tgui/packages/tgui/interfaces/Apc.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/Apc.js
rename to tgui/packages/tgui/interfaces/Apc.jsx
diff --git a/tgui/packages/tgui/interfaces/AresInterface.js b/tgui/packages/tgui/interfaces/AresInterface.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/AresInterface.js
rename to tgui/packages/tgui/interfaces/AresInterface.jsx
diff --git a/tgui/packages/tgui/interfaces/Autodispenser.js b/tgui/packages/tgui/interfaces/Autodispenser.jsx
similarity index 99%
rename from tgui/packages/tgui/interfaces/Autodispenser.js
rename to tgui/packages/tgui/interfaces/Autodispenser.jsx
index 0c8ce91512e5..5d029b72b894 100644
--- a/tgui/packages/tgui/interfaces/Autodispenser.js
+++ b/tgui/packages/tgui/interfaces/Autodispenser.jsx
@@ -11,7 +11,6 @@ export const Autodispenser = (_props, context) => {
multiplier,
cycle_limit,
automode,
- linked_storage,
networked_storage,
smartlink,
outputmode,
diff --git a/tgui/packages/tgui/interfaces/Autolathe.js b/tgui/packages/tgui/interfaces/Autolathe.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/Autolathe.js
rename to tgui/packages/tgui/interfaces/Autolathe.jsx
diff --git a/tgui/packages/tgui/interfaces/Binoculars.js b/tgui/packages/tgui/interfaces/Binoculars.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/Binoculars.js
rename to tgui/packages/tgui/interfaces/Binoculars.jsx
diff --git a/tgui/packages/tgui/interfaces/BioSyntheticPrinter.js b/tgui/packages/tgui/interfaces/BioSyntheticPrinter.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/BioSyntheticPrinter.js
rename to tgui/packages/tgui/interfaces/BioSyntheticPrinter.jsx
diff --git a/tgui/packages/tgui/interfaces/BotanyEditor.js b/tgui/packages/tgui/interfaces/BotanyEditor.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/BotanyEditor.js
rename to tgui/packages/tgui/interfaces/BotanyEditor.jsx
diff --git a/tgui/packages/tgui/interfaces/BotanyExtractor.js b/tgui/packages/tgui/interfaces/BotanyExtractor.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/BotanyExtractor.js
rename to tgui/packages/tgui/interfaces/BotanyExtractor.jsx
diff --git a/tgui/packages/tgui/interfaces/BrigCell.js b/tgui/packages/tgui/interfaces/BrigCell.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/BrigCell.js
rename to tgui/packages/tgui/interfaces/BrigCell.jsx
diff --git a/tgui/packages/tgui/interfaces/CameraConsole.js b/tgui/packages/tgui/interfaces/CameraConsole.jsx
similarity index 100%
rename from tgui/packages/tgui/interfaces/CameraConsole.js
rename to tgui/packages/tgui/interfaces/CameraConsole.jsx
diff --git a/tgui/packages/tgui/interfaces/CanvasLayer.jsx b/tgui/packages/tgui/interfaces/CanvasLayer.jsx
new file mode 100644
index 000000000000..e647ae765b1c
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/CanvasLayer.jsx
@@ -0,0 +1,311 @@
+import { Box, Icon, Tooltip } from '../components';
+import { Component, createRef } from 'inferno';
+
+// this file should probably not be in interfaces, should move it later.
+export class CanvasLayer extends Component {
+ constructor(props) {
+ super(props);
+ this.canvasRef = createRef();
+
+ // color selection
+ // using this.state prevents unpredictable behavior
+ this.state = {
+ selection: this.props.selection,
+ mapLoad: true,
+ };
+
+ // needs to be of type png of jpg
+ this.img = null;
+ this.imageSrc = this.props.imageSrc;
+
+ // stores the stacked lines
+ this.lineStack = [];
+
+ // stores the individual line drawn
+ this.currentLine = [];
+
+ this.ctx = null;
+ this.isPainting = false;
+ this.lastX = null;
+ this.lastY = null;
+
+ this.complexity = 0;
+ }
+
+ componentDidMount() {
+ this.ctx = this.canvasRef.current.getContext('2d');
+ this.ctx.lineWidth = 4;
+ this.ctx.lineCap = 'round';
+
+ this.img = new Image();
+
+ this.img.src = this.imageSrc;
+
+ this.img.onload = () => {
+ this.setState({ mapLoad: true });
+ };
+
+ this.img.onerror = () => {
+ this.setState({ mapLoad: false });
+ };
+
+ this.drawCanvas();
+ }
+
+ handleMouseDown = (e) => {
+ this.isPainting = true;
+
+ const rect = this.canvasRef.current.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ this.ctx.beginPath();
+ this.ctx.moveTo(this.lastX, this.lastY);
+ this.lastX = x;
+ this.lastY = y;
+ };
+
+ handleMouseMove = (e) => {
+ if (!this.isPainting || !this.state.selection) {
+ return;
+ }
+ if (e.buttons === 0) {
+ // We probably dragged off the window - lets not get stuck drawing
+ this.handleMouseUp(e);
+ return;
+ }
+
+ this.ctx.strokeStyle = this.state.selection;
+
+ const rect = this.canvasRef.current.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ if (this.lastX !== null && this.lastY !== null) {
+ // this controls how often we make new strokes
+ if (Math.abs(this.lastX - x) + Math.abs(this.lastY - y) < 20) {
+ return;
+ }
+
+ this.ctx.moveTo(this.lastX, this.lastY);
+ this.ctx.lineTo(x, y);
+ this.ctx.stroke();
+ this.currentLine.push([
+ this.lastX,
+ this.lastY,
+ x,
+ y,
+ this.ctx.strokeStyle,
+ ]);
+ }
+
+ this.lastX = x;
+ this.lastY = y;
+ };
+
+ handleMouseUp = (e) => {
+ if (
+ this.isPainting &&
+ this.state.selection &&
+ this.lastX !== null &&
+ this.lastY !== null
+ ) {
+ const rect = this.canvasRef.current.getBoundingClientRect();
+ const x = e.clientX - rect.left;
+ const y = e.clientY - rect.top;
+
+ this.ctx.moveTo(this.lastX, this.lastY);
+ this.ctx.lineTo(x, y);
+ this.ctx.stroke();
+ this.currentLine.push([
+ this.lastX,
+ this.lastY,
+ x,
+ y,
+ this.ctx.strokeStyle,
+ ]);
+ }
+
+ this.isPainting = false;
+ this.lastX = null;
+ this.lastY = null;
+
+ if (this.currentLine.length === 0) {
+ return;
+ }
+
+ this.lineStack.push([...this.currentLine]);
+ this.currentLine = [];
+ this.complexity = this.getComplexity();
+ this.props.onDraw();
+ };
+
+ handleSelectionChange = () => {
+ const { selection } = this.props;
+
+ if (selection === 'clear') {
+ this.ctx.clearRect(
+ 0,
+ 0,
+ this.canvasRef.current.width,
+ this.canvasRef.current.height
+ );
+ this.ctx.drawImage(
+ this.img,
+ 0,
+ 0,
+ this.canvasRef.current.width,
+ this.canvasRef.current.height
+ );
+
+ this.lineStack = [];
+ this.complexity = 0;
+ return;
+ }
+
+ if (selection === 'undo') {
+ if (this.lineStack.length === 0) {
+ return;
+ }
+
+ const line = this.lineStack.pop();
+ if (line.length === 0) {
+ return;
+ }
+
+ const prevColor = line[0][4];
+
+ this.ctx.clearRect(
+ 0,
+ 0,
+ this.canvasRef.current.width,
+ this.canvasRef.current.height
+ );
+ this.ctx.drawImage(
+ this.img,
+ 0,
+ 0,
+ this.canvasRef.current.width,
+ this.canvasRef.current.height
+ );
+ this.ctx.globalCompositeOperation = 'source-over';
+
+ this.lineStack.forEach((currentLine) => {
+ currentLine.forEach(([lastX, lastY, x, y, colorSelection]) => {
+ this.ctx.strokeStyle = colorSelection;
+ this.ctx.beginPath();
+ this.ctx.moveTo(lastX, lastY);
+ this.ctx.lineTo(x, y);
+ this.ctx.stroke();
+ });
+ });
+
+ this.complexity = this.getComplexity();
+ this.setState({ selection: prevColor });
+ this.props.onUndo(prevColor);
+ return;
+ }
+
+ if (selection === 'export') {
+ const svgData = this.convertToSVG();
+ this.props.onImageExport(svgData);
+ return;
+ }
+
+ this.setState({ selection: selection });
+ };
+
+ componentDidUpdate(prevProps) {
+ if (prevProps.actionQueueChange !== this.props.actionQueueChange) {
+ this.handleSelectionChange();
+ }
+ }
+
+ drawCanvas() {
+ this.img.onload = () => {
+ // this onload may or may not be causing problems.
+ this.ctx.drawImage(
+ this.img,
+ 0,
+ 0,
+ this.canvasRef.current?.width,
+ this.canvasRef.current?.height
+ );
+ };
+ }
+
+ convertToSVG() {
+ const lines = this.lineStack.flat();
+ const combinedArray = lines.flatMap(
+ ([lastX, lastY, x, y, colorSelection]) => [
+ lastX,
+ lastY,
+ x,
+ y,
+ colorSelection,
+ ]
+ );
+ return combinedArray;
+ }
+
+ getComplexity() {
+ let count = 0;
+ this.lineStack.forEach((item) => {
+ count += item.length;
+ });
+ return count;
+ }
+
+ displayCanvas() {
+ return (
+
+ {this.complexity > 500 && (
+
+
+
+ )}
+
+ );
+ }
+
+ displayLoading() {
+ return (
+
+
+
+ Please wait a few minutes before attempting to access the canvas.
+