diff --git a/.github/workflows/autochangelog.yml b/.github/workflows/autochangelog.yml
new file mode 100644
index 00000000000..7953929ce55
--- /dev/null
+++ b/.github/workflows/autochangelog.yml
@@ -0,0 +1,43 @@
+name: Autochangelog
+on:
+ pull_request_target:
+ types: closed
+ branches:
+ - master
+
+env:
+ BASENAME: "polaris"
+
+jobs:
+ autochangelog:
+ name: Autochangelog
+ runs-on: ubuntu-16.04
+ if: github.event.pull_request.merged == true
+ steps:
+ - uses: /actions/checkout@v2
+ with:
+ ref: master
+ - name: Update repository to master
+ run: git pull "origin" master
+ - name: Ensure +x on CI directory
+ run: |
+ chmod -R +x ./tools/ci
+ - uses: actions/setup-python@v2
+ with:
+ python-version: '3.7'
+ - name: Generate Changelog
+ run: |
+ pip install pyyaml
+ python tools/GenerateChangelog/ss13_autochangelog.py \
+ html/changelogs \
+ ${{ github.event.pull_request.number }} \
+ "${{ github.event.pull_request.user.login }}" \
+ "${{ github.event.pull_request.body }}"
+ python tools/GenerateChangelog/ss13_genchangelog.py \
+ html/changelog.html \
+ html/changelogs
+ - uses: stefanzweifel/git-auto-commit-action@v4
+ with:
+ commit_message: Automatic changelog generation for ${{ github.events.pull_request.number }}
+ branch: ${{ github.events.pull_request.base }}
+ commit_user_name: Autochangelog Bot
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f6e206bc339..13022f96fde 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -41,7 +41,7 @@ jobs:
run: |
sudo dpkg --add-architecture i386
sudo apt update || true
- sudo apt install libc6:i386 libgcc1:i386 libstdc++6:i386 libssl1.0.0:i386 g++-7 g++-7-multilib gcc-multilib zlib1g:i386
+ sudo apt install libc6:i386 libgcc1:i386 libstdc++6:i386 libssl1.0.0:i386 zlib1g:i386
ldd librust_g.so
- name: Unit Tests
run: |
diff --git a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
index be7f905a77e..a3a368852f6 100644
--- a/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
+++ b/code/ATMOSPHERICS/components/omni_devices/omni_base.dm
@@ -96,15 +96,6 @@
"You hear a ratchet.")
deconstruct()
-/obj/machinery/atmospherics/omni/can_unwrench()
- var/int_pressure = 0
- for(var/datum/omni_port/P in ports)
- int_pressure += P.air.return_pressure()
- var/datum/gas_mixture/env_air = loc.return_air()
- if((int_pressure - env_air.return_pressure()) > 2*ONE_ATMOSPHERE)
- return 0
- return 1
-
/obj/machinery/atmospherics/omni/attack_hand(user as mob)
if(..())
return
diff --git a/code/__defines/_planes+layers.dm b/code/__defines/_planes+layers.dm
index 4e9d7fd6ad7..a2e15e6890e 100644
--- a/code/__defines/_planes+layers.dm
+++ b/code/__defines/_planes+layers.dm
@@ -173,6 +173,5 @@ What is the naming convention for planes or layers?
plane = initial(plane)
layer = initial(layer)
-
// Check if a mob can "logically" see an atom plane
#define MOB_CAN_SEE_PLANE(M, P) (P <= PLANE_WORLD || (P in M.planes_visible))
diff --git a/code/__defines/belly_modes_vr.dm b/code/__defines/belly_modes_vr.dm
index ccffcf43416..d497391d3fc 100644
--- a/code/__defines/belly_modes_vr.dm
+++ b/code/__defines/belly_modes_vr.dm
@@ -9,30 +9,17 @@
#define DM_SIZE_STEAL "Size Steal"
#define DM_HEAL "Heal"
#define DM_EGG "Encase In Egg"
-#define DM_TRANSFORM "Transform"
//#define DM_ITEMWEAK "Digest (Item Friendly)"
//#define DM_STRIPDIGEST "Strip Digest (Items Only)"
//#define DM_DIGEST_NUMB "Digest (Numbing)"
-//TF modes
-#define DM_TRANSFORM_HAIR_AND_EYES "Transform (Hair and eyes)"
-#define DM_TRANSFORM_MALE "Transform (Male)"
-#define DM_TRANSFORM_FEMALE "Transform (Female)"
-#define DM_TRANSFORM_KEEP_GENDER "Transform (Keep Gender)"
-#define DM_TRANSFORM_REPLICA "Transform (Replica Of Self)"
-#define DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR "Transform (Change Species and Taur)"
-#define DM_TRANSFORM_CHANGE_SPECIES_AND_TAUR_EGG "Transform (Change Species and Taur) (EGG)"
-#define DM_TRANSFORM_REPLICA_EGG "Transform (Replica Of Self) (EGG)"
-#define DM_TRANSFORM_KEEP_GENDER_EGG "Transform (Keep Gender) (EGG)"
-#define DM_TRANSFORM_MALE_EGG "Transform (Male) (EGG)"
-#define DM_TRANSFORM_FEMALE_EGG "Transform (Female) (EGG)"
-
//Addon mode flags
#define DM_FLAG_NUMBING 0x1
#define DM_FLAG_STRIPPING 0x2
#define DM_FLAG_LEAVEREMAINS 0x4
#define DM_FLAG_THICKBELLY 0x8
+#define DM_FLAG_AFFECTWORN 0x10
//Item related modes
#define IM_HOLD "Hold"
diff --git a/code/__defines/damage_organs.dm b/code/__defines/damage_organs.dm
index c87b9942dfc..db1a71c77a6 100644
--- a/code/__defines/damage_organs.dm
+++ b/code/__defines/damage_organs.dm
@@ -61,4 +61,8 @@
#define INFECTION_LEVEL_ONE 100
#define INFECTION_LEVEL_TWO 500
#define INFECTION_LEVEL_THREE 1000
-#define INFECTION_LEVEL_MAX 1500
\ No newline at end of file
+#define INFECTION_LEVEL_MAX 1500
+
+#define MODULAR_BODYPART_INVALID 0 // Cannot be detached or reattached.
+#define MODULAR_BODYPART_PROSTHETIC 1 // Can be detached or reattached freely.
+#define MODULAR_BODYPART_CYBERNETIC 2 // Can be detached or reattached to compatible parent organs.
diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index 3e86c138560..f9ce5a1b7f3 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -157,6 +157,16 @@
#define MAT_GRAPHITE "graphite"
#define MAT_LEATHER "leather"
#define MAT_CHITIN "chitin"
+#define MAT_CLOTH "cloth"
+#define MAT_SYNCLOTH "syncloth"
+#define MAT_COPPER "copper"
+#define MAT_QUARTZ "quartz"
+#define MAT_TIN "tin"
+#define MAT_VOPAL "void opal"
+#define MAT_ALUMINIUM "aluminium"
+#define MAT_BRONZE "bronze"
+#define MAT_PAINITE "painite"
+#define MAT_BOROSILICATE "borosilicate glass"
#define SHARD_SHARD "shard"
#define SHARD_SHRAPNEL "shrapnel"
@@ -480,4 +490,15 @@ GLOBAL_LIST_INIT(all_volume_channels, list(
VOLUME_CHANNEL_ALARMS,
VOLUME_CHANNEL_VORE,
VOLUME_CHANNEL_DOORS,
-))
\ No newline at end of file
+))
+
+#define APPEARANCECHANGER_CHANGED_RACE "Race"
+#define APPEARANCECHANGER_CHANGED_GENDER "Gender"
+#define APPEARANCECHANGER_CHANGED_GENDER_ID "Gender Identity"
+#define APPEARANCECHANGER_CHANGED_SKINTONE "Skin Tone"
+#define APPEARANCECHANGER_CHANGED_SKINCOLOR "Skin Color"
+#define APPEARANCECHANGER_CHANGED_HAIRSTYLE "Hair Style"
+#define APPEARANCECHANGER_CHANGED_HAIRCOLOR "Hair Color"
+#define APPEARANCECHANGER_CHANGED_F_HAIRSTYLE "Facial Hair Style"
+#define APPEARANCECHANGER_CHANGED_F_HAIRCOLOR "Facial Hair Color"
+#define APPEARANCECHANGER_CHANGED_EYES "Eye Color"
diff --git a/code/__defines/species_languages.dm b/code/__defines/species_languages.dm
index 34c68ebd089..3239e8fa1ad 100644
--- a/code/__defines/species_languages.dm
+++ b/code/__defines/species_languages.dm
@@ -24,6 +24,30 @@
#define EMP_TOX_DMG 0x80 // EMPs inflict toxin damage
#define EMP_OXY_DMG 0x100 // EMPs inflict oxy damage
+// Species allergens
+#define MEAT 0x1 // Skrell won't like this.
+#define FISH 0x2 // Seperate for completion's sake. Still bad for skrell.
+#define FRUIT 0x4 // An apple a day only keeps the doctor away if they're allergic.
+#define VEGETABLE 0x8 // Taters 'n' carrots. Potato allergy is a thing, apparently.
+#define GRAINS 0x10 // Wheat, oats, etc.
+#define BEANS 0x20 // The musical fruit! Includes soy.
+#define SEEDS 0x40 // Hope you don't have a nut allergy.
+#define DAIRY 0x80 // Lactose intolerance, ho! Also bad for skrell.
+#define FUNGI 0x100 // Delicious shrooms.
+#define COFFEE 0x200 // Mostly here for tajara.
+#define GENERIC 0x400 // Catchall for stuff that doesn't fall into the groups above. You shouldn't be allergic to this type, ever.
+#define SUGARS 0x800 // For unathi-like reactions
+#define EGGS 0x1000 // For Skrell eggs allergy
+
+// Allergen reactions
+#define AG_TOX_DMG 0x1 // the classic
+#define AG_OXY_DMG 0x2 // intense airway reactions
+#define AG_EMOTE 0x4 // general emote reactions based on affect type
+#define AG_PAIN 0x8 // short-lived hurt
+#define AG_WEAKEN 0x10 // too weak to move, oof
+#define AG_BLURRY 0x20 // blurred vision!
+#define AG_SLEEPY 0x40 // fatigue/exhaustion
+
// Species spawn flags
#define SPECIES_IS_WHITELISTED 0x1 // Must be whitelisted to play.
#define SPECIES_IS_RESTRICTED 0x2 // Is not a core/normally playable species. (castes, mutantraces)
@@ -68,7 +92,7 @@
#define LANGUAGE_ALAI "Alai"
#define LANGUAGE_ZADDAT "Vedahq"
#define LANGUAGE_PROMETHEAN "Promethean Biolinguistics"
-#define LANGUAGE_BLOB "Blob"
+#define LANGUAGE_BLOB "Chemosense Transmission"
#define LANGUAGE_GIBBERISH "Babel"
// Language flags.
diff --git a/code/__defines/species_languages_vr.dm b/code/__defines/species_languages_vr.dm
index 8909238db2d..78054e6ba86 100644
--- a/code/__defines/species_languages_vr.dm
+++ b/code/__defines/species_languages_vr.dm
@@ -10,6 +10,7 @@
#define LANGUAGE_ENOCHIAN "Enochian"
#define LANGUAGE_VESPINAE "Vespinae"
#define LANGUAGE_SPACER "Spacer"
+#define LANGUAGE_CLOWNISH "Coulrian"
#define LANGUAGE_CHIMPANZEE "Chimpanzee"
#define LANGUAGE_NEAERA "Neaera"
diff --git a/code/_global_vars/lists/misc.dm b/code/_global_vars/lists/misc.dm
index e02c99290c7..742708face2 100644
--- a/code/_global_vars/lists/misc.dm
+++ b/code/_global_vars/lists/misc.dm
@@ -5,4 +5,7 @@ GLOBAL_LIST_EMPTY(meteor_list)
GLOBAL_LIST_EMPTY(wire_color_directory) // This is an associative list with the `holder_type` as the key, and a list of colors as the value.
// Reference list for disposal sort junctions. Filled up by sorting junction's New()
-GLOBAL_LIST_EMPTY(tagger_locations)
\ No newline at end of file
+GLOBAL_LIST_EMPTY(tagger_locations)
+
+GLOBAL_LIST_INIT(char_directory_tags, list("Pred", "Prey", "Switch", "Non-Vore", "Unset"))
+GLOBAL_LIST_INIT(char_directory_erptags, list("Top", "Bottom", "Switch", "No ERP", "Unset"))
\ No newline at end of file
diff --git a/code/_helpers/_global_objects.dm b/code/_helpers/_global_objects.dm
index 4cbbcf33147..adbd2785e85 100644
--- a/code/_helpers/_global_objects.dm
+++ b/code/_helpers/_global_objects.dm
@@ -1 +1,2 @@
-var/datum/gear_tweak/color/gear_tweak_free_color_choice = new()
\ No newline at end of file
+var/datum/gear_tweak/color/gear_tweak_free_color_choice = new()
+var/datum/gear_tweak/implant_location/gear_tweak_implant_location = new()
\ No newline at end of file
diff --git a/code/_helpers/global_lists.dm b/code/_helpers/global_lists.dm
index 371f35b0515..4f95bfcf7d6 100644
--- a/code/_helpers/global_lists.dm
+++ b/code/_helpers/global_lists.dm
@@ -43,6 +43,11 @@ var/global/list/facial_hair_styles_male_list = list()
var/global/list/facial_hair_styles_female_list = list()
var/global/list/skin_styles_female_list = list() //unused
var/global/list/body_marking_styles_list = list() //stores /datum/sprite_accessory/marking indexed by name
+var/global/list/ear_styles_list = list() // Stores /datum/sprite_accessory/ears indexed by type
+var/global/list/tail_styles_list = list() // Stores /datum/sprite_accessory/tail indexed by type
+var/global/list/wing_styles_list = list() // Stores /datum/sprite_accessory/wing indexed by type
+
+GLOBAL_LIST(custom_species_bases)
//Underwear
var/datum/category_collection/underwear/global_underwear = new()
@@ -94,13 +99,13 @@ var/global/list/string_slot_flags = list(
"holster" = SLOT_HOLSTER
)
-/proc/get_mannequin(var/ckey)
- if(!mannequins_)
- mannequins_ = new()
- . = mannequins_[ckey]
- if(!.)
- . = new/mob/living/carbon/human/dummy/mannequin()
- mannequins_[ckey] = .
+GLOBAL_LIST_EMPTY(mannequins)
+/proc/get_mannequin(var/ckey = "NULL")
+ var/mob/living/carbon/human/dummy/mannequin/M = GLOB.mannequins[ckey]
+ if(!istype(M))
+ GLOB.mannequins[ckey] = new /mob/living/carbon/human/dummy/mannequin(null)
+ M = GLOB.mannequins[ckey]
+ return M
//////////////////////////
/////Initial Building/////
@@ -214,13 +219,65 @@ var/global/list/string_slot_flags = list(
var/decl/closet_appearance/app = new T()
GLOB.closet_appearances[T] = app
+ paths = typesof(/datum/sprite_accessory/ears) - /datum/sprite_accessory/ears
+ for(var/path in paths)
+ var/obj/item/clothing/head/instance = new path()
+ ear_styles_list[path] = instance
+
+ // Custom Tails
+ paths = typesof(/datum/sprite_accessory/tail) - /datum/sprite_accessory/tail - /datum/sprite_accessory/tail/taur
+ for(var/path in paths)
+ var/datum/sprite_accessory/tail/instance = new path()
+ tail_styles_list[path] = instance
+
+ // Custom Wings
+ paths = typesof(/datum/sprite_accessory/wing) - /datum/sprite_accessory/wing
+ for(var/path in paths)
+ var/datum/sprite_accessory/wing/instance = new path()
+ wing_styles_list[path] = instance
+
// VOREStation Add - Vore Modes!
- paths = typesof(/datum/digest_mode) - /datum/digest_mode/transform
+ paths = typesof(/datum/digest_mode)
for(var/T in paths)
var/datum/digest_mode/DM = new T
GLOB.digest_modes[DM.id] = DM
// VOREStation Add End
+/*
+ // Custom species traits
+ paths = typesof(/datum/trait) - /datum/trait
+ for(var/path in paths)
+ var/datum/trait/instance = new path()
+ if(!instance.name)
+ continue //A prototype or something
+ var/cost = instance.cost
+ traits_costs[path] = cost
+ all_traits[path] = instance
+ switch(cost)
+ if(-INFINITY to -0.1)
+ negative_traits[path] = instance
+ if(0)
+ neutral_traits[path] = instance
+ if(0.1 to INFINITY)
+ positive_traits[path] = instance
+*/
+
+ // Custom species icon bases
+ var/list/blacklisted_icons = list(SPECIES_CUSTOM,SPECIES_PROMETHEAN) //VOREStation Edit
+ var/list/whitelisted_icons = list(SPECIES_FENNEC,SPECIES_XENOHYBRID) //VOREStation Edit
+ for(var/species_name in GLOB.playable_species)
+ if(species_name in blacklisted_icons)
+ continue
+ var/datum/species/S = GLOB.all_species[species_name]
+ if(S.spawn_flags & SPECIES_IS_WHITELISTED)
+ continue
+ GLOB.custom_species_bases += species_name
+ for(var/species_name in whitelisted_icons)
+ GLOB.custom_species_bases += species_name
+
+ return 1 // Hooks must return 1
+
+
return 1
/* // Uncomment to debug chemical reaction list.
diff --git a/code/_helpers/global_lists_vr.dm b/code/_helpers/global_lists_vr.dm
index 0406099616a..dd75d8a62e0 100644
--- a/code/_helpers/global_lists_vr.dm
+++ b/code/_helpers/global_lists_vr.dm
@@ -2,20 +2,17 @@
* VOREStation global lists
*/
-var/global/list/ear_styles_list = list() // Stores /datum/sprite_accessory/ears indexed by type
var/global/list/hair_accesories_list= list()// Stores /datum/sprite_accessory/hair_accessory indexed by type
-var/global/list/tail_styles_list = list() // Stores /datum/sprite_accessory/tail indexed by type
-var/global/list/wing_styles_list = list() // Stores /datum/sprite_accessory/wing indexed by type
var/global/list/negative_traits = list() // Negative custom species traits, indexed by path
var/global/list/neutral_traits = list() // Neutral custom species traits, indexed by path
+var/global/list/everyone_traits = list() // Neutral traits available to all species, indexed by path
var/global/list/positive_traits = list() // Positive custom species traits, indexed by path
var/global/list/traits_costs = list() // Just path = cost list, saves time in char setup
var/global/list/all_traits = list() // All of 'em at once (same instances)
+var/global/list/active_ghost_pods = list()
var/global/list/sensorpreflist = list("Off", "Binary", "Vitals", "Tracking", "No Preference") //TFF 5/8/19 - Suit Sensors global list
-var/global/list/custom_species_bases = list() // Species that can be used for a Custom Species icon base
-
//stores numeric player size options indexed by name
var/global/list/player_sizes_list = list(
"Macro" = RESIZE_HUGE,
@@ -106,30 +103,74 @@ var/global/list/fancy_release_sounds = list(
)
var/global/list/global_vore_egg_types = list(
- "Unathi" = UNATHI_EGG,
- "Tajaran" = TAJARAN_EGG,
- "Akula" = AKULA_EGG,
- "Skrell" = SKRELL_EGG,
- "Nevrean" = NEVREAN_EGG,
- "Sergal" = SERGAL_EGG,
- "Human" = HUMAN_EGG,
- "Slime" = SLIME_EGG,
- "Egg" = EGG_EGG,
- "Xenochimera" = XENOCHIMERA_EGG,
- "Xenomorph" = XENOMORPH_EGG)
+ "Unathi",
+ "Tajara",
+ "Akula",
+ "Skrell",
+ "Sergal",
+ "Nevrean",
+ "Human",
+ "Slime",
+ "Egg",
+ "Xenochimera",
+ "Xenomorph",
+ "Chocolate",
+ "Boney",
+ "Slime glob",
+ "Chicken",
+ "Synthetic",
+ "Bluespace Floppy",
+ "Bluespace Compressed File",
+ "Bluespace CD",
+ "Escape pod",
+ "Cooking error",
+ "Web cocoon",
+ "Honeycomb",
+ "Bug cocoon",
+ "Rock",
+ "Yellow",
+ "Blue",
+ "Green",
+ "Orange",
+ "Purple",
+ "Red",
+ "Rainbow",
+ "Spotted pink")
var/global/list/tf_vore_egg_types = list(
- "Unathi" = /obj/structure/closet/secure_closet/egg/unathi,
- "Tajara" = /obj/structure/closet/secure_closet/egg/tajaran,
- "Akula" = /obj/structure/closet/secure_closet/egg/shark,
- "Skrell" = /obj/structure/closet/secure_closet/egg/skrell,
- "Sergal" = /obj/structure/closet/secure_closet/egg/sergal,
- "Nevrean" = /obj/structure/closet/secure_closet/egg/nevrean,
- "Human" = /obj/structure/closet/secure_closet/egg/human,
- "Slime" = /obj/structure/closet/secure_closet/egg/slime,
- "Egg" = /obj/structure/closet/secure_closet/egg,
- "Xenochimera" = /obj/structure/closet/secure_closet/egg/scree,
- "Xenomorph" = /obj/structure/closet/secure_closet/egg/xenomorph)
+ "Unathi" = /obj/item/weapon/storage/vore_egg/unathi,
+ "Tajara" = /obj/item/weapon/storage/vore_egg/tajaran,
+ "Akula" = /obj/item/weapon/storage/vore_egg/shark,
+ "Skrell" = /obj/item/weapon/storage/vore_egg/skrell,
+ "Sergal" = /obj/item/weapon/storage/vore_egg/sergal,
+ "Nevrean" = /obj/item/weapon/storage/vore_egg/nevrean,
+ "Human" = /obj/item/weapon/storage/vore_egg/human,
+ "Slime" = /obj/item/weapon/storage/vore_egg/slime,
+ "Egg" = /obj/item/weapon/storage/vore_egg,
+ "Xenochimera" = /obj/item/weapon/storage/vore_egg/scree,
+ "Xenomorph" = /obj/item/weapon/storage/vore_egg/xenomorph,
+ "Chocolate" = /obj/item/weapon/storage/vore_egg/chocolate,
+ "Boney" = /obj/item/weapon/storage/vore_egg/owlpellet,
+ "Slime glob" = /obj/item/weapon/storage/vore_egg/slimeglob,
+ "Chicken" = /obj/item/weapon/storage/vore_egg/chicken,
+ "Synthetic" = /obj/item/weapon/storage/vore_egg/synthetic,
+ "Bluespace Floppy" = /obj/item/weapon/storage/vore_egg/floppy,
+ "Bluespace Compressed File" = /obj/item/weapon/storage/vore_egg/file,
+ "Bluespace CD" = /obj/item/weapon/storage/vore_egg/cd,
+ "Escape pod" = /obj/item/weapon/storage/vore_egg/escapepod,
+ "Cooking error" = /obj/item/weapon/storage/vore_egg/badrecipe,
+ "Web cocoon" = /obj/item/weapon/storage/vore_egg/cocoon,
+ "Honeycomb" = /obj/item/weapon/storage/vore_egg/honeycomb,
+ "Bug cocoon" = /obj/item/weapon/storage/vore_egg/bugcocoon,
+ "Rock" = /obj/item/weapon/storage/vore_egg/rock,
+ "Yellow" = /obj/item/weapon/storage/vore_egg/yellow,
+ "Blue" = /obj/item/weapon/storage/vore_egg/blue,
+ "Green" = /obj/item/weapon/storage/vore_egg/green,
+ "Orange" = /obj/item/weapon/storage/vore_egg/orange,
+ "Purple" = /obj/item/weapon/storage/vore_egg/purple,
+ "Red" = /obj/item/weapon/storage/vore_egg/red,
+ "Rainbow" = /obj/item/weapon/storage/vore_egg/rainbow,
+ "Spotted pink" = /obj/item/weapon/storage/vore_egg/pinkspots)
var/global/list/edible_trash = list(/obj/item/broken_device,
/obj/item/clothing/accessory/collar, //TFF 10/7/19 - add option to nom collars,
@@ -180,7 +221,8 @@ var/global/list/edible_trash = list(/obj/item/broken_device,
/obj/item/weapon/storage/fancy/cigarettes,
/obj/item/weapon/storage/fancy/crayons,
/obj/item/weapon/storage/fancy/egg_box,
- /obj/item/weapon/storage/wallet)
+ /obj/item/weapon/storage/wallet,
+ /obj/item/weapon/storage/vore_egg)
var/global/list/contamination_flavors = list(
"Generic" = contamination_flavors_generic,
@@ -434,30 +476,12 @@ var/global/list/remainless_species = list(SPECIES_PROMETHEAN,
/hook/startup/proc/init_vore_datum_ref_lists()
var/paths
- // Custom Ears
- paths = typesof(/datum/sprite_accessory/ears) - /datum/sprite_accessory/ears
- for(var/path in paths)
- var/obj/item/clothing/head/instance = new path()
- ear_styles_list[path] = instance
-
- // Custom Tails
- paths = typesof(/datum/sprite_accessory/tail) - /datum/sprite_accessory/tail - /datum/sprite_accessory/tail/taur
- for(var/path in paths)
- var/datum/sprite_accessory/tail/instance = new path()
- tail_styles_list[path] = instance
-
- // Custom Wings
- paths = typesof(/datum/sprite_accessory/wing) - /datum/sprite_accessory/wing
- for(var/path in paths)
- var/datum/sprite_accessory/wing/instance = new path()
- wing_styles_list[path] = instance
-
// Custom Hair Accessories
paths = typesof(/datum/sprite_accessory/hair_accessory) - /datum/sprite_accessory/hair_accessory
for(var/path in paths)
var/datum/sprite_accessory/hair_accessory/instance = new path()
hair_accesories_list[path] = instance
-
+
// Custom species traits
paths = typesof(/datum/trait) - /datum/trait
for(var/path in paths)
@@ -472,20 +496,27 @@ var/global/list/remainless_species = list(SPECIES_PROMETHEAN,
negative_traits[path] = instance
if(0)
neutral_traits[path] = instance
+ if(!(instance.custom_only))
+ everyone_traits[path] = instance
if(0.1 to INFINITY)
positive_traits[path] = instance
- // Custom species icon bases
- var/list/blacklisted_icons = list(SPECIES_CUSTOM,SPECIES_PROMETHEAN) //Just ones that won't work well.
- var/list/whitelisted_icons = list(SPECIES_FENNEC,SPECIES_XENOHYBRID) //Include these anyway
- for(var/species_name in GLOB.playable_species)
- if(species_name in blacklisted_icons)
- continue
- var/datum/species/S = GLOB.all_species[species_name]
- if(S.spawn_flags & SPECIES_IS_WHITELISTED)
- continue
- custom_species_bases += species_name
- for(var/species_name in whitelisted_icons)
- custom_species_bases += species_name
+ // Weaver recipe stuff
+ paths = typesof(/datum/weaver_recipe/structure) - /datum/weaver_recipe/structure
+ for(var/path in paths)
+ var/datum/weaver_recipe/instance = new path()
+ if(!instance.title)
+ continue //A prototype or something
+ weavable_structures[instance.title] = instance
+
+ paths = typesof(/datum/weaver_recipe/item) - /datum/weaver_recipe/item
+ for(var/path in paths)
+ var/datum/weaver_recipe/instance = new path()
+ if(!instance.title)
+ continue //A prototype or something
+ weavable_items[instance.title] = instance
return 1 // Hooks must return 1
+
+var/global/list/weavable_structures = list()
+var/global/list/weavable_items = list()
\ No newline at end of file
diff --git a/code/_helpers/unsorted.dm b/code/_helpers/unsorted.dm
index bc7dca1d749..6a8e6482ec8 100644
--- a/code/_helpers/unsorted.dm
+++ b/code/_helpers/unsorted.dm
@@ -1284,12 +1284,19 @@ var/list/WALLITEMS = list(
colour += temp_col
return colour
+/proc/color_square(red, green, blue, hex)
+ var/color = hex ? hex : "#[num2hex(red, 2)][num2hex(green, 2)][num2hex(blue, 2)]"
+ return "___"
+
var/mob/dview/dview_mob = new
//Version of view() which ignores darkness, because BYOND doesn't have it.
/proc/dview(var/range = world.view, var/center, var/invis_flags = 0)
if(!center)
return
+ if(!dview_mob) //VOREStation Add: Debugging
+ dview_mob = new
+ log_error("Had to recreate the dview mob!")
dview_mob.loc = center
@@ -1613,6 +1620,46 @@ GLOBAL_REAL_VAR(list/stack_trace_storage)
/proc/href(href_src, list/href_params, href_text)
return "[href_text]"
+// This is a helper for anything that wants to render the map in TGUI
+/proc/get_tgui_plane_masters()
+ . = list()
+ // 'Utility' planes
+ . += new /obj/screen/plane_master/fullbright //Lighting system (lighting_overlay objects)
+ . += new /obj/screen/plane_master/lighting //Lighting system (but different!)
+ . += new /obj/screen/plane_master/ghosts //Ghosts!
+ . += new /obj/screen/plane_master{plane = PLANE_AI_EYE} //AI Eye!
+
+ . += new /obj/screen/plane_master{plane = PLANE_CH_STATUS} //Status is the synth/human icon left side of medhuds
+ . += new /obj/screen/plane_master{plane = PLANE_CH_HEALTH} //Health bar
+ . += new /obj/screen/plane_master{plane = PLANE_CH_LIFE} //Alive-or-not icon
+ . += new /obj/screen/plane_master{plane = PLANE_CH_ID} //Job ID icon
+ . += new /obj/screen/plane_master{plane = PLANE_CH_WANTED} //Wanted status
+ . += new /obj/screen/plane_master{plane = PLANE_CH_IMPLOYAL} //Loyalty implants
+ . += new /obj/screen/plane_master{plane = PLANE_CH_IMPTRACK} //Tracking implants
+ . += new /obj/screen/plane_master{plane = PLANE_CH_IMPCHEM} //Chemical implants
+ . += new /obj/screen/plane_master{plane = PLANE_CH_SPECIAL} //"Special" role stuff
+ . += new /obj/screen/plane_master{plane = PLANE_CH_STATUS_OOC} //OOC status HUD
+
+ . += new /obj/screen/plane_master{plane = PLANE_ADMIN1} //For admin use
+ . += new /obj/screen/plane_master{plane = PLANE_ADMIN2} //For admin use
+ . += new /obj/screen/plane_master{plane = PLANE_ADMIN3} //For admin use
+
+ . += new /obj/screen/plane_master{plane = PLANE_MESONS} //Meson-specific things like open ceilings.
+ . += new /obj/screen/plane_master{plane = PLANE_BUILDMODE} //Things that only show up while in build mode
+
+ // Real tangible stuff planes
+ . += new /obj/screen/plane_master/main{plane = TURF_PLANE}
+ . += new /obj/screen/plane_master/main{plane = OBJ_PLANE}
+ . += new /obj/screen/plane_master/main{plane = MOB_PLANE}
+ . += new /obj/screen/plane_master/cloaked //Cloaked atoms!
+
+ //VOREStation Add - Random other plane masters
+ . += new /obj/screen/plane_master{plane = PLANE_CH_STATUS_R} //Right-side status icon
+ . += new /obj/screen/plane_master{plane = PLANE_CH_HEALTH_VR} //Health bar but transparent at 100
+ . += new /obj/screen/plane_master{plane = PLANE_CH_BACKUP} //Backup implant status
+ . += new /obj/screen/plane_master{plane = PLANE_CH_VANTAG} //Vore Antags
+ . += new /obj/screen/plane_master{plane = PLANE_AUGMENTED} //Augmented reality
+ //VOREStation Add End
/proc/CallAsync(datum/source, proctype, list/arguments)
set waitfor = FALSE
- return call(source, proctype)(arglist(arguments))
\ No newline at end of file
+ return call(source, proctype)(arglist(arguments))
diff --git a/code/_helpers/view.dm b/code/_helpers/view.dm
index 13ee837caa7..be60a56697f 100644
--- a/code/_helpers/view.dm
+++ b/code/_helpers/view.dm
@@ -10,3 +10,7 @@
viewX = text2num(viewrangelist[1])
viewY = text2num(viewrangelist[2])
return list(viewX, viewY)
+
+// Used to get `atom/O as obj|mob|turf in view()` to match against strings containing apostrophes immediately after substrings that match to other objects. Somehow. - Ater
+/proc/_validate_atom(atom/A)
+ return view()
\ No newline at end of file
diff --git a/code/_macros.dm b/code/_macros.dm
index 4796f93b472..33bdf30ceb9 100644
--- a/code/_macros.dm
+++ b/code/_macros.dm
@@ -37,4 +37,7 @@
#define random_id(key,min_id,max_id) uniqueness_repository.Generate(/datum/uniqueness_generator/id_random, key, min_id, max_id)
-#define ARGS_DEBUG log_debug("[__FILE__] - [__LINE__]") ; for(var/arg in args) { log_debug("\t[log_info_line(arg)]") }
\ No newline at end of file
+#define ARGS_DEBUG log_debug("[__FILE__] - [__LINE__]") ; for(var/arg in args) { log_debug("\t[log_info_line(arg)]") }
+
+#define isitem(A) istype(A, /obj/item)
+#define isTaurTail(A) istype(A, /datum/sprite_accessory/tail/taur)
diff --git a/code/_macros_vr.dm b/code/_macros_vr.dm
index 6a2134fb718..2eecbe69ed1 100644
--- a/code/_macros_vr.dm
+++ b/code/_macros_vr.dm
@@ -1,3 +1 @@
#define isbelly(A) istype(A, /obj/belly)
-#define isitem(A) istype(A, /obj/item)
-#define isTaurTail(A) istype(A, /datum/sprite_accessory/tail/taur)
diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm
index 6a4579f1919..b29a1192d9b 100644
--- a/code/_onclick/click.dm
+++ b/code/_onclick/click.dm
@@ -354,19 +354,13 @@
facedir(direction)
/obj/screen/click_catcher
+ name = "Darkness"
icon = 'icons/mob/screen_gen.dmi'
icon_state = "click_catcher"
plane = CLICKCATCHER_PLANE
+ layer = LAYER_HUD_UNDER
mouse_opacity = 2
- screen_loc = "CENTER-7,CENTER-7"
-
-/obj/screen/click_catcher/proc/MakeGreed()
- . = list()
- for(var/i = 0, i<15, i++)
- for(var/j = 0, j<15, j++)
- var/obj/screen/click_catcher/CC = new()
- CC.screen_loc = "NORTH-[i],EAST-[j]"
- . += CC
+ screen_loc = "SOUTHWEST to NORTHEAST"
/obj/screen/click_catcher/Click(location, control, params)
var/list/modifiers = params2list(params)
@@ -374,7 +368,8 @@
var/mob/living/carbon/C = usr
C.swap_hand()
else
- var/turf/T = screen_loc2turf(screen_loc, get_turf(usr))
+ var/list/P = params2list(params)
+ var/turf/T = screen_loc2turf(P["screen-loc"], get_turf(usr))
if(T)
T.Click(location, control, params)
. = 1
diff --git a/code/_onclick/cyborg.dm b/code/_onclick/cyborg.dm
index d63d49e8d76..213fe57b90e 100644
--- a/code/_onclick/cyborg.dm
+++ b/code/_onclick/cyborg.dm
@@ -60,6 +60,8 @@
// Cyborgs have no range-checking unless there is item use
if(!W)
+ if(bolt && !bolt.malfunction && A.loc != module)
+ return
A.add_hiddenprint(src)
A.attack_robot(src)
return
@@ -120,35 +122,56 @@
/atom/proc/BorgCtrlShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden
CtrlShiftClick(user)
-/obj/machinery/door/airlock/BorgCtrlShiftClick(mob/user)
+/obj/machinery/door/airlock/BorgCtrlShiftClick(var/mob/living/silicon/robot/user)
+ if(user.bolt && !user.bolt.malfunction)
+ return
+
AICtrlShiftClick(user)
/atom/proc/BorgShiftClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden
ShiftClick(user)
-/obj/machinery/door/airlock/BorgShiftClick(mob/user) // Opens and closes doors! Forwards to AI code.
+/obj/machinery/door/airlock/BorgShiftClick(var/mob/living/silicon/robot/user) // Opens and closes doors! Forwards to AI code.
+ if(user.bolt && !user.bolt.malfunction)
+ return
+
AIShiftClick(user)
/atom/proc/BorgCtrlClick(var/mob/living/silicon/robot/user) //forward to human click if not overriden
CtrlClick(user)
-/obj/machinery/door/airlock/BorgCtrlClick(mob/user) // Bolts doors. Forwards to AI code.
+/obj/machinery/door/airlock/BorgCtrlClick(var/mob/living/silicon/robot/user) // Bolts doors. Forwards to AI code.
+ if(user.bolt && !user.bolt.malfunction)
+ return
+
AICtrlClick(user)
-/obj/machinery/power/apc/BorgCtrlClick(mob/user) // turns off/on APCs. Forwards to AI code.
+/obj/machinery/power/apc/BorgCtrlClick(var/mob/living/silicon/robot/user) // turns off/on APCs. Forwards to AI code.
+ if(user.bolt && !user.bolt.malfunction)
+ return
+
AICtrlClick(user)
-/obj/machinery/turretid/BorgCtrlClick(mob/user) //turret control on/off. Forwards to AI code.
+/obj/machinery/turretid/BorgCtrlClick(var/mob/living/silicon/robot/user) //turret control on/off. Forwards to AI code.
+ if(user.bolt && !user.bolt.malfunction)
+ return
+
AICtrlClick(user)
/atom/proc/BorgAltClick(var/mob/living/silicon/robot/user)
AltClick(user)
return
-/obj/machinery/door/airlock/BorgAltClick(mob/user) // Eletrifies doors. Forwards to AI code.
+/obj/machinery/door/airlock/BorgAltClick(var/mob/living/silicon/robot/user) // Eletrifies doors. Forwards to AI code.
+ if(user.bolt && !user.bolt.malfunction)
+ return
+
AIAltClick(user)
-/obj/machinery/turretid/BorgAltClick(mob/user) //turret lethal on/off. Forwards to AI code.
+/obj/machinery/turretid/BorgAltClick(var/mob/living/silicon/robot/user) //turret lethal on/off. Forwards to AI code.
+ if(user.bolt && !user.bolt.malfunction)
+ return
+
AIAltClick(user)
/*
diff --git a/code/_onclick/hud/_defines.dm b/code/_onclick/hud/_defines.dm
index d31a64dcda6..247d1d3f8bf 100644
--- a/code/_onclick/hud/_defines.dm
+++ b/code/_onclick/hud/_defines.dm
@@ -161,6 +161,13 @@
#define ui_ghost_pai "SOUTH: 6,CENTER+2:24"
#define ui_ghost_updown "SOUTH: 6,CENTER+3:24"
+// NIF Soulcatcher guest ones
+#define ui_nifsc_reenter "SOUTH:6,CENTER-3:24"
+#define ui_nifsc_arproj "SOUTH:6,CENTER-2:24"
+#define ui_nifsc_jumptoowner "SOUTH:6,CENTER-1:24"
+#define ui_nifsc_nme "SOUTH:6,CENTER:24"
+#define ui_nifsc_nsay "SOUTH:6,CENTER+1:24"
+
// Rig panel
#define ui_rig_deco1 "WEST:-7, SOUTH+5"
#define ui_rig_deco2 "WEST:-7, SOUTH+6"
diff --git a/code/_onclick/hud/_defines_vr.dm b/code/_onclick/hud/_defines_vr.dm
index 2b4f4fb85e2..b419c6bd7f8 100644
--- a/code/_onclick/hud/_defines_vr.dm
+++ b/code/_onclick/hud/_defines_vr.dm
@@ -1,3 +1,2 @@
-#define ui_shadekin_dark_display "EAST-1:28,CENTER-3:15"
-#define ui_shadekin_energy_display "EAST-1:28,CENTER-4:15"
+#define ui_shadekin_display "EAST-1:28,CENTER-3:15"
#define ui_xenochimera_danger_display "EAST-1:28,CENTER-3:15"
\ No newline at end of file
diff --git a/code/_onclick/hud/human.dm b/code/_onclick/hud/human.dm
index 6387f40d9ec..22e8e459fc5 100644
--- a/code/_onclick/hud/human.dm
+++ b/code/_onclick/hud/human.dm
@@ -14,7 +14,7 @@
var/other = list()
var/hotkeybuttons = list()
var/slot_info = list()
-
+
HUD.adding = adding
HUD.other = other
HUD.hotkeybuttons = hotkeybuttons //These can be disabled for hotkey users
@@ -258,15 +258,10 @@
hud_elements |= healths
//VOREStation Addition begin
- shadekin_dark_display = new /obj/screen/shadekin/darkness()
- shadekin_dark_display.screen_loc = ui_shadekin_dark_display
- shadekin_dark_display.icon_state = "dark"
- hud_elements |= shadekin_dark_display
-
- shadekin_energy_display = new /obj/screen/shadekin/energy()
- shadekin_energy_display.screen_loc = ui_shadekin_energy_display
- shadekin_energy_display.icon_state = "energy0"
- hud_elements |= shadekin_energy_display
+ shadekin_display = new /obj/screen/shadekin()
+ shadekin_display.screen_loc = ui_shadekin_display
+ shadekin_display.icon_state = "shadekin"
+ hud_elements |= shadekin_display
xenochimera_danger_display = new /obj/screen/xenochimera/danger_level()
xenochimera_danger_display.screen_loc = ui_xenochimera_danger_display
diff --git a/code/_onclick/hud/screen_objects_vr.dm b/code/_onclick/hud/screen_objects_vr.dm
index b3388f7bf76..1d8df98a38b 100644
--- a/code/_onclick/hud/screen_objects_vr.dm
+++ b/code/_onclick/hud/screen_objects_vr.dm
@@ -11,6 +11,11 @@
var/mob/living/simple_mob/shadekin/SK = usr
if(istype(SK))
to_chat(usr,"Energy: [SK.energy] ([SK.dark_gains])")
+ if("shadekin status")
+ var/turf/T = get_turf(usr)
+ if(T)
+ var/darkness = round(1 - T.get_lumcount(),0.1)
+ to_chat(usr,"Darkness: [darkness]")
var/mob/living/carbon/human/H = usr
if(istype(H) && istype(H.species, /datum/species/shadekin))
to_chat(usr,"Energy: [H.shadekin_get_energy(H)]")
diff --git a/code/_onclick/hud/soulcatcher_guest.dm b/code/_onclick/hud/soulcatcher_guest.dm
new file mode 100644
index 00000000000..555bcb8ebaf
--- /dev/null
+++ b/code/_onclick/hud/soulcatcher_guest.dm
@@ -0,0 +1,102 @@
+/obj/screen/nifsc
+ icon = 'icons/mob/screen_nifsc.dmi'
+
+/obj/screen/nifsc/MouseEntered(location,control,params)
+ flick(icon_state + "_anim", src)
+ openToolTip(usr, src, params, title = name, content = desc)
+
+/obj/screen/nifsc/MouseExited()
+ closeToolTip(usr)
+
+/obj/screen/nifsc/Click()
+ closeToolTip(usr)
+
+/obj/screen/nifsc/reenter
+ name = "Re-enter NIF"
+ desc = "Return into the NIF"
+ icon_state = "reenter"
+
+/obj/screen/nifsc/reenter/Click()
+ ..()
+ var/mob/living/carbon/brain/caught_soul/CS = usr
+ CS.reenter_soulcatcher()
+
+/obj/screen/nifsc/arproj
+ name = "AR project"
+ desc = "Project your form into Augmented Reality for those around your predator with the appearance of your loaded character."
+ icon_state = "arproj"
+
+/obj/screen/nifsc/arproj/Click()
+ ..()
+ var/mob/living/carbon/brain/caught_soul/CS = usr
+ CS.ar_project()
+
+/obj/screen/nifsc/jumptoowner
+ name = "Jump back to host"
+ desc = "Jumb back to the Soulcather host"
+ icon_state = "jump"
+
+/obj/screen/nifsc/jumptoowner/Click()
+ ..()
+ var/mob/living/carbon/brain/caught_soul/CS = usr
+ CS.jump_to_owner()
+
+/obj/screen/nifsc/nme
+ name = "Emote into Soulcatcher"
+ desc = "Emote into the NIF's Soulcatcher (circumventing AR emoting)"
+ icon_state = "nme"
+
+/obj/screen/nifsc/nme/Click()
+ ..()
+ var/mob/living/carbon/brain/caught_soul/CS = usr
+ CS.nme()
+
+/obj/screen/nifsc/nsay
+ name = "Speak into Soulcatcher"
+ desc = "Speak into the NIF's Soulcatcher (circumventing AR speaking)"
+ icon_state = "nsay"
+
+/obj/screen/nifsc/nsay/Click()
+ ..()
+ var/mob/living/carbon/brain/caught_soul/CS = usr
+ CS.nsay()
+
+
+/mob/living/carbon/brain/caught_soul/create_mob_hud(datum/hud/HUD, apply_to_client = TRUE)
+ ..()
+
+ var/list/adding = list()
+ HUD.adding = adding
+
+ var/obj/screen/using
+
+ using = new /obj/screen/nifsc/reenter()
+ using.screen_loc = ui_nifsc_reenter
+ using.hud = src
+ adding += using
+
+ using = new /obj/screen/nifsc/arproj()
+ using.screen_loc = ui_nifsc_arproj
+ using.hud = src
+ adding += using
+
+ using = new /obj/screen/nifsc/jumptoowner()
+ using.screen_loc = ui_nifsc_jumptoowner
+ using.hud = src
+ adding += using
+
+ using = new /obj/screen/nifsc/nme()
+ using.screen_loc = ui_nifsc_nme
+ using.hud = src
+ adding += using
+
+ using = new /obj/screen/nifsc/nsay()
+ using.screen_loc = ui_nifsc_nsay
+ using.hud = src
+ adding += using
+
+
+ if(client && apply_to_client)
+ client.screen = list()
+ client.screen += HUD.adding
+ client.screen += client.void
diff --git a/code/controllers/configuration.dm b/code/controllers/configuration.dm
index 2b7aa15bbc0..67d14623cf6 100644
--- a/code/controllers/configuration.dm
+++ b/code/controllers/configuration.dm
@@ -496,7 +496,7 @@ var/list/gamemode_cache = list()
config.respawn_time = raw_minutes MINUTES
if ("respawn_message")
- config.respawn_message = value
+ config.respawn_message = "[value]"
if ("servername")
config.server_name = value
diff --git a/code/controllers/subsystems/overlays.dm b/code/controllers/subsystems/overlays.dm
index 60b08c71d2c..77c9d3ab94a 100644
--- a/code/controllers/subsystems/overlays.dm
+++ b/code/controllers/subsystems/overlays.dm
@@ -5,7 +5,6 @@ SUBSYSTEM_DEF(overlays)
priority = FIRE_PRIORITY_OVERLAYS
init_order = INIT_ORDER_OVERLAY
- var/initialized = FALSE
var/list/queue // Queue of atoms needing overlay compiling (TODO-VERIFY!)
var/list/stats
var/list/overlay_icon_state_caches // Cache thing
@@ -22,7 +21,6 @@ var/global/image/appearance_bro = new() // Temporarily super-global because of B
stats = list()
/datum/controller/subsystem/overlays/Initialize()
- initialized = TRUE
fire(mc_check = FALSE)
..()
diff --git a/code/controllers/subsystems/processing/chemistry.dm b/code/controllers/subsystems/processing/chemistry.dm
index 7f4fd9c42b6..b4641ba7e00 100644
--- a/code/controllers/subsystems/processing/chemistry.dm
+++ b/code/controllers/subsystems/processing/chemistry.dm
@@ -22,6 +22,7 @@ PROCESSING_SUBSYSTEM_DEF(chemistry)
/datum/controller/subsystem/processing/chemistry/Initialize()
initialize_chemical_reactions()
initialize_chemical_reagents()
+ ..()
//Chemical Reactions - Initialises all /datum/chemical_reaction into a list
// It is filtered into multiple lists within a list.
diff --git a/code/controllers/subsystems/shuttles.dm b/code/controllers/subsystems/shuttles.dm
index 0bce9403851..40039edceb5 100644
--- a/code/controllers/subsystems/shuttles.dm
+++ b/code/controllers/subsystems/shuttles.dm
@@ -4,9 +4,6 @@
// Also handles initialization and processing of overmap sectors.
//
-// This global variable exists for legacy support so we don't have to rename every shuttle_controller to SSshuttles yet.
-var/global/datum/controller/subsystem/shuttles/shuttle_controller
-
SUBSYSTEM_DEF(shuttles)
name = "Shuttles"
wait = 2 SECONDS
@@ -35,9 +32,6 @@ SUBSYSTEM_DEF(shuttles)
var/tmp/list/current_run // Shuttles remaining to process this fire() tick
-/datum/controller/subsystem/shuttles/PreInit()
- global.shuttle_controller = src // TODO - Remove this! Change everything to point at SSshuttles intead
-
/datum/controller/subsystem/shuttles/Initialize(timeofday)
last_landmark_registration_time = world.time
// Find all declared shuttle datums and initailize them. (Okay, queue them for initialization a few lines further down)
diff --git a/code/controllers/subsystems/ticker.dm b/code/controllers/subsystems/ticker.dm
index cdb2adefde3..750f6807cca 100644
--- a/code/controllers/subsystems/ticker.dm
+++ b/code/controllers/subsystems/ticker.dm
@@ -49,10 +49,7 @@ var/global/datum/controller/subsystem/ticker/ticker
/datum/controller/subsystem/ticker/Initialize()
pregame_timeleft = config.pregame_time
send2mainirc("Server lobby is loaded and open at byond://[config.serverurl ? config.serverurl : (config.server ? config.server : "[world.address]:[world.port]")]")
-
- // Set up the global announcer
- GLOB.autospeaker = new (null, null, null, 1)
-
+ GLOB.autospeaker = new (null, null, null, 1) //Set up Global Announcer
return ..()
/datum/controller/subsystem/ticker/fire(resumed = FALSE)
@@ -186,11 +183,6 @@ var/global/datum/controller/subsystem/ticker/ticker
if(adm["total"] == 0)
send2adminirc("A round has started with no admins online.")
-/* supply_controller.process() //Start the supply shuttle regenerating points -- TLE // handled in scheduler
- master_controller.process() //Start master_controller.process()
- lighting_controller.process() //Start processing DynamicAreaLighting updates
- */
-
current_state = GAME_STATE_PLAYING
Master.SetRunLevel(RUNLEVEL_GAME)
diff --git a/code/datums/autolathe/arms.dm b/code/datums/autolathe/arms.dm
index 169232d8451..b2bb0c98b7d 100644
--- a/code/datums/autolathe/arms.dm
+++ b/code/datums/autolathe/arms.dm
@@ -326,6 +326,15 @@
category = list("Arms and Ammunition")
hidden = 1*/
+/*
+ * High Caliber
+ */
+
+/datum/category_item/autolathe/arms/rifle_145
+ name = "14.5mm round (sabot)"
+ path = /obj/item/ammo_casing/a145/highvel
+ hidden = 1
+
///////////////////////////////
/*Ammo clips and Speedloaders*/
///////////////////////////////
diff --git a/code/datums/autolathe/autolathe.dm b/code/datums/autolathe/autolathe.dm
index 4af1abfccdb..03d1ca0fddb 100644
--- a/code/datums/autolathe/autolathe.dm
+++ b/code/datums/autolathe/autolathe.dm
@@ -1,6 +1,13 @@
/datum/category_item/autolathe/New()
..()
- var/obj/item/I = new path()
+ var/obj/item/I
+ if(path)
+ I = new path()
+
+ if(!I) // Something has gone horribly wrong, or right.
+ log_debug("[name] created an Autolathe design without an assigned path. This is expected for only the Material Sheet generation.")
+ return
+
if(I.matter && !resources)
resources = list()
for(var/material in I.matter)
@@ -57,6 +64,42 @@
name = "Tools"
category_item_type = /datum/category_item/autolathe/tools
+/datum/category_group/autolathe/materials
+ name = "Materials"
+ category_item_type = /datum/category_item/autolathe/materials
+
+/datum/category_group/autolathe/materials/New()
+ ..()
+
+ for(var/Name in name_to_material)
+ var/datum/material/M = name_to_material[Name]
+
+ if(!M.stack_type) // Shouldn't happen, but might. Never know.
+ continue
+
+ if(istype(M, /datum/material/alienalloy))
+ continue
+
+ var/obj/item/stack/material/Mat = new M.stack_type()
+
+ if(Mat.name in items_by_name)
+ qdel(Mat)
+ continue
+
+ var/datum/category_item/autolathe/materials/WorkDat = new(src)
+
+ WorkDat.name = "[Mat.name]"
+ WorkDat.resources = Mat.matter.Copy()
+ WorkDat.is_stack = TRUE
+ WorkDat.no_scale = TRUE
+ WorkDat.max_stack = Mat.max_amount
+ WorkDat.path = M.stack_type
+
+ qdel(Mat)
+
+ items |= WorkDat
+ items_by_name[WorkDat.name] = WorkDat
+
/*******************
* Category entries *
*******************/
diff --git a/code/datums/autolathe/devices.dm b/code/datums/autolathe/devices.dm
index 9c6ab5bb97e..eed4839159c 100644
--- a/code/datums/autolathe/devices.dm
+++ b/code/datums/autolathe/devices.dm
@@ -26,6 +26,12 @@
name = "mechanical trap"
path =/obj/item/weapon/beartrap
+/datum/category_item/autolathe/devices/barbedwire
+ name = "barbed wire"
+ path = /obj/item/weapon/material/barbedwire
+ hidden = 1
+ resources = list(DEFAULT_WALL_MATERIAL = 10000)
+
/datum/category_item/autolathe/devices/electropack
name = "electropack"
path =/obj/item/device/radio/electropack
diff --git a/code/datums/autolathe/engineering_vr.dm b/code/datums/autolathe/engineering_vr.dm
index 08e1cf986bf..90970c6e481 100644
--- a/code/datums/autolathe/engineering_vr.dm
+++ b/code/datums/autolathe/engineering_vr.dm
@@ -4,4 +4,24 @@
/datum/category_item/autolathe/engineering/id_restorer
name = "ID restoration console electronics"
- path =/obj/item/weapon/circuitboard/id_restorer
\ No newline at end of file
+ path =/obj/item/weapon/circuitboard/id_restorer
+
+/datum/category_item/autolathe/engineering/oven
+ name = "oven electronics"
+ path =/obj/item/weapon/circuitboard/oven
+
+/datum/category_item/autolathe/engineering/fryer
+ name = "fryer electronics"
+ path =/obj/item/weapon/circuitboard/fryer
+
+/datum/category_item/autolathe/engineering/grill
+ name = "grill electronics"
+ path =/obj/item/weapon/circuitboard/grill
+
+/datum/category_item/autolathe/engineering/cerealmaker
+ name = "cereal maker electronics"
+ path =/obj/item/weapon/circuitboard/cerealmaker
+
+/datum/category_item/autolathe/engineering/candymachine
+ name = "candy machine electronics"
+ path =/obj/item/weapon/circuitboard/candymachine
\ No newline at end of file
diff --git a/code/datums/autolathe/general.dm b/code/datums/autolathe/general.dm
index 8ee77ce6564..00151d6e757 100644
--- a/code/datums/autolathe/general.dm
+++ b/code/datums/autolathe/general.dm
@@ -85,44 +85,6 @@
name = "welding mask"
path =/obj/item/clothing/head/welding
-/datum/category_item/autolathe/general/metal
- name = "steel sheets"
- path =/obj/item/stack/material/steel
- is_stack = TRUE
- no_scale = TRUE //prevents material duplication exploits
-
-/datum/category_item/autolathe/general/glass
- name = "glass sheets"
- path =/obj/item/stack/material/glass
- is_stack = TRUE
- no_scale = TRUE //prevents material duplication exploits
-
-/datum/category_item/autolathe/general/rglass
- name = "reinforced glass sheets"
- path =/obj/item/stack/material/glass/reinforced
- is_stack = TRUE
- no_scale = TRUE //prevents material duplication exploits
-
-/datum/category_item/autolathe/general/rods
- name = "metal rods"
- path =/obj/item/stack/rods
- is_stack = TRUE
- no_scale = TRUE //prevents material duplication exploits
-
-/datum/category_item/autolathe/general/plasteel
- name = "plasteel sheets"
- path =/obj/item/stack/material/plasteel
- is_stack = TRUE
- no_scale = TRUE //prevents material duplication exploits
- resources = list(MAT_PLASTEEL = 2000)
-
-/datum/category_item/autolathe/general/plastic
- name = "plastic sheets"
- path =/obj/item/stack/material/plastic
- is_stack = TRUE
- no_scale = TRUE //prevents material duplication exploits
- resources = list(MAT_PLASTIC = 2000)
-
//TFF 24/12/19 - Let people print more spray bottles if needed.
/datum/category_item/autolathe/general/spraybottle
name = "spray bottle"
diff --git a/code/datums/autolathe/materials.dm b/code/datums/autolathe/materials.dm
new file mode 100644
index 00000000000..653fca8222e
--- /dev/null
+++ b/code/datums/autolathe/materials.dm
@@ -0,0 +1,38 @@
+
+/datum/category_item/autolathe/materials/metal
+ name = "steel sheets"
+ path =/obj/item/stack/material/steel
+ is_stack = TRUE
+ no_scale = TRUE //prevents material duplication exploits
+
+/datum/category_item/autolathe/materials/glass
+ name = "glass sheets"
+ path =/obj/item/stack/material/glass
+ is_stack = TRUE
+ no_scale = TRUE //prevents material duplication exploits
+
+/datum/category_item/autolathe/materials/rglass
+ name = "reinforced glass sheets"
+ path =/obj/item/stack/material/glass/reinforced
+ is_stack = TRUE
+ no_scale = TRUE //prevents material duplication exploits
+
+/datum/category_item/autolathe/materials/rods
+ name = "metal rods"
+ path =/obj/item/stack/rods
+ is_stack = TRUE
+ no_scale = TRUE //prevents material duplication exploits
+
+/datum/category_item/autolathe/materials/plasteel
+ name = "plasteel sheets"
+ path =/obj/item/stack/material/plasteel
+ is_stack = TRUE
+ no_scale = TRUE //prevents material duplication exploits
+ resources = list(MAT_PLASTEEL = 2000)
+
+/datum/category_item/autolathe/materials/plastic
+ name = "plastic sheets"
+ path =/obj/item/stack/material/plastic
+ is_stack = TRUE
+ no_scale = TRUE //prevents material duplication exploits
+ resources = list(MAT_PLASTIC = 2000)
diff --git a/code/datums/autolathe/tools.dm b/code/datums/autolathe/tools.dm
index 9e9a87ea71f..9b88a496fa9 100644
--- a/code/datums/autolathe/tools.dm
+++ b/code/datums/autolathe/tools.dm
@@ -48,6 +48,11 @@
path = /obj/item/weapon/reagent_containers/spray
resources = list(MAT_PLASTIC = 2000)
+/datum/category_item/autolathe/devices/slowwire
+ name = "snare wire"
+ path = /obj/item/weapon/material/barbedwire/plastic
+ resources = list(MAT_PLASTIC = 10000)
+
/datum/category_item/autolathe/tools/spraynozzle
name = "spray nozzle"
path = /obj/item/weapon/reagent_containers/spray
diff --git a/code/datums/mind.dm b/code/datums/mind.dm
index bca9df5ae1e..82e5f1f78bd 100644
--- a/code/datums/mind.dm
+++ b/code/datums/mind.dm
@@ -55,6 +55,9 @@
var/rev_cooldown = 0
var/tcrystals = 0
+ var/list/purchase_log = new
+ var/used_TC = 0
+
// the world.time since the mob has been brigged, or -1 if not at all
var/brigged_since = -1
@@ -73,7 +76,7 @@
/datum/mind/New(var/key)
src.key = key
-
+ purchase_log = list()
..()
/datum/mind/proc/transfer_to(mob/living/new_character)
@@ -510,8 +513,9 @@
//HUMAN
/mob/living/carbon/human/mind_initialize()
- ..()
- if(!mind.assigned_role) mind.assigned_role = USELESS_JOB //defualt //VOREStation Edit - Visitor not Assistant
+ . = ..()
+ if(!mind.assigned_role)
+ mind.assigned_role = USELESS_JOB //defualt //VOREStation Edit - Visitor not Assistant
//slime
/mob/living/simple_mob/slime/mind_initialize()
diff --git a/code/datums/observation/~cleanup.dm b/code/datums/observation/~cleanup.dm
index 825902d4839..9dcc601436a 100644
--- a/code/datums/observation/~cleanup.dm
+++ b/code/datums/observation/~cleanup.dm
@@ -43,7 +43,7 @@ GLOBAL_LIST_EMPTY(event_listen_count)
for(var/entry in GLOB.all_observable_events.events)
var/decl/observ/event = entry
if(event.unregister_global(listener))
- log_debug("[event] - [listener] was deleted while still registered to global events.")
+ // log_debug("[event] - [listener] was deleted while still registered to global events.") // TODO: Apply axe, reimplement with datum component listeners
if(!(--listen_count))
return
@@ -55,7 +55,7 @@ GLOBAL_LIST_EMPTY(event_listen_count)
if(proc_owners)
for(var/proc_owner in proc_owners)
if(event.unregister(event_source, proc_owner))
- log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].")
+ // log_debug("[event] - [event_source] was deleted while still being listened to by [proc_owner].") // TODO: Apply axe, reimplement with datum component listeners
if(!(--source_listener_count))
return
@@ -65,6 +65,6 @@ GLOBAL_LIST_EMPTY(event_listen_count)
var/decl/observ/event = entry
for(var/event_source in event.event_sources)
if(event.unregister(event_source, listener))
- log_debug("[event] - [listener] was deleted while still listening to [event_source].")
+ // log_debug("[event] - [listener] was deleted while still listening to [event_source].") // TODO: Apply axe, reimplement with datum component listeners
if(!(--listener_count))
return
\ No newline at end of file
diff --git a/code/datums/outfits/jobs/special_vr.dm b/code/datums/outfits/jobs/special_vr.dm
index dd8316358b6..010010291dd 100644
--- a/code/datums/outfits/jobs/special_vr.dm
+++ b/code/datums/outfits/jobs/special_vr.dm
@@ -9,6 +9,21 @@
id_type = /obj/item/weapon/card/id/centcom
pda_type = /obj/item/device/pda/centcom
+/decl/hierarchy/outfit/job/emergency_responder
+ name = OUTFIT_JOB_NAME("Emergency Responder")
+ uniform = /obj/item/clothing/under/ert
+ shoes = /obj/item/clothing/shoes/boots/swat
+ gloves = /obj/item/clothing/gloves/swat
+ l_ear = /obj/item/device/radio/headset/ert
+ glasses = /obj/item/clothing/glasses/sunglasses
+ back = /obj/item/weapon/storage/backpack/satchel
+ id_type = /obj/item/weapon/card/id/centcom/ERT
+ pda_type = /obj/item/device/pda/centcom
+
+ post_equip(var/mob/living/carbon/human/H)
+ ..()
+ ert.add_antagonist(H.mind)
+
/decl/hierarchy/outfit/job/clown
name = OUTFIT_JOB_NAME("Clown")
uniform = /obj/item/clothing/under/rank/clown
diff --git a/code/datums/roundstats/_defines_local.dm b/code/datums/roundstats/_defines_local.dm
new file mode 100644
index 00000000000..951d7118ff8
--- /dev/null
+++ b/code/datums/roundstats/_defines_local.dm
@@ -0,0 +1,7 @@
+
+#define GOAL_GENERAL "Common Goal"
+#define GOAL_MEDICAL "Medical Goal"
+#define GOAL_SECURITY "Security Goal"
+#define GOAL_ENGINEERING "Engineering Goal"
+#define GOAL_CARGO "Cargo Goal"
+#define GOAL_RESEARCH "Research Goal"
diff --git a/code/datums/roundstats/departmentgoal.dm b/code/datums/roundstats/departmentgoal.dm
new file mode 100644
index 00000000000..333e6c03963
--- /dev/null
+++ b/code/datums/roundstats/departmentgoal.dm
@@ -0,0 +1,101 @@
+
+GLOBAL_LIST(department_goals)
+GLOBAL_LIST(active_department_goals)
+
+/hook/startup/proc/initializeDepartmentGoals()
+ GLOB.department_goals = list(GOAL_GENERAL, GOAL_MEDICAL, GOAL_SECURITY, GOAL_ENGINEERING, GOAL_CARGO, GOAL_RESEARCH)
+ GLOB.active_department_goals = list(GOAL_GENERAL, GOAL_MEDICAL, GOAL_SECURITY, GOAL_ENGINEERING, GOAL_CARGO, GOAL_RESEARCH)
+
+ for(var/category in GLOB.department_goals)
+ GLOB.department_goals[category] = list()
+
+ for(var/subtype in subtypesof(/datum/goal))
+ var/datum/goal/SG = new subtype()
+
+ if(SG.name == "goal")
+ continue
+
+ if(SG.category == category)
+ GLOB.department_goals[category] |= SG
+
+ for(var/category in GLOB.active_department_goals)
+ GLOB.active_department_goals[category] = list()
+ var/list/cat_goals = GLOB.department_goals[category]
+
+ var/goal_count = rand(2,4)
+
+ for(var/count = 1 to goal_count)
+ var/datum/goal/G
+
+ if(LAZYLEN(cat_goals))
+ G = pick(cat_goals)
+
+ if(G)
+ G.active_goal = TRUE
+ cat_goals -= G
+
+ GLOB.active_department_goals[category] |= G
+ return 1
+
+/hook/roundend/proc/checkDepartmentGoals()
+ for(var/category in GLOB.active_department_goals)
+ var/list/cat_goals = GLOB.active_department_goals[category]
+
+ to_world("[category]")
+
+ if(!LAZYLEN(cat_goals))
+ to_world("There were no assigned goals!")
+
+ else
+ for(var/datum/goal/G in cat_goals)
+ var/success = G.check_completion()
+ to_world("[success ? "[G.name]" : "[G.name]"]")
+ to_world("[G.goal_text]")
+ return 1
+
+/datum/goal
+ var/name = "goal"
+
+ var/goal_text = "Do nothing! Congratulations."
+
+ var/active_goal = FALSE
+
+ var/category = GOAL_GENERAL
+
+/datum/goal/proc/check_completion()
+ return FALSE
+
+/datum/goal/common
+ name = "goal"
+
+ goal_text = "Congratulations, you still do nothing."
+
+/datum/goal/medical
+ name = "goal"
+
+ goal_text = "Congratulations, you still do nothing."
+ category = GOAL_MEDICAL
+
+/datum/goal/security
+ name = "goal"
+
+ goal_text = "Congratulations, you still do nothing."
+ category = GOAL_SECURITY
+
+/datum/goal/engineering
+ name = "goal"
+
+ goal_text = "Congratulations, you still do nothing."
+ category = GOAL_ENGINEERING
+
+/datum/goal/cargo
+ name = "goal"
+
+ goal_text = "Congratulations, you still do nothing."
+ category = GOAL_CARGO
+
+/datum/goal/research
+ name = "goal"
+
+ goal_text = "Congratulations, you still do nothing."
+ category = GOAL_RESEARCH
diff --git a/code/datums/roundstats/roundstats.dm b/code/datums/roundstats/roundstats.dm
new file mode 100644
index 00000000000..c1453b18aff
--- /dev/null
+++ b/code/datums/roundstats/roundstats.dm
@@ -0,0 +1,57 @@
+
+/*
+ * lbnesquik - Github
+ * Provided massive components of this. Polaris PR #5720.
+ */
+
+//This is for the round end stats system.
+
+//roundstat is used for easy finding of the variables, if you ever want to delete all of this,
+//just search roundstat and you'll find everywhere this thing reaches into.
+//It used to be bazinga but it only fly with microwaves.
+
+GLOBAL_VAR_INIT(cans_opened_roundstat, 0)
+GLOBAL_VAR_INIT(lights_switched_on_roundstat, 0)
+GLOBAL_VAR_INIT(turbo_lift_floors_moved_roundstat, 0)
+GLOBAL_VAR_INIT(lost_limbs_shift_roundstat, 0)
+GLOBAL_VAR_INIT(seed_planted_shift_roundstat, 0)
+GLOBAL_VAR_INIT(step_taken_shift_roundstat, 0)
+GLOBAL_VAR_INIT(destroyed_research_items_roundstat, 0)
+GLOBAL_VAR_INIT(items_sold_shift_roundstat, 0)
+GLOBAL_VAR_INIT(disposals_flush_shift_roundstat, 0)
+GLOBAL_VAR_INIT(rocks_drilled_roundstat, 0)
+GLOBAL_VAR_INIT(mech_destroyed_roundstat, 0)
+
+/hook/roundend/proc/RoundTrivia()//bazinga
+ var/list/valid_stats_list = list() //This is to be populated with the good shit
+
+ if(GLOB.lost_limbs_shift_roundstat > 1)
+ valid_stats_list.Add("[GLOB.lost_limbs_shift_roundstat] limbs left their owners bodies this shift, oh no!")
+ else if(GLOB.destroyed_research_items_roundstat > 13)
+ valid_stats_list.Add("[GLOB.destroyed_research_items_roundstat] objects were destroyed in the name of Science! Keep it up!")
+ else if(GLOB.mech_destroyed_roundstat > 1)
+ valid_stats_list.Add("[GLOB.mech_destroyed_roundstat] mechs were destroyed this shift. What did you do?")
+ else if(GLOB.seed_planted_shift_roundstat > 20)
+ valid_stats_list.Add("[GLOB.seed_planted_shift_roundstat] seeds were planted according to our sensors this shift.")
+
+ if(GLOB.rocks_drilled_roundstat > 80)
+ valid_stats_list.Add("Our strong miners pulverized a whole [GLOB.rocks_drilled_roundstat] piles of pathetic rubble.")
+ else if(GLOB.items_sold_shift_roundstat > 15)
+ valid_stats_list.Add("The vending machines sold [GLOB.items_sold_shift_roundstat] items today.")
+ else if(GLOB.step_taken_shift_roundstat > 900)
+ valid_stats_list.Add("The employees walked a total of [GLOB.step_taken_shift_roundstat] steps for this shift! It should put them on the road to fitness!")
+
+ if(GLOB.cans_opened_roundstat > 0)
+ valid_stats_list.Add("[GLOB.cans_opened_roundstat] cans were drank today!")
+ else if(GLOB.lights_switched_on_roundstat > 0)
+ valid_stats_list.Add("[GLOB.lights_switched_on_roundstat] light switches were flipped today!")
+ else if(GLOB.turbo_lift_floors_moved_roundstat > 20)
+ valid_stats_list.Add("The elevator moved up [GLOB.turbo_lift_floors_moved_roundstat] floors today!")
+ else if(GLOB.disposals_flush_shift_roundstat > 40)
+ valid_stats_list.Add("The disposal system flushed a whole [GLOB.disposals_flush_shift_roundstat] times for this shift. We should really invest in waste treatement.")
+
+ if(LAZYLEN(valid_stats_list))
+ to_world("Shift trivia!")
+
+ for(var/body in valid_stats_list)
+ to_world("[body]")
diff --git a/code/datums/supplypacks/engineering.dm b/code/datums/supplypacks/engineering.dm
index 165c5fbfef2..28a7431ec16 100644
--- a/code/datums/supplypacks/engineering.dm
+++ b/code/datums/supplypacks/engineering.dm
@@ -77,6 +77,14 @@
containertype = /obj/structure/closet/crate/focalpoint
containername = "advanced hull shield generator crate"
+/datum/supply_pack/eng/pointdefense
+ name = "Point Defense Turret"
+ contains = list(/obj/machinery/porta_turret/pointdefense/orderable)
+ cost = 70
+ containertype = /obj/structure/closet/crate/large/secure/heph
+ containername = "point defense crate"
+ access = access_security
+
/datum/supply_pack/eng/electrical
name = "Electrical maintenance crate"
contains = list(
diff --git a/code/datums/supplypacks/materials.dm b/code/datums/supplypacks/materials.dm
index 95f15caa6d1..87780766d96 100644
--- a/code/datums/supplypacks/materials.dm
+++ b/code/datums/supplypacks/materials.dm
@@ -35,6 +35,13 @@
containertype = /obj/structure/closet/crate/grayson
containername = "Plastic sheets crate"
+/datum/supply_pack/materials/copper50
+ name = "50 copper ingots"
+ contains = list(/obj/fiftyspawner/copper)
+ cost = 60
+ containertype = /obj/structure/closet/crate/grayson
+ containername = "Copper ingots crate"
+
/datum/supply_pack/materials/cardboard_sheets
contains = list(/obj/fiftyspawner/cardboard)
name = "50 cardboard sheets"
diff --git a/code/datums/supplypacks/misc.dm b/code/datums/supplypacks/misc.dm
index 0aa29b7b9c9..ed528d3bdd0 100644
--- a/code/datums/supplypacks/misc.dm
+++ b/code/datums/supplypacks/misc.dm
@@ -84,7 +84,8 @@
/obj/item/toy/plushie/borgplushie/scrubpuppy,
/obj/item/toy/plushie/foxbear,
/obj/item/toy/plushie/nukeplushie,
- /obj/item/toy/plushie/otter)
+ /obj/item/toy/plushie/otter,
+ /obj/item/toy/plushie/vox)
//VOREStation Add End
name = "Plushies Crate"
cost = 15
diff --git a/code/datums/supplypacks/munitions_vr.dm b/code/datums/supplypacks/munitions_vr.dm
index e8674dd390c..75f2124c962 100644
--- a/code/datums/supplypacks/munitions_vr.dm
+++ b/code/datums/supplypacks/munitions_vr.dm
@@ -2,7 +2,7 @@
name = "Frontier phaser (station-locked) crate"
contains = list(
/obj/item/weapon/gun/energy/locked/frontier = 2,
- /obj/item/weapon/gun/energy/locked/frontier/holdout = 1,
+ /obj/item/weapon/gun/energy/locked/frontier/holdout = 2,
)
cost = 35
containertype = /obj/structure/closet/crate/secure
diff --git a/code/datums/supplypacks/recreation.dm b/code/datums/supplypacks/recreation.dm
index 9bb6b1a4429..eae37c5869b 100644
--- a/code/datums/supplypacks/recreation.dm
+++ b/code/datums/supplypacks/recreation.dm
@@ -51,7 +51,7 @@
/obj/item/weapon/reagent_containers/glass/paint/purple,
/obj/item/weapon/reagent_containers/glass/paint/black,
/obj/item/weapon/reagent_containers/glass/paint/white,
- /obj/item/weapon/contraband/poster,
+ /obj/item/weapon/contraband/poster/custom,
/obj/item/weapon/wrapping_paper = 3
)
cost = 10
diff --git a/code/datums/supplypacks/recreation_vr.dm b/code/datums/supplypacks/recreation_vr.dm
index 5c2266523f8..db81cd20619 100644
--- a/code/datums/supplypacks/recreation_vr.dm
+++ b/code/datums/supplypacks/recreation_vr.dm
@@ -20,7 +20,7 @@
/obj/item/clothing/suit/straight_jacket,
/obj/item/weapon/handcuffs/legcuffs/fuzzy,
/obj/item/weapon/melee/fluff/holochain/mass,
- /obj/item/weapon/material/twohanded/fluff/riding_crop,
+ /obj/item/weapon/material/twohanded/riding_crop,
/obj/item/clothing/under/fluff/latexmaid
)
containertype = /obj/structure/closet/crate
diff --git a/code/datums/supplypacks/robotics.dm b/code/datums/supplypacks/robotics.dm
index 5f8cf6337c8..1928ee7db68 100644
--- a/code/datums/supplypacks/robotics.dm
+++ b/code/datums/supplypacks/robotics.dm
@@ -189,6 +189,17 @@
containername = "Jumper kit crate"
access = access_robotics
+/datum/supply_pack/robotics/restrainingbolt
+ name = "Restraining bolt crate"
+ contains = list(
+ /obj/item/weapon/implanter = 1,
+ /obj/item/weapon/implantcase/restrainingbolt = 2
+ )
+ cost = 40
+ containertype = /obj/structure/closet/crate/secure/cybersolutions
+ containername = "Restraining bolt crate"
+ access = access_robotics
+
/datum/supply_pack/robotics/bike
name = "Spacebike Crate"
contains = list()
diff --git a/code/datums/supplypacks/security.dm b/code/datums/supplypacks/security.dm
index 5fd24a473fe..32c847ece2e 100644
--- a/code/datums/supplypacks/security.dm
+++ b/code/datums/supplypacks/security.dm
@@ -281,10 +281,7 @@
name = "Armor - Riot plates"
contains = list(
/obj/item/clothing/head/helmet/riot,
- /obj/item/clothing/suit/armor/pcarrier,
- /obj/item/clothing/accessory/armor/armorplate/riot,
- /obj/item/clothing/accessory/armor/armguards/riot,
- /obj/item/clothing/accessory/armor/legguards/riot
+ /obj/item/clothing/suit/armor/pcarrier/riot/full
)
cost = 40
containertype = /obj/structure/closet/crate/secure/lawson
@@ -308,10 +305,7 @@
name = "Armor - Ablative plates"
contains = list(
/obj/item/clothing/head/helmet/laserproof,
- /obj/item/clothing/suit/armor/pcarrier,
- /obj/item/clothing/accessory/armor/armorplate/laserproof,
- /obj/item/clothing/accessory/armor/armguards/laserproof,
- /obj/item/clothing/accessory/armor/legguards/laserproof
+ /obj/item/clothing/suit/armor/pcarrier/laserproof/full
)
cost = 50
containertype = /obj/structure/closet/crate/secure/lawson
@@ -336,10 +330,7 @@
name = "Armor - Ballistic plates"
contains = list(
/obj/item/clothing/head/helmet/bulletproof,
- /obj/item/clothing/suit/armor/pcarrier,
- /obj/item/clothing/accessory/armor/armorplate/bulletproof,
- /obj/item/clothing/accessory/armor/armguards/bulletproof,
- /obj/item/clothing/accessory/armor/legguards/bulletproof
+ /obj/item/clothing/suit/armor/pcarrier/bulletproof/full
)
cost = 50
containertype = /obj/structure/closet/crate/secure/heph
diff --git a/code/datums/underwear/undershirts.dm b/code/datums/underwear/undershirts.dm
index 7da82fa5801..6b2cc3d10f6 100644
--- a/code/datums/underwear/undershirts.dm
+++ b/code/datums/underwear/undershirts.dm
@@ -186,4 +186,14 @@
/datum/category_item/underwear/undershirt/pinkblack_tshirt
name = "Pink and Black T-Shirt"
- icon_state = "pinkblack_tshirt"
\ No newline at end of file
+ icon_state = "pinkblack_tshirt"
+
+/datum/category_item/underwear/undershirt/turtle
+ name = "Turtleneck"
+ icon_state = "turtleneck"
+ has_color = TRUE
+
+/datum/category_item/underwear/undershirt/sleevelessturtle
+ name = "Turtleneck, Sleeveless"
+ icon_state = "sleevelessturtle"
+ has_color = TRUE
\ No newline at end of file
diff --git a/code/datums/uplink/ammunition_vr.dm b/code/datums/uplink/ammunition_vr.dm
index 3235bb7311f..18235e53432 100644
--- a/code/datums/uplink/ammunition_vr.dm
+++ b/code/datums/uplink/ammunition_vr.dm
@@ -18,3 +18,5 @@
name = "Void cell"
path = /obj/item/weapon/cell/device/weapon/recharge/alien/hybrid
item_cost = DEFAULT_TELECRYSTAL_AMOUNT * 1.5
+ antag_roles = list("ert")
+ blacklisted = 1
diff --git a/code/datums/uplink/backup.dm b/code/datums/uplink/backup.dm
index 40f2a468f67..3e21676da3b 100644
--- a/code/datums/uplink/backup.dm
+++ b/code/datums/uplink/backup.dm
@@ -11,7 +11,7 @@
This type comes with a directional shield projector, a supressive fire energy weapon, \
a stunbaton, handcuffs, an agent ID, energy sword, pinpointer, and a jetpack."
item_cost = DEFAULT_TELECRYSTAL_AMOUNT * 1.5
- antag_roles = list("mercenary")
+ antag_roles = list("mercenary", "ert") //VOREStation Edit
path = /obj/item/weapon/antag_spawner/syndicate_drone/protector
/datum/uplink_item/item/backup/syndicate_drone_combat_medic
@@ -21,7 +21,7 @@
a powerful hypospray that can create many potent chemicals, an agent ID, energy \
sword, pinpointer, and a jetpack."
item_cost = DEFAULT_TELECRYSTAL_AMOUNT * 1.5
- antag_roles = list("mercenary")
+ antag_roles = list("mercenary", "ert") //VOREStation Edit
path = /obj/item/weapon/antag_spawner/syndicate_drone/combat_medic
/datum/uplink_item/item/backup/syndicate_drone_mechanist
@@ -31,5 +31,5 @@
a cryptographic sequencer, an AI detector, the ability to analyze and repair full-body prosthetics, \
a set of construction materials, an ionic rapier, an agent ID, energy sword, pinpointer, and a jetpack."
item_cost = DEFAULT_TELECRYSTAL_AMOUNT * 1.5
- antag_roles = list("mercenary")
+ antag_roles = list("mercenary", "ert") //VOREStation Edit
path = /obj/item/weapon/antag_spawner/syndicate_drone/mechanist
\ No newline at end of file
diff --git a/code/datums/uplink/badassery.dm b/code/datums/uplink/badassery.dm
index 65f71f25847..8addcc3f64e 100644
--- a/code/datums/uplink/badassery.dm
+++ b/code/datums/uplink/badassery.dm
@@ -22,22 +22,22 @@
desc = "Buys you one random item."
/datum/uplink_item/item/badassery/random_one/buy(var/obj/item/device/uplink/U, var/mob/user)
- var/datum/uplink_item/item = default_uplink_selection.get_random_item(U.uses)
+ var/datum/uplink_item/item = default_uplink_selection.get_random_item((user ? user.mind.tcrystals : DEFAULT_TELECRYSTAL_AMOUNT), U)
return item.buy(U, user)
-/datum/uplink_item/item/badassery/random_one/can_buy(obj/item/device/uplink/U)
- return default_uplink_selection.get_random_item(U.uses, U) != null
+/datum/uplink_item/item/badassery/random_one/can_buy(var/obj/item/device/uplink/U, var/telecrystals)
+ return default_uplink_selection.get_random_item(telecrystals, U) != null
/datum/uplink_item/item/badassery/random_many
name = "Random Items"
desc = "Buys you as many random items you can afford. Convenient packaging NOT included."
-/datum/uplink_item/item/badassery/random_many/cost(var/telecrystals)
+/datum/uplink_item/item/badassery/random_many/cost(obj/item/device/uplink/U, var/telecrystals)
return max(1, telecrystals)
-/datum/uplink_item/item/badassery/random_many/get_goods(var/obj/item/device/uplink/U, var/loc)
+/datum/uplink_item/item/badassery/random_many/get_goods(var/obj/item/device/uplink/U, var/loc, var/mob/M)
var/list/bought_items = list()
- for(var/datum/uplink_item/UI in get_random_uplink_items(U, U.uses, loc))
+ for(var/datum/uplink_item/UI in get_random_uplink_items(U, M.mind.tcrystals, loc))
UI.purchase_log(U)
var/obj/item/I = UI.get_goods(U, loc)
if(istype(I))
@@ -47,7 +47,7 @@
/datum/uplink_item/item/badassery/random_many/purchase_log(obj/item/device/uplink/U)
feedback_add_details("traitor_uplink_items_bought", "[src]")
- log_and_message_admins("used \the [U.loc] to buy \a [src]")
+ log_and_message_admins("used \the [U.loc] to buy \a [src] at random")
/****************
* Surplus Crate *
diff --git a/code/datums/uplink/medical_vr.dm b/code/datums/uplink/medical_vr.dm
index 8f0264d3e9d..5b4a0f31ccc 100644
--- a/code/datums/uplink/medical_vr.dm
+++ b/code/datums/uplink/medical_vr.dm
@@ -100,3 +100,66 @@
name = "Healing Nanite pill bottle"
item_cost = 30
path = /obj/item/weapon/storage/pill_bottle/healing_nanites
+
+/datum/uplink_item/item/medical/vermicetol
+ name = "Vermicetol Bottle"
+ item_cost = 30
+ path = /obj/item/weapon/reagent_containers/glass/bottle/vermicetol
+ antag_roles = list("ert")
+ blacklisted = 1
+
+/datum/uplink_item/item/medical/dermaline
+ name = "Dermaline Bottle"
+ item_cost = 30
+ path = /obj/item/weapon/reagent_containers/glass/bottle/dermaline
+ antag_roles = list("ert")
+ blacklisted = 1
+
+/datum/uplink_item/item/medical/carthatoline
+ name = "Carthatoline Bottle"
+ item_cost = 30
+ path = /obj/item/weapon/reagent_containers/glass/bottle/carthatoline
+ antag_roles = list("ert")
+ blacklisted = 1
+
+/datum/uplink_item/item/medical/dexalinp
+ name = "Dexalin Plus Bottle"
+ item_cost = 30
+ path = /obj/item/weapon/reagent_containers/glass/bottle/dexalinp
+ antag_roles = list("ert")
+ blacklisted = 1
+
+/datum/uplink_item/item/medical/tramadol
+ name = "Tramadol Bottle"
+ item_cost = 30
+ path = /obj/item/weapon/reagent_containers/glass/bottle/tramadol
+ antag_roles = list("ert")
+ blacklisted = 1
+
+/datum/uplink_item/item/medical/arithrazine
+ name = "Arithrazine Bottle"
+ item_cost = 50
+ path = /obj/item/weapon/reagent_containers/glass/bottle/arithrazine
+ antag_roles = list("ert")
+ blacklisted = 1
+
+/datum/uplink_item/item/medical/corophizine
+ name = "Corophizine Bottle"
+ item_cost = 50
+ path = /obj/item/weapon/reagent_containers/glass/bottle/corophizine
+ antag_roles = list("ert")
+ blacklisted = 1
+
+/datum/uplink_item/item/medical/rezadone
+ name = "Rezadone Bottle"
+ item_cost = 50
+ path = /obj/item/weapon/reagent_containers/glass/bottle/rezadone
+ antag_roles = list("ert")
+ blacklisted = 1
+
+/datum/uplink_item/item/medical/defib
+ name = "Combat Defibrilator"
+ item_cost = 90
+ path = /obj/item/device/defib_kit/compact/combat
+ antag_roles = list("mercenary", "ert")
+ blacklisted = 1
diff --git a/code/datums/uplink/telecrystals.dm b/code/datums/uplink/telecrystals.dm
index f814b55232d..66a099581ee 100644
--- a/code/datums/uplink/telecrystals.dm
+++ b/code/datums/uplink/telecrystals.dm
@@ -5,8 +5,8 @@
category = /datum/uplink_category/telecrystals
blacklisted = 1
-/datum/uplink_item/item/telecrystal/get_goods(var/obj/item/device/uplink/U, var/loc)
- return new /obj/item/stack/telecrystal(loc, cost(U.uses))
+/datum/uplink_item/item/telecrystal/get_goods(var/obj/item/device/uplink/U, var/loc, var/mob/M)
+ return new /obj/item/stack/telecrystal(loc, cost(U, M.mind.tcrystals))
/datum/uplink_item/item/telecrystal/one
name = "Telecrystal - 01"
@@ -35,5 +35,5 @@
/datum/uplink_item/item/telecrystal/all
name = "Telecrystals - Empty Uplink"
-/datum/uplink_item/item/telecrystal/all/cost(var/telecrystals)
- return max(1, telecrystals)
\ No newline at end of file
+/datum/uplink_item/item/telecrystal/all/cost(obj/item/device/uplink/U, mob/M)
+ return max(1, M.mind.tcrystals)
\ No newline at end of file
diff --git a/code/datums/uplink/tools.dm b/code/datums/uplink/tools.dm
index 51d7ec7cd22..eee41e96993 100644
--- a/code/datums/uplink/tools.dm
+++ b/code/datums/uplink/tools.dm
@@ -92,6 +92,12 @@
desc = "A device which is capable of disrupting subspace communications, preventing the use of headsets, PDAs, and communicators within \
a radius of seven meters. It runs off weapon cells, which can be replaced as needed. One cell will last for approximately ten minutes."
+/datum/uplink_item/item/tools/wall_elecrtifier
+ name = "Wall Electrifier"
+ item_cost = 10
+ path = /obj/item/weapon/cell/spike
+ desc = "A modified powercell which will electrify walls and reinforced floors in a 3x3 tile range around it. Always active."
+
/datum/uplink_item/item/tools/emag
name = "Cryptographic Sequencer"
item_cost = 30
diff --git a/code/datums/uplink/tools_vr.dm b/code/datums/uplink/tools_vr.dm
index 30b2cd725e0..ad68f769229 100644
--- a/code/datums/uplink/tools_vr.dm
+++ b/code/datums/uplink/tools_vr.dm
@@ -26,6 +26,11 @@
item_cost = 5
path = /obj/item/device/survivalcapsule
+/datum/uplink_item/item/tools/popcabin
+ name = "Cabin Capsule"
+ item_cost = 5
+ path = /obj/item/device/survivalcapsule/popcabin
+
/datum/uplink_item/item/tools/nanopaste
name = "Nanopaste (Advanced)"
item_cost = 10
@@ -36,11 +41,26 @@
item_cost = 10
path = /obj/item/clothing/suit/space/void/autolok
+/datum/uplink_item/item/tools/inflatable
+ name = "Inflatables"
+ item_cost = 10
+ path = /obj/item/weapon/storage/briefcase/inflatable
+
/datum/uplink_item/item/tools/elitetablet
name = "Tablet (Advanced)"
item_cost = 15
path = /obj/item/modular_computer/tablet/preset/custom_loadout/advanced
+/datum/uplink_item/item/tools/metal
+ name = "Metal (50 sheets)"
+ item_cost = 15
+ path = /obj/fiftyspawner/steel
+
+/datum/uplink_item/item/tools/glass
+ name = "Glass (50 sheets)"
+ item_cost = 15
+ path = /obj/fiftyspawner/glass
+
/datum/uplink_item/item/tools/elitelaptop
name = "Laptop (Advanced)"
item_cost = 20
diff --git a/code/datums/uplink/uplink_categories.dm b/code/datums/uplink/uplink_categories.dm
index d9e6d84db7d..f7236ddbb08 100644
--- a/code/datums/uplink/uplink_categories.dm
+++ b/code/datums/uplink/uplink_categories.dm
@@ -6,12 +6,6 @@
..()
items = list()
-/datum/uplink_category/proc/can_view(obj/item/device/uplink/U)
- for(var/datum/uplink_item/item in items)
- if(item.can_view(U))
- return 1
- return 0
-
datum/uplink_category/ammunition
name = "Ammunition"
diff --git a/code/datums/uplink/uplink_items.dm b/code/datums/uplink/uplink_items.dm
index 8d9de8f7321..e02e604984f 100644
--- a/code/datums/uplink/uplink_items.dm
+++ b/code/datums/uplink/uplink_items.dm
@@ -31,7 +31,7 @@ var/datum/uplink/uplink = new()
var/item_cost = 0
var/datum/uplink_category/category // Item category
var/list/datum/antagonist/antag_roles // Antag roles this item is displayed to. If empty, display to all.
- var/blacklisted = 0
+ var/blacklisted = FALSE
/datum/uplink_item/item
var/path = null
@@ -48,50 +48,34 @@ var/datum/uplink/uplink = new()
if(!extra_args)
return
- if(!can_buy(U))
+ if(!can_buy(U, user.mind.tcrystals))
return
- if(U.CanUseTopic(user, GLOB.tgui_inventory_state) != STATUS_INTERACTIVE)
+ if(U.tgui_status(user, GLOB.tgui_deep_inventory_state) != STATUS_INTERACTIVE)
return
- var/cost = cost(U.uses, U)
+ var/cost = cost(U, user.mind.tcrystals)
var/goods = get_goods(U, get_turf(user), user, extra_args)
if(!goods)
return
- purchase_log(U)
+ purchase_log(user)
user.mind.tcrystals -= cost
- U.used_TC += cost
+ user.mind.used_TC += cost
return goods
// Any additional arguments you wish to send to the get_goods
/datum/uplink_item/proc/extra_args(var/mob/user)
- return 1
+ return TRUE
-/datum/uplink_item/proc/can_buy(obj/item/device/uplink/U)
- if(cost(U.uses, U) > U.uses)
- return 0
+/datum/uplink_item/proc/can_buy(var/obj/item/device/uplink/U, var/telecrystals)
+ if(cost(U, telecrystals) > telecrystals)
+ return FALSE
- return can_view(U)
+ return TRUE
-/datum/uplink_item/proc/can_view(obj/item/device/uplink/U)
- // Making the assumption that if no uplink was supplied, then we don't care about antag roles
- if(!U || !antag_roles.len)
- return 1
-
- // With no owner, there's no need to check antag status.
- if(!U.uplink_owner)
- return 0
-
- for(var/antag_role in antag_roles)
- var/datum/antagonist/antag = all_antag_types[antag_role]
- if(!isnull(antag))
- if(antag.is_antagonist(U.uplink_owner))
- return 1
- return 0
-
-/datum/uplink_item/proc/cost(var/telecrystals, obj/item/device/uplink/U)
+/datum/uplink_item/proc/cost(obj/item/device/uplink/U, mob/M)
. = item_cost
if(U)
. = U.get_item_cost(src, .)
@@ -100,19 +84,19 @@ var/datum/uplink/uplink = new()
return desc
// get_goods does not necessarily return physical objects, it is simply a way to acquire the uplink item without paying
-/datum/uplink_item/proc/get_goods(var/obj/item/device/uplink/U, var/loc)
- return 0
+/datum/uplink_item/proc/get_goods(var/obj/item/device/uplink/U, var/loc, mob/user)
+ return FALSE
/datum/uplink_item/proc/log_icon()
return
-/datum/uplink_item/proc/purchase_log(obj/item/device/uplink/U)
+/datum/uplink_item/proc/purchase_log(mob/M)
feedback_add_details("traitor_uplink_items_bought", "[src]")
- log_and_message_admins("used \the [U.loc] to buy \a [src]")
- U.purchase_log[src] = U.purchase_log[src] + 1
+ log_and_message_admins("\the [M] bought \a [src] through the uplink")
+ M.mind.purchase_log[src] += 1
datum/uplink_item/dd_SortValue()
- return cost(INFINITY)
+ return item_cost
/********************************
* *
@@ -133,7 +117,7 @@ datum/uplink_item/dd_SortValue()
A.put_in_any_hand_if_possible(I)
return I
-/datum/uplink_item/item/get_goods(var/obj/item/device/uplink/U, var/loc)
+/datum/uplink_item/item/get_goods(var/obj/item/device/uplink/U, var/loc, var/mob/user)
var/obj/item/I = new path(loc)
return I
@@ -208,7 +192,7 @@ datum/uplink_item/dd_SortValue()
/proc/get_surplus_items(var/obj/item/device/uplink/U, var/remaining_TC, var/loc)
var/list/bought_items = list()
- var/override = 1
+ var/override = TRUE
while(remaining_TC)
var/datum/uplink_item/I = all_uplink_selection.get_random_item(remaining_TC, U, bought_items, override)
if(!I)
diff --git a/code/datums/uplink/visible_weapons.dm b/code/datums/uplink/visible_weapons.dm
index d3ed1dcec34..b939e953de3 100644
--- a/code/datums/uplink/visible_weapons.dm
+++ b/code/datums/uplink/visible_weapons.dm
@@ -103,7 +103,7 @@
name = "Anti-Materiel Rifle (14.5mm)"
item_cost = DEFAULT_TELECRYSTAL_AMOUNT
path = /obj/item/weapon/gun/projectile/heavysniper
- antag_roles = list("mercenary")
+ antag_roles = list("mercenary", "ert") //VOREStation Edit
/datum/uplink_item/item/visible_weapons/heavysnipertraitor
name = "Anti-Materiel Rifle (14.5mm)"
diff --git a/code/datums/wires/mines.dm b/code/datums/wires/mines.dm
index 209fcc4c307..5e757ad16c3 100644
--- a/code/datums/wires/mines.dm
+++ b/code/datums/wires/mines.dm
@@ -1,5 +1,5 @@
/datum/wires/mines
- wire_count = 6
+ wire_count = 7
randomize = TRUE
holder_type = /obj/effect/mine
proper_name = "Explosive Wires"
@@ -7,6 +7,7 @@
/datum/wires/mines/New(atom/_holder)
wires = list(WIRE_EXPLODE, WIRE_EXPLODE_DELAY, WIRE_DISARM, WIRE_BADDISARM)
return ..()
+#define WIRE_TRAP 64
/datum/wires/mines/get_status()
. = ..()
@@ -29,7 +30,13 @@
if(WIRE_DISARM)
C.visible_message("[bicon(C)] *click!*", "[bicon(C)] *click!*")
- new C.mineitemtype(get_turf(C))
+ var/obj/effect/mine/MI = new C.mineitemtype(get_turf(C))
+
+ if(C.trap)
+ MI.trap = C.trap
+ C.trap = null
+ MI.trap.forceMove(MI)
+
spawn(0)
qdel(C)
@@ -37,6 +44,15 @@
C.visible_message("[bicon(C)] *BEEPBEEPBEEP*", "[bicon(C)] *BEEPBEEPBEEP*")
spawn(20)
C.explode()
+
+ if(WIRE_TRAP)
+ C.visible_message("[bicon(C)] *click!*", "[bicon(C)] *click!*")
+
+ if(mend)
+ C.visible_message("[bicon(C)] - The mine recalibrates[C.camo_net ? ", revealing \the [C.trap] inside." : "."]")
+
+ C.alpha = 255
+
..()
/datum/wires/mines/on_pulse(wire)
@@ -57,6 +73,10 @@
if(WIRE_BADDISARM)
C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
+
+ if(WIRE_TRAP)
+ C.visible_message("[bicon(C)] *ping*", "[bicon(C)] *ping*")
+
..()
/datum/wires/mines/interactable(mob/user)
diff --git a/code/game/antagonist/antagonist_print.dm b/code/game/antagonist/antagonist_print.dm
index efcd5955f74..99216b9ef55 100644
--- a/code/game/antagonist/antagonist_print.dm
+++ b/code/game/antagonist/antagonist_print.dm
@@ -1,7 +1,7 @@
/datum/antagonist/proc/print_player_summary()
if(!current_antagonists.len)
- return 0
+ return FALSE
var/text = "
The [current_antagonists.len == 1 ? "[role_text] was" : "[role_text_plural] were"]:"
for(var/datum/mind/P in current_antagonists)
@@ -21,7 +21,7 @@
else
text += "Fail."
feedback_add_details(feedback_tag,"[O.type]|FAIL")
- failed = 1
+ failed = TRUE
num++
if(failed)
text += "
The [role_text] has failed."
@@ -32,7 +32,7 @@
text += "
Their objectives were:"
var/num = 1
for(var/datum/objective/O in global_objectives)
- text += print_objective(O, num, 1)
+ text += print_objective(O, num, TRUE)
num++
// Display the results.
@@ -68,14 +68,14 @@
/datum/antagonist/proc/print_player_full(var/datum/mind/ply)
var/text = print_player_lite(ply)
- var/TC_uses = 0
- var/uplink_true = 0
+ var/TC_uses = FALSE
+ var/uplink_true = FALSE
var/purchases = ""
- for(var/obj/item/device/uplink/H in world_uplinks)
- if(H && H.uplink_owner && H.uplink_owner == ply)
- TC_uses += H.used_TC
- uplink_true = 1
- purchases += get_uplink_purchases(H)
+ for(var/mob/M in player_list)
+ if(M.mind && M.mind.used_TC)
+ TC_uses += M.mind.used_TC
+ uplink_true = TRUE
+ purchases += get_uplink_purchases(M.mind)
if(uplink_true)
text += " (used [TC_uses] TC)"
if(purchases)
@@ -83,18 +83,8 @@
return text
-/proc/print_ownerless_uplinks()
- var/has_printed = 0
- for(var/obj/item/device/uplink/H in world_uplinks)
- if(isnull(H.uplink_owner) && H.used_TC)
- if(!has_printed)
- has_printed = 1
- to_world("Ownerless Uplinks")
- to_world("[H.loc] (used [H.used_TC] TC)")
- to_world(get_uplink_purchases(H))
-
-/proc/get_uplink_purchases(var/obj/item/device/uplink/H)
+/proc/get_uplink_purchases(var/datum/mind/M)
var/list/refined_log = new()
- for(var/datum/uplink_item/UI in H.purchase_log)
- refined_log.Add("[H.purchase_log[UI]]x[UI.log_icon()][UI.name]")
+ for(var/datum/uplink_item/UI in M.purchase_log)
+ refined_log.Add("[M.purchase_log[UI]]x[UI.log_icon()][UI.name]")
. = english_list(refined_log, nothing_text = "")
diff --git a/code/game/area/areas.dm b/code/game/area/areas.dm
index 04075fe8255..9c8bbccc798 100644
--- a/code/game/area/areas.dm
+++ b/code/game/area/areas.dm
@@ -50,13 +50,12 @@
var/turf/base_turf //The base turf type of the area, which can be used to override the z-level's base turf
var/forbid_events = FALSE // If true, random events will not start inside this area.
var/no_spoilers = FALSE // If true, makes it much more difficult to see what is inside an area with things like mesons.
+ var/soundproofed = FALSE // If true, blocks sounds from other areas and prevents hearers on other areas from hearing the sounds within.
/area/Initialize()
. = ..()
-
luminosity = !(dynamic_lighting)
icon_state = ""
-
return INITIALIZE_HINT_LATELOAD // Areas tradiationally are initialized AFTER other atoms.
/area/LateInitialize()
@@ -67,7 +66,6 @@
power_change() // all machines set to current power level, also updates lighting icon
if(no_spoilers)
set_spoiler_obfuscation(TRUE)
- return INITIALIZE_HINT_LATELOAD
// Changes the area of T to A. Do not do this manually.
// Area is expected to be a non-null instance.
@@ -379,9 +377,9 @@ var/list/mob/living/forced_ambiance_list = new
// Ambience goes down here -- make sure to list each area seperately for ease of adding things in later, thanks! Note: areas adjacent to each other should have the same sounds to prevent cutoff when possible.- LastyScratch
if(!(L && L.is_preference_enabled(/datum/client_preference/play_ambiance)))
return
-
+
var/volume_mod = L.get_preference_volume_channel(VOLUME_CHANNEL_AMBIENCE)
-
+
// If we previously were in an area with force-played ambiance, stop it.
if((L in forced_ambiance_list) && initial)
L << sound(null, channel = CHANNEL_AMBIENCE_FORCED)
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 5ec5af0e6b0..c20c29be7b9 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -627,7 +627,7 @@
speech_bubble_hearers += M.client
if(length(speech_bubble_hearers))
- var/image/I = image('icons/mob/talk.dmi', src, "[bubble_icon][say_test(message)]", FLY_LAYER)
+ var/image/I = generate_speech_bubble(src, "[bubble_icon][say_test(message)]", FLY_LAYER)
I.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
INVOKE_ASYNC(GLOBAL_PROC, /.proc/flick_overlay, I, speech_bubble_hearers, 30)
diff --git a/code/game/atoms_movable.dm b/code/game/atoms_movable.dm
index bf5fc0ab18c..4bc8892273f 100644
--- a/code/game/atoms_movable.dm
+++ b/code/game/atoms_movable.dm
@@ -134,7 +134,7 @@
for(var/i in loc)
var/atom/movable/thing = i
// We don't call parent so we are calling this for byond
- thing.Crossed(src)
+ thing.Crossed(src, oldloc)
// We're a multi-tile object (multiple locs)
else if(. && newloc)
@@ -303,6 +303,8 @@
if(AM == src)
continue
AM.Uncrossed(src)
+ if(loc != destination) // Uncrossed() triggered a separate movement
+ return
// Information about turf and z-levels for source and dest collected
var/turf/oldturf = get_turf(oldloc)
@@ -327,6 +329,8 @@
if(AM == src)
continue
AM.Crossed(src, oldloc)
+ if(loc != destination) // Crossed triggered a separate movement
+ return
// Call our thingy to inform everyone we moved
Moved(oldloc, NONE, TRUE)
@@ -462,6 +466,8 @@
minor_dir = dx
minor_dist = dist_x
+ range = min(dist_x + dist_y, range)
+
while(src && target && src.throwing && istype(src.loc, /turf) \
&& ((abs(target.x - src.x)+abs(target.y - src.y) > 0 && dist_travelled < range) \
|| (a && a.has_gravity == 0) \
diff --git a/code/game/dna/dna2.dm b/code/game/dna/dna2.dm
index 4141281df9d..ef0af0fab79 100644
--- a/code/game/dna/dna2.dm
+++ b/code/game/dna/dna2.dm
@@ -118,6 +118,10 @@ var/global/list/datum/dna/gene/dna_genes[0]
var/base_species = "Human"
var/list/species_traits = list()
var/blood_color = "#A10808"
+ var/custom_say
+ var/custom_ask
+ var/custom_whisper
+ var/custom_exclaim
// VOREStation
// New stuff
@@ -139,6 +143,10 @@ var/global/list/datum/dna/gene/dna_genes[0]
new_dna.custom_species=custom_species //VOREStaton Edit
new_dna.species_traits=species_traits.Copy() //VOREStation Edit
new_dna.blood_color=blood_color //VOREStation Edit
+ new_dna.custom_say=custom_say //VOREStaton Edit
+ new_dna.custom_ask=custom_ask //VOREStaton Edit
+ new_dna.custom_whisper=custom_whisper //VOREStaton Edit
+ new_dna.custom_exclaim=custom_exclaim //VOREStaton Edit
for(var/b=1;b<=DNA_SE_LENGTH;b++)
new_dna.SE[b]=SE[b]
if(b<=DNA_UI_LENGTH)
@@ -202,23 +210,13 @@ var/global/list/datum/dna/gene/dna_genes[0]
// Technically custom_species is not part of the UI, but this place avoids merge problems.
src.custom_species = character.custom_species
- if(istype(character.species,/datum/species/custom))
- var/datum/species/custom/CS = character.species
- src.species_traits = CS.traits.Copy()
- src.base_species = CS.base_species
- src.blood_color = CS.blood_color
-
- if(istype(character.species,/datum/species/xenochimera))
- var/datum/species/xenochimera/CS = character.species
- //src.species_traits = CS.traits.Copy() //No traits
- src.base_species = CS.base_species
- src.blood_color = CS.blood_color
-
- if(istype(character.species,/datum/species/alraune))
- var/datum/species/alraune/CS = character.species
- //src.species_traits = CS.traits.Copy() //No traits
- src.base_species = CS.base_species
- src.blood_color = CS.blood_color
+ src.base_species = character.species.base_species
+ src.blood_color = character.species.blood_color
+ src.species_traits = character.species.traits.Copy()
+ src.custom_say = character.custom_say
+ src.custom_ask = character.custom_ask
+ src.custom_whisper = character.custom_whisper
+ src.custom_exclaim = character.custom_exclaim
// +1 to account for the none-of-the-above possibility
SetUIValueRange(DNA_UI_EAR_STYLE, ear_style + 1, ear_styles_list.len + 1, 1)
diff --git a/code/game/dna/dna2_helpers.dm b/code/game/dna/dna2_helpers.dm
index 0edc6bb636b..d250c441ad4 100644
--- a/code/game/dna/dna2_helpers.dm
+++ b/code/game/dna/dna2_helpers.dm
@@ -237,20 +237,13 @@
// Technically custom_species is not part of the UI, but this place avoids merge problems.
H.custom_species = dna.custom_species
- if(istype(H.species,/datum/species/custom))
- var/datum/species/custom/CS = H.species
- var/datum/species/custom/new_CS = CS.produceCopy(dna.base_species,dna.species_traits,src)
- new_CS.blood_color = dna.blood_color
-
- if(istype(H.species,/datum/species/xenochimera))
- var/datum/species/xenochimera/CS = H.species
- var/datum/species/xenochimera/new_CS = CS.produceCopy(dna.base_species,dna.species_traits,src)
- new_CS.blood_color = dna.blood_color
-
- if(istype(H.species,/datum/species/alraune))
- var/datum/species/alraune/CS = H.species
- var/datum/species/alraune/new_CS = CS.produceCopy(dna.base_species,dna.species_traits,src)
- new_CS.blood_color = dna.blood_color
+ H.custom_say = dna.custom_say
+ H.custom_ask = dna.custom_ask
+ H.custom_whisper = dna.custom_whisper
+ H.custom_exclaim = dna.custom_exclaim
+ H.species.blood_color = dna.blood_color
+ var/datum/species/S = H.species
+ S.produceCopy(dna.base_species,dna.species_traits,src)
// VOREStation Edit End
H.force_update_organs() //VOREStation Add - Gotta do this too
diff --git a/code/game/gamemodes/cult/cult_structures.dm b/code/game/gamemodes/cult/cult_structures.dm
index bbf4bfb3437..241d6132756 100644
--- a/code/game/gamemodes/cult/cult_structures.dm
+++ b/code/game/gamemodes/cult/cult_structures.dm
@@ -34,7 +34,7 @@
var/last_activation = 0
/obj/structure/cult/pylon/Initialize()
- ..()
+ . = ..()
START_PROCESSING(SSobj, src)
/obj/structure/cult/pylon/attack_hand(mob/M as mob)
diff --git a/code/game/gamemodes/game_mode.dm b/code/game/gamemodes/game_mode.dm
index 42e6a6ddd00..18d58a33ae8 100644
--- a/code/game/gamemodes/game_mode.dm
+++ b/code/game/gamemodes/game_mode.dm
@@ -292,7 +292,6 @@ var/global/list/additional_antag_types = list()
antag.check_victory()
antag.print_player_summary()
sleep(10)
- print_ownerless_uplinks()
var/clients = 0
var/surviving_humans = 0
diff --git a/code/game/gamemodes/meteor/meteors.dm b/code/game/gamemodes/meteor/meteors.dm
index 0b0b8d014c7..a6ceb219c84 100644
--- a/code/game/gamemodes/meteor/meteors.dm
+++ b/code/game/gamemodes/meteor/meteors.dm
@@ -13,7 +13,7 @@
/obj/effect/meteor/big=3,
/obj/effect/meteor/flaming=1,
/obj/effect/meteor/irradiated=3
- )
+ )
//for threatening meteor event
/var/list/meteors_threatening = list(
@@ -206,6 +206,21 @@
return
..()
+/obj/effect/meteor/bullet_act(var/obj/item/projectile/Proj)
+ if(Proj.excavation_amount)
+ get_hit()
+ if(!QDELETED(src))
+ wall_power -= Proj.excavation_amount + Proj.damage + (Proj.hitscan * 25) // Instant-impact projectiles are inherently better at dealing with meteors.
+ wall_power = max(1, wall_power)
+
+ if(wall_power < Proj.excavation_amount)
+ if(prob(min(90, 100 - Proj.damage)))
+ die(TRUE)
+ else
+ die(FALSE)
+ return
+ return
+
/obj/effect/meteor/proc/make_debris()
for(var/throws = dropamt, throws > 0, throws--)
var/obj/item/O = new meteordrop(get_turf(src))
diff --git a/code/game/jobs/access_datum_vr.dm b/code/game/jobs/access_datum_vr.dm
index 16038248d01..bd3906f16c5 100644
--- a/code/game/jobs/access_datum_vr.dm
+++ b/code/game/jobs/access_datum_vr.dm
@@ -27,4 +27,22 @@ var/const/access_pilot = 67
/datum/access/entertainment
id = access_entertainment
desc = "Entertainment Backstage"
- region = ACCESS_REGION_GENERAL
\ No newline at end of file
+ region = ACCESS_REGION_GENERAL
+
+/var/const/access_mime = 138
+/datum/access/mime
+ id = access_mime
+ desc = "Mime Office"
+ region = ACCESS_REGION_GENERAL
+
+/var/const/access_clown = 136
+/datum/access/clown
+ id = access_clown
+ desc = "Clown Office"
+ region = ACCESS_REGION_GENERAL
+
+/var/const/access_tomfoolery = 137
+/datum/access/tomfoolery
+ id = access_tomfoolery
+ desc = "Tomfoolery Closet"
+ region = ACCESS_REGION_GENERAL
diff --git a/code/game/jobs/job/captain_vr.dm b/code/game/jobs/job/captain_vr.dm
index d2b830ad7ba..dd057fff7bf 100644
--- a/code/game/jobs/job/captain_vr.dm
+++ b/code/game/jobs/job/captain_vr.dm
@@ -26,13 +26,13 @@
access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
- access_hop, access_RC_announce, access_keycard_auth)
+ access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway)
minimal_access = list(access_security, access_sec_doors, access_brig, access_forensics_lockers,
access_medical, access_engine, access_change_ids, access_ai_upload, access_eva, access_heads,
access_all_personal_lockers, access_maint_tunnels, access_bar, access_janitor, access_construction, access_morgue,
access_crematorium, access_kitchen, access_cargo, access_cargo_bot, access_mailsorting, access_qm, access_hydroponics, access_lawyer,
access_chapel_office, access_library, access_research, access_mining, access_heads_vault, access_mining_station,
- access_hop, access_RC_announce, access_keycard_auth)
+ access_hop, access_RC_announce, access_clown, access_tomfoolery, access_mime, access_keycard_auth, access_gateway)
/datum/alt_title/deputy_manager
title = "Deputy Manager"
diff --git a/code/game/jobs/job/engineering_vr.dm b/code/game/jobs/job/engineering_vr.dm
index 8799aa39058..39905f0bc85 100644
--- a/code/game/jobs/job/engineering_vr.dm
+++ b/code/game/jobs/job/engineering_vr.dm
@@ -6,12 +6,12 @@
access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels,
access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
access_heads, access_construction,
- access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload)
+ access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload, access_gateway)
minimal_access = list(access_engine, access_engine_equip, access_tech_storage, access_maint_tunnels,
access_teleporter, access_external_airlocks, access_atmospherics, access_emergency_storage, access_eva,
access_heads, access_construction,
- access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload)
+ access_ce, access_RC_announce, access_keycard_auth, access_tcomsat, access_ai_upload, access_gateway)
alt_titles = list("Head Engineer" = /datum/alt_title/head_engineer, "Foreman" = /datum/alt_title/foreman, "Maintenance Manager" = /datum/alt_title/maintenance_manager)
/datum/alt_title/head_engineer
diff --git a/code/game/jobs/job/exploration_vr.dm b/code/game/jobs/job/exploration_vr.dm
index 0e6e003f7db..5189ca39b0c 100644
--- a/code/game/jobs/job/exploration_vr.dm
+++ b/code/game/jobs/job/exploration_vr.dm
@@ -1,8 +1,3 @@
-var/const/PATHFINDER =(1<<11)
-var/const/EXPLORER =(1<<12)
-var/const/PILOT =(1<<13)
-var/const/SAR =(1<<14)
-
/obj/item/weapon/card/id/medical/sar
assignment = "Field Medic"
rank = "Field Medic"
@@ -64,13 +59,13 @@ var/const/SAR =(1<<14)
/datum/job/pilot
title = "Pilot"
flag = PILOT
- departments = list(DEPARTMENT_PLANET)
- department_flag = MEDSCI
+ departments = list(DEPARTMENT_CIVILIAN)
+ department_flag = CIVILIAN
faction = "Station"
- total_positions = 4
- spawn_positions = 4
- supervisors = "the Pathfinder and the Head of Personnel"
- selection_color = "#999440"
+ total_positions = 5
+ spawn_positions = 5
+ supervisors = "the Head of Personnel"
+ selection_color = "#515151"
economic_modifier = 5
minimal_player_age = 3
pto_type = PTO_EXPLORATION
diff --git a/code/game/jobs/job/medical_vr.dm b/code/game/jobs/job/medical_vr.dm
index 2679137cf0f..6d5ee57c4e4 100644
--- a/code/game/jobs/job/medical_vr.dm
+++ b/code/game/jobs/job/medical_vr.dm
@@ -5,11 +5,11 @@
access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
- access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
+ access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels, access_gateway)
minimal_access = list(access_medical, access_medical_equip, access_morgue, access_genetics, access_heads,
access_chemistry, access_virology, access_cmo, access_surgery, access_RC_announce,
- access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels)
+ access_keycard_auth, access_psychiatrist, access_eva, access_external_airlocks, access_maint_tunnels, access_gateway)
alt_titles = list("Chief Physician" = /datum/alt_title/chief_physician, "Medical Director" = /datum/alt_title/medical_director, "Healthcare Manager" = /datum/alt_title/healthcare_manager)
/datum/alt_title/chief_physician
diff --git a/code/game/jobs/job/science_vr.dm b/code/game/jobs/job/science_vr.dm
index 0356656446b..52647422b4f 100644
--- a/code/game/jobs/job/science_vr.dm
+++ b/code/game/jobs/job/science_vr.dm
@@ -10,7 +10,7 @@
minimal_access = list(access_rd, access_heads, access_tox, access_genetics, access_morgue,
access_tox_storage, access_teleporter,
access_research, access_robotics, access_xenobiology, access_ai_upload, access_tech_storage,
- access_RC_announce, access_keycard_auth, access_tcomsat, access_xenoarch, access_eva, access_network, access_xenobotany)
+ access_RC_announce, access_keycard_auth, access_tcomsat, access_gateway, access_xenoarch, access_eva, access_network, access_xenobotany)
alt_titles = list("Research Supervisor" = /datum/alt_title/research_supervisor, "Research Manager" = /datum/alt_title/research_manager,
"Head of Development" = /datum/alt_title/head_of_development,"Head Scientist" = /datum/alt_title/head_scientist)
diff --git a/code/game/jobs/job/security_vr.dm b/code/game/jobs/job/security_vr.dm
index e9b9017d9af..082531d944e 100644
--- a/code/game/jobs/job/security_vr.dm
+++ b/code/game/jobs/job/security_vr.dm
@@ -6,11 +6,11 @@
access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
access_construction,
- access_heads, access_hos, access_RC_announce, access_keycard_auth, access_external_airlocks)
+ access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
minimal_access = list(access_security, access_eva, access_sec_doors, access_brig, access_armory,
access_forensics_lockers, access_morgue, access_maint_tunnels, access_all_personal_lockers,
access_construction,
- access_heads, access_hos, access_RC_announce, access_keycard_auth, access_external_airlocks)
+ access_heads, access_hos, access_RC_announce, access_keycard_auth, access_gateway, access_external_airlocks)
alt_titles = list("Security Commander" = /datum/alt_title/sec_commander, "Chief of Security" = /datum/alt_title/sec_chief, "Security Manager" = /datum/alt_title/security_manager)
/datum/alt_title/security_manager
diff --git a/code/game/jobs/job/special_vr.dm b/code/game/jobs/job/special_vr.dm
index d2de3db85c0..34cc2321ce8 100644
--- a/code/game/jobs/job/special_vr.dm
+++ b/code/game/jobs/job/special_vr.dm
@@ -24,47 +24,31 @@
get_access()
return get_all_accesses().Copy()
-/*/datum/job/centcom_visitor //For Pleasure // You mean for admin abuse... -Ace
- title = "CentCom Visitor"
- department = "Civilian"
- head_position = 1
+/datum/job/emergency_responder //For staff managing/leading ERTs
+ title = "Emergency Responder"
+ departments = list("Central Command")
+ department_accounts = list(DEPARTMENT_COMMAND, DEPARTMENT_ENGINEERING, DEPARTMENT_MEDICAL, DEPARTMENT_RESEARCH, DEPARTMENT_SECURITY, DEPARTMENT_CARGO, DEPARTMENT_PLANET, DEPARTMENT_CIVILIAN)
faction = "Station"
total_positions = 2
spawn_positions = 1
supervisors = "company officials and Corporate Regulations"
selection_color = "#1D1D4F"
- idtype = /obj/item/weapon/card/id/centcom
access = list()
minimal_access = list()
minimal_player_age = 14
economic_modifier = 20
whitelist_only = 1
latejoin_only = 1
+ outfit_type = /decl/hierarchy/outfit/job/emergency_responder
+ job_description = "Emergency Responders are usually called in to deal with on-station emergencies that the crew require assistance to deal with."
- minimum_character_age = 25
- ideal_character_age = 40
+ minimum_character_age = 18
+ ideal_character_age = 30
- equip(var/mob/living/carbon/human/H)
- if(!H) return 0
- H.equip_to_slot_or_del(new /obj/item/device/radio/headset/centcom(H), slot_l_ear)
- switch(H.backbag)
- if(2) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack(H), slot_back)
- if(3) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back)
- if(4) H.equip_to_slot_or_del(new /obj/item/weapon/storage/backpack/satchel(H), slot_back)
- H.equip_to_slot_or_del(new /obj/item/clothing/under/rank/centcom, slot_w_uniform)
- H.equip_to_slot_or_del(new /obj/item/device/pda/centcom(H), slot_belt)
- H.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(H), slot_shoes)
- H.equip_to_slot_or_del(new /obj/item/clothing/gloves/white(H), slot_gloves)
- H.equip_to_slot_or_del(new /obj/item/clothing/head/beret/centcom/officer(H), slot_head)
- H.equip_to_slot_or_del(new /obj/item/clothing/glasses/omnihud(H), slot_l_store)
-
- H.implant_loyalty()
-
- return 1
+ pto_type = PTO_CIVILIAN
get_access()
- var/access = get_all_accesses()
- return access*/
+ return get_all_accesses().Copy()
/datum/job/clown
title = "Clown"
@@ -72,14 +56,14 @@
departments = list(DEPARTMENT_CIVILIAN)
department_flag = CIVILIAN
faction = "Station"
- total_positions = -1
- spawn_positions = -1
+ total_positions = 1
+ spawn_positions = 1
supervisors = "the spirit of laughter"
selection_color = "#515151"
economic_modifier = 1
job_description = "A Clown is there to entertain the crew and keep high morale using various harmless pranks and ridiculous jokes!"
whitelist_only = 1
- latejoin_only = 1
+ latejoin_only = 0
outfit_type = /decl/hierarchy/outfit/job/clown
pto_type = PTO_CIVILIAN
alt_titles = list("Jester" = /datum/alt_title/jester, "Fool" = /datum/alt_title/fool)
@@ -92,9 +76,9 @@
/datum/job/clown/get_access()
if(config.assistant_maint)
- return list(access_maint_tunnels, access_entertainment)
+ return list(access_maint_tunnels, access_entertainment, access_clown, access_tomfoolery)
else
- return list(access_entertainment)
+ return list(access_entertainment, access_clown, access_tomfoolery)
/datum/job/mime
title = "Mime"
@@ -102,15 +86,15 @@
departments = list(DEPARTMENT_CIVILIAN)
department_flag = CIVILIAN
faction = "Station"
- total_positions = -1
- spawn_positions = -1
+ total_positions = 1
+ spawn_positions = 1
supervisors = "the spirit of performance"
selection_color = "#515151"
economic_modifier = 1
job_description = "A Mime is there to entertain the crew and keep high morale using unbelievable performances and acting skills!"
alt_titles = list("Poseur" = /datum/alt_title/poseur)
whitelist_only = 1
- latejoin_only = 1
+ latejoin_only = 0
outfit_type = /decl/hierarchy/outfit/job/mime
pto_type = PTO_CIVILIAN
@@ -119,6 +103,6 @@
/datum/job/mime/get_access()
if(config.assistant_maint)
- return list(access_maint_tunnels, access_entertainment)
+ return list(access_maint_tunnels, access_entertainment, access_tomfoolery, access_mime)
else
- return list(access_entertainment)
+ return list(access_entertainment, access_tomfoolery, access_mime)
diff --git a/code/game/jobs/job_controller.dm b/code/game/jobs/job_controller.dm
index 4e53589c2ff..96dfbd31834 100644
--- a/code/game/jobs/job_controller.dm
+++ b/code/game/jobs/job_controller.dm
@@ -415,7 +415,7 @@ var/global/datum/controller/occupations/job_master
// Implants get special treatment
if(G.slot == "implant")
- var/obj/item/weapon/implant/I = G.spawn_item(H)
+ var/obj/item/weapon/implant/I = G.spawn_item(H, H.client.prefs.gear[G.display_name])
I.invisibility = 100
I.implant_loadout(H)
continue
@@ -514,11 +514,12 @@ var/global/datum/controller/occupations/job_master
var/obj/item/organ/external/l_foot = H.get_organ("l_foot")
var/obj/item/organ/external/r_foot = H.get_organ("r_foot")
var/obj/item/weapon/storage/S = locate() in H.contents
- var/obj/item/wheelchair/R = null
+ var/obj/item/wheelchair/R
if(S)
R = locate() in S.contents
if(!l_foot || !r_foot || R)
- var/obj/structure/bed/chair/wheelchair/W = new /obj/structure/bed/chair/wheelchair(H.loc)
+ var/wheelchair_type = R?.unfolded_type || /obj/structure/bed/chair/wheelchair
+ var/obj/structure/bed/chair/wheelchair/W = new wheelchair_type(H.loc)
W.buckle_mob(H)
H.update_canmove()
W.set_dir(H.dir)
diff --git a/code/game/jobs/jobs.dm b/code/game/jobs/jobs.dm
index 40f0fdb4a41..9312c84571d 100644
--- a/code/game/jobs/jobs.dm
+++ b/code/game/jobs/jobs.dm
@@ -26,7 +26,10 @@ var/const/PSYCHIATRIST =(1<<7)
var/const/ROBOTICIST =(1<<8)
var/const/XENOBIOLOGIST =(1<<9)
var/const/PARAMEDIC =(1<<10)
-var/const/XENOBOTANIST =(1<<15) //VOREStation Add
+var/const/PATHFINDER =(1<<11) //VOREStation Add
+var/const/EXPLORER =(1<<12) //VOREStation Add
+var/const/SAR =(1<<13) //VOREStation Add
+var/const/XENOBOTANIST =(1<<14) //VOREStation Add
var/const/CIVILIAN =(1<<2)
@@ -43,9 +46,10 @@ var/const/LAWYER =(1<<9)
var/const/CHAPLAIN =(1<<10)
var/const/ASSISTANT =(1<<11)
var/const/BRIDGE =(1<<12)
-var/const/CLOWN =(1<<13) //VOREStation Add
-var/const/MIME =(1<<14) //VOREStation Add
-var/const/ENTERTAINER =(1<<15) //VOREStation Add
+var/const/PILOT =(1<<13) //VOREStation Add
+var/const/CLOWN =(1<<14) //VOREStation Add
+var/const/MIME =(1<<15) //VOREStation Add
+var/const/ENTERTAINER =(1<<16) //VOREStation Add
//VOREStation Add
var/const/TALON =(1<<3)
diff --git a/code/game/machinery/Sleeper.dm b/code/game/machinery/Sleeper.dm
index a97fbf986f7..e0ff3a6086c 100644
--- a/code/game/machinery/Sleeper.dm
+++ b/code/game/machinery/Sleeper.dm
@@ -529,5 +529,5 @@
stasis_level = 100 //Just one setting
/obj/machinery/sleeper/survival_pod/Initialize()
- ..()
+ . = ..()
RefreshParts(1)
diff --git a/code/game/machinery/adv_med.dm b/code/game/machinery/adv_med.dm
index 267524b9797..08e22f96e0e 100644
--- a/code/game/machinery/adv_med.dm
+++ b/code/game/machinery/adv_med.dm
@@ -14,7 +14,6 @@
active_power_usage = 10000 //10 kW. It's a big all-body scanner.
light_color = "#00FF00"
var/obj/machinery/body_scanconsole/console
- var/known_implants = list(/obj/item/weapon/implant/health, /obj/item/weapon/implant/chem, /obj/item/weapon/implant/death_alarm, /obj/item/weapon/implant/loyalty, /obj/item/weapon/implant/tracking, /obj/item/weapon/implant/language, /obj/item/weapon/implant/language/eal, /obj/item/weapon/implant/backup, /obj/item/device/nif) //VOREStation Add - Backup Implant, NIF
var/printing_text = null
/obj/machinery/bodyscanner/Initialize()
@@ -255,12 +254,11 @@
organData["broken"] = E.min_broken_damage
var/implantData[0]
- for(var/obj/I in E.implants)
+ for(var/obj/thing in E.implants)
var/implantSubData[0]
- implantSubData["name"] = I.name
- if(is_type_in_list(I, known_implants))
- implantSubData["known"] = 1
-
+ var/obj/item/weapon/implant/I = thing
+ implantSubData["name"] = I.name
+ implantSubData["known"] = istype(I) && I.known_implant
implantData.Add(list(implantSubData))
organData["implants"] = implantData
@@ -464,8 +462,9 @@
infected = "Gangrene Detected:"
var/unknown_body = 0
- for(var/I in e.implants)
- if(is_type_in_list(I,known_implants))
+ for(var/thing in e.implants)
+ var/obj/item/weapon/implant/I = thing
+ if(istype(I) && I.known_implant)
imp += "[I] implanted:"
else
unknown_body++
diff --git a/code/game/machinery/autolathe.dm b/code/game/machinery/autolathe.dm
index 3cde4792387..80ff6aee29a 100644
--- a/code/game/machinery/autolathe.dm
+++ b/code/game/machinery/autolathe.dm
@@ -36,6 +36,14 @@
if(!autolathe_recipes)
autolathe_recipes = new()
wires = new(src)
+
+ for(var/Name in name_to_material)
+ if(Name in stored_material)
+ continue
+
+ stored_material[Name] = 0
+ storage_capacity[Name] = 0
+
default_apply_parts()
RefreshParts()
@@ -270,6 +278,15 @@
//Create the desired item.
var/obj/item/I = new making.path(src.loc)
+
+ if(LAZYLEN(I.matter)) // Sadly we must obey the laws of equivalent exchange.
+ I.matter.Cut()
+ else
+ I.matter = list()
+
+ for(var/material in making.resources) // Handle the datum's autoscaling for waste, so we're properly wasting material, but not so much if we have efficiency.
+ I.matter[material] = round(making.resources[material] / (making.no_scale ? 1 : 1.25)) * (making.no_scale ? 1 : mat_efficiency)
+
flick("[initial(icon_state)]_finish", src)
if(multiplier > 1)
if(istype(I, /obj/item/stack))
@@ -277,7 +294,16 @@
S.amount = multiplier
else
for(multiplier; multiplier > 1; --multiplier) // Create multiple items if it's not a stack.
- new making.path(src.loc)
+ I = new making.path(src.loc)
+ // We've already deducted the cost of multiple items. Process the matter the same.
+ if(LAZYLEN(I.matter))
+ I.matter.Cut()
+
+ else
+ I.matter = list()
+
+ for(var/material in making.resources)
+ I.matter[material] = round(making.resources[material] / (making.no_scale ? 1 : 1.25)) * (making.no_scale ? 1 : mat_efficiency)
return TRUE
return FALSE
@@ -303,10 +329,9 @@
for(var/obj/item/weapon/stock_parts/manipulator/M in component_parts)
man_rating += M.rating
- storage_capacity[DEFAULT_WALL_MATERIAL] = mb_rating * 25000
- storage_capacity[MAT_PLASTIC] = mb_rating * 20000
- storage_capacity[MAT_PLASTEEL] = mb_rating * 16250
- storage_capacity["glass"] = mb_rating * 12500
+ for(var/mat_name in storage_capacity)
+ storage_capacity[mat_name] = mb_rating * 25000
+
build_time = 50 / man_rating
mat_efficiency = 1.1 - man_rating * 0.1// Normally, price is 1.25 the amount of material, so this shouldn't go higher than 0.6. Maximum rating of parts is 5
update_tgui_static_data(usr)
diff --git a/code/game/machinery/cloning.dm b/code/game/machinery/cloning.dm
index 8ddb76c68a1..2c34326fa7d 100644
--- a/code/game/machinery/cloning.dm
+++ b/code/game/machinery/cloning.dm
@@ -465,6 +465,7 @@
/obj/item/weapon/implant/health
name = "health implant"
+ known_implant = TRUE
var/healthstring = ""
/obj/item/weapon/implant/health/proc/sensehealth()
diff --git a/code/game/machinery/computer/arcade.dm b/code/game/machinery/computer/arcade.dm
index 7ff97c83e85..2c12343c883 100644
--- a/code/game/machinery/computer/arcade.dm
+++ b/code/game/machinery/computer/arcade.dm
@@ -1,9 +1,8 @@
-/obj/machinery/computer/arcade/
+/obj/machinery/computer/arcade
name = "random arcade"
desc = "random arcade machine"
- icon_state = "arcade"
+ icon_state = "arcade1"
icon_keyboard = null
- icon_screen = "invaders"
clicksound = null //Gets too spammy and makes no sense for arcade to have the console keyboard noise anyway
var/list/prizes = list( /obj/item/weapon/storage/box/snappops = 2,
/obj/item/toy/blink = 2,
@@ -25,15 +24,15 @@
/obj/item/toy/stickhorse = 2
)
-/obj/machinery/computer/arcade/New()
- ..()
+/obj/machinery/computer/arcade/Initialize()
+ . = ..()
// If it's a generic arcade machine, pick a random arcade
// circuit board for it and make the new machine
if(!circuit)
var/choice = pick(subtypesof(/obj/item/weapon/circuitboard/arcade) - /obj/item/weapon/circuitboard/arcade/clawmachine)
var/obj/item/weapon/circuitboard/CB = new choice()
new CB.build_path(loc, CB)
- qdel(src)
+ return INITIALIZE_HINT_QDEL
/obj/machinery/computer/arcade/proc/prizevend()
if(!(contents-circuit).len)
@@ -77,9 +76,10 @@
///////////////////
/obj/machinery/computer/arcade/battle
- name = "arcade machine"
- desc = "Does not support Pinball."
- icon_state = "arcade"
+ name = "Battler"
+ desc = "Fight through what space has to offer!"
+ icon_state = "arcade2"
+ icon_screen = "battler"
circuit = /obj/item/weapon/circuitboard/arcade/battle
var/enemy_name = "Space Villian"
var/temp = "Winners don't use space drugs" //Temporary message, for attack messages, etc
@@ -310,7 +310,8 @@
/obj/machinery/computer/arcade/orion_trail
name = "The Orion Trail"
desc = "Learn how our ancestors got to Orion, and have fun in the process!"
- icon_state = "arcade"
+ icon_state = "arcade1"
+ icon_screen = "orion"
circuit = /obj/item/weapon/circuitboard/arcade/orion_trail
var/busy = 0 //prevent clickspam that allowed people to ~speedrun~ the game.
var/engine = 0
diff --git a/code/game/machinery/computer/cloning.dm b/code/game/machinery/computer/cloning.dm
index cc05d632176..8d4202d4213 100644
--- a/code/game/machinery/computer/cloning.dm
+++ b/code/game/machinery/computer/cloning.dm
@@ -26,7 +26,7 @@
light_color = "#315ab4"
/obj/machinery/computer/cloning/Initialize()
- ..()
+ . = ..()
pods = list()
records = list()
set_scan_temp("Scanner ready.", "good")
diff --git a/code/game/machinery/computer/guestpass.dm b/code/game/machinery/computer/guestpass.dm
index 5fc8c77bd0e..20fd6991a01 100644
--- a/code/game/machinery/computer/guestpass.dm
+++ b/code/game/machinery/computer/guestpass.dm
@@ -168,9 +168,9 @@
if(reas)
reason = reas
if("duration")
- var/dur = input("Duration (in minutes) during which pass is valid (up to 120 minutes).", "Duration") as num|null
+ var/dur = input("Duration (in minutes) during which pass is valid (up to 360 minutes).", "Duration") as num|null //VOREStation Edit
if(dur)
- if(dur > 0 && dur <= 120)
+ if(dur > 0 && dur <= 360) //VOREStation Edit
duration = dur
else
to_chat(usr, "Invalid duration.")
diff --git a/code/game/machinery/computer/medical.dm b/code/game/machinery/computer/medical.dm
index adf53c80a8e..680ce44345f 100644
--- a/code/game/machinery/computer/medical.dm
+++ b/code/game/machinery/computer/medical.dm
@@ -29,7 +29,7 @@
/obj/machinery/computer/med_data/Initialize()
- ..()
+ . = ..()
field_edit_questions = list(
// General
"sex" = "Please select new sex:",
diff --git a/code/game/machinery/computer/message.dm b/code/game/machinery/computer/message.dm
index 1caa7b61a4d..430b42591cf 100644
--- a/code/game/machinery/computer/message.dm
+++ b/code/game/machinery/computer/message.dm
@@ -335,7 +335,7 @@
name = "Monitor Decryption Key"
/obj/item/weapon/paper/monitorkey/Initialize()
- ..() //Late init
+ ..()
return INITIALIZE_HINT_LATELOAD
/obj/item/weapon/paper/monitorkey/LateInitialize()
diff --git a/code/game/machinery/computer/pod.dm b/code/game/machinery/computer/pod.dm
index dbd5ba8383f..5eae5e82d08 100644
--- a/code/game/machinery/computer/pod.dm
+++ b/code/game/machinery/computer/pod.dm
@@ -13,7 +13,7 @@
var/title = "Mass Driver Controls"
/obj/machinery/computer/pod/Initialize()
- ..() //Not returning parent because lateload
+ ..()
return INITIALIZE_HINT_LATELOAD
/obj/machinery/computer/pod/LateInitialize()
diff --git a/code/game/machinery/computer/prisoner.dm b/code/game/machinery/computer/prisoner.dm
index 9932934a83d..c26d2c5365b 100644
--- a/code/game/machinery/computer/prisoner.dm
+++ b/code/game/machinery/computer/prisoner.dm
@@ -15,6 +15,9 @@
var/stop = 0.0
var/screen = 0 // 0 - No Access Denied, 1 - Access allowed
+/obj/machinery/computer/prisoner/attack_ai(var/mob/user as mob)
+ return src.attack_hand(user)
+
/obj/machinery/computer/prisoner/attack_hand(mob/user)
if(..())
return
@@ -28,7 +31,7 @@
/obj/machinery/computer/prisoner/tgui_data(mob/user)
var/list/data = list()
-
+
data["locked"] = !screen
data["chemImplants"] = list()
data["trackImplants"] = list()
@@ -65,24 +68,22 @@
return data
+
/obj/machinery/computer/prisoner/tgui_act(action, list/params)
if(..())
return TRUE
-
switch(action)
if("inject")
var/obj/item/weapon/implant/I = locate(params["imp"])
if(I)
I.activate(clamp(params["val"], 0, 10))
. = TRUE
-
if("lock")
if(allowed(usr))
screen = !screen
else
to_chat(usr, "Unauthorized Access.")
. = TRUE
-
if("warn")
var/warning = sanitize(input(usr, "Message:", "Enter your message here!", ""))
if(!warning)
@@ -91,5 +92,4 @@
if(I && I.imp_in)
to_chat(I.imp_in, "You hear a voice in your head saying: '[warning]'")
. = TRUE
-
add_fingerprint(usr)
diff --git a/code/game/machinery/computer/security.dm b/code/game/machinery/computer/security.dm
index 0b6ab77d7a2..4222e1264cd 100644
--- a/code/game/machinery/computer/security.dm
+++ b/code/game/machinery/computer/security.dm
@@ -25,7 +25,7 @@
var/static/list/field_edit_choices
/obj/machinery/computer/secure_data/Initialize()
- ..()
+ . = ..()
field_edit_questions = list(
// General
"name" = "Please enter new name:",
@@ -317,16 +317,16 @@
if(!length(t1))
return
- for(var/datum/data/record/R in data_core.security)
- if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["b_dna"]))
- active2 = R
+ for(var/datum/data/record/R in data_core.general)
+ if(t1 == lowertext(R.fields["name"]) || t1 == lowertext(R.fields["id"]) || t1 == lowertext(R.fields["fingerprint"]))
+ active1 = R
break
- if(!active2)
- set_temp("Security record not found. You must enter the person's exact name, ID or DNA.", "danger")
+ if(!active1)
+ set_temp("Security record not found. You must enter the person's exact name, ID, or fingerprint.", "danger")
return
- for(var/datum/data/record/E in data_core.general)
- if(E.fields["name"] == active2.fields["name"] && E.fields["id"] == active2.fields["id"])
- active1 = E
+ for(var/datum/data/record/E in data_core.security)
+ if(E.fields["name"] == active1.fields["name"] && E.fields["id"] == active1.fields["id"])
+ active2 = E
break
screen = SEC_DATA_RECORD
if("print_p")
@@ -389,11 +389,11 @@
if(field == "age")
answer = text2num(answer)
-
+
if(field == "rank")
if(answer in joblist)
active1.fields["real_rank"] = answer
-
+
if(field == "criminal")
for(var/mob/living/carbon/human/H in player_list)
BITSET(H.hud_updateflag, WANTED_HUD)
diff --git a/code/game/machinery/computer/skills.dm b/code/game/machinery/computer/skills.dm
index 47b9e8ce256..e11f404b165 100644
--- a/code/game/machinery/computer/skills.dm
+++ b/code/game/machinery/computer/skills.dm
@@ -30,7 +30,7 @@
var/static/list/field_edit_choices
/obj/machinery/computer/skills/Initialize()
- ..()
+ . = ..()
field_edit_questions = list(
// General
"name" = "Please input new name:",
diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm
index db275597960..64a3cc1fc78 100644
--- a/code/game/machinery/deployable.dm
+++ b/code/game/machinery/deployable.dm
@@ -1,111 +1,8 @@
/*
CONTAINS:
Deployable items
-Barricades
*/
-//Barricades!
-/obj/structure/barricade
- name = "barricade"
- desc = "This space is blocked off by a barricade."
- icon = 'icons/obj/structures.dmi'
- icon_state = "barricade"
- anchored = 1.0
- density = 1.0
- var/health = 100
- var/maxhealth = 100
- var/datum/material/material
-
-/obj/structure/barricade/New(var/newloc, var/material_name)
- ..(newloc)
- if(!material_name)
- material_name = "wood"
- material = get_material_by_name("[material_name]")
- if(!material)
- qdel(src)
- return
- name = "[material.display_name] barricade"
- desc = "This space is blocked off by a barricade made of [material.display_name]."
- color = material.icon_colour
- maxhealth = material.integrity
- health = maxhealth
-
-/obj/structure/barricade/get_material()
- return material
-
-/obj/structure/barricade/attackby(obj/item/W as obj, mob/user as mob)
- user.setClickCooldown(user.get_attack_speed(W))
- if(istype(W, /obj/item/stack))
- var/obj/item/stack/D = W
- if(D.get_material_name() != material.name)
- return //hitting things with the wrong type of stack usually doesn't produce messages, and probably doesn't need to.
- if(health < maxhealth)
- if(D.get_amount() < 1)
- to_chat(user, "You need one sheet of [material.display_name] to repair \the [src].")
- return
- visible_message("[user] begins to repair \the [src].")
- if(do_after(user,20) && health < maxhealth)
- if(D.use(1))
- health = maxhealth
- visible_message("[user] repairs \the [src].")
- return
- return
- else
- switch(W.damtype)
- if("fire")
- health -= W.force * 1
- if("brute")
- health -= W.force * 0.75
- if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
- playsound(src, 'sound/effects/woodcutting.ogg', 100, 1)
- else
- playsound(src, 'sound/weapons/smash.ogg', 50, 1)
- CheckHealth()
- ..()
-
-/obj/structure/barricade/proc/CheckHealth()
- if(health <= 0)
- dismantle()
- return
-
-/obj/structure/barricade/take_damage(var/damage)
- health -= damage
- CheckHealth()
- return
-
-/obj/structure/barricade/attack_generic(var/mob/user, var/damage, var/attack_verb)
- visible_message("[user] [attack_verb] the [src]!")
- if(material == get_material_by_name("resin"))
- playsound(src, 'sound/effects/attackblob.ogg', 100, 1)
- else if(material == (get_material_by_name(MAT_WOOD) || get_material_by_name(MAT_SIFWOOD)))
- playsound(src, 'sound/effects/woodcutting.ogg', 100, 1)
- else
- playsound(src, 'sound/weapons/smash.ogg', 50, 1)
- user.do_attack_animation(src)
- health -= damage
- CheckHealth()
- return
-
-/obj/structure/barricade/proc/dismantle()
- material.place_dismantled_product(get_turf(src))
- visible_message("\The [src] falls apart!")
- qdel(src)
- return
-
-/obj/structure/barricade/ex_act(severity)
- switch(severity)
- if(1.0)
- dismantle()
- if(2.0)
- health -= 25
- CheckHealth()
-
-/obj/structure/barricade/CanPass(atom/movable/mover, turf/target)//So bullets will fly over and stuff.
- if(istype(mover) && mover.checkpass(PASSTABLE))
- return TRUE
- return FALSE
-
-//Actual Deployable machinery stuff
/obj/machinery/deployable
name = "deployable"
desc = "deployable"
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 014efcb5813..39d54ef96d5 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -862,14 +862,14 @@ About the new airlock wires panel:
/obj/machinery/door/airlock/tgui_data(mob/user)
var/list/data = list()
-
+
var/list/power = list()
power["main"] = main_power_lost_until > 0 ? 0 : 2
power["main_timeleft"] = round(main_power_lost_until > 0 ? max(main_power_lost_until - world.time, 0) / 10 : main_power_lost_until, 1)
power["backup"] = backup_power_lost_until > 0 ? 0 : 2
power["backup_timeleft"] = round(backup_power_lost_until > 0 ? max(backup_power_lost_until - world.time, 0) / 10 : backup_power_lost_until, 1)
data["power"] = power
-
+
data["shock"] = (electrified_until == 0) ? 2 : 0
data["shock_timeleft"] = round(electrified_until > 0 ? max(electrified_until - world.time, 0) / 10 : electrified_until, 1)
data["id_scanner"] = !aiDisabledIdScanner
diff --git a/code/game/machinery/doors/blast_door.dm b/code/game/machinery/doors/blast_door.dm
index 08e0979ed57..8526820c33b 100644
--- a/code/game/machinery/doors/blast_door.dm
+++ b/code/game/machinery/doors/blast_door.dm
@@ -29,6 +29,7 @@
var/close_sound = 'sound/machines/door/blastdoorclose.ogg'
var/damage = BLAST_DOOR_CRUSH_DAMAGE
var/multiplier = 1 // The multiplier for how powerful our YEET is.
+ var/istransparent = 0
closed_layer = ON_WINDOW_LAYER // Above airlocks when closed
var/id = 1.0
@@ -108,10 +109,13 @@
src.density = 1
update_nearby_tiles()
src.update_icon()
- src.set_opacity(1)
+ if(src.istransparent)
+ src.set_opacity(0)
+ else
+ src.set_opacity(1)
sleep(15)
src.operating = 0
-
+
// Blast door crushing.
for(var/turf/turf in locs)
for(var/atom/movable/AM in turf)
@@ -276,10 +280,11 @@
// Parameters: None
// Description: Closes the door. Does necessary checks.
/obj/machinery/door/blast/close()
+
if (src.operating || (stat & BROKEN || stat & NOPOWER))
return
- force_close()
+ force_close()
// Proc: repair()
// Parameters: None
@@ -323,5 +328,52 @@ obj/machinery/door/blast/regular/open
icon_state = "shutter1"
damage = SHUTTER_CRUSH_DAMAGE
+// SUBTYPE: Transparent
+// Not technically a blast door but operates like one. Allows air and light.
+obj/machinery/door/blast/gate
+ name = "thick gate"
+ icon_state_open = "tshutter0"
+ icon_state_opening = "tshutterc0"
+ icon_state_closed = "tshutter1"
+ icon_state_closing = "tshutterc1"
+ icon_state = "tshutter1"
+ damage = SHUTTER_CRUSH_DAMAGE
+ maxhealth = 400
+ block_air_zones = 0
+ opacity = 0
+ istransparent = 1
+
+obj/machinery/door/blast/gate/open
+ icon_state = "tshutter0"
+ density = 0
+
+/obj/machinery/door/blast/gate/thin
+ name = "thin gate"
+ icon_state_open = "shutter2_0"
+ icon_state_opening = "shutter2_c0"
+ icon_state_closed = "shutter2_1"
+ icon_state_closing = "shutter2_c1"
+ icon_state = "shutter2_1"
+ maxhealth = 200
+ opacity = 0
+
+/obj/machinery/door/blast/gate/thin/open
+ icon_state = "shutter2_1"
+ density = 0
+
+/obj/machinery/door/blast/gate/bars
+ name = "prison bars"
+ icon_state_open = "bars_0"
+ icon_state_opening = "bars_c0"
+ icon_state_closed = "bars_1"
+ icon_state_closing = "bars_c1"
+ icon_state = "bars_1"
+ maxhealth = 600
+ opacity = 0
+
+/obj/machinery/door/blast/gate/bars/open
+ icon_state = "bars_1"
+ density = 0
+
#undef BLAST_DOOR_CRUSH_DAMAGE
#undef SHUTTER_CRUSH_DAMAGE
\ No newline at end of file
diff --git a/code/game/machinery/doors/brigdoors.dm b/code/game/machinery/doors/brigdoors.dm
index f4d9c900ed3..e3098507f21 100644
--- a/code/game/machinery/doors/brigdoors.dm
+++ b/code/game/machinery/doors/brigdoors.dm
@@ -8,8 +8,6 @@
#define PRESET_MEDIUM 5 MINUTES
#define PRESET_LONG 10 MINUTES
-//This file was auto-corrected by findeclaration.exe on 25.5.2012 20:42:31
-
///////////////////////////////////////////////////////////////////////////////////////////////
// Brig Door control displays.
// Description: This is a controls the timer for the brig doors, displays the timer on itself and
@@ -25,22 +23,21 @@
layer = ABOVE_WINDOW_LAYER
desc = "A remote control for a door."
req_access = list(access_brig)
- anchored = 1.0 // can't pick it up
- density = 0 // can walk through it.
- var/id = null // id of door it controls.
-
+ anchored = 1.0 // can't pick it up
+ density = 0 // can walk through it.
+ var/id = null // id of door it controls.
var/activation_time = 0
var/timer_duration = 0
var/timing = FALSE // boolean, true/1 timer is on, false/0 means it's not timing
var/list/obj/machinery/targets = list()
+
maptext_height = 26
maptext_width = 32
/obj/machinery/door_timer/Initialize()
..()
- //Doors need to go first, and can't rely on init order, so come back to me.
return INITIALIZE_HINT_LATELOAD
/obj/machinery/door_timer/LateInitialize()
@@ -72,12 +69,12 @@
/obj/machinery/door_timer/process()
if(stat & (NOPOWER|BROKEN))
return
-
if(timing)
if(world.time - activation_time >= timer_duration)
timer_end() // open doors, reset timer, clear status screen
update_icon()
+
// has the door power situation changed, if so update icon.
/obj/machinery/door_timer/power_change()
..()
@@ -108,7 +105,7 @@
C.icon_state = "closed_locked"
return 1
-// Opens and unlocks doors, power check
+/// Opens and unlocks doors, power check
/obj/machinery/door_timer/proc/timer_end(forced = FALSE)
if(stat & (NOPOWER|BROKEN))
return 0
@@ -145,6 +142,9 @@
if(timer_duration && activation_time && timing) // Setting it while active will reset the activation time
activation_time = world.time
+/obj/machinery/door_timer/attack_ai(mob/user)
+ return src.attack_hand(user)
+
/obj/machinery/door_timer/attack_hand(mob/user)
if(..())
return TRUE
diff --git a/code/game/machinery/lightswitch.dm b/code/game/machinery/lightswitch.dm
index a208e6eefd2..c078b854d0c 100644
--- a/code/game/machinery/lightswitch.dm
+++ b/code/game/machinery/lightswitch.dm
@@ -68,6 +68,7 @@
L.updateicon()
area.power_change()
+ GLOB.lights_switched_on_roundstat++
/obj/machinery/light_switch/power_change()
diff --git a/code/game/machinery/newscaster.dm b/code/game/machinery/newscaster.dm
index c23d02f4d01..af506f4fe95 100644
--- a/code/game/machinery/newscaster.dm
+++ b/code/game/machinery/newscaster.dm
@@ -4,6 +4,7 @@
/datum/feed_message
var/author =""
+ var/title
var/body =""
var/message_type ="Story"
var/datum/feed_channel/parent_channel
@@ -58,9 +59,6 @@
var/list/datum/feed_channel/network_channels = list()
var/datum/feed_message/wanted_issue
-/datum/feed_network/New()
- CreateFeedChannel("Station Announcements", "SS13", 1, 1, "New Station Announcement Available")
-
/datum/feed_network/proc/CreateFeedChannel(var/channel_name, var/author, var/locked, var/adminChannel = 0, var/announcement_message)
var/datum/feed_channel/newChannel = new /datum/feed_channel
newChannel.channel_name = channel_name
@@ -73,12 +71,16 @@
newChannel.announcement = "Breaking news from [channel_name]!"
network_channels += newChannel
-/datum/feed_network/proc/SubmitArticle(var/msg, var/author, var/channel_name, var/obj/item/weapon/photo/photo, var/adminMessage = 0, var/message_type = "")
+/datum/feed_network/proc/SubmitArticle(var/msg, var/author, var/channel_name, var/obj/item/weapon/photo/photo, var/adminMessage = 0, var/message_type = "", var/title)
var/datum/feed_message/newMsg = new /datum/feed_message
newMsg.author = author
newMsg.body = msg
newMsg.time_stamp = "[stationtime2text()]"
newMsg.is_admin_message = adminMessage
+ if(title)
+ newMsg.title = title
+ else
+ newMsg.title = "News Update"
newMsg.post_time = round_duration_in_ds // Should be almost universally unique
if(message_type)
newMsg.message_type = message_type
@@ -147,6 +149,7 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
// 1 = there has
var/scanned_user = "Unknown" //Will contain the name of the person who currently uses the newscaster
var/msg = ""; //Feed message
+ var/title = ""; // Feed title
var/datum/news_photo/photo_data = null
var/channel_name = ""; //the feed channel which will be receiving the feed, or being created
var/c_locked=0; //Will our new channel be locked to public submissions?
@@ -164,7 +167,7 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
securityCaster = 1
/obj/machinery/newscaster/Initialize()
- ..() //Not returning . because lateload below
+ ..()
allCasters += src
unit_no = ++unit_no_cur
paper_remaining = 15
@@ -371,7 +374,6 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
/obj/machinery/newscaster/tgui_act(action, list/params, datum/tgui/ui, datum/tgui_state/state)
if(..())
return TRUE
-
switch(action)
if("cleartemp")
temp = null
@@ -434,6 +436,10 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
msg = sanitize(input(usr, "Write your Feed story", "Network Channel Handler", "") as message|null)
return TRUE
+ if("set_new_title")
+ title = sanitize(input(usr, "Enter your Feed title", "Network Channel Handler", "") as message|null)
+ return TRUE
+
if("set_attachment")
AttachPhoto(usr)
return TRUE
@@ -449,10 +455,13 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
if(channel_name == "")
set_temp("Error: Could not submit feed message to network: No feed channel selected.", "danger", FALSE)
return TRUE
+ if(title == "")
+ set_temp("Error: Invalid Title.", "danger", FALSE)
+ return TRUE
var/image = photo_data ? photo_data.photo : null
feedback_inc("newscaster_stories",1)
- news_network.SubmitArticle(msg, our_user, channel_name, image, 0)
+ news_network.SubmitArticle(msg, our_user, channel_name, image, 0, "", title)
set_temp("Feed message created successfully.", "success", FALSE)
return TRUE
@@ -629,153 +638,6 @@ GLOBAL_LIST_BOILERPLATE(allCasters, /obj/machinery/newscaster)
photo_data = new(selection, 1)
-//########################################################################################################################
-//###################################### NEWSPAPER! ######################################################################
-//########################################################################################################################
-
-/obj/item/weapon/newspaper
- name = "newspaper"
- desc = "An issue of The Griffon, the newspaper circulating aboard most stations."
- icon = 'icons/obj/bureaucracy.dmi'
- icon_state = "newspaper"
- w_class = ITEMSIZE_SMALL //Let's make it fit in trashbags!
- attack_verb = list("bapped")
- var/screen = 0
- var/pages = 0
- var/curr_page = 0
- var/list/datum/feed_channel/news_content = list()
- var/datum/feed_message/important_message = null
- var/scribble=""
- var/scribble_page = null
- drop_sound = 'sound/items/drop/wrapper.ogg'
- pickup_sound = 'sound/items/pickup/wrapper.ogg'
-
-obj/item/weapon/newspaper/attack_self(mob/user)
- if(ishuman(user))
- var/mob/living/carbon/human/human_user = user
- var/dat
- pages = 0
- switch(screen)
- if(0) //Cover
- dat+="
The Griffon
"
- dat+="[using_map.company_name]-standard newspaper, for use on [using_map.company_name]© Space Facilities
"
- if(isemptylist(news_content))
- if(important_message)
- dat+="Contents:
**Important Security Announcement** \[page [pages+2]\]
"
- else
- dat+="Other than the title, the rest of the newspaper is unprinted..."
- else
- dat+="Contents:
"
- for(var/datum/feed_channel/NP in news_content)
- pages++
- if(important_message)
- dat+="**Important Security Announcement** \[page [pages+2]\]
"
- var/temp_page=0
- for(var/datum/feed_channel/NP in news_content)
- temp_page++
- dat+="[NP.channel_name] \[page [temp_page+1]\]
"
- dat+="
"
- if(scribble_page==curr_page)
- dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\""
- dat+= "
"
- if(1) // X channel pages inbetween.
- for(var/datum/feed_channel/NP in news_content)
- pages++ //Let's get it right again.
- var/datum/feed_channel/C = news_content[curr_page]
- dat+="[C.channel_name] \[created by: [C.author]\]
"
- if(C.censored)
- dat+="This channel was deemed dangerous to the general welfare of the station and therefore marked with a D-Notice. Its contents were not transferred to the newspaper at the time of printing."
- else
- if(isemptylist(C.messages))
- dat+="No Feed stories stem from this channel..."
- else
- dat+=""
- var/i = 0
- for(var/datum/feed_message/MESSAGE in C.messages)
- i++
- dat+="-[MESSAGE.body]
"
- if(MESSAGE.img)
- user << browse_rsc(MESSAGE.img, "tmp_photo[i].png")
- dat+="
"
- dat+="\[[MESSAGE.message_type] by [MESSAGE.author]\]
"
- dat+="
"
- if(scribble_page==curr_page)
- dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\""
- dat+= "
"
- if(2) //Last page
- for(var/datum/feed_channel/NP in news_content)
- pages++
- if(important_message!=null)
- dat+="Wanted Issue:
"
- dat+="Criminal name: [important_message.author]
"
- dat+="Description: [important_message.body]
"
- dat+="Photo:: "
- if(important_message.img)
- user << browse_rsc(important_message.img, "tmp_photow.png")
- dat+="
"
- else
- dat+="None"
- else
- dat+="Apart from some uninteresting Classified ads, there's nothing on this page..."
- if(scribble_page==curr_page)
- dat+="
There is a small scribble near the end of this page... It reads: \"[scribble]\""
- dat+= "
"
- else
- dat+="I'm sorry to break your immersion. This shit's bugged. Report this bug to Agouri, polyxenitopalidou@gmail.com"
-
- dat+="
[curr_page+1]
"
- human_user << browse(dat, "window=newspaper_main;size=300x400")
- onclose(human_user, "newspaper_main")
- else
- to_chat(user, "The paper is full of intelligible symbols!")
-
-obj/item/weapon/newspaper/Topic(href, href_list)
- var/mob/living/U = usr
- ..()
- if((src in U.contents) || (istype(loc, /turf) && in_range(src, U)))
- U.set_machine(src)
- if(href_list["next_page"])
- if(curr_page == pages+1)
- return //Don't need that at all, but anyway.
- if(curr_page == pages) //We're at the middle, get to the end
- screen = 2
- else
- if(curr_page == 0) //We're at the start, get to the middle
- screen = 1
- curr_page++
- playsound(src, "pageturn", 50, 1)
-
- else if(href_list["prev_page"])
- if(curr_page == 0)
- return
- if(curr_page == 1)
- screen = 0
-
- else
- if(curr_page == pages+1) //we're at the end, let's go back to the middle.
- screen = 1
- curr_page--
- playsound(src, "pageturn", 50, 1)
-
- if(istype(src.loc, /mob))
- attack_self(src.loc)
-
-obj/item/weapon/newspaper/attackby(obj/item/weapon/W as obj, mob/user)
- if(istype(W, /obj/item/weapon/pen))
- if(scribble_page == curr_page)
- to_chat(user, "There's already a scribble in this page... You wouldn't want to make things too cluttered, would you?")
- else
- var/s = sanitize(input(user, "Write something", "Newspaper", ""))
- s = sanitize(s)
- if(!s)
- return
- if(!in_range(src, usr) && src.loc != usr)
- return
- scribble_page = curr_page
- scribble = s
- attack_self(user)
- return
-
////////////////////////////////////helper procs
/obj/machinery/newscaster/proc/tgui_user_name(mob/user)
if(ishuman(user))
diff --git a/code/game/machinery/pointdefense.dm b/code/game/machinery/pointdefense.dm
index 5b10e398a3b..51f48c416b0 100644
--- a/code/game/machinery/pointdefense.dm
+++ b/code/game/machinery/pointdefense.dm
@@ -371,10 +371,13 @@ GLOBAL_LIST_BOILERPLATE(pointdefense_turrets, /obj/machinery/power/pointdefense)
/obj/effect/projectile/tracer/pointdefense
+ icon = 'icons/obj/projectiles_vr.dmi'
icon_state = "beam_pointdef"
/obj/effect/projectile/muzzle/pointdefense
+ icon = 'icons/obj/projectiles_vr.dmi'
icon_state = "muzzle_pointdef"
/obj/effect/projectile/impact/pointdefense
+ icon = 'icons/obj/projectiles_vr.dmi'
icon_state = "impact_pointdef"
diff --git a/code/game/machinery/portable_turret.dm b/code/game/machinery/portable_turret.dm
index 01a890bd79d..8e9e6da8f71 100644
--- a/code/game/machinery/portable_turret.dm
+++ b/code/game/machinery/portable_turret.dm
@@ -74,6 +74,7 @@
var/check_anomalies = TRUE //checks if it can shoot at unidentified lifeforms (ie xenos)
var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg
var/check_all = FALSE //If active, will fire on anything, including synthetics.
+ var/fire_at_movement = FALSE // If active, will fire on the most recent thing to move in range, as soon as possible.
var/ailock = FALSE // AI cannot use this
var/check_down = FALSE //If active, will shoot to kill when lethals are also on
var/faction = null //if set, will not fire at people in the same faction for any reason.
@@ -95,6 +96,8 @@
var/timeout = 10 // When a turret pops up, then finds nothing to shoot at, this number decrements until 0, when it pops down.
var/can_salvage = TRUE // If false, salvaging doesn't give you anything.
+ var/stay_up = FALSE // If true, the turret will remain open while it is powered.
+
/obj/machinery/porta_turret/crescent
req_one_access = list(access_cent_specops)
enabled = FALSE
@@ -276,6 +279,31 @@
)
return data
+/obj/machinery/porta_turret/pointdefense
+ name = "point-defense turret"
+ turret_type = "core"
+ desc = "A basic ship-mounted rock-breaker."
+ description_info = "This turret is capable of blasting incoming meteors into gravel, but it is very limited in range."
+
+ installation = /obj/item/weapon/gun/energy/mininglaser
+
+ check_arrest = FALSE
+ check_records = FALSE
+ check_weapons = FALSE
+ check_access = FALSE
+ check_anomalies = FALSE
+ check_synth = FALSE
+ check_all = FALSE
+ fire_at_movement = TRUE
+ stay_up = TRUE
+ ailock = FALSE
+ check_down = FALSE
+
+/obj/machinery/porta_turret/pointdefense/orderable
+ enabled = FALSE
+ anchored = FALSE
+ locked = FALSE
+
/obj/machinery/porta_turret/Initialize()
//Sets up a spark system
spark_system = new /datum/effect/effect/system/spark_spread
@@ -322,6 +350,8 @@
var/obj/item/projectile/P = initial(E.projectile_type)
//var/obj/item/ammo_casing/shottype = E.projectile_type
+ //GLOB.moved_event.register_global(src, /obj/machinery/porta_turret/proc/point_defense) //VOREStation Removal
+
projectile = P
lethal_projectile = projectile
shot_sound = initial(P.fire_sound)
@@ -377,11 +407,18 @@
lethal_shot_sound = 'sound/weapons/eluger.ogg'
shot_sound = 'sound/weapons/Taser.ogg'
-/obj/machinery/porta_turret/proc/HasController()
- var/area/A = get_area(src)
- return A && A.turret_controls.len > 0
+ if(/obj/item/weapon/gun/energy/mininglaser)
+ lethal_icon_color = "green"
+ lethal_projectile = /obj/item/projectile/beam/mininglaser
+ lethal_shot_sound = 'sound/weapons/eluger.ogg'
+ icon_color = "red"
+ projectile = /obj/item/projectile/beam/weaklaser
+ shot_sound = 'sound/weapons/Laser.ogg'
/obj/machinery/porta_turret/proc/isLocked(mob/user)
+ if(locked && !issilicon(user))
+ to_chat(user, "Controls locked.")
+ return 1
if(HasController())
return TRUE
if(isrobot(user) || isAI(user))
@@ -409,6 +446,10 @@
/obj/machinery/porta_turret/attack_hand(mob/user)
tgui_interact(user)
+/obj/machinery/porta_turret/proc/HasController()
+ var/area/A = get_area(src)
+ return A && A.turret_controls.len > 0
+
/obj/machinery/porta_turret/tgui_interact(mob/user, datum/tgui/ui = null)
if(HasController())
to_chat(user, "[src] can only be controlled using the assigned turret controller.")
@@ -671,6 +712,10 @@
popDown()
return
+ if(stay_up)
+ timeout = 10
+ popUp()
+
var/list/targets = list() //list of primary targets
var/list/secondarytargets = list() //targets that are least important
@@ -693,7 +738,7 @@
if(!tryToShootAt(targets))
if(!tryToShootAt(secondarytargets)) // if no valid targets, go for secondary targets
timeout--
- if(timeout <= 0)
+ if(timeout <= 0 && !stay_up)
spawn()
popDown() // no valid targets, close the cover
@@ -701,6 +746,14 @@
use_power(20000)
health = min(health+1, maxhealth) // 1HP for 20kJ
+// We're expecting the first arg to be a target, for this we don't care about previous and next turfs.
+/obj/machinery/porta_turret/proc/point_defense(var/atom/movable/Targ)
+ if((stat & (NOPOWER|BROKEN)) || !fire_at_movement) // Are we even able or supposed to fire at non-moving targets?
+ return
+
+ if((isliving(Targ) && assess_living(Targ)) || ((istype(Targ, /obj/item) || istype(Targ, /obj/effect/meteor)) && Targ.invisibility < INVISIBILITY_LEVEL_ONE && Targ in view(7,src))) // Is the target a living thing, if so, is it a valid target? Or if it's not living, is it in sight?
+ target(Targ) // Yes? Blast it.
+
/obj/machinery/porta_turret/proc/assess_and_assign(var/mob/living/L, var/list/targets, var/list/secondarytargets)
switch(assess_living(L))
if(TURRET_PRIORITY_TARGET)
@@ -727,10 +780,10 @@
if(L.stat == DEAD && !emagged) //if the perp is dead, no need to bother really
return TURRET_NOT_TARGET //move onto next potential victim!
- if(get_dist(src, L) > 7) //if it's too far away, why bother?
+ if(get_dist(src, get_turf(L)) > 7) //if it's too far away, why bother?
return TURRET_NOT_TARGET
- if(!(L in check_trajectory(L, src))) //check if we have true line of sight
+ if(!(L in check_trajectory(get_turf(L), src))) //check if we have true line of sight
return TURRET_NOT_TARGET
if(emagged) // If emagged not even the dead get a rest
@@ -837,8 +890,9 @@
last_target = target
spawn()
popUp() //pop the turret up if it's not already up.
- set_dir(get_dir(src, target)) //even if you can't shoot, follow the target
- playsound(src, 'sound/machines/turrets/turret_rotate.ogg', 100, 1) // Play rotating sound
+ if(dir != get_dir(src, target))
+ set_dir(get_dir(src, target)) //even if you can't shoot, follow the target
+ playsound(src, 'sound/machines/turrets/turret_rotate.ogg', 100, 1) // Play rotating sound
spawn()
shootAt(target)
return 1
@@ -903,6 +957,8 @@
var/check_anomalies
var/check_all
var/check_down
+ var/fire_at_movement
+ var/stay_up
var/ailock
/obj/machinery/porta_turret/proc/setState(var/datum/turret_checks/TC)
@@ -919,6 +975,8 @@
check_anomalies = TC.check_anomalies
check_all = TC.check_all
check_down = TC.check_down
+ fire_at_movement = TC.fire_at_movement
+ stay_up = TC.stay_up
ailock = TC.ailock
power_change()
diff --git a/code/game/machinery/syndicatebeacon_vr.dm b/code/game/machinery/syndicatebeacon_vr.dm
index ef6b3da0bbf..668b36dcb70 100644
--- a/code/game/machinery/syndicatebeacon_vr.dm
+++ b/code/game/machinery/syndicatebeacon_vr.dm
@@ -25,7 +25,7 @@
updateUsrDialog()
return
var/mob/M = locate(href_list["traitormob"])
- if(M.mind.special_role || jobban_isbanned(M, "Syndicate"))
+ if(M.mind.tcrystals > 0 || jobban_isbanned(M, "Syndicate"))
temptext = "We have no need for you at this time. Have a pleasant day.
"
updateUsrDialog()
return
@@ -33,7 +33,9 @@
if(istype(M, /mob/living/carbon/human))
var/mob/living/carbon/human/N = M
to_chat(N, "Access granted, here are the supplies!")
- traitors.equip(N)
+ traitors.spawn_uplink(N)
+ N.mind.tcrystals = DEFAULT_TELECRYSTAL_AMOUNT
+ N.mind.accept_tcrystals = 1
message_admins("[N]/([N.ckey]) has recieved an uplink and telecrystals from the syndicate beacon.")
updateUsrDialog()
diff --git a/code/game/machinery/transportpod.dm b/code/game/machinery/transportpod.dm
index 0b499096fea..4a43cb18904 100644
--- a/code/game/machinery/transportpod.dm
+++ b/code/game/machinery/transportpod.dm
@@ -32,7 +32,7 @@
sleep(2)
go_out()
sleep(2)
- del(src)
+ qdel(src)
/obj/machinery/transportpod/relaymove(mob/user as mob)
if(user.stat)
diff --git a/code/game/machinery/turret_control.dm b/code/game/machinery/turret_control.dm
index ad55fe14a17..7f5a1d8e567 100644
--- a/code/game/machinery/turret_control.dm
+++ b/code/game/machinery/turret_control.dm
@@ -28,9 +28,12 @@
var/check_synth = FALSE //if active, will shoot at anything not an AI or cyborg
var/check_all = FALSE //If active, will shoot at anything.
var/check_down = TRUE //If active, won't shoot laying targets.
+ var/stay_up = FALSE //If active, the turret will not pop-down unless it loses power or is disabled.
+ var/fire_at_movement = FALSE //If active, the turret will prioritize objects or creatures that move in its range.
var/ailock = FALSE //Silicons cannot use this
var/syndicate = FALSE
+
req_access = list(access_ai_upload)
/obj/machinery/turretid/stun
@@ -194,6 +197,8 @@
TC.check_anomalies = check_anomalies
TC.check_all = check_all
TC.check_down = check_down
+ TC.stay_up = stay_up
+ TC.fire_at_movement = fire_at_movement
TC.ailock = ailock
if(istype(control_area))
diff --git a/code/game/machinery/vending.dm b/code/game/machinery/vending.dm
index 4f3d532c279..58107d9d0b4 100644
--- a/code/game/machinery/vending.dm
+++ b/code/game/machinery/vending.dm
@@ -572,7 +572,7 @@ GLOBAL_LIST_EMPTY(vending_products)
vend_ready = 1
currently_vending = null
SStgui.update_uis(src)
-
+ GLOB.items_sold_shift_roundstat++
/obj/machinery/vending/proc/do_logging(datum/stored_item/vending_product/R, mob/user, var/vending = 0)
if(user.GetIdCard())
diff --git a/code/game/machinery/vending_machines.dm b/code/game/machinery/vending_machines.dm
index e04568c1d08..098d231ce77 100644
--- a/code/game/machinery/vending_machines.dm
+++ b/code/game/machinery/vending_machines.dm
@@ -753,7 +753,9 @@
/obj/item/toy/plushie/borgplushie/scrubpuppy = 1,
/obj/item/toy/plushie/foxbear = 1,
/obj/item/toy/plushie/nukeplushie = 1,
- /obj/item/toy/plushie/otter = 1)
+ /obj/item/toy/plushie/otter = 1,
+ /obj/item/toy/plushie/vox = 1,
+ /obj/item/toy/mistletoe = 1)
//VOREStation Add End
premium = list(/obj/item/weapon/reagent_containers/food/drinks/bottle/champagne = 1,
/obj/item/weapon/storage/trinketbox = 2)
@@ -793,7 +795,9 @@
/obj/item/toy/plushie/borgplushie/scrubpuppy = 50,
/obj/item/toy/plushie/foxbear = 50,
/obj/item/toy/plushie/nukeplushie = 50,
- /obj/item/toy/plushie/otter = 50)
+ /obj/item/toy/plushie/otter = 50,
+ /obj/item/toy/plushie/vox = 50,
+ /obj/item/toy/mistletoe = 50)
//VOREStation Add End
diff --git a/code/game/machinery/vending_machines_vr.dm b/code/game/machinery/vending_machines_vr.dm
index fd113ee799b..c4c4e663d4b 100644
--- a/code/game/machinery/vending_machines_vr.dm
+++ b/code/game/machinery/vending_machines_vr.dm
@@ -1446,7 +1446,7 @@
/obj/item/seeds/riceseed = 3,
/obj/item/seeds/rose = 3,
/obj/item/seeds/soyaseed = 3,
- /obj/item/seeds/spineapple = 3,
+ /obj/item/seeds/pineapple = 3,
/obj/item/seeds/sugarcaneseed = 3,
/obj/item/seeds/sunflowerseed = 3,
/obj/item/seeds/shandseed = 2,
@@ -3940,7 +3940,7 @@
/obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/orangecake = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/peanutcake = 10,
- /obj/item/weapon/reagent_containers/food/snacks/slice/pineapple = 10,
+ /obj/item/weapon/reagent_containers/food/snacks/pineappleslice = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/plaincake = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/tofubread = 10,
@@ -4404,7 +4404,7 @@
/obj/item/weapon/reagent_containers/food/snacks/slice/mushroompizza = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/orangecake = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/peanutcake = 10,
- /obj/item/weapon/reagent_containers/food/snacks/slice/pineapple = 10,
+ /obj/item/weapon/reagent_containers/food/snacks/pineappleslice = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/plaincake = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/pumpkinpie = 10,
/obj/item/weapon/reagent_containers/food/snacks/slice/tofubread = 10,
@@ -4576,7 +4576,7 @@
/obj/item/seeds/riceseed = 3,
/obj/item/seeds/rose = 3,
/obj/item/seeds/soyaseed = 3,
- /obj/item/seeds/spineapple = 3,
+ /obj/item/seeds/pineapple = 3,
/obj/item/seeds/sugarcaneseed = 3,
/obj/item/seeds/sunflowerseed = 3,
/obj/item/seeds/shandseed = 2,
diff --git a/code/game/mecha/combat/durand.dm b/code/game/mecha/combat/durand.dm
index aa5a9e000c1..19bd2b9c53e 100644
--- a/code/game/mecha/combat/durand.dm
+++ b/code/game/mecha/combat/durand.dm
@@ -33,6 +33,9 @@
defence_mode_possible = 1
+ icon_scale_x = 1.5
+ icon_scale_y = 1.5
+
/*
/obj/mecha/combat/durand/New()
..()
diff --git a/code/game/mecha/combat/fighter_vr.dm b/code/game/mecha/combat/fighter_vr.dm
new file mode 100644
index 00000000000..4bc4782e9f8
--- /dev/null
+++ b/code/game/mecha/combat/fighter_vr.dm
@@ -0,0 +1,8 @@
+/obj/mecha/combat/fighter
+ starting_components = list(
+ /obj/item/mecha_parts/component/hull/lightweight,
+ /obj/item/mecha_parts/component/actuator,
+ /obj/item/mecha_parts/component/armor,
+ /obj/item/mecha_parts/component/gas,
+ /obj/item/mecha_parts/component/electrical
+ )
diff --git a/code/game/mecha/combat/gorilla.dm b/code/game/mecha/combat/gorilla.dm
index 4052afe8e6a..fecb361f1a2 100644
--- a/code/game/mecha/combat/gorilla.dm
+++ b/code/game/mecha/combat/gorilla.dm
@@ -31,7 +31,7 @@
thrusters_possible = 1
/obj/mecha/combat/gorilla/Initialize()
- ..()
+ . = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tesla_energy_relay(src) // This thing basically cannot function without an external power supply.
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/cannon(src)
diff --git a/code/game/mecha/combat/gygax.dm b/code/game/mecha/combat/gygax.dm
index 0323124c479..1f9d4a0b6e3 100644
--- a/code/game/mecha/combat/gygax.dm
+++ b/code/game/mecha/combat/gygax.dm
@@ -31,6 +31,9 @@
overload_possible = 1
+ icon_scale_x = 1.35
+ icon_scale_y = 1.35
+
//Not quite sure how to move those yet.
/obj/mecha/combat/gygax/get_commands()
var/output = {"
diff --git a/code/game/mecha/combat/marauder.dm b/code/game/mecha/combat/marauder.dm
index e2c0b9467a3..fd0442a2948 100644
--- a/code/game/mecha/combat/marauder.dm
+++ b/code/game/mecha/combat/marauder.dm
@@ -44,6 +44,9 @@
/obj/item/mecha_parts/mecha_equipment/antiproj_armor_booster
)
+ icon_scale_x = 1.5
+ icon_scale_y = 1.5
+
/obj/mecha/combat/marauder/seraph
desc = "Heavy-duty, command-type exosuit. This is a custom model, utilized only by high-ranking military personnel."
name = "Seraph"
diff --git a/code/game/mecha/combat/phazon.dm b/code/game/mecha/combat/phazon.dm
index 3ae3e41e131..a1ea2ab4519 100644
--- a/code/game/mecha/combat/phazon.dm
+++ b/code/game/mecha/combat/phazon.dm
@@ -40,7 +40,7 @@
switch_dmg_type_possible = TRUE
/obj/mecha/combat/phazon/equipped/Initialize()
- ..()
+ . = ..()
starting_equipment = list(
/obj/item/mecha_parts/mecha_equipment/tool/rcd,
/obj/item/mecha_parts/mecha_equipment/gravcatapult
diff --git a/code/game/mecha/components/_component.dm b/code/game/mecha/components/_component.dm
index aadf390c615..3d770e0dce0 100644
--- a/code/game/mecha/components/_component.dm
+++ b/code/game/mecha/components/_component.dm
@@ -43,7 +43,7 @@
. += "
It is completely destroyed."
/obj/item/mecha_parts/component/Initialize()
- ..()
+ . = ..()
integrity = max_integrity
if(start_damaged)
diff --git a/code/game/mecha/equipment/mecha_equipment.dm b/code/game/mecha/equipment/mecha_equipment.dm
index bec2b1a6c36..c716b1f33e6 100644
--- a/code/game/mecha/equipment/mecha_equipment.dm
+++ b/code/game/mecha/equipment/mecha_equipment.dm
@@ -49,6 +49,9 @@
..()
return
+/obj/item/mecha_parts/mecha_equipment/proc/add_equip_overlay(obj/mecha/M as obj)
+ return
+
/obj/item/mecha_parts/mecha_equipment/proc/update_chassis_page()
if(chassis)
send_byjax(chassis.occupant,"exosuit.browser","eq_list",chassis.get_equipment_list())
diff --git a/code/game/mecha/equipment/tools/inflatables.dm b/code/game/mecha/equipment/tools/inflatables.dm
index b18ba2eae11..ff766577ded 100644
--- a/code/game/mecha/equipment/tools/inflatables.dm
+++ b/code/game/mecha/equipment/tools/inflatables.dm
@@ -14,7 +14,7 @@
var/obj/item/weapon/inflatable_dispenser/my_deployer = null
/obj/item/mecha_parts/mecha_equipment/tool/powertool/inflatables/Initialize()
- ..()
+ . = ..()
my_deployer = my_tool
/obj/item/mecha_parts/mecha_equipment/tool/powertool/inflatables/Topic(href, href_list)
diff --git a/code/game/mecha/equipment/tools/repair_droid.dm b/code/game/mecha/equipment/tools/repair_droid.dm
index 7cd8ebd9ab7..acae64142f8 100644
--- a/code/game/mecha/equipment/tools/repair_droid.dm
+++ b/code/game/mecha/equipment/tools/repair_droid.dm
@@ -26,9 +26,10 @@
pr_repair_droid = null
..()
-/obj/item/mecha_parts/mecha_equipment/repair_droid/attach(obj/mecha/M as obj)
+/obj/item/mecha_parts/mecha_equipment/repair_droid/add_equip_overlay(obj/mecha/M as obj)
..()
- droid_overlay = new(src.icon, icon_state = "repair_droid")
+ if(!droid_overlay)
+ droid_overlay = new(src.icon, icon_state = "repair_droid")
M.add_overlay(droid_overlay)
return
diff --git a/code/game/mecha/equipment/tools/running_board.dm b/code/game/mecha/equipment/tools/running_board.dm
new file mode 100644
index 00000000000..aa2748c7a78
--- /dev/null
+++ b/code/game/mecha/equipment/tools/running_board.dm
@@ -0,0 +1,17 @@
+// concept borrowed from vgstation-coders/vgstation13#26316 on GitHub
+/obj/item/mecha_parts/mecha_equipment/runningboard
+ name = "hacked powered exosuit running board"
+ desc = "A running board with a power-lifter attachment, to quickly catapult exosuit pilots into the cockpit. Fits any exosuit."
+ icon_state = "mecha_runningboard"
+ origin_tech = list(TECH_MATERIAL = 6)
+ equip_type = EQUIP_HULL
+
+/obj/item/mecha_parts/mecha_equipment/runningboard/limited
+ name = "powered exosuit running board"
+ desc = "A running board with a power-lifter attachment, to quickly catapult exosuit pilots into the cockpit. Only fits to working exosuits."
+
+/obj/item/mecha_parts/mecha_equipment/runningboard/limited/can_attach(obj/mecha/M)
+ if(istype(M, /obj/mecha/working)) // is this a ripley?
+ . = ..()
+ else
+ return FALSE
\ No newline at end of file
diff --git a/code/game/mecha/equipment/tools/shield.dm b/code/game/mecha/equipment/tools/shield.dm
index ce0c43e7da9..0a50869e884 100644
--- a/code/game/mecha/equipment/tools/shield.dm
+++ b/code/game/mecha/equipment/tools/shield.dm
@@ -37,15 +37,19 @@
my_shield = null
..()
+/obj/item/mecha_parts/mecha_equipment/combat_shield/add_equip_overlay(obj/mecha/M as obj)
+ ..()
+ if(!drone_overlay)
+ drone_overlay = new(src.icon, icon_state = "shield_droid")
+ M.overlays += drone_overlay
+ return
+
/obj/item/mecha_parts/mecha_equipment/combat_shield/attach(obj/mecha/M as obj)
..()
if(chassis)
my_shield.shield_health = 0
my_shield.my_mecha = chassis
my_shield.forceMove(chassis)
-
- drone_overlay = new(src.icon, icon_state = "shield_droid")
- M.overlays += drone_overlay
return
/obj/item/mecha_parts/mecha_equipment/combat_shield/detach()
diff --git a/code/game/mecha/equipment/tools/syringe_gun.dm b/code/game/mecha/equipment/tools/syringe_gun.dm
index 7449d80c0f1..fd73d74fc2e 100644
--- a/code/game/mecha/equipment/tools/syringe_gun.dm
+++ b/code/game/mecha/equipment/tools/syringe_gun.dm
@@ -318,7 +318,7 @@
equip_type = EQUIP_HULL
/obj/item/mecha_parts/mecha_equipment/crisis_drone/Initialize()
- ..()
+ . = ..()
drone_overlay = new(src.icon, icon_state = droid_state)
/obj/item/mecha_parts/mecha_equipment/crisis_drone/Destroy()
@@ -467,11 +467,15 @@
if(enabled)
set_ready_state(0)
log_message("Activated.")
- chassis.overlays += drone_overlay
else
set_ready_state(1)
log_message("Deactivated.")
- chassis.overlays -= drone_overlay
+
+/obj/item/mecha_parts/mecha_equipment/crisis_drone/add_equip_overlay(obj/mecha/M as obj)
+ ..()
+ if(enabled)
+ M.add_overlay(drone_overlay)
+ return
/obj/item/mecha_parts/mecha_equipment/crisis_drone/Topic(href, href_list)
..()
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index fe8ec5876d9..4a3a105e9af 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -83,6 +83,14 @@
/obj/machinery/mecha_part_fabricator/Initialize()
. = ..()
+
+// Go through all materials, and add them to the possible storage, but hide them unless we contain them.
+ for(var/Name in name_to_material)
+ if(Name in materials)
+ continue
+
+ materials[Name] = 0
+
default_apply_parts()
files = new /datum/research(src) //Setup the research data holder.
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index e9e3397bba8..60bb48c5f6b 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -198,7 +198,7 @@
var/weapons_only_cycle = FALSE //So combat mechs don't switch to their equipment at times.
/obj/mecha/Initialize()
- ..()
+ . = ..()
for(var/path in starting_components)
var/obj/item/mecha_parts/component/C = new path(src)
@@ -208,6 +208,7 @@
for(var/path in starting_equipment)
var/obj/item/mecha_parts/mecha_equipment/ME = new path(src)
ME.attach(src)
+ update_transform()
/obj/mecha/drain_power(var/drain_check)
@@ -321,6 +322,8 @@
if(smoke_possible) //Just making sure nothing is running.
qdel(smoke_system)
+ GLOB.mech_destroyed_roundstat++
+
QDEL_NULL(pr_int_temp_processor)
QDEL_NULL(pr_inertial_movement)
QDEL_NULL(pr_give_air)
@@ -1576,11 +1579,12 @@
src.verbs += /obj/mecha/verb/eject
src.Entered(mmi_as_oc)
src.Move(src.loc)
- src.icon_state = src.reset_icon()
+ update_icon()
set_dir(dir_in)
src.log_message("[mmi_as_oc] moved in as pilot.")
if(!hasInternalDamage())
src.occupant << sound('sound/mecha/nominal.ogg',volume=50)
+ update_icon()
return 1
else
return 0
@@ -1803,6 +1807,14 @@
set src in oview(1)
move_inside()
+//returns an equipment object if we have one of that type, useful since is_type_in_list won't return the object
+//since is_type_in_list uses caching, this is a slower operation, so only use it if needed
+/obj/mecha/proc/get_equipment(var/equip_type)
+ for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment)
+ if(istype(ME,equip_type))
+ return ME
+ return null
+
/obj/mecha/proc/move_inside()
if (usr.stat || !ishuman(usr))
return
@@ -1843,18 +1855,22 @@
return
// to_chat(usr, "You start climbing into [src.name]")
-
- visible_message("
\The [usr] starts to climb into [src.name]")
-
- if(enter_after(40,usr))
- if(!src.occupant)
- moved_inside(usr)
- if(ishuman(occupant)) //Aeiou
- GrantActions(occupant, 1)
- else if(src.occupant!=usr)
- to_chat(usr, "[src.occupant] was faster. Try better next time, loser.")
+ if(get_equipment(/obj/item/mecha_parts/mecha_equipment/runningboard))
+ visible_message("
\The [usr] is instantly lifted into [src.name] by the running board!")
+ moved_inside(usr)
+ if(ishuman(occupant))
+ GrantActions(occupant, 1)
else
- to_chat(usr, "You stop entering the exosuit.")
+ visible_message("
\The [usr] starts to climb into [src.name]")
+ if(enter_after(40,usr))
+ if(!src.occupant)
+ moved_inside(usr)
+ if(ishuman(occupant)) //Aeiou
+ GrantActions(occupant, 1)
+ else if(src.occupant!=usr)
+ to_chat(usr, "[src.occupant] was faster. Try better next time, loser.")
+ else
+ to_chat(usr, "You stop entering the exosuit.")
return
/obj/mecha/proc/moved_inside(var/mob/living/carbon/human/H as mob)
@@ -1871,7 +1887,7 @@
src.forceMove(src.loc)
src.verbs += /obj/mecha/verb/eject
src.log_append_to_last("[H] moved in as pilot.")
- src.icon_state = src.reset_icon()
+ update_icon()
//VOREStation Edit Add
if(occupant.hud_used)
minihud = new (occupant.hud_used, src)
@@ -1991,7 +2007,7 @@
occupant.clear_alert("mech damage")
occupant.in_enclosed_vehicle = 0
occupant = null
- icon_state = src.reset_icon()+"-open"
+ update_icon()
set_dir(dir_in)
verbs -= /obj/mecha/verb/eject
@@ -2651,13 +2667,6 @@
return 1
return 0
-/obj/mecha/proc/reset_icon()
- if (initial_icon)
- icon_state = initial_icon
- else
- icon_state = initial(icon_state)
- return icon_state
-
//This is for mobs mostly.
/obj/mecha/attack_generic(var/mob/user, var/damage, var/attack_message)
diff --git a/code/game/mecha/mecha_appearance.dm b/code/game/mecha/mecha_appearance.dm
new file mode 100644
index 00000000000..5136ef070b6
--- /dev/null
+++ b/code/game/mecha/mecha_appearance.dm
@@ -0,0 +1,65 @@
+
+
+/obj/mecha
+ // Show the pilot.
+ var/show_pilot = FALSE
+
+ // The state of the 'face', or the thing that overlays on the pilot. If this isn't set, it will probably look really weird.
+ var/face_state = null
+ var/icon/face_overlay
+
+ var/icon/pilot_image
+
+ // How many pixels do we bump the pilot upward?
+ var/pilot_lift = 0
+
+/obj/mecha/update_transform()
+ // Now for the regular stuff.
+ var/matrix/M = matrix()
+ M.Scale(icon_scale_x, icon_scale_y)
+ M.Translate(0, 16*(icon_scale_y-1))
+ animate(src, transform = M, time = 10)
+ return
+
+/obj/mecha/update_icon()
+ if(!initial_icon)
+ initial_icon = initial(icon_state)
+
+ if(occupant)
+ icon_state = initial_icon
+ else
+ icon_state = "[initial_icon]-open"
+
+ cut_overlays()
+
+ if(show_pilot)
+ if(occupant)
+ pilot_image = getCompoundIcon(occupant)
+
+ if(!istype(occupant, /mob/living/carbon/brain))
+
+ var/icon/Cutter
+
+ if("[initial_icon]_cutter" in icon_states(icon))
+ Cutter = new(src.icon, "[initial_icon]_cutter")
+
+ if(Cutter)
+ pilot_image.Blend(Cutter, ICON_MULTIPLY, y = (-1 * pilot_lift))
+
+ var/image/Pilot = image(pilot_image)
+
+ Pilot.pixel_y = pilot_lift
+
+ add_overlay(Pilot)
+ else
+ pilot_image = null
+
+ if(face_state && !face_overlay)
+ face_overlay = new(src.icon, icon_state = face_state)
+
+ if(face_overlay)
+ add_overlay(face_overlay)
+
+ for(var/obj/item/mecha_parts/mecha_equipment/ME in equipment)
+ ME.add_equip_overlay(src)
+ return
diff --git a/code/game/mecha/medical/odysseus.dm b/code/game/mecha/medical/odysseus.dm
index dbba0cd2518..316d39bacee 100644
--- a/code/game/mecha/medical/odysseus.dm
+++ b/code/game/mecha/medical/odysseus.dm
@@ -17,6 +17,9 @@
step_energy_drain = 6
var/obj/item/clothing/glasses/hud/health/mech/hud
+ icon_scale_x = 1.2
+ icon_scale_y = 1.2
+
/obj/mecha/medical/odysseus/New()
..()
hud = new /obj/item/clothing/glasses/hud/health/mech(src)
@@ -124,7 +127,7 @@
C.images += holder
*/
/obj/mecha/medical/odysseus/loaded/Initialize()
- ..()
+ . = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/sleeper
ME.attach(src)
ME = new /obj/item/mecha_parts/mecha_equipment/tool/sleeper
diff --git a/code/game/mecha/micro/mechfab_designs_vr.dm b/code/game/mecha/micro/mechfab_designs_vr.dm
index 80d7945ea4d..3371302795b 100644
--- a/code/game/mecha/micro/mechfab_designs_vr.dm
+++ b/code/game/mecha/micro/mechfab_designs_vr.dm
@@ -117,7 +117,7 @@
name = "\improper PC-20 \"Lance\" light laser cannon"
id = "micro_laser_heavy"
req_tech = list(TECH_COMBAT = 4, TECH_MATERIAL = 3, TECH_POWER = 3)
- materials = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 1000, "diamond" = 2000)
+ materials = list(DEFAULT_WALL_MATERIAL = 10000, "glass" = 1000, MAT_COPPER = 1000, "diamond" = 1000)
build_path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/laser/microheavy
/datum/design/item/mecha/weapon/grenade_launcher/micro
@@ -191,5 +191,5 @@
desc = "A portable medical system used to treat external injuries from afar."
id = "mech_medigun"
req_tech = list(TECH_MATERIAL = 5, TECH_COMBAT = 5, TECH_BIO = 6)
- materials = list(DEFAULT_WALL_MATERIAL = 8000, "gold" = 2000, "silver" = 1750, "diamond" = 1500, "phoron" = 4000)
+ materials = list(DEFAULT_WALL_MATERIAL = 8000, MAT_COPPER = 4000, "gold" = 2000, "silver" = 1750, "diamond" = 1500)
build_path = /obj/item/mecha_parts/mecha_equipment/weapon/energy/medigun
\ No newline at end of file
diff --git a/code/game/mecha/working/ripley.dm b/code/game/mecha/working/ripley.dm
index aff19e301dd..4e92f757d27 100644
--- a/code/game/mecha/working/ripley.dm
+++ b/code/game/mecha/working/ripley.dm
@@ -24,6 +24,9 @@
/obj/item/mecha_parts/component/electrical
)
+ icon_scale_x = 1.2
+ icon_scale_y = 1.2
+
/obj/mecha/working/ripley/Destroy()
for(var/atom/movable/A in src.cargo)
A.loc = loc
@@ -67,7 +70,7 @@
max_special_equip = 1
/obj/mecha/working/ripley/deathripley/Initialize()
- ..()
+ . = ..()
var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/tool/hydraulic_clamp/safety
ME.attach(src)
return
@@ -77,7 +80,7 @@
name = "APLU \"Miner\""
/obj/mecha/working/ripley/mining/Initialize()
- ..()
+ . = ..()
//Attach drill
if(prob(25)) //Possible diamond drill... Feeling lucky?
var/obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill/D = new /obj/item/mecha_parts/mecha_equipment/tool/drill/diamonddrill
@@ -92,6 +95,20 @@
for(var/obj/item/mecha_parts/mecha_tracking/B in src.contents)//Deletes the beacon so it can't be found easily
qdel (B)
+/obj/mecha/working/ripley/antique
+ name = "APLU \"Geiger\""
+ desc = "You can't beat the classics."
+ icon_state = "ripley-old"
+ initial_icon = "ripley-old"
+
+ show_pilot = TRUE
+ pilot_lift = 5
+
+ max_utility_equip = 1
+ max_universal_equip = 3
+
+ icon_scale_x = 1
+ icon_scale_y = 1
//Vorestation Edit Start
diff --git a/code/game/objects/buckling.dm b/code/game/objects/buckling.dm
index 533414d50cc..088ed16440d 100644
--- a/code/game/objects/buckling.dm
+++ b/code/game/objects/buckling.dm
@@ -40,10 +40,7 @@
return TRUE
/atom/movable/proc/has_buckled_mobs()
- if(!buckled_mobs)
- return FALSE
- if(buckled_mobs.len)
- return TRUE
+ return LAZYLEN(buckled_mobs)
/atom/movable/Destroy()
unbuckle_all_mobs()
diff --git a/code/game/objects/effects/chem/coating.dm b/code/game/objects/effects/chem/coating.dm
index a777bbe5e05..2e9ad26049c 100644
--- a/code/game/objects/effects/chem/coating.dm
+++ b/code/game/objects/effects/chem/coating.dm
@@ -11,7 +11,7 @@
create_reagents(100)
/obj/effect/decal/cleanable/chemcoating/Initialize()
- ..()
+ . = ..()
var/turf/T = get_turf(src)
if(T)
for(var/obj/O in get_turf(src))
diff --git a/code/game/objects/effects/decals/contraband.dm b/code/game/objects/effects/decals/contraband.dm
index c3716b031c1..5286670849d 100644
--- a/code/game/objects/effects/decals/contraband.dm
+++ b/code/game/objects/effects/decals/contraband.dm
@@ -90,6 +90,39 @@
serial_number = given_serial
..(loc)
+//Selectable subtype
+/obj/item/weapon/contraband/poster/custom
+ name = "rolled-up poly-poster"
+ desc = "The poster comes with its own automatic adhesive mechanism, for easy pinning to any vertical surface. This one is made from some kind of e-paper, and could display almost anything!"
+ poster_type = /obj/structure/sign/poster/custom
+
+/obj/item/weapon/contraband/poster/custom/New(turf/loc, var/given_serial = 0)
+ if(given_serial == 0)
+ serial_number = 1 //Decidedly unrandom
+ else
+ serial_number = given_serial
+ ..(loc)
+
+/obj/item/weapon/contraband/poster/custom/verb/select_poster()
+ set name = "Set Poster type"
+ set category = "Object"
+ set desc = "Click to choose a poster to display."
+
+ var/mob/M = usr
+ var/list/options = list()
+ for(var/datum/poster/posteroption in poster_designs)
+ options[posteroption.listing_name] = posteroption
+
+ var/choice = input(M,"Choose a poster!","Customize Poster") in options
+ if(src && choice && !M.stat && in_range(M,src))
+ var serial = poster_designs.Find(options[choice])
+ serial_number = serial
+ name = "rolled-up poly-poster - No.[serial]"
+ to_chat(M, "The poster is now: [choice].")
+ return 1
+
+
+
//############################## THE ACTUAL DECALS ###########################
/obj/structure/sign/poster
@@ -187,6 +220,7 @@
// Description suffix
var/desc=""
var/icon_state=""
+ var/listing_name=""
// NT poster subtype.
/obj/structure/sign/poster/nanotrasen
@@ -201,3 +235,8 @@
set_poster(design)
..(newloc, placement_dir, serial, itemtype)
+
+//Non-Random Posters
+
+/obj/structure/sign/poster/custom
+ roll_type = /obj/item/weapon/contraband/poster/custom
\ No newline at end of file
diff --git a/code/game/objects/effects/decals/posters/bs12.dm b/code/game/objects/effects/decals/posters/bs12.dm
index 7aadcb2ead0..5c1c32d98b0 100644
--- a/code/game/objects/effects/decals/posters/bs12.dm
+++ b/code/game/objects/effects/decals/posters/bs12.dm
@@ -1,290 +1,348 @@
// baystation12 posters
/datum/poster/bay_1
icon_state="bsposter1"
- name = "Unlucky Space Explorer"
- desc = "This particular one depicts a skeletal form within a space suit."
+ name = "PSA: Unlucky Space Explorer"
+ desc = "This grim PSA depicts a skeletal form within a space suit. Thousands die every year as a result of failing to follow EVA safety guidelines."
+ listing_name = "PSA - EVA Accidents"
/datum/poster/bay_2
icon_state="bsposter2"
- name = "Positronic Logic Conflicts"
- desc = "This particular one depicts the cold, unmoving stare of a particular advanced AI."
+ name = "PSA: Disobedient Drones"
+ desc = "This PSA depicts the cold, unmoving stare of a particularly advanced AI. Contact information for the Emergent Intelligence Oversight is included."
+ listing_name = "PSA - Emergent Drones"
/datum/poster/bay_3
icon_state="bsposter3"
- name = "Paranoia"
- desc = "This particular one warns of the dangers of trusting your co-workers too much."
+ name = "PSA: Corporate Espionage"
+ desc = "This PSA warns of the dangers of trusting your co-workers with sensitive department information. They may be spying for a rival corporation, or worse!"
+ listing_name = "PSA - Corporate Espionage"
/datum/poster/bay_4
icon_state="bsposter4"
name = "Keep Calm"
- desc = "This particular one is of a famous New Earth design, although a bit modified. Someone has scribbled an O over the A on the poster."
+ desc = "An incredibly vague message, presented in a classic form. Someone has scribbled an O over the A on the poster."
+ listing_name = "PSA - Keep Calm"
/datum/poster/bay_5
icon_state="bsposter5"
- name = "Martian Warlord"
- desc = "This particular one depicts the cartoony mug of a certain Martial Warmonger."
+ name = "PSA: Saboteurs!"
+ desc = "A company PSA reminding employees to keep an eye out for suspicious activity, and report it immediately."
+ listing_name = "PSA - Saboteur"
/datum/poster/bay_6
icon_state="bsposter6"
- name = "Technological Singularity"
- desc = "This particular one is of the blood-curdling symbol of a long-since defeated enemy of humanity."
+ name = "Eradicator XV"
+ desc = "An ad for the fifteenth installment in the Eradicator movie franchise, about a violent robotic uprising hellbent on wiping out humanity."
+ listing_name = "Ad - Eradicator XV"
/datum/poster/bay_7
icon_state="bsposter7"
- name = "Wasteland"
- desc = "This particular one is of a couple of ragged gunmen, one male and one female, on top of a mound of rubble. The number \"12\" is visible on their blue jumpsuits."
+ name = "Wasteland: Battle for Earth"
+ desc = "This action movie ad shows a couple of ragged post-apocalyptic gunmen, one male and one female, on top of a mound of rubble."
+ listing_name = "Ad - Battle for Earth"
/datum/poster/bay_8
icon_state="bsposter8"
name = "Pinup Girl Cindy"
- desc = "This particular one is of a historical corporate PR girl, Cindy, in a particularly feminine pose."
+ desc = "This is a vintage 2450s pin-up of NanoTrasen's PR girl, Cindy, in a particularly feminine pose."
+ listing_name = "Pin-up - Cindi"
/datum/poster/bay_9
icon_state="bsposter9"
name = "Pinup Girl Amy"
- desc = "This particular one is of Amy, the nymphomaniac urban legend of deep space. How this photograph came to be is not known."
+ desc = "This pin-up is of Amy, one of NanoTrasen's most popular PR models."
+ listing_name = "Pin-up - Amy"
/datum/poster/bay_10
icon_state="bsposter10"
name = "Don't Panic"
- desc = "This particular one depicts some sort of star in a grimace. The \"Don't Panic\" is written in big, friendly letters."
+ desc = "This ad for Vey-Medical anxiety pills depicts some sort of star in a grimace. The \"Don't Panic\" is written in big, friendly letters."
+ listing_name = "Ad - Don't panic."
/datum/poster/bay_11
icon_state="bsposter11"
- name = "Underwater Laboratory"
- desc = "This particular one is of the fabled last crew of a previous Company project."
+ name = "Underwater Living"
+ desc = "This immigration poster encourages you to move to Earth;s premiere underwater city, Atlantis. One bedroom apartments start at half your salary."
+ listing_name = "Ad - Atlantis"
/datum/poster/bay_12
icon_state="bsposter12"
- name = "Rogue AI"
- desc = "This particular one depicts the shell of the infamous AI that catastropically comandeered one of humanity's earliest space stations. Back then, the Company was just known as TriOptimum."
+ name = "Beware Rogue AI"
+ desc = "This ad for the Emergent Intelligence Oversight Recruitment Division depicts a menacing AI and asks if you're a bad enough dude to take it on."
+ listing_name = "Recruitment - EIO"
/datum/poster/bay_13
icon_state="bsposter13"
- name = "User of the Arcane Arts"
- desc = "This particular one depicts a wizard, casting a spell. You can't really make out if it's an actual photograph or a computer-generated image."
+ name = "Become A User of the Arcane Arts"
+ desc = "This ad for popular Virtual Reality online game 'Wiz Online' depicts a wizard, casting a spell. You can't really make out if it's an actual photograph or a computer-generated image. Incredible graphics!"
+ listing_name = "Ad - Wiz Online"
/datum/poster/bay_14
icon_state="bsposter14"
name = "Levitating Skull"
- desc = "This particular one is the portrait of a flying enchanted skull. Its adventures along with its fabled companion are now fading through history..."
+ desc = "This tacky ad is a portrait of the flying enchanted skull, Bones. Its adventures along with its fabled companion are showing now on a broadcast service near you!"
+ listing_name = "Ad - Bones Adventures"
/datum/poster/bay_15
icon_state="bsposter15"
name = "Augmented Legend"
- desc = "This particular one is of an obviously augmented individual, gazing towards the sky. The cyber-city in the backround is rather punkish."
+ desc = "This ad for Ward-Takahashi cybernetic implants shows obviously augmented individual, gazing towards the sky. Is your body augmented?"
+ listing_name = "Ad - Ward-Takahashi Augments"
/datum/poster/bay_16
icon_state="bsposter16"
- name = "Dangerous Static"
- desc = "This particular one depicts nothing remarkable other than a rather mesmerising pattern of monitor static. There's a tag on the sides of the poster, but it's ripped off."
+ name = "Snow Crash"
+ desc = "This particular one depicts nothing remarkable other than a rather mesmerising pattern of monitor static. You think it's an ad for something, but you're not sure what."
+ listing_name = "Ad - Snow Crash"
/datum/poster/bay_17
icon_state="bsposter17"
name = "Pinup Girl Val"
desc = "Luscious Val McNeil, the vertically challenged Legal Extraordinaire, winner of Miss Space two years running and favoured pinup girl of Lawyers Weekly."
+ listing_name = "Pin-up - Val"
/datum/poster/bay_18
icon_state="bsposter18"
name = "Derpman, Enforcer of the State"
- desc = "Here to protect and serve... your donuts! A generously proportioned man, he teaches you the value of hiding your snacks."
+ desc = "An ad for Centauri Provisions donuts. Officer Derpman is here to protect and serve... your donuts! A generously proportioned man, he teaches you the value of hiding your snacks."
+ listing_name = "Ad - Officer Derpman Donuts"
/datum/poster/bay_19
icon_state="bsposter19"
name = "Respect an Unathi"
- desc = "This poster depicts a well dressed looking Unathi receiving a prestigious award. It appears to espouse greater co-operation and harmony between the two races."
+ desc = "This poster depicts a sharply dressed Unathi receiving a prestigious award. It appears to espouse greater co-operation and harmony between humanity and the Unathi."
+ listing_name = "PSA - Unathi"
/datum/poster/bay_20
icon_state="bsposter20"
- name = "Skrell Twilight"
- desc = "This poster depicts a mysteriously inscrutable, alien scene. Numerous Skrell can be seen conversing amidst great, crystalline towers rising above crashing waves"
+ name = "Skrell Tourism"
+ desc = "This tourism poster depicts a mysteriously inscrutable, alien scene. Numerous Skrell can be seen conversing amidst great, crystalline towers rising above crashing waves."
+ listing_name = "Ad - Skrellian Tourism"
/datum/poster/bay_21
icon_state="bsposter21"
name = "Join the Fuzz!"
desc = "It's a nice recruitment poster of a white haired Chinese woman that says; \"Big Guns, Hot Women, Good Times. Security. We get it done.\""
+ listing_name = "Recruitment - NanoTrasen Security - Pinup"
/datum/poster/bay_22
icon_state="bsposter22"
name = "Looking for a career with excitement?"
desc = "A recruitment poster starring a dark haired woman with glasses and a purple shirt that has \"Got Brains? Got Talent? Not afraid of electric flying monsters that want to suck the soul out of you? Then Xenobiology could use someone like you!\" written on the bottom."
+ listing_name = "Recruitment - Xenobiology"
/datum/poster/bay_23
icon_state="bsposter23"
name = "Safety first: because electricity doesn't wait!"
desc = "A safety poster starring a clueless looking redhead with frazzled hair. \"Every year, hundreds of NT employees expose themselves to electric shock. Play it safe. Avoid suspicious doors after electrical storms, and always wear protection when doing electric maintenance.\""
+ listing_name = "Safety - Electric Shock"
/datum/poster/bay_24
icon_state="bsposter24"
name = "Responsible medbay habits, No #259"
desc = "A poster with a nervous looking geneticist on it states; \"Friends Tell Friends They're Clones. It can cause severe and irreparable emotional trauma if a person is not properly informed of their recent demise. Always follow your contractual obligation and inform them of their recent rejuvenation.\""
+ listing_name = "Medical - Clone Disclosure"
/datum/poster/bay_25
icon_state="bsposter25"
name = "Irresponsible medbay habits, No #2"
desc = "This is a safety poster starring a perverted looking naked doctor. \"Sexual harassment is never okay. REPORT any acts of sexual deviance or harassment that disrupt a healthy working environment.\""
+ listing_name = "Medical - Sexual Harassment"
/datum/poster/bay_26
icon_state="bsposter26"
name = "The Men We Knew"
- desc = "This movie poster depicts a group of soldiers fighting a large mech, the movie seems to be a patriotic war movie."
+ desc = "This movie poster depicts a group of soldiers fighting a large mech, it seems to be some kind of movie set during the Hegemony War."
+ listing_name = "Ad - Men We Knew"
/datum/poster/bay_27
icon_state="bsposter27"
name = "Plastic Sheep Can't Scream"
- desc = "This is a movie poster for an upcoming horror movie, it features an AI in the front of it."
+ desc = "This is a movie poster for an upcoming horror movie, featuring a frightening looking robotic creature."
+ listing_name = "Ad - Plastic Sheep Can't Scream"
/datum/poster/bay_28
icon_state="bsposter28"
name = "The Stars Know Love"
- desc = "This is a movie poster. A bleeding woman is shown drawing a heart in her blood on the window of space ship, it seems to be a romantic Drama."
+ desc = "This is a movie poster. A bleeding woman is shown drawing a heart in her blood on the window of space ship, it seems to be a romantic drama."
+ listing_name = "Ad - The Stars Know Love"
/datum/poster/bay_29
icon_state="bsposter29"
name = "Winter Is Coming"
- desc = "On the poster is a frighteningly large wolf, he warns: \"Only YOU can keep the station from freezing during planetary occultation!\""
+ desc = "On the poster is a frighteningly large wolf, he warns: \"Only YOU can keep yourself from freezing this winter!\". Below is the logo of NanoThreads clothing."
+ listing_name = "Ad - Cold-weather Gear"
/datum/poster/bay_30
icon_state="bsposter30"
name = "Ambrosia Vulgaris"
- desc = "Just looking at this poster makes you feel a little bit dizzy."
+ desc = "It's an ad for getting absolutely shitfaced on psychadelics. Just looking at this poster makes you feel a little bit dizzy. Use responsibly."
+ listing_name = "Ad - Ambrosia Vulgaris"
/datum/poster/bay_31
icon_state="bsposter31"
- name = "Donut Corp"
- desc = "This is an advertisement for Donut Corp, the new innovation in donut technology!"
+ name = "Donut Panic"
+ desc = "This is an advertisement for Donut Panic, the bi-monthly periodical for donut lovers galaxy-wide."
+ listing_name = "Ad - Donuts Panic"
/datum/poster/bay_32
icon_state="bsposter32"
name = "Eat!"
- desc = "A poster depicting a hamburger. The poster orders you to consume the hamburger."
+ desc = "A NanoPastures poster depicting a synthmeat hamburger. The poster COMMANDS you to consume the hamburger."
+ listing_name = "Ad - Hamburger"
/datum/poster/bay_33
icon_state="bsposter33"
- name = "Tools, tools, tools"
- desc = "You can never have enough tools, thats for sure!"
+ name = "Tools, tools, tools!"
+ desc = "Xion Manufacturing reminds you: Never trust an off-brand tool. "
+ listing_name = "Ad - Xion Tools"
/datum/poster/bay_34
icon_state="bsposter34"
name = "Power Up!"
- desc = "High reward, higher risk!"
+ desc = "NanoTrasen are leaders in Phoron-based supermatter power! High reward, higher risk!"
+ listing_name = "Ad - Phoron Power"
/datum/poster/bay_35
icon_state="bsposter35"
- name = "Lamarr"
- desc = "This is a poster depicting the pet and mascot of the science department."
+ name = "Kendrick"
+ desc = "This is a poster depicting the pet and mascot of the science department, and national corporate ambassador for slime-based science solutions.."
+ listing_name = "Ad - Slime Science"
/datum/poster/bay_36
icon_state="bsposter36"
name = "Fancy Borg"
- desc = "A poster depicting a cyborg using the service module. 'Fancy Borg' is written on it."
+ desc = "A poster depicting a cyborg dressed to the nines. An ad for cybernetics enthusiast magazine, Borg Fancy."
+ listing_name = "Ad - Borg Fancy A"
/datum/poster/bay_37
icon_state="bsposter37"
name = "Fancier Borg"
- desc = "A poster depicting a cyborg using the service module. 'Fancy Borg' is written on it. This is even fancier than the first poster."
+ desc = "A poster depicting a cyborg dressed to the nines. An ad for cybernetics enthusiast magazine, Borg Fancy. This is even fancier than the other poster."
+ listing_name = "Ad - Borg Fancy B"
/datum/poster/bay_38
icon_state="bsposter38"
name = "Toaster Love"
- desc = "This is a poster of a toaster containing two slices of bread. The word LOVE is written in big pink letters underneath."
+ desc = "This is a poster of a toaster containing two slices of bread. The word LOVE is written in big pink letters underneath. An ad for a cybernetics 'enthusiast' magazine. "
+ listing_name = "Ad - Toaster Love"
/datum/poster/bay_39
icon_state="bsposter39"
name = "Responsible medbay habits, No #91"
desc = "A safety poster with a chemist holding a vial. \"Always wear safety gear while handling dangerous chemicals, even if it concerns only small amounts.\""
+ listing_name = "Safety - Chemicals"
/datum/poster/bay_40
icon_state="bsposter40"
name = "Agreeable work environment"
desc = "This poster depicts a young woman in a stylish dress. \"Try to aim for a pleasant atmosphere in the workspace. A friendly word can do more than forms in triplicate.\""
+ listing_name = "PSA - Agreeable Work Environment"
/datum/poster/bay_41
icon_state="bsposter41"
name = "Professional work environment"
desc = "A safety poster featuring a green haired woman in a shimmering blue dress. \"As an Internal Affairs Agent, your job is to create a fair and agreeable work environment for the crewmembers, as discreetly and professionally as possible.\""
+ listing_name = "Recruitment - Internal Affairs"
/datum/poster/bay_42
icon_state="bsposter42"
name = "Engineering pinup"
desc = "This is pin-up poster. A half-naked girl with white hair, toned muscles and stunning blue eyes looks back at you from the poster. Her welding helmet, tattoos and grey jumpsuit hanging around her waist gives a bit of a rugged feel."
+ listing_name = "Pin-up - Engineer"
/datum/poster/bay_43
icon_state="bsposter43"
name = "Responsible medbay habits, No #3"
desc = "A safety poster with a purple-haired surgeon. She looks a bit cross. \"Let the surgeons do their work. NEVER replace or remove a surgery tool from where the surgeon put it.\""
+ listing_name = "Safety - Surgical Tools"
/datum/poster/bay_44
icon_state="bsposter44"
name = "Time for a drink?"
- desc = "This poster depicts a friendly-looking Tajaran holding a tray of drinks."
+ desc = "This poster for a brand for \"Tajaran-style\" rum produced by Gilthari Exports depicts a friendly-looking Tajaran holding a tray of drinks."
+ listing_name = "Ad - Rarkajar Rum"
/datum/poster/bay_45
icon_state="bsposter45"
name = "Responsible engineering habits, No #1"
desc = "A safety poster featuring a blue haired engineer. \"When repairing a machine or construction, always aim for long-term solutions.\""
+ listing_name = "Safety - No Shortcut Fixes"
/datum/poster/bay_46
icon_state="bsposter46"
name = "Inspirational lawyer"
- desc = "An inspirational poster depicting a Skrellian lawyer. He seems to be shouting something, while pointing fiercely to the right."
+ desc = "An inspirational poster depicting a Skrellian lawyer. He seems to be shouting something, while pointing fiercely to the right. It's an ad for a NanoTrasen subsidiary law firm."
+ listing_name = "Ad - NanoTrasen Law"
/datum/poster/bay_47
icon_state="bsposter47"
name = "Security pinup"
desc = "This is a pin-up poster. A dark skinned white haired girl poses in the sunlight wearing a tank top with her stomach exposed. The text on the poster states \"M, Succubus of Security.\" and a lipstick mark stains the top right corner, as if kissed by the model herself."
+ listing_name = "Pin-up - Security"
/datum/poster/bay_48
icon_state="bsposter48"
- name = "Borg pinup?"
- desc = "This is a.. pin-up poster? It is a diagram on an old model of cyborg with a note scribbled in marker on the bottom, on the top there is a large XO written in red marker."
+ name = "Remote Drones 4 U"
+ desc = "This is an ad for a fairly basic model of drone produced by Grayson Manufactories Ltd. for use in hazardous environments."
+ listing_name = "Ad - Grayson Drones"
/datum/poster/bay_49
icon_state="bsposter49"
name = "Engineering recruitment"
desc = "This is a poster showing an engineer relaxing by a computer, the text states \"Living the life! Join Engineering today!\""
+ listing_name = "Recruitment - Engineering"
/datum/poster/bay_50
icon_state="bsposter50"
name = "Pinup Girl Cindy Kate"
- desc = "This particular one is of Cindy Kate, a seductive performer well known among less savoury circles."
+ desc = "This particular one is of Cindy Kate, a seductive virtual performer well known among less savoury exonet circles."
+ listing_name = "Pin-up - Cindi-Kate"
/datum/poster/bay_51
icon_state="bsposter51"
- name = "space appreciation poster"
- desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. One of three."
+ name = "space tourism poster"
+ desc = "This is a poster produced by the Visit Space Society. This one is targeted at planet-dwellers, suggesting they generally visit space."
+ listing_name = "Tourism - Space"
/datum/poster/bay_52
icon_state="bsposter52"
name = "fire safety poster"
desc = "This is a poster reminding you of what you should do if you are on fire, or if you are at a dance party."
+ listing_name = "Safety - Stop Drop and Roll"
/datum/poster/bay_53
icon_state="bsposter53"
name = "fire extinguisher poster"
desc = "This is a poster reminding you of what you should use to put out a fire."
+ listing_name = "Safety - Fire Extinguishers"
/datum/poster/bay_54
icon_state="bsposter54"
name = "firefighter poster"
desc = "This is a poster of a particularly stern looking firefighter. The caption reads, \"Only you can prevent space fires.\""
+ listing_name = "Safety - Prevent Fires"
/datum/poster/bay_55
icon_state="bsposter55"
- name = "Earth appreciation poster"
- desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. Two of three."
+ name = "Binma tourism poster"
+ desc = "This is a poster produced by the Visit Space Society. This one suggests you visit the exotic garden world of Binma, and try not to get eaten."
+ listing_name = "Tourism - Binma"
/datum/poster/bay_56
icon_state="bsposter56"
name = "Mars appreciation poster"
- desc = "This is a poster produced by the Generic Space Company, as a part of a series of commemorative posters on the wonders of space. Three of three."
+ desc = "This is a poster produced by the Visit Space Society. This one suggests you visit historic Mars. Come for the domes, stay for the monuments to hubris!"
/datum/poster/bay_57
icon_state="bsposter57"
name = "space carp warning poster"
desc = "This poster tells of the dangers of space carp infestations."
+ listing_name = "Safety - Carp"
/datum/poster/bay_58
icon_state="bsposter58"
name = "space carp information poster"
- desc = "This poster showcases an old spacer saying on the dangers of migrant space carp."
\ No newline at end of file
+ desc = "This poster showcases an old spacer saying on the dangers of migrant space carp."
+ listing_name = "Safety - Carp Information"
+
diff --git a/code/game/objects/effects/decals/posters/polarisposters.dm b/code/game/objects/effects/decals/posters/polarisposters.dm
index d40cdd0db0f..45cfd8622d1 100644
--- a/code/game/objects/effects/decals/posters/polarisposters.dm
+++ b/code/game/objects/effects/decals/posters/polarisposters.dm
@@ -2,41 +2,49 @@
icon_state="polposter1"
name = "Safety!"
desc = "A poster advising you to learn how to put on your internals at a moment's notice."
+ listing_name = "Safety - Internals"
/datum/poster/pol_2
icon_state="polposter2"
name = "Safety!"
desc = "A blue and white colored poster. This one advises you to wear your safety goggles when handling chemicals."
+ listing_name = "Safety - Goggles"
/datum/poster/pol_3
icon_state="polposter3"
name = "Safety!"
desc = "A safety poster instructing you to comply with the authorities, especially in an emergency."
+ listing_name = "Safety - Follow Instruction"
/datum/poster/pol_4
icon_state="polposter4"
name = "Clean Hands Save Lives"
desc = "A safety poster reminding you to wash your hands."
+ listing_name = "Safety - Hand Washing"
/datum/poster/pol_5
icon_state="polposter5"
name = "Help!"
desc = "This poster depicts a man helping another man get up."
+ listing_name = "Safety - Help Others"
/datum/poster/pol_6
icon_state="polposter6"
name = "Walk!"
desc = "This poster depicts a man walking, presumably to encourage you not to run in the halls."
+ listing_name = "Safety - No Running"
/datum/poster/pol_7
icon_state="polposter7"
name = "Place your signs!"
desc = "A safety poster reminding custodial staff to place wet floor signs where needed. This reminder's rarely heeded."
+ listing_name = "Safety - Wet Floor Signs"
/datum/poster/pol_8
icon_state="polposter8"
name = "Safety!"
desc = "An advertisement / safety poster for EVA training and certification. Training is available at your local Central Command."
+ listing_name = "Safety - EVA Training"
/datum/poster/pol_9
icon_state="poster10" //Recycling this icon
@@ -44,52 +52,138 @@
desc = "This poster appears to be reference material for maintenance personnel, instructing to always wear insulated gloves, that wirecutters and \
a multitool are the optimal tools to use, and where to find the maintenance panel on most airlocks. Unfortunately, the poster does not mention any \
wire codes."
+ listing_name = "Safety - Airlock Maintenance"
/datum/poster/pol_10
icon_state="polposter9"
name = "orchid"
desc = "This poster appears strangely familiar, depicting the flower of a tree native to the planet Earth."
+ listing_name = "General - Orchid"
-// A new subset of poster datum for Security posters.
+/datum/poster/pol_11
+ icon_state="polposter10"
+ name = "firefighter pinup"
+ desc = "A buff firefighter with his shirt off. Maybe he's trying to raise awareness about fire safety, but you're a little distracted."
+ listing_name = "Pin-up - Firefighter"
+
+/datum/poster/pol_12
+ icon_state="polposter11"
+ name = "CHUCK"
+ desc = "With the budget Cyber Solutions 'Chuck' model work drone, your days of menial labour are numbered! \"With Cyber Solutions, there's always someone beside you, helping you. You know their face. You know my face.\""
+ listing_name = "Ad - Chuck"
+
+/datum/poster/pol_13
+ icon_state="polposter12"
+ name = "New You"
+ desc = "An ad for Kaleidoscope Cosmetics. \"The common factor in all your failed relationships is you. Fix it with affordable gene therapy!\""
+ listing_name = "Ad - Kaleidoscope"
+
+/datum/poster/pol_14
+ icon_state="polposter13"
+ name = "Take a Taxi"
+ desc = "An ad for the Major Bill's Transportation drone-operated taxi service operating in most major cities throughout Solar space."
+ listing_name = "Ad - Taxi"
+
+/datum/poster/pol_15
+ icon_state="polposter14"
+ name = "Adopt A Teshpet"
+ desc = "An ad for definitively racist virtual pet game, Teshpets."
+ listing_name = "Ad - Teshpets"
+
+/datum/poster/pol_16
+ icon_state="polposter15"
+ name = "Train and Fight"
+ desc = "This poster of sweaty, near-naked wrestlers is the most masculine thing you've ever seen. You can barely tell where one man ends and the other begins. Always seek manliness!"
+ listing_name = "Pinup - Wrestling"
+
+/datum/poster/nt_3
+ icon_state = "ntposter03"
+ name = "Mechatronic Safety"
+ desc = "This poster displays three cutting-edge gygaxes standing in line in front of a man in plain clothes.\
+ The poster's captions explain the importance of knowing how to operate a mechatronic vehicle safely, especially near other personnel.\
+ The image seems important."
+ listing_name = "Safety - Mech Operation"
+
+/datum/poster/nt_4
+ icon_state = "ntposter04"
+ name = "Beware Aetotheans"
+ desc = "This poster displays a distinctly hostile-looking red Promethean in a black coat. The fine-print around the edges warns the reader about the dangers posed by Almachi Prometheans."
+ listing_name = "Safety - Aetothean Danger"
+
+/datum/poster/nt_5
+ icon_state = "ntposter05"
+ name = "Promethean"
+ desc = "This poster displays a friendly-looking green Promethean in a labcoat. The fine-print around the edges talks about the benefits Prometheans give in laboratories."
+ listing_name = "Safety - Prometheans"
+
+/datum/poster/nt_6
+ icon_state = "ntposter06"
+ name = "NanoTrasen"
+ desc = "This poster showcases an NT emblem. There is writing in the ring around the inner points, probably some sort of slogan no one bothers to memorize."
+ listing_name = "Ad - NanoTrasen"
+
+/datum/poster/nt_7
+ icon_state = "ntposter07"
+ name = "SolGov"
+ desc = "This poster showcases an SCG emblem. The outer ring reads,\
+ \"
NIL MORTALIBUS ARDUI EST\".\
+ Solar Confederate Government."
+ listing_name = "Political - SolGov"
+
+/datum/poster/nt_8
+ icon_state = "ntposter08"
+ name = "wildlife hazard"
+ desc = "This SifGov poster warns against attempting to kill a fully grown giant spider or other hostile life-form alone."
+ listing_name = "Safety - Spiders"
+
+// A new subset of poster datum for ONLY 'Internal' NanoTrasen posters, given to Security.
/datum/poster/nanotrasen
icon_state = "polposter1"
name = "Safety!"
desc = "A poster advising you to learn how to put on your internals at a moment's notice."
+ listing_name = "Safety - Internals"
/datum/poster/nanotrasen/pol_2
icon_state="polposter2"
name = "Safety!"
desc = "A blue and white colored poster. This one advises you to wear your safety goggles when handling chemicals."
+ listing_name = "Safety - Goggles"
/datum/poster/nanotrasen/pol_3
icon_state="polposter3"
name = "Safety!"
desc = "A safety poster instructing you to comply with the authorities, especially in an emergency."
+ listing_name = "Safety - Follow Instruction"
/datum/poster/nanotrasen/pol_4
icon_state="polposter4"
name = "Clean Hands Save Lives"
desc = "A safety poster reminding you to wash your hands."
+ listing_name = "Safety - Hand Washing"
/datum/poster/nanotrasen/pol_5
icon_state="polposter5"
name = "Help!"
desc = "This poster depicts a man helping another man get up."
+ listing_name = "Safety - Help Others"
/datum/poster/nanotrasen/pol_6
icon_state="polposter6"
name = "Walk!"
desc = "This poster depicts a man walking, presumably to encourage you not to run in the halls."
+ listing_name = "Safety - No Running"
/datum/poster/nanotrasen/pol_7
icon_state="polposter7"
name = "Place your signs!"
desc = "A safety poster reminding custodial staff to place wet floor signs where needed. This reminder's rarely heeded."
+ listing_name = "Safety - Wet Floor Signs"
/datum/poster/nanotrasen/pol_8
icon_state="polposter8"
name = "Safety!"
desc = "An advertisement / safety poster for EVA training and certification. Training is available at your local Central Command."
+ listing_name = "Safety - EVA Training"
/datum/poster/nanotrasen/pol_9
icon_state="poster10"
@@ -97,81 +191,97 @@
desc = "This poster appears to be reference material for maintenance personnel, instructing to always wear insulated gloves, that wirecutters and \
a multitool are the optimal tools to use, and where to find the maintenance panel on most airlocks. Unfortunately, the poster does not mention any \
wire codes."
+ listing_name = "Safety - Airlock Maintenance"
/datum/poster/nanotrasen/pol_10
icon_state="polposter9"
name = "orchid"
desc = "This poster suggests a feeling of peace. It depicts the flower of a tree native to the planet Earth."
+ listing_name = "General - Orchid"
/datum/poster/nanotrasen/bay_9
icon_state="bsposter9"
name = "Pinup Girl Amy"
desc = "This particular one is of Amy, the nymphomaniac urban legend of deep space. How this photograph came to be is not known."
+ listing_name = "Pin-up - Amy"
/datum/poster/nanotrasen/bay_21
icon_state="bsposter21"
name = "Join the Fuzz!"
desc = "It's a nice recruitment poster of a white haired Chinese woman that says; \"Big Guns, Hot Women, Good Times. Security. We get it done.\""
+ listing_name = "Recruitment - NanoTrasen Security - Pinup"
/datum/poster/nanotrasen/bay_22
icon_state="bsposter22"
name = "Looking for a career with excitement?"
desc = "A recruitment poster starring a dark haired woman with glasses and a purple shirt that has \"Got Brains? Got Talent? Not afraid of electric flying monsters that want to suck the soul out of you? Then Xenobiology could use someone like you!\" written on the bottom."
+ listing_name = "Recruitment - Xenobiology"
/datum/poster/nanotrasen/bay_23
icon_state="bsposter23"
name = "Safety first: because electricity doesn't wait!"
desc = "A safety poster starring a clueless looking redhead with frazzled hair. \"Every year, hundreds of NT employees expose themselves to electric shock. Play it safe. Avoid suspicious doors after electrical storms, and always wear protection when doing electric maintenance.\""
+ listing_name = "Safety - Electric Shock"
/datum/poster/nanotrasen/bay_24
icon_state="bsposter24"
name = "Responsible medbay habits, No #259"
desc = "A poster with a nervous looking geneticist on it states; \"Friends Tell Friends They're Clones. It can cause severe and irreparable emotional trauma if a person is not properly informed of their recent demise. Always follow your contractual obligation and inform them of their recent rejuvenation.\""
+ listing_name = "Medical - Clone Disclosure"
/datum/poster/nanotrasen/bay_25
icon_state="bsposter25"
name = "Irresponsible medbay habits, No #2"
desc = "This is a safety poster starring a perverted looking naked doctor. \"Sexual harassment is never okay. REPORT any acts of sexual deviance or harassment that disrupt a healthy working environment.\""
+ listing_name = "Medical - Sexual Harassment"
/datum/poster/nanotrasen/bay_49
icon_state="bsposter49"
name = "Engineering recruitment"
desc = "This is a poster showing an engineer relaxing by a computer, the text states \"Living the life! Join Engineering today!\""
+ listing_name = "Recruitment - Engineering"
/datum/poster/nanotrasen/bay_52
icon_state="bsposter52"
name = "fire safety poster"
desc = "This is a poster reminding you of what you should do if you are on fire, or if you are at a dance party."
+ listing_name = "Safety - Stop Drop And Roll"
/datum/poster/nanotrasen/bay_53
icon_state="bsposter53"
name = "fire extinguisher poster"
desc = "This is a poster reminding you of what you should use to put out a fire."
+ listing_name = "Safety - Extinguishers"
/datum/poster/nanotrasen/bay_54
icon_state="bsposter54"
name = "firefighter poster"
desc = "This is a poster of a particularly stern looking firefighter. The caption reads, \"Only you can prevent space fires.\""
+ listing_name = "Safety - Prevent Fires"
/datum/poster/nanotrasen/bay_57
icon_state="bsposter57"
name = "space carp warning poster"
desc = "This poster tells of the dangers of space carp infestations."
+ listing_name = "Safety - Carp"
/datum/poster/nanotrasen/bay_58
icon_state="bsposter58"
name = "space carp information poster"
desc = "This poster showcases an old spacer saying on the dangers of migrant space carp."
+ listing_name = "Safety - Carp Information"
/datum/poster/nanotrasen/nt_1
icon_state = "ntposter01"
name = "Security recruitment"
desc = "This poster showcases an NT security guard in an excited pose, with a small blurb about the importance of Security."
+ listing_name = "Recruitment - NanoTrasen Security - Importance"
/datum/poster/nanotrasen/nt_2
icon_state = "ntposter02"
name = "Security recruitment"
desc = "This poster showcases an NT security guard in an excited pose, with a small blurb about Security Employee benefits."
+ listing_name = "Recruitment - NanoTrasen Security - Benefits"
/datum/poster/nanotrasen/nt_3
icon_state = "ntposter03"
@@ -179,6 +289,7 @@
desc = "This poster displays three cutting-edge gygaxes standing in line in front of a man in plain clothes.\
The poster's captions explain the importance of knowing how to operate a mechatronic vehicle safely, especially near other personnel.\
The image seems important."
+ listing_name = "Safety - Mech Operation"
//VOREStation Removal Start TFF 17/12/19 - lore not used in our station's own lore.
/*
@@ -186,6 +297,7 @@
icon_state = "ntposter04"
name = "Beware Aetotheans"
desc = "This poster displays a distinctly hostile-looking red Promethean in a black coat. The fine-print around the edges warns the reader about the dangers posed by Almachi Prometheans."
+ listing_name = "Safety - Aetothean Danger"
*/
//VOREstation Removal End
@@ -193,11 +305,13 @@
icon_state = "ntposter05"
name = "Promethean"
desc = "This poster displays a friendly-looking green Promethean in a labcoat. The fine-print around the edges talks about the benefits Prometheans give in laboratories."
+ listing_name = "Safety - Prometheans"
/datum/poster/nanotrasen/nt_6
icon_state = "ntposter06"
name = "NanoTrasen"
desc = "This poster showcases an NT emblem. There is writing in the ring around the inner points, probably some sort of slogan no one bothers to memorize."
+ listing_name = "Ad - NanoTrasen"
/datum/poster/nanotrasen/nt_7
icon_state = "ntposter07"
@@ -205,13 +319,16 @@
desc = "This poster showcases an SCG emblem. The outer ring reads,\
\"
NIL MORTALIBUS ARDUI EST\".\
Solar Confederate Government."
+ listing_name = "Political - SolGov"
/datum/poster/nanotrasen/nt_8
icon_state = "ntposter08"
name = "wildlife hazard"
desc = "This poster warns against attempting to kill a fully grown giant spider or other hostile life-form alone."
+ listing_name = "Safety - Spiders"
/datum/poster/nanotrasen/nt_9
icon_state = "ntposter09"
name = "Regulations and You"
- desc = "This poster showcases an NT security guard reading from her PDA. The blurb advocates for the reader to keep corporate regulations in mind at all times, as an emergency can occur at any time."
+ desc = "This SifGov poster showcases an NT security guard reading from her PDA. The blurb advocates for the reader to keep corporate regulations in mind at all times, as an emergency can occur at any time."
+ listing_name = "Safety - Corporate Regulations"
diff --git a/code/game/objects/effects/decals/warning_stripes.dm b/code/game/objects/effects/decals/warning_stripes.dm
index db7c4bf74f1..0e3d12897d8 100644
--- a/code/game/objects/effects/decals/warning_stripes.dm
+++ b/code/game/objects/effects/decals/warning_stripes.dm
@@ -1,10 +1,10 @@
/obj/effect/decal/warning_stripes
icon = 'icons/effects/warning_stripes.dmi'
-/obj/effect/decal/warning_stripes/New()
+/obj/effect/decal/warning_stripes/Initialize()
. = ..()
var/turf/T=get_turf(src)
var/image/I=image(icon, icon_state = icon_state, dir = dir)
I.color=color
T.overlays += I
- qdel(src)
+ return INITIALIZE_HINT_QDEL
diff --git a/code/game/objects/effects/effect_system.dm b/code/game/objects/effects/effect_system.dm
index 1e804bbb266..0ec3f40036b 100644
--- a/code/game/objects/effects/effect_system.dm
+++ b/code/game/objects/effects/effect_system.dm
@@ -33,6 +33,9 @@ would spawn and follow the beaker, even if it is carried or thrown.
proc/start()
+ Destroy()
+ holder = null
+ return ..()
/////////////////////////////////////////////
// GENERIC STEAM SPREAD SYSTEM
diff --git a/code/game/objects/effects/landmarks_vr.dm b/code/game/objects/effects/landmarks_vr.dm
index 1111b717248..b9dd81e9673 100644
--- a/code/game/objects/effects/landmarks_vr.dm
+++ b/code/game/objects/effects/landmarks_vr.dm
@@ -1,3 +1,6 @@
+/obj/effect/landmark
+ var/abductor = 0
+
/obj/effect/landmark/late_antag
name = "Antag Latespawn"
var/antag_id
diff --git a/code/game/objects/effects/mines.dm b/code/game/objects/effects/mines.dm
index c522b4300e0..c49a4e06665 100644
--- a/code/game/objects/effects/mines.dm
+++ b/code/game/objects/effects/mines.dm
@@ -7,29 +7,72 @@
icon_state = "uglymine"
var/triggered = 0
var/smoke_strength = 3
- var/mineitemtype = /obj/item/weapon/mine
+ var/obj/item/weapon/mine/mineitemtype = /obj/item/weapon/mine
var/panel_open = 0
var/datum/wires/mines/wires = null
- register_as_dangerous_object = TRUE
+ var/camo_net = FALSE // Will the mine 'cloak' on deployment?
-/obj/effect/mine/New()
+ // The trap item will be triggered in some manner when detonating. Default only checks for grenades.
+ var/obj/item/trap = null
+
+/obj/effect/mine/Initialize()
icon_state = "uglyminearmed"
wires = new(src)
+ . = ..()
+ if(ispath(trap))
+ trap = new trap(src)
+ register_dangerous_to_step()
+ if(camo_net)
+ alpha = 50
/obj/effect/mine/Destroy()
+ unregister_dangerous_to_step()
+ if(trap)
+ QDEL_NULL(trap)
qdel_null(wires)
return ..()
+/obj/effect/mine/Moved(atom/oldloc)
+ . = ..()
+ if(.)
+ var/turf/old_turf = get_turf(oldloc)
+ var/turf/new_turf = get_turf(src)
+ if(old_turf != new_turf)
+ old_turf.unregister_dangerous_object(src)
+ new_turf.register_dangerous_object(src)
+
/obj/effect/mine/proc/explode(var/mob/living/M)
var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread()
triggered = 1
s.set_up(3, 1, src)
s.start()
- explosion(loc, 0, 2, 3, 4) //land mines are dangerous, folks.
- visible_message("\The [src.name] detonates!")
+
+ if(trap)
+ trigger_trap(M)
+ visible_message("\The [src.name] flashes as it is triggered!")
+
+ else
+ explosion(loc, 0, 2, 3, 4) //land mines are dangerous, folks.
+ visible_message("\The [src.name] detonates!")
+
qdel(s)
qdel(src)
+/obj/effect/mine/proc/trigger_trap(var/mob/living/victim)
+ if(istype(trap, /obj/item/weapon/grenade))
+ var/obj/item/weapon/grenade/G = trap
+ trap = null
+ G.forceMove(get_turf(src))
+ if(victim.ckey)
+ msg_admin_attack("[key_name_admin(victim)] stepped on \a [src.name], triggering [trap]")
+ G.activate()
+
+ if(istype(trap, /obj/item/device/transfer_valve))
+ var/obj/item/device/transfer_valve/TV = trap
+ trap = null
+ TV.forceMove(get_turf(src))
+ TV.toggle_valve()
+
/obj/effect/mine/bullet_act()
if(prob(50))
explode()
@@ -63,6 +106,9 @@
"
You very carefully screw the mine's panel [panel_open ? "open" : "closed"].")
playsound(src, W.usesound, 50, 1)
+ // Panel open, stay uncloaked, or uncloak if already cloaked. If you don't cloak on place, ignore it and just be normal alpha.
+ alpha = camo_net ? (panel_open ? 255 : 50) : 255
+
else if((W.is_wirecutter() || istype(W, /obj/item/device/multitool)) && panel_open)
interact(user)
else
@@ -74,6 +120,9 @@
user.set_machine(src)
wires.Interact(user)
+/obj/effect/mine/camo
+ camo_net = TRUE
+
/obj/effect/mine/dnascramble
mineitemtype = /obj/item/weapon/mine/dnascramble
@@ -193,6 +242,9 @@
spawn(0)
qdel(src)
+/obj/effect/mine/emp/camo
+ camo_net = TRUE
+
/obj/effect/mine/incendiary
mineitemtype = /obj/item/weapon/mine/incendiary
@@ -208,6 +260,26 @@
spawn(0)
qdel(src)
+/obj/effect/mine/gadget
+ mineitemtype = /obj/item/weapon/mine/gadget
+
+/obj/effect/mine/gadget/explode(var/mob/living/M)
+ var/datum/effect/effect/system/spark_spread/s = new /datum/effect/effect/system/spark_spread()
+ triggered = 1
+ s.set_up(3, 1, src)
+ s.start()
+
+ if(trap)
+ trigger_trap(M)
+ visible_message("\The [src.name] flashes as it is triggered!")
+
+ else
+ explosion(loc, 0, 0, 2, 2)
+ visible_message("\The [src.name] detonates!")
+
+ qdel(s)
+ qdel(src)
+
/////////////////////////////////////////////
// The held item version of the above mines
/////////////////////////////////////////////
@@ -219,6 +291,10 @@
var/countdown = 10
var/minetype = /obj/effect/mine //This MUST be an /obj/effect/mine type, or it'll runtime.
+ var/obj/item/trap = null
+
+ var/list/allowed_gadgets = null
+
/obj/item/weapon/mine/attack_self(mob/user as mob) // You do not want to move or throw a land mine while priming it... Explosives + Sudden Movement = Bad Times
add_fingerprint(user)
msg_admin_attack("[key_name_admin(user)] primed \a [src]")
@@ -231,11 +307,39 @@
prime(user, TRUE)
return
+/obj/item/weapon/mine/attackby(obj/item/W as obj, mob/living/user as mob)
+ if(W.is_screwdriver() && trap)
+ to_chat(user, "
You begin removing \the [trap].")
+ if(do_after(user, 10 SECONDS))
+ to_chat(user, "
You finish disconnecting the mine's trigger.")
+ trap.forceMove(get_turf(src))
+ trap = null
+ return
+
+ if(LAZYLEN(allowed_gadgets) && !trap)
+ var/allowed = FALSE
+
+ for(var/path in allowed_gadgets)
+ if(istype(W, path))
+ allowed = TRUE
+ break
+
+ if(allowed)
+ user.drop_from_inventory(W)
+ W.forceMove(src)
+ trap = W
+
+ ..()
+
/obj/item/weapon/mine/proc/prime(mob/user as mob, var/explode_now = FALSE)
visible_message("\The [src.name] beeps as the priming sequence completes.")
var/obj/effect/mine/R = new minetype(get_turf(src))
src.transfer_fingerprints_to(R)
R.add_fingerprint(user)
+ if(trap)
+ R.trap = trap
+ trap = null
+ R.trap.forceMove(R)
if(explode_now)
R.explode(user)
spawn(0)
@@ -286,8 +390,14 @@
desc = "A small explosive mine with a fire symbol on the side."
minetype = /obj/effect/mine/incendiary
+/obj/item/weapon/mine/gadget
+ name = "gadget mine"
+ desc = "A small pressure-triggered device. If no component is added, the internal release bolts will detonate in unison when triggered."
+
+ allowed_gadgets = list(/obj/item/weapon/grenade, /obj/item/device/transfer_valve)
+
// This tells AI mobs to not be dumb and step on mines willingly.
/obj/item/weapon/mine/is_safe_to_step(mob/living/L)
if(!L.hovering)
return FALSE
- return ..()
\ No newline at end of file
+ return ..()
diff --git a/code/game/objects/effects/prop/columnblast.dm b/code/game/objects/effects/prop/columnblast.dm
index fc604235c82..ce0e4b2aadb 100644
--- a/code/game/objects/effects/prop/columnblast.dm
+++ b/code/game/objects/effects/prop/columnblast.dm
@@ -17,7 +17,7 @@
..()
/obj/effect/temporary_effect/eruption/Initialize()
- ..()
+ . = ..()
flick("[icon_state]_create",src)
/obj/effect/temporary_effect/eruption/Destroy()
diff --git a/code/game/objects/effects/spawners/bombspawner.dm b/code/game/objects/effects/spawners/bombspawner.dm
index c848a2f1dfe..eb025f9ba40 100644
--- a/code/game/objects/effects/spawners/bombspawner.dm
+++ b/code/game/objects/effects/spawners/bombspawner.dm
@@ -159,7 +159,6 @@
/obj/effect/spawner/newbomb/Initialize(newloc)
..(newloc)
-
var/obj/item/device/transfer_valve/V = new(src.loc)
var/obj/item/weapon/tank/phoron/PT = new(V)
var/obj/item/weapon/tank/oxygen/OT = new(V)
@@ -183,19 +182,14 @@
OT.air_contents.temperature = PHORON_MINIMUM_BURN_TEMPERATURE+1
OT.air_contents.update_values()
-
var/obj/item/device/assembly/S = new assembly_type(V)
-
-
V.attached_device = S
S.holder = V
S.toggle_secure()
V.update_icon()
-
- qdel(src)
-
+ return INITIALIZE_HINT_QDEL
///////////////////////
diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm
index 6da2255e1b8..94121f3b658 100644
--- a/code/game/objects/items.dm
+++ b/code/game/objects/items.dm
@@ -610,9 +610,6 @@ var/list/global/slot_flags_enumeration = list(
. = ..()
if(blood_overlay)
overlays.Remove(blood_overlay)
- if(istype(src, /obj/item/clothing/gloves))
- var/obj/item/clothing/gloves/G = src
- G.transfer_blood = 0
/obj/item/reveal_blood()
if(was_bloodied && !fluorescent)
@@ -789,7 +786,7 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
drop_sound = 'sound/items/drop/device.ogg'
//Worn icon generation for on-mob sprites
-/obj/item/proc/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer,var/icon/clip_mask = null) //VOREStation edit - add 'clip mask' argument.
+/obj/item/proc/make_worn_icon(var/body_type,var/slot_name,var/inhands,var/default_icon,var/default_layer,var/icon/clip_mask = null)
//Get the required information about the base icon
var/icon/icon2use = get_worn_icon_file(body_type = body_type, slot_name = slot_name, default_icon = default_icon, inhands = inhands)
var/state2use = get_worn_icon_state(slot_name = slot_name)
@@ -819,6 +816,9 @@ modules/mob/living/carbon/human/life.dm if you die, you will be zoomed out.
if(istype(clip_mask)) //VOREStation Edit - For taur bodies/tails clipping off parts of uniforms and suits.
standing.filters += filter(type = "alpha", icon = clip_mask)
+ if(istype(clip_mask)) //For taur bodies/tails clipping off parts of uniforms and suits.
+ standing.filters += filter(type = "alpha", icon = clip_mask)
+
//Apply any special features
if(!inhands)
apply_blood(standing) //Some items show blood when bloodied
diff --git a/code/game/objects/items/devices/communicator/UI_tgui.dm b/code/game/objects/items/devices/communicator/UI_tgui.dm
index 8dabf77f42f..4745a024885 100644
--- a/code/game/objects/items/devices/communicator/UI_tgui.dm
+++ b/code/game/objects/items/devices/communicator/UI_tgui.dm
@@ -1,3 +1,103 @@
+// Etc UI-only vars
+/obj/item/device/communicator
+ // Stuff for moving cameras
+ var/turf/last_camera_turf
+ // Stuff needed to render the map
+ var/map_name
+ var/obj/screen/map_view/cam_screen
+ var/list/cam_plane_masters
+ var/obj/screen/background/cam_background
+ var/obj/screen/skybox/local_skybox
+
+// Proc: setup_tgui_camera()
+// Parameters: None
+// Description: This sets up all of the variables above to handle in-UI map windows.
+/obj/item/device/communicator/proc/setup_tgui_camera()
+ map_name = "communicator_[REF(src)]_map"
+
+ // Initialize map objects
+ 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_plane_masters = get_tgui_plane_masters()
+
+ for(var/plane in cam_plane_masters)
+ var/obj/screen/instance = plane
+ instance.assigned_map = map_name
+ instance.del_on_map_removal = FALSE
+ instance.screen_loc = "[map_name]:CENTER"
+
+ local_skybox = new()
+ local_skybox.assigned_map = map_name
+ local_skybox.del_on_map_removal = FALSE
+ local_skybox.screen_loc = "[map_name]:CENTER,CENTER"
+ cam_plane_masters += local_skybox
+
+ cam_background = new
+ cam_background.assigned_map = map_name
+ cam_background.del_on_map_removal = FALSE
+
+// Proc: update_active_camera_screen()
+// Parameters: None
+// Description: This refreshes the camera location
+/obj/item/device/communicator/proc/update_active_camera_screen()
+ if(!video_source?.can_use())
+ show_static()
+ return
+
+ var/newturf = get_turf(video_source)
+ if(!is_on_same_plane_or_station(get_z(newturf), get_z(src)))
+ show_static()
+ return
+
+ var/obj/item/device/communicator/communicator = video_source.loc
+ if(istype(communicator))
+ if(communicator.selfie_mode)
+ var/mob/target = get(communicator, /mob)
+ if(istype(target))
+ cam_screen.vis_contents = list(target)
+ else
+ cam_screen.vis_contents = list(communicator)
+ cam_background.fill_rect(1, 1, 1, 1)
+ cam_background.icon_state = "clear"
+ local_skybox.cut_overlays()
+ 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.
+ if(last_camera_turf == newturf)
+ return
+
+ // We get a new turf in case they've moved in the last half decisecond (it's BYOND, it might happen)
+ last_camera_turf = get_turf(video_source)
+
+ if(!is_on_same_plane_or_station(get_z(last_camera_turf), get_z(src)))
+ show_static()
+ return
+
+ var/list/visible_turfs = list()
+ var/list/visible_things = view(video_range, last_camera_turf)
+ for(var/turf/visible_turf in visible_things)
+ visible_turfs += visible_turf
+
+ cam_screen.vis_contents = visible_turfs
+ cam_background.icon_state = "clear"
+ cam_background.fill_rect(1, 1, (video_range * 2), (video_range * 2))
+
+ local_skybox.cut_overlays()
+ local_skybox.add_overlay(SSskybox.get_skybox(get_z(last_camera_turf)))
+ local_skybox.scale_to_view(video_range * 2)
+ local_skybox.set_position("CENTER", "CENTER", (world.maxx>>1) - last_camera_turf.x, (world.maxy>>1) - last_camera_turf.y)
+
+/obj/item/device/communicator/proc/show_static()
+ cam_screen.vis_contents.Cut()
+ cam_background.icon_state = "scanline2"
+ cam_background.fill_rect(1, 1, (video_range * 2), (video_range * 2))
+ local_skybox.cut_overlays()
+
// Proc: tgui_state()
// Parameters: User
// Description: This tells TGUI to only allow us to be interacted with while in a mob inventory.
@@ -9,7 +109,15 @@
// Description: This proc handles opening the UI. It's basically just a standard stub.
/obj/item/device/communicator/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui, datum/tgui_state/custom_state)
ui = SStgui.try_update_ui(user, src, ui)
+ // Update the camera every SStgui tick in case it moves
+ update_active_camera_screen()
if(!ui)
+ // Register map objects
+ user.client.register_map_obj(cam_screen)
+ for(var/plane in cam_plane_masters)
+ user.client.register_map_obj(plane)
+ user.client.register_map_obj(cam_background)
+ // Setup UI
ui = new(user, src, "Communicator", name)
if(custom_state)
ui.set_state(custom_state)
@@ -188,6 +296,7 @@
data["target_feed"] = data["feeds"][newsfeed_channel]
else
data["target_feed"] = null
+ data["selfie_mode"] = selfie_mode
return data
@@ -200,6 +309,7 @@
if(data_core)
data_core.get_manifest_list()
data["manifest"] = PDA_Manifest
+ data["mapRef"] = map_name
return data
// Proc: tgui-act()
@@ -231,6 +341,9 @@
if("toggle_ringer")
ringer = !ringer
+ if("selfie_mode")
+ selfie_mode = !selfie_mode
+
if("add_hex")
var/hex = params["add_hex"]
add_to_EPv2(hex)
@@ -324,3 +437,4 @@
if("newsfeed")
newsfeed_channel = text2num(params["newsfeed"])
+#undef DEFAULT_MAP_SIZE
\ No newline at end of file
diff --git a/code/game/objects/items/devices/communicator/communicator.dm b/code/game/objects/items/devices/communicator/communicator.dm
index 358ef3b61b6..6adbbf811cd 100644
--- a/code/game/objects/items/devices/communicator/communicator.dm
+++ b/code/game/objects/items/devices/communicator/communicator.dm
@@ -26,9 +26,9 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
show_messages = 1
origin_tech = list(TECH_ENGINEERING = 2, TECH_MAGNET = 2, TECH_BLUESPACE = 2, TECH_DATA = 2)
- matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10)
+ matter = list(DEFAULT_WALL_MATERIAL = 30,"glass" = 10, MAT_COPPER = 10)
- var/video_range = 4
+ var/video_range = 3
var/obj/machinery/camera/communicator/video_source // Their camera
var/obj/machinery/camera/communicator/camera // Our camera
@@ -72,6 +72,9 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
var/update_ticks = 0
var/newsfeed_channel = 0
+ // If you turn this on, it changes the way communicator video works. User configurable option.
+ var/selfie_mode = FALSE
+
// Proc: New()
// Parameters: None
// Description: Adds the new communicator to the global list of all communicators, sorts the list, obtains a reference to the Exonet node, then tries to
@@ -86,6 +89,8 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
camera.name = "[src] #[rand(100,999)]"
camera.c_tag = camera.name
+ setup_tgui_camera()
+
//This is a pretty terrible way of doing this.
addtimer(CALLBACK(src, .proc/register_to_holder), 5 SECONDS)
@@ -124,12 +129,9 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
/obj/item/device/communicator/examine(mob/user)
. = ..()
- if(Adjacent(user) && video_source)
- . += "
It looks like it's on a video call: \[view\]"
-
for(var/mob/living/voice/voice in contents)
. += "
On the screen, you can see a image feed of [voice]."
-
+
if(voice && voice.key)
switch(voice.stat)
if(CONSCIOUS)
@@ -142,17 +144,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
else
. += "
The device doesn't appear to be transmitting any data."
-// Proc: Topic()
-// Parameters: href, href_list - Data from a link
-// Description: Used by the above examine.
-/obj/item/device/communicator/Topic(href, href_list)
- if(..())
- return 1
-
- if(href_list["watchvideo"])
- if(video_source)
- watch_video(usr)
-
// Proc: emp_act()
// Parameters: None
// Description: Drops all calls when EMPed, so the holder can then get murdered by the antagonist.
@@ -234,8 +225,6 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
alert_called = 0
update_icon()
tgui_interact(user)
- if(video_source)
- watch_video(user)
// Proc: MouseDrop()
//Same thing PDAs do
@@ -316,6 +305,11 @@ var/global/list/obj/item/device/communicator/all_communicators = list()
QDEL_NULL(camera)
QDEL_NULL(exonet)
+ last_camera_turf = null
+ qdel(cam_screen)
+ QDEL_LIST(cam_plane_masters)
+ qdel(cam_background)
+
return ..()
// Proc: update_icon()
diff --git a/code/game/objects/items/devices/communicator/phone.dm b/code/game/objects/items/devices/communicator/phone.dm
index 7075dbe9582..bb25dce953f 100644
--- a/code/game/objects/items/devices/communicator/phone.dm
+++ b/code/game/objects/items/devices/communicator/phone.dm
@@ -332,12 +332,15 @@
if(video_source) //Already in a video
to_chat(user, "
You are already connected to a video call!")
+ return
if(user.blinded) //User is blinded
to_chat(user, "
You cannot see well enough to do that!")
+ return
if(!(src in comm.communicating) || !comm.camera) //You called someone with a broken communicator or one that's fake or yourself or something
to_chat(user, "
[bicon(src)]ERROR: Video failed. Either bandwidth is too low, or the other communicator is malfunctioning.")
+ return
to_chat(user, "
[bicon(src)] Attempting to start video over existing call.")
sleep(30)
@@ -345,42 +348,16 @@
video_source = comm.camera
comm.visible_message("
[bicon(src)] New video connection from [comm].")
- watch_video(user)
+ update_active_camera_screen()
+ GLOB.moved_event.register(video_source, src, .proc/update_active_camera_screen)
update_icon()
-// Proc: watch_video()
-// Parameters: user - the mob doing the viewing of video
-// Description: Moves a mob's eye to the far end for the duration of viewing the far end
-/obj/item/device/communicator/proc/watch_video(mob/user)
- if(!Adjacent(user) || !video_source) return
- user.set_machine(video_source)
- user.reset_view(video_source)
- to_chat(user, "
Now viewing video session. To leave camera view, close the communicator window OR: OOC -> Cancel Camera View")
- to_chat(user, "
To return to an active video session, use the communicator in your hand.")
- spawn(0)
- while(user.machine == video_source && Adjacent(user))
- var/turf/T = get_turf(video_source)
- if(!T || !is_on_same_plane_or_station(T.z, user.z) || !video_source.can_use())
- to_chat(user, "
The screen bursts into static, then goes black.")
- video_cleanup(user)
- return
- sleep(10)
-
- video_cleanup(user)
-
-// Proc: video_cleanup()
-// Parameters: user - the mob who doesn't want to see video anymore
-// Description: Cleans up mob's client when they stop watching a video
-/obj/item/device/communicator/proc/video_cleanup(mob/user)
- if(!user) return
-
- user.reset_view(null)
- user.unset_machine()
-
// Proc: end_video()
// Parameters: reason - the text reason to print for why it ended
// Description: Ends the video call by clearing video_source
/obj/item/device/communicator/proc/end_video(var/reason)
+ GLOB.moved_event.unregister(video_source, src, .proc/update_active_camera_screen)
+ show_static()
video_source = null
. = "
[bicon(src)] [reason ? reason : "Video session ended"]."
diff --git a/code/game/objects/items/devices/defib.dm b/code/game/objects/items/devices/defib.dm
index 8e5fa683c90..f938f0eab18 100644
--- a/code/game/objects/items/devices/defib.dm
+++ b/code/game/objects/items/devices/defib.dm
@@ -509,8 +509,8 @@
return // Still no brain.
// If the brain'd `defib_timer` var gets below this number, brain damage will happen at a linear rate.
- // This is measures in `Life()` ticks. E.g. 10 minute defib timer = 6000 world.time units = 3000 `Life()` ticks.
- var/brain_damage_timer = ((config.defib_timer MINUTES) / 2) - ((config.defib_braindamage_timer MINUTES) / 2)
+ // This is measures in `Life()` ticks. E.g. 10 minute defib timer = 300 `Life()` ticks. // Original math was VERY off. Life() tick occurs every ~2 seconds, not every 2 world.time ticks.
+ var/brain_damage_timer = ((config.defib_timer MINUTES) / 20) - ((config.defib_braindamage_timer MINUTES) / 20)
if(brain.defib_timer > brain_damage_timer)
return // They got revived before brain damage got a chance to set in.
diff --git a/code/game/objects/items/devices/flash.dm b/code/game/objects/items/devices/flash.dm
index 2247674f60c..facc87ae64a 100644
--- a/code/game/objects/items/devices/flash.dm
+++ b/code/game/objects/items/devices/flash.dm
@@ -33,7 +33,7 @@
var/cell_type = /obj/item/weapon/cell/device
/obj/item/device/flash/Initialize()
- ..()
+ . = ..()
power_supply = new cell_type(src)
/obj/item/device/flash/attackby(var/obj/item/W, var/mob/user)
diff --git a/code/game/objects/items/devices/gps.dm b/code/game/objects/items/devices/gps.dm
index e14a4c0edf6..610ebbc26cd 100644
--- a/code/game/objects/items/devices/gps.dm
+++ b/code/game/objects/items/devices/gps.dm
@@ -9,24 +9,119 @@ var/list/GPS_list = list()
slot_flags = SLOT_BELT
origin_tech = list(TECH_MATERIAL = 2, TECH_BLUESPACE = 2, TECH_MAGNET = 1)
matter = list(DEFAULT_WALL_MATERIAL = 500)
+
var/gps_tag = "GEN0"
var/emped = FALSE
- var/updating = TRUE // Lets users lock the UI so they don't have to deal with constantly shifting signals
var/tracking = FALSE // Will not show other signals or emit its own signal if false.
var/long_range = FALSE // If true, can see farther, depending on get_map_levels().
var/local_mode = FALSE // If true, only GPS signals of the same Z level are shown.
var/hide_signal = FALSE // If true, signal is not visible to other GPS devices.
var/can_hide_signal = FALSE // If it can toggle the above var.
+ var/mob/holder
+ var/is_in_processing_list = FALSE
+ var/list/tracking_devices
+ var/list/showing_tracked_names
+ var/obj/compass_holder/compass
+
/obj/item/device/gps/Initialize()
. = ..()
+ compass = new(src)
GPS_list += src
name = "global positioning system ([gps_tag])"
+ update_holder()
update_icon()
+/obj/item/device/gps/proc/check_visible_to_holder()
+ . = (holder && (holder.get_active_hand() == src || holder.get_inactive_hand() == src))
+
+/obj/item/device/gps/proc/update_holder()
+
+ if(holder && loc != holder)
+ GLOB.moved_event.unregister(holder, src)
+ GLOB.dir_set_event.unregister(holder, src)
+ holder.client?.screen -= compass
+ holder = null
+
+ if(istype(loc, /mob))
+ holder = loc
+ GLOB.moved_event.register(holder, src, .proc/update_compass)
+ GLOB.dir_set_event.register(holder, src, .proc/update_compass)
+
+ if(holder && tracking)
+ if(!is_in_processing_list)
+ START_PROCESSING(SSobj, src)
+ is_in_processing_list = TRUE
+ if(holder.client)
+ if(check_visible_to_holder())
+ holder.client.screen |= compass
+ else
+ holder.client.screen -= compass
+ else
+ STOP_PROCESSING(SSobj, src)
+ is_in_processing_list = FALSE
+ if(holder?.client)
+ holder.client.screen -= compass
+
+/obj/item/device/gps/pickup()
+ . = ..()
+ update_holder()
+
+/obj/item/device/gps/equipped()
+ . = ..()
+ update_holder()
+
+/obj/item/device/gps/dropped()
+ . = ..()
+ update_holder()
+
+/obj/item/device/gps/process()
+ if(!tracking)
+ is_in_processing_list = FALSE
+ return PROCESS_KILL
+ update_holder()
+ if(holder)
+ update_compass(TRUE)
+
/obj/item/device/gps/Destroy()
+ STOP_PROCESSING(SSobj, src)
+ is_in_processing_list = FALSE
GPS_list -= src
- return ..()
+ . = ..()
+ update_holder()
+ QDEL_NULL(compass)
+
+/obj/item/device/gps/proc/can_track(var/obj/item/device/gps/other, var/reachable_z_levels)
+ if(!other.tracking || other.emped || other.hide_signal)
+ return FALSE
+ var/turf/origin = get_turf(src)
+ var/turf/target = get_turf(other)
+ if(!istype(origin) || !istype(target))
+ return FALSE
+ if(origin.z == target.z)
+ return TRUE
+ if(local_mode)
+ return FALSE
+ reachable_z_levels = reachable_z_levels || using_map.get_map_levels(origin.z, long_range)
+ return (target.z in reachable_z_levels)
+
+/obj/item/device/gps/proc/update_compass(var/update_compass_icon)
+ compass.hide_waypoints(FALSE)
+ for(var/thing in tracking_devices)
+ var/obj/item/device/gps/gps = locate(thing)
+ if(!istype(gps) || QDELETED(gps))
+ LAZYREMOVE(tracking_devices, thing)
+ LAZYREMOVE(showing_tracked_names, thing)
+ continue
+ var/turf/gps_turf = get_turf(gps)
+ var/gps_tag = LAZYACCESS(showing_tracked_names, thing) ? gps.gps_tag : null
+ if(istype(gps_turf))
+ compass.set_waypoint("\ref[gps]", gps_tag, gps_turf.x, gps_turf.y, gps_turf.z, LAZYACCESS(tracking_devices, "\ref[gps]"))
+ else
+ compass.set_waypoint("\ref[gps]", gps_tag, 0, 0, 0, LAZYACCESS(tracking_devices, "\ref[gps]"))
+ if(can_track(gps))
+ compass.show_waypoint("\ref[gps]")
+ compass.rebuild_overlay_lists(update_compass_icon)
/obj/item/device/gps/AltClick(mob/user)
toggletracking(user)
@@ -37,14 +132,25 @@ var/list/GPS_list = list()
if(emped)
to_chat(user, "It's busted!")
return
+
+ toggle_tracking()
if(tracking)
to_chat(user, "[src] is no longer tracking, or visible to other GPS devices.")
- tracking = FALSE
- update_icon()
else
to_chat(user, "[src] is now tracking, and visible to other GPS devices.")
- tracking = TRUE
- update_icon()
+
+/obj/item/device/gps/proc/toggle_tracking()
+ tracking = !tracking
+ if(tracking)
+ if(!is_in_processing_list)
+ is_in_processing_list = TRUE
+ START_PROCESSING(SSobj, src)
+ else
+ is_in_processing_list = FALSE
+ STOP_PROCESSING(SSobj, src)
+ update_compass()
+ update_holder()
+ update_icon()
/obj/item/device/gps/emp_act(severity)
if(emped) // Without a fancy callback system, this will have to do.
@@ -67,11 +173,7 @@ var/list/GPS_list = list()
add_overlay("working")
/obj/item/device/gps/attack_self(mob/user)
- tgui_interact(user)
-
-/obj/item/device/gps/examine(mob/user)
- . = ..()
- . += display()
+ display(user)
// Compiles all the data not available directly from the GPS
// Like the positions and directions to all other GPS units
@@ -90,15 +192,8 @@ var/list/GPS_list = list()
dat["z_level_detection"] = using_map.get_map_levels(curr.z, long_range)
for(var/obj/item/device/gps/G in GPS_list - src)
- if(!G.tracking || G.emped || G.hide_signal)
- continue
- var/turf/T = get_turf(G)
- if(!T)
- continue
- if(local_mode && curr.z != T.z)
- continue
- if(!(T.z in dat["z_level_detection"]))
+ if(!can_track(G, dat["z_level_detection"]))
continue
var/gps_data[0]
@@ -108,6 +203,7 @@ var/list/GPS_list = list()
var/area/A = get_area(G)
gps_data["area_name"] = A.get_name()
+ var/turf/T = get_turf(G)
gps_data["z_name"] = using_map.get_zlevel_name(T.z)
gps_data["direction"] = get_adir(curr, T)
gps_data["degrees"] = round(Get_Angle(curr,T))
@@ -122,37 +218,102 @@ var/list/GPS_list = list()
return dat
-/obj/item/device/gps/proc/display()
- if(!tracking)
- . = "The device is off. Alt-click it to turn it on."
- return
+/obj/item/device/gps/proc/display(mob/user)
+
if(emped)
- . = "It's busted!"
+ to_chat(user, "It's busted!")
return
var/list/dat = list()
var/list/gps_data = display_list()
- dat += "Current location: [gps_data["my_area_name"]]
([gps_data["curr_x"]], [gps_data["curr_y"]], [gps_data["curr_z_name"]])"
- dat += "[hide_signal ? "Tagged" : "Broadcasting"] as '[gps_tag]'.
\[Change Tag\] \
-
\[Toggle Scan Range\] \
- [can_hide_signal ? "
\[Toggle Signal Visibility\]":""]"
-
- if(gps_data["gps_list"].len)
- dat += "Detected signals;"
- for(var/gps in gps_data["gps_list"])
- if(istype(gps_data["ref"], /obj/item/device/gps/internal/poi))
- dat += " [gps["gps_tag"]]: [gps["area_name"]] - [gps["local"] ? "[gps["direction"]] Dist: [round(gps["distance"], 10)]m" : "in \the [gps["z_name"]]"]"
- else
- dat += " [gps["gps_tag"]]: [gps["area_name"]], ([gps["x"]], [gps["y"]]) - [gps["local"] ? "[gps["direction"]] Dist: [gps["distX"] ? "[abs(round(gps["distX"], 1))]m [(gps["distX"] > 0) ? "E" : "W"], " : ""][gps["distY"] ? "[abs(round(gps["distY"], 1))]m [(gps["distY"] > 0) ? "N" : "S"]" : ""]" : "in \the [gps["z_name"]]"]"
+ dat += "
"
+ if(!tracking)
+ dat += " | \[Switch On]\]
"
else
- dat += "No other signals detected."
+ dat += " | \[Switch Off]\]
"
+ dat += "| Current location | [gps_data["my_area_name"]] | ([gps_data["curr_x"]], [gps_data["curr_y"]], [gps_data["curr_z_name"]]) |
"
+ dat += "| [hide_signal ? "Tagged" : "Broadcasting"] as '[gps_tag]'. | "
+ dat += "\[Change Tag\]\[Toggle Scan Range\][can_hide_signal ? "\[Toggle Signal Visibility\]":""] |
"
- . = dat
+ if(gps_data["gps_list"].len)
+ dat += "| Detected signals |
"
+ for(var/gps in gps_data["gps_list"])
+ dat += ""
+ var/gps_ref = "\ref[gps["ref"]]"
+ dat += "| [gps["gps_tag"]] | [gps["area_name"]] | "
+
+ if(istype(gps_data["ref"], /obj/item/device/gps/internal/poi))
+ dat += "[gps["local"] ? "[gps["direction"]] Dist: [round(gps["distance"], 10)]m" : "in \the [gps["z_name"]]"] | "
+ else
+ dat += "([gps["x"]], [gps["y"]], [gps["z_name"]]) | "
+
+ if(gps["local"])
+ dat += "[gps["distance"]]m | "
+ dat += "[gps["degrees"]]° ([gps["direction"]]) | "
+ else
+ dat += "Non-local signal. | "
+
+ if(LAZYACCESS(tracking_devices, gps_ref))
+ dat += "\[Stop Tracking\] \[Colour [color_square(hex = LAZYACCESS(tracking_devices, gps_ref))]\] Show/Hide Label | "
+ else
+ dat += "\[Start Tracking\] | "
+ dat += "
"
+ else
+ dat += "| No other signals detected. |
"
+ dat += "
"
+
+ var/datum/browser/popup = new(user, "gps_\ref[src]", "Global Positioning System", 700, 1000)
+ popup.set_content(dat.Join(null))
+ popup.open()
/obj/item/device/gps/Topic(var/href, var/list/href_list)
if(..())
- return 1
+ return TRUE
+
+ if(href_list["toggle_power"])
+ toggle_tracking()
+ . = TRUE
+
+ if(href_list["track_label"])
+ var/gps_ref = href_list["track_label"]
+ var/obj/item/device/gps/gps = locate(gps_ref)
+ if(istype(gps) && !QDELETED(gps) && !LAZYACCESS(showing_tracked_names, gps_ref))
+ LAZYSET(showing_tracked_names, gps_ref, TRUE)
+ else
+ LAZYREMOVE(showing_tracked_names, gps_ref)
+ to_chat(usr, SPAN_NOTICE("\The [src] is [LAZYACCESS(showing_tracked_names, gps_ref) ? "now showing" : "no longer showing"] labels for [gps.gps_tag]."))
+
+ if(href_list["stop_track"])
+ var/gps_ref = href_list["stop_track"]
+ var/obj/item/device/gps/gps = locate(gps_ref)
+ compass.clear_waypoint(gps_ref)
+ LAZYREMOVE(tracking_devices, gps_ref)
+ LAZYREMOVE(showing_tracked_names, gps_ref)
+ if(istype(gps) && !QDELETED(gps))
+ to_chat(usr, SPAN_NOTICE("\The [src] is no longer tracking [gps.gps_tag]."))
+ update_compass()
+ . = TRUE
+
+ if(href_list["start_track"])
+ var/gps_ref = href_list["start_track"]
+ var/obj/item/device/gps/gps = locate(gps_ref)
+ if(istype(gps) && !QDELETED(gps))
+ LAZYSET(tracking_devices, gps_ref, "#00ffff")
+ LAZYSET(showing_tracked_names, gps_ref, TRUE)
+ to_chat(usr, SPAN_NOTICE("\The [src] is now tracking [gps.gps_tag]."))
+ update_compass()
+ . = TRUE
+
+ if(href_list["track_color"])
+ var/obj/item/device/gps/gps = locate(href_list["track_color"])
+ if(istype(gps) && !QDELETED(gps))
+ var/new_colour = input("Enter a new tracking color.", "GPS Waypoint Color") as color|null
+ if(new_colour && istype(gps) && !QDELETED(gps) && holder == usr && !usr.incapacitated())
+ to_chat(usr, SPAN_NOTICE("You adjust the colour \the [src] is using to highlight [gps.gps_tag]."))
+ LAZYSET(tracking_devices, href_list["track_color"], new_colour)
+ update_compass()
+ . = TRUE
if(href_list["tag"])
var/a = input("Please enter desired tag.", name, gps_tag) as text
@@ -161,95 +322,22 @@ var/list/GPS_list = list()
gps_tag = a
name = "global positioning system ([gps_tag])"
to_chat(usr, "You set your GPS's tag to '[gps_tag]'.")
+ . = TRUE
if(href_list["range"])
local_mode = !local_mode
to_chat(usr, "You set the signal receiver to [local_mode ? "'NARROW'" : "'BROAD'"].")
+ . = TRUE
if(href_list["hide"])
if(!can_hide_signal)
return
hide_signal = !hide_signal
to_chat(usr, "You set the device to [hide_signal ? "not " : ""]broadcast a signal while scanning for other signals.")
+ . = TRUE
-/obj/item/device/gps/tgui_interact(mob/user, datum/tgui/ui)
- if(emped)
- to_chat(user, "
[src] fizzles weakly.")
- return
- ui = SStgui.try_update_ui(user, src, ui)
- if(!ui)
- ui = new(user, src, "Gps", name)
- ui.open()
- ui.set_autoupdate(updating)
-
-/obj/item/device/gps/tgui_data(mob/user)
- var/list/data = list()
- data["power"] = tracking
- data["tag"] = gps_tag
- data["updating"] = updating
- data["globalmode"] = !local_mode
- if(!tracking || emped) //Do not bother scanning if the GPS is off or EMPed
- return data
-
- var/turf/curr = get_turf(src)
- data["currentArea"] = "[get_area_name(curr, TRUE)]"
- data["currentCoords"] = list(curr.x, curr.y, curr.z)
- data["currentCoordsText"] = "[curr.x], [curr.y], [using_map.get_zlevel_name(curr.z)]"
-
- data["zLevelDetection"] = using_map.get_map_levels(curr.z, long_range)
-
- var/list/signals = list()
- data["signals"] = list()
-
- for(var/obj/item/device/gps/G in GPS_list - src)
- if(!G.tracking || G.emped || G.hide_signal)
- continue
-
- var/turf/T = get_turf(G)
- if(!T)
- continue
- if(local_mode && curr.z != T.z)
- continue
- if(!(T.z in data["zLevelDetection"]))
- continue
-
- var/list/signal = list()
- signal["entrytag"] = G.gps_tag //Name or 'tag' of the GPS
- signal["coords"] = list(T.x, T.y, T.z)
- signal["coordsText"] = "[T.x], [T.y], [using_map.get_zlevel_name(T.z)]"
- if(T.z == curr.z) //Distance/Direction calculations for same z-level only
- signal["dist"] = max(get_dist(curr, T), 0) //Distance between the src and remote GPS turfs
- signal["degrees"] = round(Get_Angle(curr, T)) //0-360 degree directional bearing, for more precision.
- signals += list(signal) //Add this signal to the list of signals
- data["signals"] = signals
- return data
-
-/obj/item/device/gps/tgui_act(action, params)
- if(..())
- return TRUE
-
- switch(action)
- if("rename")
- var/a = stripped_input(usr, "Please enter desired tag.", name, gps_tag, 20)
-
- if(!a)
- return
-
- gps_tag = a
- name = "global positioning system ([gps_tag])"
- . = TRUE
-
- if("power")
- toggletracking(usr)
- . = TRUE
-
- if("updating")
- updating = !updating
- . = TRUE
-
- if("globalmode")
- local_mode = !local_mode
- . = TRUE
+ if(. && loc == usr)
+ display(usr)
/obj/item/device/gps/on // Defaults to off to avoid polluting the signal list with a bunch of GPSes without owners. If you need to spawn active ones, use these.
tracking = TRUE
@@ -373,26 +461,43 @@ var/list/GPS_list = list()
can_hide_signal = TRUE
/obj/item/device/gps/syndie/display(mob/user)
- if(!tracking)
- . = "The device is off. Alt-click it to turn it on."
- return
+
if(emped)
- . = "It's busted!"
+ to_chat(user, "It's busted!")
return
var/list/dat = list()
var/list/gps_data = display_list()
- dat += "Current location: [gps_data["my_area_name"]]
([gps_data["curr_x"]], [gps_data["curr_y"]], [gps_data["curr_z_name"]])"
- dat += "[hide_signal ? "Tagged" : "Broadcasting"] as '[gps_tag]'.
\[Change Tag\] \
-
\[Toggle Scan Range\] \
- [can_hide_signal ? "
\[Toggle Signal Visibility\]":""]"
-
- if(gps_data["gps_list"].len)
- dat += "Detected signals;"
- for(var/gps in gps_data["gps_list"])
- dat += " [gps["gps_tag"]]: [gps["area_name"]] ([gps["x"]], [gps["y"]], [gps["z_name"]]) [gps["local"] ? "Dist: [gps["distance"]]m Dir: [gps["degrees"]]° ([gps["direction"]])" :""]"
+ dat += "
"
+
+ var/datum/browser/popup = new(user, "gps_\ref[src]", "Global Positioning System", 700, 1000)
+ popup.set_content(dat.Join(null))
+ popup.open()
diff --git a/code/game/objects/items/devices/laserpointer.dm b/code/game/objects/items/devices/laserpointer.dm
index 810147dbc44..7ccad467f66 100644
--- a/code/game/objects/items/devices/laserpointer.dm
+++ b/code/game/objects/items/devices/laserpointer.dm
@@ -6,7 +6,7 @@
item_state = "pen"
var/pointer_icon_state
slot_flags = SLOT_BELT
- matter = list("glass" = 500,"metal" = 500)
+ matter = list("glass" = 500,"metal" = 500, MAT_COPPER = 10)
w_class = 2 //Increased to 2, because diodes are w_class 2. Conservation of matter.
origin_tech = list(TECH_MAGNET = 2, TECH_COMBAT = 1)
var/turf/pointer_loc
diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm
index 837c6616f78..8ac7a071996 100644
--- a/code/game/objects/items/devices/multitool.dm
+++ b/code/game/objects/items/devices/multitool.dm
@@ -17,7 +17,7 @@
drop_sound = 'sound/items/drop/multitool.ogg'
pickup_sound = 'sound/items/pickup/multitool.ogg'
- matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20)
+ matter = list(DEFAULT_WALL_MATERIAL = 50,"glass" = 20, MAT_COPPER = 10)
var/mode_index = 1
var/toolmode = MULTITOOL_MODE_STANDARD
diff --git a/code/game/objects/items/devices/radio/electropack.dm b/code/game/objects/items/devices/radio/electropack.dm
index cc555f80730..55b79eaef3f 100644
--- a/code/game/objects/items/devices/radio/electropack.dm
+++ b/code/game/objects/items/devices/radio/electropack.dm
@@ -11,7 +11,7 @@
slot_flags = SLOT_BACK
w_class = ITEMSIZE_HUGE
- matter = list(DEFAULT_WALL_MATERIAL = 10000,"glass" = 2500)
+ matter = list(DEFAULT_WALL_MATERIAL = 10000,"glass" = 2500, MAT_COPPER = 1550)
var/code = 2
diff --git a/code/game/objects/items/devices/radio/headset_vr.dm b/code/game/objects/items/devices/radio/headset_vr.dm
index 9204c81dd17..2682d9db97c 100644
--- a/code/game/objects/items/devices/radio/headset_vr.dm
+++ b/code/game/objects/items/devices/radio/headset_vr.dm
@@ -84,7 +84,6 @@
desc = "A headset used by pilots, has access to the explorer channel."
icon_state = "pilot_headset"
adhoc_fallback = TRUE
- ks2type = /obj/item/device/encryptionkey/pilot
/obj/item/device/radio/headset/pilot/alt
name = "pilot's bowman headset"
@@ -120,7 +119,7 @@
desc = "A headset used by volunteers to expedition teams, has access to the exploration channel."
icon_state = "pilot_headset"
adhoc_fallback = TRUE
- ks2type = /obj/item/device/encryptionkey/pilot
+ ks2type = /obj/item/device/encryptionkey/explorer
/obj/item/device/radio/headset/talon
name = "talon headset"
diff --git a/code/game/objects/items/devices/radio/radio.dm b/code/game/objects/items/devices/radio/radio.dm
index d2511038dcc..88e957f76ed 100644
--- a/code/game/objects/items/devices/radio/radio.dm
+++ b/code/game/objects/items/devices/radio/radio.dm
@@ -61,7 +61,7 @@ var/global/list/default_medbay_channels = list(
var/bs_tx_preload_id
var/bs_rx_preload_id
- matter = list("glass" = 25,DEFAULT_WALL_MATERIAL = 75)
+ matter = list("glass" = 25, DEFAULT_WALL_MATERIAL = 75, MAT_COPPER = 15)
var/const/FREQ_LISTENING = 1
var/list/internal_channels
@@ -297,7 +297,8 @@ var/global/list/default_medbay_channels = list(
playsound(src, "button", 10)
GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
-/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel, var/list/zlevels) //BS12 EDIT
+
+/obj/item/device/radio/proc/autosay(var/message, var/from, var/channel, var/list/zlevels)
if(!GLOB.autospeaker)
return
var/datum/radio_frequency/connection = null
@@ -308,7 +309,7 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
else
connection = radio_connection
channel = null
- if (!istype(connection))
+ if(!istype(connection))
return
if(!LAZYLEN(zlevels))
@@ -507,7 +508,7 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
else if(adhoc_fallback) //Less huzzah, we have to fallback
to_chat(loc, "
\The [src] pings as it falls back to local radio transmission.")
subspace_transmission = FALSE
-
+
else //Oh well
return FALSE
@@ -594,7 +595,7 @@ GLOBAL_DATUM(autospeaker, /mob/living/silicon/ai/announcer)
/obj/item/device/radio/examine(mob/user)
. = ..()
-
+
if((in_range(src, user) || loc == user))
if(b_stat)
. += "
\The [src] can be attached and modified!"
diff --git a/code/game/objects/items/devices/scanners.dm b/code/game/objects/items/devices/scanners.dm
index c949884c6f0..291202f41f2 100644
--- a/code/game/objects/items/devices/scanners.dm
+++ b/code/game/objects/items/devices/scanners.dm
@@ -21,7 +21,7 @@ HALOGEN COUNTER - Radcount on mobs
w_class = ITEMSIZE_SMALL
throw_speed = 5
throw_range = 10
- matter = list(DEFAULT_WALL_MATERIAL = 200)
+ matter = list(DEFAULT_WALL_MATERIAL = 200, MAT_COPPER = 25)
origin_tech = list(TECH_MAGNET = 1, TECH_BIO = 1)
var/mode = 1;
var/advscan = 0
diff --git a/code/game/objects/items/devices/spy_bug.dm b/code/game/objects/items/devices/spy_bug.dm
index 03d0bdd60ca..60ca5cc1a29 100644
--- a/code/game/objects/items/devices/spy_bug.dm
+++ b/code/game/objects/items/devices/spy_bug.dm
@@ -88,6 +88,14 @@
if(get_dist(user, src) == 0)
. += "It has a tiny camera inside. Needs to be both configured and brought in contact with monitor device to be fully functional."
+/obj/item/device/camerabug/update_icon()
+ ..()
+
+ if(anchored) // Standard versions are relatively obvious if not hidden in a container. Anchoring them is advised, to disguise them.
+ alpha = 50
+ else
+ alpha = 255
+
/obj/item/device/camerabug/attackby(obj/item/W as obj, mob/living/user as mob)
if(istype(W, /obj/item/device/bug_monitor))
var/obj/item/device/bug_monitor/SM = W
@@ -101,6 +109,15 @@
linkedmonitor = null
else
to_chat(user, "Error: The device is linked to another monitor.")
+
+ else if(W.is_wrench() && user.a_intent != I_HURT)
+ if(isturf(loc))
+ anchored = !anchored
+
+ to_chat(user, "
You [anchored ? "" : "un"]secure \the [src].")
+
+ update_icon()
+ return
else
if(W.force >= 5)
visible_message("\The [src] lens shatters!")
diff --git a/code/game/objects/items/devices/uplink.dm b/code/game/objects/items/devices/uplink.dm
index c4069be3ed7..4c07229df78 100644
--- a/code/game/objects/items/devices/uplink.dm
+++ b/code/game/objects/items/devices/uplink.dm
@@ -1,5 +1,3 @@
-GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
-
// I placed this here because of how relevant it is.
// You place this in your uplinkable item to check if an uplink is active or not.
// If it is, it will display the uplink menu and return 1, else it'll return false.
@@ -14,29 +12,19 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
/obj/item/device/uplink
var/welcome = "Welcome, Operative" // Welcoming menu message
- var/uses // Numbers of crystals
var/list/ItemsCategory // List of categories with lists of items
var/list/ItemsReference // List of references with an associated item
var/list/nanoui_items // List of items for NanoUI use
var/faction = "" //Antag faction holder.
- var/list/purchase_log = new
- var/datum/mind/uplink_owner = null
- var/used_TC = 0
var/offer_time = 10 MINUTES //The time increment per discount offered
var/next_offer_time
var/datum/uplink_item/discount_item //The item to be discounted
var/discount_amount //The amount as a percent the item will be discounted by
var/compact_mode = FALSE
-/obj/item/device/uplink/Initialize(var/mapload, var/datum/mind/owner = null, var/telecrystals = DEFAULT_TELECRYSTAL_AMOUNT)
+/obj/item/device/uplink/Initialize(var/mapload)
. = ..()
- uplink_owner = owner
- purchase_log = list()
- if(owner)
- uses = owner.tcrystals
- else
- uses = telecrystals
addtimer(CALLBACK(src, .proc/next_offer), offer_time) //It seems like only the /hidden type actually makes use of this...
/obj/item/device/uplink/get_item_cost(var/item_type, var/item_cost)
@@ -85,7 +73,7 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
/obj/item/device/uplink/hidden/proc/trigger(mob/user as mob)
if(!active)
toggle()
- interact(user)
+ tgui_interact(user)
// Checks to see if the value meets the target. Like a frequency being a traitor_frequency, in order to unlock a headset.
// If true, it accesses trigger() and returns 1. If it fails, it returns false. Use this to see if you need to close the
@@ -93,8 +81,8 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
/obj/item/device/uplink/hidden/proc/check_trigger(mob/user as mob, var/value, var/target)
if(value == target)
trigger(user)
- return 1
- return 0
+ return TRUE
+ return FALSE
// Legacy
/obj/item/device/uplink/hidden/interact(mob/user)
@@ -107,12 +95,11 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
return loc
/obj/item/device/uplink/hidden/tgui_state(mob/user)
- return GLOB.tgui_inventory_state
+ return GLOB.tgui_deep_inventory_state
/obj/item/device/uplink/hidden/tgui_interact(mob/user, datum/tgui/ui, datum/tgui/parent_ui)
if(!active)
toggle()
- uses = user.mind.tcrystals
ui = SStgui.try_update_ui(user, src, ui)
if(!ui)
ui = new(user, src, "Uplink", "Remote Uplink")
@@ -127,7 +114,7 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
var/list/data = ..()
- data["telecrystals"] = uses
+ data["telecrystals"] = user.mind.tcrystals
data["lockable"] = TRUE
data["compactMode"] = compact_mode
@@ -177,22 +164,19 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
data["categories"] = list()
for(var/datum/uplink_category/category in uplink.categories)
- if(category.can_view(src))
- var/list/cat = list(
+ var/list/cat = list(
"name" = category.name,
"items" = (category == selected_cat ? list() : null)
)
- for(var/datum/uplink_item/item in category.items)
- if(!item.can_view(src))
- continue
- var/cost = item.cost(uses, src) || "???"
- cat["items"] += list(list(
- "name" = item.name,
- "cost" = cost,
- "desc" = item.description(),
- "ref" = REF(item),
- ))
- data["categories"] += list(cat)
+ for(var/datum/uplink_item/item in category.items)
+ var/cost = item.cost(src, user) || "???"
+ cat["items"] += list(list(
+ "name" = item.name,
+ "cost" = cost,
+ "desc" = item.description(),
+ "ref" = REF(item),
+ ))
+ data["categories"] += list(cat)
return data
@@ -228,9 +212,9 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
//
// Includes normal radio uplink, multitool uplink,
// implant uplink (not the implant tool) and a preset headset uplink.
-/obj/item/device/radio/uplink/New(atom/loc, datum/mind/target_mind, telecrystals)
- ..(loc)
- hidden_uplink = new(src, target_mind, telecrystals)
+/obj/item/device/radio/uplink/New()
+ ..()
+ hidden_uplink = new(src)
icon_state = "radio"
/obj/item/device/radio/uplink/attack_self(mob/user as mob)
@@ -238,6 +222,7 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
hidden_uplink.trigger(user)
/obj/item/device/multitool/uplink/New()
+ ..()
hidden_uplink = new(src)
/obj/item/device/multitool/uplink/attack_self(mob/user as mob)
@@ -250,4 +235,3 @@ GLOBAL_LIST_BOILERPLATE(world_uplinks, /obj/item/device/uplink)
/obj/item/device/radio/headset/uplink/New()
..()
hidden_uplink = new(src)
- hidden_uplink.uses = DEFAULT_TELECRYSTAL_AMOUNT
diff --git a/code/game/objects/items/devices/uplink_random_lists.dm b/code/game/objects/items/devices/uplink_random_lists.dm
index de05f910136..89bfd5f0040 100644
--- a/code/game/objects/items/devices/uplink_random_lists.dm
+++ b/code/game/objects/items/devices/uplink_random_lists.dm
@@ -34,11 +34,11 @@ var/datum/uplink_random_selection/all_uplink_selection = new/datum/uplink_random
if(!prob(RI.keep_probability))
continue
var/datum/uplink_item/I = uplink.items_assoc[RI.uplink_item]
- if(I.cost(telecrystals, U) > telecrystals)
+ if(I.cost(U) > telecrystals)
continue
if(bought_items && (I in bought_items) && !prob(RI.reselect_probability))
continue
- if(U && !I.can_buy(U))
+ if(U && !I.can_buy(U, telecrystals))
continue
return I
diff --git a/code/game/objects/items/paintkit.dm b/code/game/objects/items/paintkit.dm
index 223c9a20182..45430a41c9a 100644
--- a/code/game/objects/items/paintkit.dm
+++ b/code/game/objects/items/paintkit.dm
@@ -241,7 +241,7 @@
M.initial_icon = new_icon
if(new_icon_file)
M.icon = new_icon_file
- M.reset_icon()
+ M.update_icon()
use(1, user)
/obj/mecha/attackby(var/obj/item/weapon/W, var/mob/user)
diff --git a/code/game/objects/items/pizza_voucher_vr.dm b/code/game/objects/items/pizza_voucher_vr.dm
index 1d48bc9cda7..4c968b55ace 100644
--- a/code/game/objects/items/pizza_voucher_vr.dm
+++ b/code/game/objects/items/pizza_voucher_vr.dm
@@ -8,6 +8,7 @@
w_class = ITEMSIZE_SMALL
/obj/item/pizzavoucher/New()
+ ..()
var/list/descstrings = list("24/7 PIZZA PIE HEAVEN",
"WE ALWAYS DELIVER!",
"24-HOUR PIZZA PIE POWER!",
diff --git a/code/game/objects/items/robot/robot_upgrades_vr.dm b/code/game/objects/items/robot/robot_upgrades_vr.dm
index ad2556f8101..b31f737e78d 100644
--- a/code/game/objects/items/robot/robot_upgrades_vr.dm
+++ b/code/game/objects/items/robot/robot_upgrades_vr.dm
@@ -31,8 +31,8 @@
return 1
/obj/item/borg/upgrade/bellysizeupgrade
- name = "robotic Hound process capacity upgrade Module"
- desc = "Used to upgrade a hound belly capacity. This only affects total volume and such, you won't be able to support more than one patient. Usable once."
+ name = "robohound capacity expansion module"
+ desc = "Used to double a robohound's belly capacity. This only affects total volume, and won't allow support of more than one patient in case of sleeper bellies. Can only be applied once."
icon_state = "cyborg_upgrade2"
item_state = "cyborg_upgrade"
require_module = 1
diff --git a/code/game/objects/items/stacks/fifty_spawner.dm b/code/game/objects/items/stacks/fifty_spawner.dm
index 81dfce96913..e3ba667703a 100644
--- a/code/game/objects/items/stacks/fifty_spawner.dm
+++ b/code/game/objects/items/stacks/fifty_spawner.dm
@@ -7,15 +7,12 @@
var/obj/item/stack/type_to_spawn = null
/obj/fiftyspawner/Initialize()
- ..() //We're not returning . because we're going to ask to be deleted.
-
+ ..()
var/turf/T = get_turf(src)
- var/obj/item/stack/M = new type_to_spawn(T)
+ var/obj/structure/closet/C = locate() in T
+ var/obj/item/stack/M = new type_to_spawn(C || T)
M.amount = M.max_amount //some stuff spawns with 60, we're still calling it fifty
M.update_icon() // Some stacks have different sprites depending on how full they are.
- var/obj/structure/closet/C = locate() in T
- if(C)
- C.contents += M
return INITIALIZE_HINT_QDEL //Bye!
/obj/fiftyspawner/rods
diff --git a/code/game/objects/items/stacks/matter_synth.dm b/code/game/objects/items/stacks/matter_synth.dm
index d92cd5f8dda..02c6518374e 100644
--- a/code/game/objects/items/stacks/matter_synth.dm
+++ b/code/game/objects/items/stacks/matter_synth.dm
@@ -56,3 +56,6 @@
name = "Bandage Synthesizer"
max_energy = 10
recharge_rate = 1
+
+/datum/matter_synth/cloth
+ name = "Cloth Synthesizer"
diff --git a/code/game/objects/items/stacks/rods.dm b/code/game/objects/items/stacks/rods.dm
index 6ffa7100ca8..9844ae1cba9 100644
--- a/code/game/objects/items/stacks/rods.dm
+++ b/code/game/objects/items/stacks/rods.dm
@@ -14,6 +14,8 @@
max_amount = 60
attack_verb = list("hit", "bludgeoned", "whacked")
+ color = "#666666"
+
/obj/item/stack/rods/cyborg
name = "metal rod synthesizer"
desc = "A device that makes metal rods."
@@ -24,8 +26,8 @@
stacktype = /obj/item/stack/rods
no_variants = TRUE
-/obj/item/stack/rods/New()
- ..()
+/obj/item/stack/rods/Initialize()
+ . = ..()
recipes = rods_recipes
update_icon()
diff --git a/code/game/objects/items/stacks/sandbags.dm b/code/game/objects/items/stacks/sandbags.dm
new file mode 100644
index 00000000000..6eff93bfc5f
--- /dev/null
+++ b/code/game/objects/items/stacks/sandbags.dm
@@ -0,0 +1,150 @@
+/obj/item/stack/sandbags
+ name = "sandbag"
+ desc = "Filled sandbags. Fortunately pre-filled."
+ singular_name = "sandbag"
+ icon = 'icons/obj/sandbags.dmi'
+ icon_state = "sandbag"
+ w_class = ITEMSIZE_LARGE
+ force = 10.0
+ throwforce = 20.0
+ throw_speed = 5
+ throw_range = 3
+ drop_sound = 'sound/items/drop/clothing.ogg'
+ pickup_sound = 'sound/items/pickup/clothing.ogg'
+ matter = list(MAT_CLOTH = SHEET_MATERIAL_AMOUNT * 2)
+ max_amount = 30
+ attack_verb = list("hit", "bludgeoned", "pillowed")
+ no_variants = TRUE
+ stacktype = /obj/item/stack/sandbags
+
+ pass_color = TRUE
+
+ var/bag_material = "cloth"
+
+/obj/item/stack/sandbags/cyborg
+ name = "sandbag synthesizer"
+ desc = "A device that makes filled sandbags. Don't ask how."
+ gender = NEUTER
+ matter = null
+ uses_charge = 1
+ charge_costs = list(500)
+ stacktype = /obj/item/stack/sandbags
+
+ bag_material = MAT_SYNCLOTH
+
+/obj/item/stack/sandbags/Initialize(var/ml, var/amt, var/bag_mat)
+ . = ..(ml, amt)
+ recipes = sandbag_recipes
+ update_icon()
+ if(bag_mat)
+ bag_material = bag_mat
+ var/datum/material/M = get_material_by_name("[bag_material]")
+ if(!M)
+ return INITIALIZE_HINT_QDEL
+ color = M.icon_colour
+
+/obj/item/stack/sandbags/update_icon()
+ var/amount = get_amount()
+
+ slowdown = round(amount / 10, 0.1)
+
+var/global/list/datum/stack_recipe/sandbag_recipes = list( \
+ new/datum/stack_recipe("barricade", /obj/structure/barricade/sandbag, 3, time = 5 SECONDS, one_per_turf = 1, on_floor = 1, pass_stack_color = TRUE))
+
+/obj/item/stack/sandbags/produce_recipe(datum/stack_recipe/recipe, var/quantity, mob/user)
+ var/required = quantity*recipe.req_amount
+ var/produced = min(quantity*recipe.res_amount, recipe.max_res_amount)
+
+ if (!can_use(required))
+ if (produced>1)
+ to_chat(user, "
You haven't got enough [src] to build \the [produced] [recipe.title]\s!")
+ else
+ to_chat(user, "
You haven't got enough [src] to build \the [recipe.title]!")
+ return
+
+ if (recipe.one_per_turf && (locate(recipe.result_type) in user.loc))
+ to_chat(user, "
There is another [recipe.title] here!")
+ return
+
+ if (recipe.on_floor && !isfloor(user.loc))
+ to_chat(user, "
\The [recipe.title] must be constructed on the floor!")
+ return
+
+ if (recipe.time)
+ to_chat(user, "
Building [recipe.title] ...")
+ if (!do_after(user, recipe.time))
+ return
+
+ if (use(required))
+ var/atom/O = new recipe.result_type(user.loc, bag_material)
+
+ if(istype(O, /obj))
+ var/obj/Ob = O
+
+ if(LAZYLEN(Ob.matter)) // Law of equivalent exchange.
+ Ob.matter.Cut()
+
+ else
+ Ob.matter = list()
+
+ var/mattermult = istype(Ob, /obj/item) ? min(2000, 400 * Ob.w_class) : 2000
+
+ Ob.matter[recipe.use_material] = mattermult / produced * required
+
+ O.set_dir(user.dir)
+ O.add_fingerprint(user)
+
+ if (istype(O, /obj/item/stack))
+ var/obj/item/stack/S = O
+ S.amount = produced
+ S.add_to_stacks(user)
+
+ if (istype(O, /obj/item/weapon/storage)) //BubbleWrap - so newly formed boxes are empty
+ for (var/obj/item/I in O)
+ qdel(I)
+
+ if ((pass_color || recipe.pass_color))
+ if(!color)
+ if(recipe.use_material)
+ var/datum/material/MAT = get_material_by_name(recipe.use_material)
+ if(MAT.icon_colour)
+ O.color = MAT.icon_colour
+ else
+ return
+ else
+ O.color = color
+
+// Empty bags. Yes, you need to fill them.
+
+/obj/item/stack/emptysandbag
+ name = "sandbag"
+ desc = "Empty sandbags. You know what must be done."
+ singular_name = "sandbag"
+ icon = 'icons/obj/sandbags.dmi'
+ icon_state = "sandbag_e"
+ w_class = ITEMSIZE_LARGE
+
+ strict_color_stacking = TRUE
+ max_amount = 30
+ stacktype = /obj/item/stack/emptysandbag
+
+ pass_color = TRUE
+
+ var/bag_material = "cloth"
+
+/obj/item/stack/emptysandbag/Initialize(var/ml, var/amt, var/bag_mat)
+ . = ..(ml, amt)
+ if(bag_mat)
+ bag_material = bag_mat
+ var/datum/material/M = get_material_by_name("[bag_material]")
+ if(!M)
+ return INITIALIZE_HINT_QDEL
+ color = M.icon_colour
+
+/obj/item/stack/emptysandbag/attack_self(var/mob/user)
+ while(do_after(user, 1 SECOND) && can_use(1) && istype(get_turf(src), /turf/simulated/floor/outdoors))
+ use(1)
+ var/obj/item/stack/sandbags/SB = new (get_turf(src), 1, bag_material)
+ SB.color = color
+ if(user)
+ to_chat(user, "
You fill a sandbag.")
diff --git a/code/game/objects/items/stacks/stack.dm b/code/game/objects/items/stacks/stack.dm
index 5fa718564f4..f4b52f07aaf 100644
--- a/code/game/objects/items/stacks/stack.dm
+++ b/code/game/objects/items/stacks/stack.dm
@@ -29,14 +29,13 @@
var/pass_color = FALSE // Will the item pass its own color var to the created item? Dyed cloth, wood, etc.
var/strict_color_stacking = FALSE // Will the stack merge with other stacks that are different colors? (Dyed cloth, wood, etc)
-/obj/item/stack/New(var/loc, var/amount=null)
- ..()
- if (!stacktype)
+/obj/item/stack/Initialize(var/ml, var/amount)
+ . = ..()
+ if(!stacktype)
stacktype = type
- if (amount)
+ if(amount)
src.amount = amount
update_icon()
- return
/obj/item/stack/Destroy()
if(uses_charge)
@@ -163,15 +162,44 @@
if (recipe.time)
to_chat(user, "
Building [recipe.title] ...")
- if (!do_after(user, recipe.time, exclusive = TRUE))
+ if (!do_after(user, recipe.time))
return
if (use(required))
var/atom/O
if(recipe.use_material)
O = new recipe.result_type(user.loc, recipe.use_material)
+
+ if(istype(O, /obj))
+ var/obj/Ob = O
+
+ if(LAZYLEN(Ob.matter)) // Law of equivalent exchange.
+ Ob.matter.Cut()
+
+ else
+ Ob.matter = list()
+
+ var/mattermult = istype(Ob, /obj/item) ? min(2000, 400 * Ob.w_class) : 2000
+
+ Ob.matter[recipe.use_material] = mattermult / produced * required
+
else
O = new recipe.result_type(user.loc)
+
+ if(recipe.matter_material)
+ if(istype(O, /obj))
+ var/obj/Ob = O
+
+ if(LAZYLEN(Ob.matter)) // Law of equivalent exchange.
+ Ob.matter.Cut()
+
+ else
+ Ob.matter = list()
+
+ var/mattermult = istype(Ob, /obj/item) ? min(2000, 400 * Ob.w_class) : 2000
+
+ Ob.matter[recipe.use_material] = mattermult / produced * required
+
O.set_dir(user.dir)
O.add_fingerprint(user)
@@ -379,8 +407,9 @@
var/on_floor = 0
var/use_material
var/pass_color
+ var/matter_material // Material type used for recycling. Default, uses use_material. For non-material-based objects however, matter_material is needed.
-/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0, supplied_material = null, pass_stack_color)
+/datum/stack_recipe/New(title, result_type, req_amount = 1, res_amount = 1, max_res_amount = 1, time = 0, one_per_turf = 0, on_floor = 0, supplied_material = null, pass_stack_color, recycle_material = null)
src.title = title
src.result_type = result_type
src.req_amount = req_amount
@@ -392,6 +421,12 @@
src.use_material = supplied_material
src.pass_color = pass_stack_color
+ if(!recycle_material && src.use_material)
+ src.matter_material = src.use_material
+
+ else if(recycle_material)
+ src.matter_material = recycle_material
+
/*
* Recipe list datum
*/
diff --git a/code/game/objects/items/stacks/tickets.dm b/code/game/objects/items/stacks/tickets.dm
index 1d9cbf047ee..6681934f7ce 100644
--- a/code/game/objects/items/stacks/tickets.dm
+++ b/code/game/objects/items/stacks/tickets.dm
@@ -7,7 +7,7 @@
w_class = ITEMSIZE_TINY
max_amount = 30
-/obj/item/stack/arcadeticket/New(loc, amount = null)
+/obj/item/stack/arcadeticket/Initialize()
. = ..()
update_icon()
diff --git a/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm b/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm
index 098926f5350..e9d5f6a2a51 100644
--- a/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm
+++ b/code/game/objects/items/stacks/tiles/fifty_spawner_tiles.dm
@@ -8,6 +8,10 @@
name = "stack of sifgrass"
type_to_spawn = /obj/item/stack/tile/grass/sif
+/obj/fiftyspawner/grass/sif/forest
+ name = "stack of sifgrass"
+ type_to_spawn = /obj/item/stack/tile/grass/sif/forest
+
/obj/fiftyspawner/wood
name = "stack of wood"
type_to_spawn = /obj/item/stack/tile/wood
diff --git a/code/game/objects/items/stacks/tiles/tile_types.dm b/code/game/objects/items/stacks/tiles/tile_types.dm
index d2a6522ce20..aefe9a0cd0d 100644
--- a/code/game/objects/items/stacks/tiles/tile_types.dm
+++ b/code/game/objects/items/stacks/tiles/tile_types.dm
@@ -20,8 +20,8 @@
drop_sound = 'sound/items/drop/axe.ogg'
pickup_sound = 'sound/items/pickup/axe.ogg'
-/obj/item/stack/tile/New()
- ..()
+/obj/item/stack/tile/Initialize()
+ . = ..()
randpixel_xy()
/*
@@ -47,6 +47,11 @@
singular_name = "sivian grass floor tile"
desc = "A patch of grass like those that decorate the plains of Sif."
+/obj/item/stack/tile/grass/sif/forest
+ name = "sivian overgrowth tile"
+ singular_name = "sivian overgrowth floor tile"
+ desc = "A patch of dark overgrowth like those that decorate the plains of Sif."
+
/*
* Wood
*/
diff --git a/code/game/objects/items/toys/toys_vr.dm b/code/game/objects/items/toys/toys_vr.dm
index 91c3ed7e06f..73f73d88334 100644
--- a/code/game/objects/items/toys/toys_vr.dm
+++ b/code/game/objects/items/toys/toys_vr.dm
@@ -1,3 +1,9 @@
+/obj/item/toy/mistletoe
+ name = "mistletoe"
+ desc = "You are supposed to kiss someone under these"
+ icon = 'icons/obj/toy_vr.dmi'
+ icon_state = "mistletoe"
+
/obj/item/toy/plushie/lizardplushie
name = "lizard plushie"
desc = "An adorable stuffed toy that resembles a lizardperson."
@@ -50,6 +56,14 @@
/obj/item/toy/plushie/borgplushie/scrubpuppy
icon_state = "scrubpuppy"
+/obj/item/toy/plushie/borgplushie/drakiesec
+ icon = 'icons/obj/drakietoy_vr.dmi'
+ icon_state = "secdrake"
+
+/obj/item/toy/plushie/borgplushie/drakiemed
+ icon = 'icons/obj/drakietoy_vr.dmi'
+ icon_state = "meddrake"
+
/obj/item/toy/plushie/foxbear
name = "toy fox"
desc = "Issa fox!"
@@ -68,3 +82,22 @@
desc = "A perfectly sized snuggable river weasel! Keep away from Clams."
icon = 'icons/obj/toy_vr.dmi'
icon_state = "plushie_otter"
+
+/obj/item/toy/plushie/vox
+ name = "vox plushie"
+ desc = "A stitched-together vox, fresh from the skipjack. Press its belly to hear it skree!"
+ icon = 'icons/obj/toy_vr.dmi'
+ icon_state = "plushie_vox"
+ var/cooldown = 0
+
+/obj/item/toy/plushie/vox/attack_self(mob/user as mob)
+ if(!cooldown)
+ playsound(user, 'sound/voice/shriek1.ogg', 10, 0)
+ src.visible_message("
Skreee!")
+ cooldown = 1
+ addtimer(CALLBACK(src, .proc/cooldownreset), 50)
+ return ..()
+
+/obj/item/toy/plushie/vox/proc/cooldownreset()
+ cooldown = 0
+
diff --git a/code/game/objects/items/weapons/RPD_vr.dm b/code/game/objects/items/weapons/RPD_vr.dm
index b658db082cd..bb436a6a34b 100644
--- a/code/game/objects/items/weapons/RPD_vr.dm
+++ b/code/game/objects/items/weapons/RPD_vr.dm
@@ -24,6 +24,7 @@
throw_range = 5
w_class = ITEMSIZE_NORMAL
matter = list(MAT_STEEL = 50000, MAT_GLASS = 25000)
+ origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 2)
var/datum/effect/effect/system/spark_spread/spark_system
var/p_dir = NORTH // Next pipe will be built with this dir
var/p_flipped = FALSE // If the next pipe should be built flipped
diff --git a/code/game/objects/items/weapons/canes.dm b/code/game/objects/items/weapons/canes.dm
index 5b7f3466848..48bf6454cae 100644
--- a/code/game/objects/items/weapons/canes.dm
+++ b/code/game/objects/items/weapons/canes.dm
@@ -22,11 +22,12 @@
/obj/item/weapon/cane/concealed
var/concealed_blade
-/obj/item/weapon/cane/concealed/New()
- ..()
+/obj/item/weapon/cane/concealed/Initialize()
+ . = ..()
var/obj/item/weapon/material/butterfly/switchblade/temp_blade = new(src)
concealed_blade = temp_blade
- temp_blade.attack_self()
+ temp_blade.active = TRUE
+ temp_blade.update_force()
/obj/item/weapon/cane/concealed/attack_self(var/mob/user)
var/datum/gender/T = gender_datums[user.get_visible_gender()]
diff --git a/code/game/objects/items/weapons/circuitboards/circuitboard.dm b/code/game/objects/items/weapons/circuitboards/circuitboard.dm
index 8b913eaf45d..c8a3a672a7f 100644
--- a/code/game/objects/items/weapons/circuitboards/circuitboard.dm
+++ b/code/game/objects/items/weapons/circuitboards/circuitboard.dm
@@ -23,6 +23,8 @@
drop_sound = 'sound/items/drop/device.ogg'
pickup_sound = 'sound/items/pickup/device.ogg'
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
+
//Called when the circuitboard is used to contruct a new machine.
/obj/item/weapon/circuitboard/proc/construct(var/obj/machinery/M)
if(istype(M, build_path))
diff --git a/code/game/objects/items/weapons/circuitboards/frame.dm b/code/game/objects/items/weapons/circuitboards/frame.dm
index e9c0ee728a5..1b95cc131ed 100644
--- a/code/game/objects/items/weapons/circuitboards/frame.dm
+++ b/code/game/objects/items/weapons/circuitboards/frame.dm
@@ -10,37 +10,37 @@
name = T_BOARD("guestpass console")
build_path = /obj/machinery/computer/guestpass
board_type = new /datum/frame/frame_types/guest_pass_console
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/status_display
name = T_BOARD("status display")
build_path = /obj/machinery/status_display
board_type = new /datum/frame/frame_types/display
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/ai_status_display
name = T_BOARD("ai status display")
build_path = /obj/machinery/ai_status_display
board_type = new /datum/frame/frame_types/display
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/newscaster
name = T_BOARD("newscaster")
build_path = /obj/machinery/newscaster
board_type = new /datum/frame/frame_types/newscaster
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/atm
name = T_BOARD("atm")
build_path = /obj/machinery/atm
board_type = new /datum/frame/frame_types/atm
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/request
name = T_BOARD("request console")
build_path = /obj/machinery/requests_console
board_type = new /datum/frame/frame_types/supply_request_console
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
//Alarm
@@ -48,25 +48,25 @@
name = T_BOARD("fire alarm")
build_path = /obj/machinery/firealarm
board_type = new /datum/frame/frame_types/fire_alarm
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/airalarm
name = T_BOARD("air alarm")
build_path = /obj/machinery/alarm
board_type = new /datum/frame/frame_types/air_alarm
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/intercom
name = T_BOARD("intercom")
build_path = /obj/item/device/radio/intercom
board_type = new /datum/frame/frame_types/intercom
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/keycard_auth
name = T_BOARD("keycard authenticator")
build_path = /obj/machinery/keycard_auth
board_type = new /datum/frame/frame_types/keycard_authenticator
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
//Computer
@@ -74,7 +74,7 @@
name = T_BOARD("holopad")
build_path = /obj/machinery/hologram/holopad
board_type = new /datum/frame/frame_types/holopad
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/scanner_console
name = T_BOARD("body scanner console")
@@ -94,7 +94,7 @@
name = T_BOARD("photocopier")
build_path = /obj/machinery/photocopier
board_type = new /datum/frame/frame_types/photocopier
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/scanning_module = 1,
/obj/item/weapon/stock_parts/motor = 1,
@@ -105,7 +105,7 @@
name = T_BOARD("fax")
build_path = /obj/machinery/photocopier/faxmachine
board_type = new /datum/frame/frame_types/fax
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/scanning_module = 1,
/obj/item/weapon/stock_parts/motor = 1,
@@ -116,6 +116,7 @@
name = T_BOARD("conveyor")
build_path = /obj/machinery/conveyor
board_type = new /datum/frame/frame_types/conveyor
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/gear = 2,
/obj/item/weapon/stock_parts/motor = 2,
@@ -125,6 +126,7 @@
name = T_BOARD("recharger")
build_path = /obj/machinery/recharger
board_type = new /datum/frame/frame_types/recharger
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/capacitor = 1,
/obj/item/stack/cable_coil = 5)
@@ -138,6 +140,7 @@
name = T_BOARD("heavy-duty cell charger")
build_path = /obj/machinery/cell_charger
board_type = new /datum/frame/frame_types/cell_charger
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/capacitor = 1,
/obj/item/stack/cable_coil = 5)
@@ -146,7 +149,7 @@
name = T_BOARD("washing machine")
build_path = /obj/machinery/washing_machine
board_type = new /datum/frame/frame_types/washing_machine
- matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/motor = 1,
/obj/item/weapon/stock_parts/gear = 2)
@@ -155,6 +158,7 @@
name = T_BOARD("reagent grinder")
build_path = /obj/machinery/reagentgrinder
board_type = new /datum/frame/frame_types/grinder
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/motor = 1,
/obj/item/weapon/stock_parts/gear = 1,
@@ -163,6 +167,7 @@
/obj/item/weapon/circuitboard/distiller
build_path = /obj/machinery/portable_atmospherics/powered/reagent_distillery
board_type = new /datum/frame/frame_types/reagent_distillery
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/capacitor = 1,
/obj/item/weapon/stock_parts/micro_laser = 1,
@@ -173,6 +178,7 @@
name = T_BOARD("teleporter hub")
build_path = /obj/machinery/teleport/hub
board_type = "teleporter_hub"
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_GOLD = 100)
// origin_tech = list(TECH_DATA = 2, TECH_BLUESPACE = 4)
req_components = list(
/obj/item/weapon/stock_parts/scanning_module = 4,
@@ -183,6 +189,7 @@
name = T_BOARD("teleporter station")
build_path = /obj/machinery/teleport/station
board_type = "teleporter_station"
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_GOLD = 100)
// origin_tech = list(TECH_DATA = 2, TECH_BLUESPACE = 3)
req_components = list(
/obj/item/weapon/stock_parts/console_screen = 1,
@@ -194,6 +201,7 @@
build_path = /obj/machinery/bodyscanner
board_type = new /datum/frame/frame_types/medical_pod
origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2)
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
req_components = list(
/obj/item/weapon/stock_parts/scanning_module = 3,
/obj/item/stack/material/glass/reinforced = 2)
@@ -202,6 +210,7 @@
name = T_BOARD("sleeper")
build_path = /obj/machinery/sleeper
board_type = new /datum/frame/frame_types/medical_pod
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2)
req_components = list(
/obj/item/weapon/stock_parts/manipulator = 1,
@@ -214,6 +223,7 @@
name = T_BOARD("VR sleeper")
build_path = /obj/machinery/vr_sleeper
board_type = new /datum/frame/frame_types/medical_pod
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_GOLD = 100)
origin_tech = list(TECH_MAGNET = 2, TECH_BIO = 2)
req_components = list(
/obj/item/weapon/stock_parts/scanning_module = 1,
@@ -223,6 +233,7 @@
name = T_BOARD("dna analyzer")
build_path = /obj/machinery/dnaforensics
board_type = new /datum/frame/frame_types/dna_analyzer
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_GOLD = 100)
origin_tech = list(TECH_MAGNET = 4, TECH_BIO = 2, TECH_DATA = 2)
req_components = list(
/obj/item/weapon/stock_parts/scanning_module = 2,
@@ -233,6 +244,7 @@
name = T_BOARD("mass driver")
build_path = /obj/machinery/mass_driver
board_type = new /datum/frame/frame_types/mass_driver
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_GOLD = 100)
req_components = list(
/obj/item/weapon/stock_parts/gear = 2,
/obj/item/weapon/stock_parts/motor = 2,
diff --git a/code/game/objects/items/weapons/circuitboards/mecha.dm b/code/game/objects/items/weapons/circuitboards/mecha.dm
index 777146f385d..132cf65de6b 100644
--- a/code/game/objects/items/weapons/circuitboards/mecha.dm
+++ b/code/game/objects/items/weapons/circuitboards/mecha.dm
@@ -8,6 +8,7 @@
icon = 'icons/obj/module.dmi'
icon_state = "std_mod"
board_type = "other"
+ matter = list(DEFAULT_WALL_MATERIAL = 50, "glass" = 50, MAT_COPPER = 100)
/obj/item/weapon/circuitboard/mecha/ripley
origin_tech = list(TECH_DATA = 3)
diff --git a/code/game/objects/items/weapons/ecigs.dm b/code/game/objects/items/weapons/ecigs.dm
index 18e6062dbaa..5e26bd6e102 100644
--- a/code/game/objects/items/weapons/ecigs.dm
+++ b/code/game/objects/items/weapons/ecigs.dm
@@ -13,6 +13,7 @@
var/brightness_on = 1
chem_volume = 0 //ecig has no storage on its own but has reagent container created by parent obj
item_state = "ecigoff"
+ is_pipe = TRUE //to avoid a runtime in examine()
var/icon_off
var/icon_empty
var/ecig_colors = list(null, COLOR_DARK_GRAY, COLOR_RED_GRAY, COLOR_BLUE_GRAY, COLOR_GREEN_GRAY, COLOR_PURPLE_GRAY)
@@ -21,6 +22,28 @@
..()
ec_cartridge = new cartridge_type(src)
+/obj/item/clothing/mask/smokable/ecig/examine(mob/user)
+ . = ..()
+
+ if(active)
+ . += "
It is turned on."
+ else
+ . += "
It is turned off."
+ if(Adjacent(user))
+ if(ec_cartridge)
+ if(!ec_cartridge.reagents?.total_volume)
+ . += "
Its cartridge is empty!"
+ else if (ec_cartridge.reagents.total_volume <= ec_cartridge.volume * 0.25)
+ . += "
Its cartridge is almost empty!"
+ else if (ec_cartridge.reagents.total_volume <= ec_cartridge.volume * 0.66)
+ . += "
Its cartridge is half full!"
+ else if (ec_cartridge.reagents.total_volume <= ec_cartridge.volume * 0.90)
+ . += "
Its cartridge is almost full!"
+ else
+ . += "
Its cartridge is full!"
+ else
+ . += "
It has no cartridge."
+
/obj/item/clothing/mask/smokable/ecig/simple
name = "simple electronic cigarette"
desc = "A cheap Lucky 1337 electronic cigarette, styled like a traditional cigarette."
@@ -56,6 +79,7 @@
var/mob/living/carbon/human/C = loc
if (src == C.wear_mask && C.check_has_mouth()) // if it's in the human/monkey mouth, transfer reagents to the mob
if (!active || !ec_cartridge || !ec_cartridge.reagents.total_volume)//no cartridge
+ to_chat(C, "
[src] turns off. ")
active=0//autodisable the cigarette
STOP_PROCESSING(SSobj, src)
update_icon()
diff --git a/code/game/objects/items/weapons/gift_wrappaper.dm b/code/game/objects/items/weapons/gift_wrappaper.dm
index f828b97b23f..cd48a4a78a7 100644
--- a/code/game/objects/items/weapons/gift_wrappaper.dm
+++ b/code/game/objects/items/weapons/gift_wrappaper.dm
@@ -77,7 +77,7 @@
/obj/item/weapon/lipstick/random,
/obj/item/weapon/grenade/smokebomb,
/obj/item/weapon/corncob,
- /obj/item/weapon/contraband/poster,
+ /obj/item/weapon/contraband/poster/custom,
/obj/item/weapon/book/manual/barman_recipes,
/obj/item/weapon/book/manual/chef_recipes,
/obj/item/weapon/bikehorn,
diff --git a/code/game/objects/items/weapons/id cards/cards_vr.dm b/code/game/objects/items/weapons/id cards/cards_vr.dm
new file mode 100644
index 00000000000..c7abd117d6e
--- /dev/null
+++ b/code/game/objects/items/weapons/id cards/cards_vr.dm
@@ -0,0 +1,10 @@
+/obj/item/weapon/card/emag/examine(mob/user)
+ . = ..()
+ . += "[uses] uses remaining."
+
+/obj/item/weapon/card/emag/used
+ uses = 1
+
+/obj/item/weapon/card/emag/used/Initialize()
+ . = ..()
+ uses = rand(1, 5)
diff --git a/code/game/objects/items/weapons/id cards/station_ids_vr.dm b/code/game/objects/items/weapons/id cards/station_ids_vr.dm
index b659e756b3a..756ab3bc9cd 100644
--- a/code/game/objects/items/weapons/id cards/station_ids_vr.dm
+++ b/code/game/objects/items/weapons/id cards/station_ids_vr.dm
@@ -1,2 +1,102 @@
/obj/item/weapon/card/id/gold/captain/spare/fakespare
- rank = "null"
\ No newline at end of file
+ rank = "null"
+
+/obj/item/weapon/card/id/itg
+ name = "identification card"
+ desc = "A small card designating affiliation with the Ironcrest Transport Group."
+ icon = 'icons/obj/card_vr.dmi'
+ icon_state = "itg"
+ item_state = "itg_id"
+
+/obj/item/weapon/card/id/itg/green
+ icon_state = "itg_green"
+ item_state = "itg_green_id"
+
+/obj/item/weapon/card/id/itg/red
+ icon_state = "itg_red"
+ item_state = "itg_red_id"
+
+/obj/item/weapon/card/id/itg/purple
+ icon_state = "itg_purple"
+ item_state = "itg_purple_id"
+
+/obj/item/weapon/card/id/itg/white
+ icon_state = "itg_white"
+ item_state = "itg_white_id"
+
+/obj/item/weapon/card/id/itg/orange
+ icon_state = "itg_orange"
+ item_state = "itg_orange_id"
+
+/obj/item/weapon/card/id/itg/blue
+ icon_state = "itg_blue"
+ item_state = "itg_blue_id"
+
+/obj/item/weapon/card/id/itg/event
+ name = "\improper ITG Crew ID"
+ assignment = "Crew"
+ rank = "Crew"
+ access = list(777)
+
+/obj/item/weapon/card/id/itg/event/pilot
+ name = "\improper ITG Pilot's ID"
+ desc = "An ID card belonging to the Pilot of an ITG vessel. The Pilot's responsibility is primarily to fly the ship. They may also be tasked to assist with cargo movement duties."
+ assignment = "Pilot"
+ rank = "Pilot"
+
+/obj/item/weapon/card/id/itg/event/service
+ name = "\improper ITG Cook's ID"
+ desc = "An ID card belonging to the Cook of an ITG vessel. The Cook's responsibility is primarily to provide sustinence to the crew and passengers. The Cook answers to the Passenger Liason. In the absence of a Passenger Liason, the Cook is also responsible for tending to passenger related care and duties."
+ assignment = "Cook"
+ rank = "Cook"
+ icon_state = "itg_green"
+ item_state = "itg_green_id"
+
+/obj/item/weapon/card/id/itg/event/security
+ name = "\improper ITG Security's ID"
+ desc = "An ID card belonging to Security of an ITG vessel. Security's responsibility is primarily to protect the ship, cargo, or facility. They may also be tasked to assist with cargo movement duties and rescue operations. ITG Security is almost exclusively defensive. They should not start fights, but they are very capable of finishing them."
+ assignment = "Security"
+ rank = "Security"
+ icon_state = "itg_red"
+ item_state = "itg_red_id"
+
+/obj/item/weapon/card/id/itg/event/research
+ name = "\improper ITG Research's ID"
+ desc = "An ID card belonging to ITG Research staff. ITG Research staff primarily specializes in starship and starship engine design, and overcoming astronomic phenomena."
+ assignment = "Research"
+ rank = "Research"
+ icon_state = "itg_purple"
+ item_state = "itg_purple_id"
+
+/obj/item/weapon/card/id/itg/event/medical
+ name = "\improper ITG Medic's ID"
+ desc = "An ID card belonging to the Medic of an ITG vessel. The Medic's responsibility is primarily to treat crew and passenger injuries. They may also be tasked with rescue operations."
+ assignment = "Medic"
+ rank = "Medic"
+ icon_state = "itg_white"
+ item_state = "itg_white_id"
+
+/obj/item/weapon/card/id/itg/event/engineer
+ name = "\improper ITG Engineer's ID"
+ desc = "An ID card belonging to the Engineer of an ITG vessel. The Engineer's responsibility is primarily to maintain the ship. They may also be tasked to assist with cargo movement duties."
+ assignment = "Engineer"
+ rank = "Engineer"
+ icon_state = "itg_orange"
+ item_state = "itg_orange_id"
+
+/obj/item/weapon/card/id/itg/event/passengerliason
+ name = "\improper ITG Passenger Liason's ID"
+ desc = "An ID card belonging to the Passenger Liason of an ITG vessel. The Passenger Liason's responsibility is primarily to manage and tend to passenger needs and maintain supplies and facilities for passenger use."
+ assignment = "Passenger Liason"
+ rank = "Passenger Liason"
+ icon_state = "itg_blue"
+ item_state = "itg_blue_id"
+
+/obj/item/weapon/card/id/itg/event/captain
+ name = "\improper ITG Captain's ID"
+ desc = "An ID card belonging to the Captain of an ITG vessel. The Captain's responsibility is primarily to manage crew to ensure smooth ship operations. Captains often also often pilot the vessel when no dedicated pilot is assigned."
+ assignment = "Captain"
+ rank = "Captain"
+ icon_state = "itg_blue"
+ item_state = "itg_blue_id"
+ access = list(777, 778)
\ No newline at end of file
diff --git a/code/game/objects/items/weapons/implants/implant.dm b/code/game/objects/items/weapons/implants/implant.dm
index 81d5bb8f04e..b06e92cc4ab 100644
--- a/code/game/objects/items/weapons/implants/implant.dm
+++ b/code/game/objects/items/weapons/implants/implant.dm
@@ -7,6 +7,8 @@
icon = 'icons/obj/device.dmi'
icon_state = "implant"
w_class = ITEMSIZE_TINY
+ show_messages = TRUE
+
var/implanted = null
var/mob/imp_in = null
var/obj/item/organ/external/part = null
@@ -14,7 +16,7 @@
var/allow_reagents = 0
var/malfunction = 0
var/initialize_loc = BP_TORSO
- show_messages = 1
+ var/known_implant = FALSE
/obj/item/weapon/implant/proc/trigger(emote, source as mob)
return
@@ -65,16 +67,17 @@
malfunction = MALFUNCTION_PERMANENT
/obj/item/weapon/implant/proc/implant_loadout(var/mob/living/carbon/human/H)
- if(H)
- if(handle_implant(H, initialize_loc))
- invisibility = initial(invisibility)
- post_implant(H)
+ . = istype(H) && handle_implant(H, initialize_loc)
+ if(.)
+ invisibility = initial(invisibility)
+ known_implant = TRUE
+ post_implant(H)
/obj/item/weapon/implant/Destroy()
if(part)
part.implants.Remove(src)
+ part = null
listening_objects.Remove(src)
- part = null
imp_in = null
return ..()
@@ -100,6 +103,7 @@ GLOBAL_LIST_BOILERPLATE(all_tracking_implants, /obj/item/weapon/implant/tracking
/obj/item/weapon/implant/tracking
name = "tracking implant"
desc = "An implant normally given to dangerous criminals. Allows security to track your location."
+ known_implant = TRUE
var/id = 1
var/degrade_time = 10 MINUTES //How long before the implant stops working outside of a living body.
@@ -348,6 +352,7 @@ GLOBAL_LIST_BOILERPLATE(all_chem_implants, /obj/item/weapon/implant/chem)
name = "chemical implant"
desc = "Injects things."
allow_reagents = 1
+ known_implant = TRUE
/obj/item/weapon/implant/chem/get_data()
var/dat = {"
@@ -418,6 +423,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
/obj/item/weapon/implant/loyalty
name = "loyalty implant"
desc = "Makes you loyal or such."
+ known_implant = TRUE
/obj/item/weapon/implant/loyalty/get_data()
var/dat = {"
@@ -491,6 +497,7 @@ the implant may become unstable and either pre-maturely inject the subject or si
name = "death alarm implant"
desc = "An alarm which monitors host vital signs and transmits a radio message upon death."
origin_tech = list(TECH_MATERIAL = 1, TECH_BIO = 2, TECH_DATA = 1)
+ known_implant = TRUE
var/mobname = "Will Robinson"
/obj/item/weapon/implant/death_alarm/get_data()
diff --git a/code/game/objects/items/weapons/implants/implantcase.dm b/code/game/objects/items/weapons/implants/implantcase.dm
index c4040890283..9162be15eb5 100644
--- a/code/game/objects/items/weapons/implants/implantcase.dm
+++ b/code/game/objects/items/weapons/implants/implantcase.dm
@@ -299,3 +299,13 @@
src.imp = new /obj/item/weapon/implant/organ/limbaugment/wrist/blade( src )
..()
return
+
+/obj/item/weapon/implantcase/restrainingbolt
+ name = "glass case - 'Restraining Bolt'"
+ desc = "A case containing a restraining bolt."
+ icon_state = "implantcase-b"
+
+/obj/item/weapon/implantcase/restrainingbolt/New()
+ src.imp = new /obj/item/weapon/implant/restrainingbolt( src )
+ ..()
+ return
diff --git a/code/game/objects/items/weapons/implants/implantdud.dm b/code/game/objects/items/weapons/implants/implantdud.dm
index 110051e58d6..cabf5bc9069 100644
--- a/code/game/objects/items/weapons/implants/implantdud.dm
+++ b/code/game/objects/items/weapons/implants/implantdud.dm
@@ -4,18 +4,6 @@
icon = 'icons/obj/device.dmi'
icon_state = "implant"
initialize_loc = BP_HEAD
- var/roundstart = TRUE
/obj/item/weapon/implant/dud/torso
- name = "unknown implant"
- desc = "A small device with small connector wires."
- icon = 'icons/obj/device.dmi'
- icon_state = "implant"
initialize_loc = BP_TORSO
-
-/obj/item/weapon/implant/dud/old
- name = "old implant"
- desc = "A small device with small connector wires."
- icon = 'icons/obj/device.dmi'
- icon_state = "implant"
- roundstart = FALSE
diff --git a/code/game/objects/items/weapons/implants/implanter.dm b/code/game/objects/items/weapons/implants/implanter.dm
index c1b0d5db8dd..adb79364dcd 100644
--- a/code/game/objects/items/weapons/implants/implanter.dm
+++ b/code/game/objects/items/weapons/implants/implanter.dm
@@ -150,3 +150,12 @@
S.remove_from_storage(A)
A.loc.contents.Remove(A)
update()
+
+/obj/item/weapon/implanter/restrainingbolt
+ name = "implanter (bolt)"
+
+/obj/item/weapon/implanter/restrainingbolt/New()
+ src.imp = new /obj/item/weapon/implant/restrainingbolt( src )
+ ..()
+ update()
+ return
diff --git a/code/game/objects/items/weapons/implants/implantlanguage.dm b/code/game/objects/items/weapons/implants/implantlanguage.dm
index 6a0f2baea80..692cdd381f7 100644
--- a/code/game/objects/items/weapons/implants/implantlanguage.dm
+++ b/code/game/objects/items/weapons/implants/implantlanguage.dm
@@ -5,6 +5,7 @@
/obj/item/weapon/implant/language
name = "GalCom language implant"
desc = "An implant allowing someone to speak the range of frequencies used in Galactic Common, as well as produce any phonemes that they usually cannot. Only helps with producing sounds, not understanding them."
+ known_implant = TRUE
var/list/languages = list(LANGUAGE_GALCOM) // List of languages that this assists with
/obj/item/weapon/implant/language/post_implant(mob/M) // Amends the mob's voice organ, then deletes itself
diff --git a/code/game/objects/items/weapons/implants/implantrestrainingbolt.dm b/code/game/objects/items/weapons/implants/implantrestrainingbolt.dm
new file mode 100644
index 00000000000..7f4a562297c
--- /dev/null
+++ b/code/game/objects/items/weapons/implants/implantrestrainingbolt.dm
@@ -0,0 +1,5 @@
+
+/obj/item/weapon/implant/restrainingbolt
+ name = "\improper restraining bolt"
+ icon = 'icons/obj/device.dmi'
+ icon_state = "implant"
diff --git a/code/game/objects/items/weapons/manuals_vr.dm b/code/game/objects/items/weapons/manuals_vr.dm
index 302e19ab2aa..9eaaa56265f 100644
--- a/code/game/objects/items/weapons/manuals_vr.dm
+++ b/code/game/objects/items/weapons/manuals_vr.dm
@@ -42,4 +42,303 @@