diff --git a/code/game/machinery/vending/vendor_types/crew/medical.dm b/code/game/machinery/vending/vendor_types/crew/medical.dm
index 5dfb6b347b..54ea55e8ea 100644
--- a/code/game/machinery/vending/vendor_types/crew/medical.dm
+++ b/code/game/machinery/vending/vendor_types/crew/medical.dm
@@ -40,6 +40,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_doctor, list(
list("UNIFORM (CHOOSE 1)", 0, null, null, null),
list("Green Scrubs", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED),
list("Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/blue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
+ list("Light Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/lightblue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
list("Purple Scrubs", 0, /obj/item/clothing/under/rank/medical/purple, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
list("ARMOR (CHOOSE 1)", 0, null, null, null),
@@ -96,7 +97,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_nurse, list(
list("Green Scrubs", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED),
list("Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/blue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
list("Purple Scrubs", 0, /obj/item/clothing/under/rank/medical/purple, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
- list("Medical Nurse Scrubs", 0, /obj/item/clothing/under/rank/medical/nurse, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY),
+ list("Light Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/lightblue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY),
list("ARMOR (CHOOSE 1)", 0, null, null, null),
list("Labcoat", 0, /obj/item/clothing/suit/storage/labcoat, MARINE_CAN_BUY_ARMOR, VENDOR_ITEM_REGULAR),
@@ -152,6 +153,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_researcher, list(
list("UNIFORM (CHOOSE 1)", 0, null, null, null),
list("Green Scrubs", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED),
list("Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/blue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
+ list("Light Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/lightblue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
list("Purple Scrubs", 0, /obj/item/clothing/under/rank/medical/purple, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
list("Researcher Uniform", 0, /obj/item/clothing/under/marine/officer/researcher, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_MANDATORY),
diff --git a/code/game/machinery/vending/vendor_types/crew/senior_officers.dm b/code/game/machinery/vending/vendor_types/crew/senior_officers.dm
index 86d4a17b48..b5bc42eabb 100644
--- a/code/game/machinery/vending/vendor_types/crew/senior_officers.dm
+++ b/code/game/machinery/vending/vendor_types/crew/senior_officers.dm
@@ -222,6 +222,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_cmo, list(
list("UNIFORM (CHOOSE 1)", 0, null, null, null),
list("Green Scrubs", 0, /obj/item/clothing/under/rank/medical/green, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_RECOMMENDED),
list("Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/blue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
+ list("Light Blue Scrubs", 0, /obj/item/clothing/under/rank/medical/lightblue, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
list("Purple Scrubs", 0, /obj/item/clothing/under/rank/medical/purple, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
list("Doctor Uniform", 0, /obj/item/clothing/under/rank/medical, MARINE_CAN_BUY_UNIFORM, VENDOR_ITEM_REGULAR),
diff --git a/code/game/machinery/vending/vendor_types/crew/synthetic.dm b/code/game/machinery/vending/vendor_types/crew/synthetic.dm
index cec5627a63..1526613988 100644
--- a/code/game/machinery/vending/vendor_types/crew/synthetic.dm
+++ b/code/game/machinery/vending/vendor_types/crew/synthetic.dm
@@ -181,6 +181,7 @@ GLOBAL_LIST_INIT(cm_vending_clothing_synth, list(
GLOBAL_LIST_INIT(cm_vending_clothing_synth_snowflake, list(
list("USCM UNIFORMS", 0, null, null, null),
list("Medical Scrubs, Blue", 12, /obj/item/clothing/under/rank/medical/blue, null, VENDOR_ITEM_REGULAR),
+ list("Medical Scrubs, Light Blue", 0, /obj/item/clothing/under/rank/medical/lightblue, null, VENDOR_ITEM_REGULAR),
list("Medical Scrubs, Green", 12, /obj/item/clothing/under/rank/medical/green, null, VENDOR_ITEM_REGULAR),
list("Medical Scrubs, Purple", 12, /obj/item/clothing/under/rank/medical/purple, null, VENDOR_ITEM_REGULAR),
list("Medical Scrubs, White", 12, /obj/item/clothing/under/rank/medical, null, VENDOR_ITEM_REGULAR),
diff --git a/code/game/objects/items/devices/helmet_visors.dm b/code/game/objects/items/devices/helmet_visors.dm
index 596409c88c..7bdcf2339d 100644
--- a/code/game/objects/items/devices/helmet_visors.dm
+++ b/code/game/objects/items/devices/helmet_visors.dm
@@ -84,18 +84,6 @@
name = "advanced medical optic"
helmet_overlay = "med_sight_left"
-/obj/item/device/helmet_visor/medical/advanced/activate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
- . = ..()
-
- var/datum/action/item_action/view_publications/helmet_visor/publication_action = new(attached_helmet)
- publication_action.give_to(user)
-
-/obj/item/device/helmet_visor/medical/advanced/deactivate_visor(obj/item/clothing/head/helmet/marine/attached_helmet, mob/living/carbon/human/user)
- . = ..()
-
- var/datum/action/item_action/view_publications/helmet_visor/publication_action = locate() in attached_helmet.actions
- qdel(publication_action)
-
/obj/item/device/helmet_visor/medical/advanced/can_toggle(mob/living/carbon/human/user)
. = ..()
if(!.)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm
index 818aea5a4c..15bb136f46 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/cm_closets.dm
@@ -252,6 +252,7 @@ GLOBAL_LIST_EMPTY(co_secure_boxes)
new /obj/item/storage/belt/medical/full(src)
new /obj/item/clothing/under/rank/medical/green(src)
new /obj/item/clothing/under/rank/medical/blue(src)
+ new /obj/item/clothing/under/rank/medical/lightblue(src)
new /obj/item/clothing/under/rank/medical/purple(src)
new /obj/item/clothing/mask/surgical(src)
new /obj/item/clothing/head/surgery/green(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
index 4244fd8288..80a5664567 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/medical.dm
@@ -93,6 +93,7 @@
new /obj/item/clothing/gloves/latex(src)
new /obj/item/clothing/under/rank/medical/green(src)
new /obj/item/clothing/under/rank/medical/blue(src)
+ new /obj/item/clothing/under/rank/medical/lightblue(src)
new /obj/item/clothing/under/rank/medical/purple(src)
new /obj/item/clothing/head/surgery/green(src)
new /obj/item/clothing/head/surgery/blue(src)
diff --git a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
index daecf1906c..938a6a23cc 100644
--- a/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
+++ b/code/game/objects/structures/crates_lockers/closets/wardrobe.dm
@@ -296,6 +296,7 @@
. = ..()
new /obj/item/clothing/under/rank/medical(src)
new /obj/item/clothing/under/rank/medical(src)
+ new /obj/item/clothing/under/rank/medical/lightblue(src)
new /obj/item/clothing/under/rank/medical/blue(src)
new /obj/item/clothing/under/rank/medical/green(src)
new /obj/item/clothing/under/rank/medical/purple(src)
diff --git a/code/global.dm b/code/global.dm
index 9663800971..64a80313d6 100644
--- a/code/global.dm
+++ b/code/global.dm
@@ -120,7 +120,7 @@ var/list/AAlarmWireColorToIndex
#define MAX_EMOTE_LEN 256
#define MAX_PAPER_MESSAGE_LEN 3072
#define MAX_BOOK_MESSAGE_LEN 9216
-#define MAX_NAME_LEN 26
+#define MAX_NAME_LEN 28
/// 3 minutes in the station.
#define shuttle_time_in_station 3 MINUTES
diff --git a/code/modules/client/preferences_gear.dm b/code/modules/client/preferences_gear.dm
index 0df471e4af..c090eb94ff 100644
--- a/code/modules/client/preferences_gear.dm
+++ b/code/modules/client/preferences_gear.dm
@@ -161,6 +161,16 @@ var/global/list/gear_datums_by_name = list()
display_name = "USCM balaclava, tan"
path = /obj/item/clothing/mask/rebreather/scarf/tan
+/datum/gear/mask/uscm/skull_balaclava_blue
+ display_name = "USCM balaclava, blue skull"
+ path = /obj/item/clothing/mask/rebreather/skull
+ cost = 4
+
+/datum/gear/mask/uscm/skull_balaclava_black
+ display_name = "USCM balaclava, black skull"
+ path = /obj/item/clothing/mask/rebreather/skull/black
+ cost = 4
+
/datum/gear/headwear
category = "Headwear"
cost = 3
@@ -876,6 +886,11 @@ var/global/list/gear_datums_by_name = list()
display_name = "Facepaint, black"
path = /obj/item/facepaint/black
+/datum/gear/misc/facepaint_skull
+ display_name = "Facepaint, skull"
+ path = /obj/item/facepaint/skull
+ cost = 3
+
/datum/gear/misc/facepaint_body
display_name = "Fullbody paint"
path = /obj/item/facepaint/sniper
diff --git a/code/modules/clothing/glasses/hud.dm b/code/modules/clothing/glasses/hud.dm
index e4f9bdde48..db4669ae14 100644
--- a/code/modules/clothing/glasses/hud.dm
+++ b/code/modules/clothing/glasses/hud.dm
@@ -13,7 +13,7 @@
flags_armor_protection = 0
toggleable = TRUE
hud_type = MOB_HUD_MEDICAL_ADVANCED
- actions_types = list(/datum/action/item_action/toggle, /datum/action/item_action/view_publications)
+ actions_types = list(/datum/action/item_action/toggle)
req_skill = SKILL_MEDICAL
req_skill_level = SKILL_MEDICAL_MEDIC
diff --git a/code/modules/clothing/head/soft_caps.dm b/code/modules/clothing/head/soft_caps.dm
index 5467e94136..a0e95f7f0f 100644
--- a/code/modules/clothing/head/soft_caps.dm
+++ b/code/modules/clothing/head/soft_caps.dm
@@ -89,6 +89,18 @@
cap_color = "ferret"
black_market_value = 25
+/obj/item/clothing/head/soft/trucker
+ name = "\improper blue trucker hat"
+ desc = "It's a blue trucker hat."
+ icon_state = "truckercap_bluesoft"
+ cap_color = "truckercap_blue"
+
+/obj/item/clothing/head/soft/trucker/red
+ name = "\improper red trucker hat"
+ desc = "It's a red trucker hat."
+ icon_state = "truckercap_redsoft"
+ cap_color = "truckercap_red"
+
/obj/item/clothing/head/soft/sec
name = "security cap"
desc = "It's baseball hat in tasteful red color."
diff --git a/code/modules/clothing/shoes/miscellaneous.dm b/code/modules/clothing/shoes/miscellaneous.dm
index e3b07a76a2..1a49dc7fe1 100644
--- a/code/modules/clothing/shoes/miscellaneous.dm
+++ b/code/modules/clothing/shoes/miscellaneous.dm
@@ -72,7 +72,7 @@
/obj/item/clothing/shoes/sandal
desc = "A pair of rather plain, wooden sandals."
name = "sandals"
- icon_state = "wizard"
+ icon_state = "sandals"
flags_armor_protection = 0
/obj/item/clothing/shoes/sandal/marisa
@@ -140,6 +140,9 @@
desc = "The height of fashion, and they're pre-polished!"
icon_state = "laceups"
+/obj/item/clothing/shoes/laceup/brown
+ icon_state = "laceups_brown"
+
/obj/item/clothing/shoes/swimmingfins
desc = "Help you swim good."
name = "swimming fins"
diff --git a/code/modules/clothing/suits/marine_coat.dm b/code/modules/clothing/suits/marine_coat.dm
index 3aa43706c7..6e6752ba7b 100644
--- a/code/modules/clothing/suits/marine_coat.dm
+++ b/code/modules/clothing/suits/marine_coat.dm
@@ -287,3 +287,85 @@
icon_state = "wc_suit"
item_state = "wc_suit"
contained_sprite = TRUE
+
+//==================Corporate Liaison==================\\
+
+/obj/item/clothing/suit/storage/jacket/marine/vest
+ name = "brown vest"
+ desc = "A casual brown vest."
+ icon_state = "vest_brown"
+ item_state = "vest_brown"
+ has_buttons = FALSE
+ flags_atom = NO_SNOW_TYPE
+
+/obj/item/clothing/suit/storage/jacket/marine/vest/tan
+ name = "tan vest"
+ desc = "A casual tan vest."
+ icon_state = "vest_tan"
+ item_state = "vest_tan"
+ has_buttons = FALSE
+
+/obj/item/clothing/suit/storage/jacket/marine/vest/grey
+ name = "grey vest"
+ desc = "A casual grey vest."
+ icon_state = "vest_grey"
+ item_state = "vest_grey"
+ has_buttons = FALSE
+
+/obj/item/clothing/suit/storage/jacket/marine/corporate
+ name = "khaki suit jacket"
+ desc = "A khaki suit jacket."
+ icon_state = "corporate_ivy"
+ item_state = "corporate_ivy"
+ has_buttons = FALSE
+ flags_atom = NO_SNOW_TYPE
+
+/obj/item/clothing/suit/storage/jacket/marine/corporate/formal
+ name = "formal suit jacket"
+ desc = "An ivory suit jacket; a Weyland-Yutani corporate badge is attached to the right lapel."
+ icon_state = "corporate_formal"
+ item_state = "corporate_formal"
+ has_buttons = FALSE
+
+/obj/item/clothing/suit/storage/jacket/marine/corporate/black
+ name = "black suit jacket"
+ desc = "A black suit jacket."
+ icon_state = "corporate_black"
+ item_state = "corporate_black"
+ has_buttons = FALSE
+
+/obj/item/clothing/suit/storage/jacket/marine/corporate/brown
+ name = "brown suit jacket"
+ desc = "A brown suit jacket."
+ icon_state = "corporate_brown"
+ item_state = "corporate_brown"
+ has_buttons = FALSE
+
+/obj/item/clothing/suit/storage/jacket/marine/corporate/blue
+ name = "blue suit jacket"
+ desc = "A blue suit jacket."
+ icon_state = "corporate_blue"
+ item_state = "corporate_blue"
+ has_buttons = FALSE
+
+/obj/item/clothing/suit/storage/jacket/marine/bomber
+ name = "khaki bomber jacket"
+ desc = "A khaki bomber jacket popular among stationeers and blue-collar workers everywhere."
+ icon_state = "jacket_khaki"
+ item_state = "jacket_khaki"
+ has_buttons = FALSE
+ flags_atom = NO_SNOW_TYPE
+
+/obj/item/clothing/suit/storage/jacket/marine/bomber/red
+ name = "red bomber jacket"
+ desc = "A reddish-brown bomber jacket popular among stationeers and blue-collar workers everywhere."
+ icon_state = "jacket_red"
+ item_state = "jacket_red"
+ has_buttons = FALSE
+
+/obj/item/clothing/suit/storage/jacket/marine/bomber/grey
+ name = "grey bomber jacket"
+ desc = "A blue-grey bomber jacket popular among stationeers and blue-collar workers everywhere."
+ icon_state = "jacket_grey"
+ item_state = "jacket_grey"
+ has_buttons = FALSE
diff --git a/code/modules/clothing/under/jobs/medsci.dm b/code/modules/clothing/under/jobs/medsci.dm
index 2a6c07e959..6232f0eef4 100644
--- a/code/modules/clothing/under/jobs/medsci.dm
+++ b/code/modules/clothing/under/jobs/medsci.dm
@@ -159,12 +159,12 @@
armor_internaldamage = CLOTHING_ARMOR_LOW
item_state_slots = list(WEAR_BODY = "medical")
-/obj/item/clothing/under/rank/medical/nurse
- name = "medical nurse scrubs"
- desc = "It's made of a special fiber that provides minor protection against biohazards. This one features an orange armband."
- icon_state = "scrubsnurse"
- item_state = "scrubsnurse"
- item_state_slots = list(WEAR_BODY = "scrubsnurse")
+/obj/item/clothing/under/rank/medical/lightblue
+ name = "medical scrubs"
+ desc = "It's made of a special fiber that provides minor protection against biohazards. This one is in light blue."
+ icon_state = "scrubslightblue"
+ flags_jumpsuit = FALSE
+ item_state_slots = list(WEAR_BODY = "scrubslightblue")
/obj/item/clothing/under/rank/medical/blue
name = "medical scrubs"
@@ -187,6 +187,13 @@
flags_jumpsuit = FALSE
item_state_slots = list(WEAR_BODY = "scrubspurple")
+/obj/item/clothing/under/rank/medical/orange
+ name = "medical scrubs"
+ desc = "It's made of a special fiber that provides minor protection against biohazards. This one is in prisoner orange."
+ icon_state = "scrubsorange"
+ flags_jumpsuit = FALSE
+ item_state_slots = list(WEAR_BODY = "scrubsorange")
+
/obj/item/clothing/under/rank/psych
desc = "A basic white jumpsuit. It has turquoise markings that denote the wearer as a psychiatrist."
name = "psychiatrist's jumpsuit"
diff --git a/code/modules/clothing/under/marine_uniform.dm b/code/modules/clothing/under/marine_uniform.dm
index 04473bc62c..7d8c1428a7 100644
--- a/code/modules/clothing/under/marine_uniform.dm
+++ b/code/modules/clothing/under/marine_uniform.dm
@@ -509,6 +509,9 @@
has_sensor = UNIFORM_NO_SENSORS
suit_restricted = list(/obj/item/clothing/suit/storage/marine/veteran/bear)
+ item_icons = list(
+ WEAR_BODY = 'icons/mob/humans/onmob/uniform_1.dmi',
+ )
/obj/item/clothing/under/marine/veteran/UPP
name = "\improper UPP fatigues"
@@ -804,6 +807,42 @@
icon_state = "liaison_blue_blazer"
worn_state = "liaison_blue_blazer"
+/obj/item/clothing/under/liaison_suit/field
+ name = "corporate casual"
+ desc = "A pair of dark brown slacks paired with a dark blue button-down shirt. A popular look among those in the corporate world that conduct the majority of their business from night clubs."
+ icon_state = "corporate_field"
+ worn_state = "corporate_field"
+
+/obj/item/clothing/under/liaison_suit/ivy
+ name = "country club outfit"
+ desc = "A pair of khaki slacks paired with a light blue button-down shirt. A popular look with those in the corporate world that conduct the majority of their business from country clubs."
+ icon_state = "corporate_ivy"
+ worn_state = "corporate_ivy"
+
+/obj/item/clothing/under/liaison_suit/corporate_formal
+ name = "white suit pants"
+ desc = "A pair of ivory slacks paired with a white shirt. A popular pairing for formal corporate events."
+ icon_state = "corporate_formal"
+ worn_state = "corporate_formal"
+
+/obj/item/clothing/under/liaison_suit/black
+ name = "black suit pants"
+ desc = "A pair of black slacks paired with a white shirt. The most common pairing among corporate workers."
+ icon_state = "corporate_black"
+ worn_state = "corporate_black"
+
+/obj/item/clothing/under/liaison_suit/brown
+ name = "brown suit pants"
+ desc = "A pair of brown slacks paired with a white shirt. A common pairing among corporate workers."
+ icon_state = "corporate_brown"
+ worn_state = "corporate_brown"
+
+/obj/item/clothing/under/liaison_suit/blue
+ name = "blue suit pants"
+ desc = "A pair of blue slacks paired with a white shirt. A common pairing among corporate workers."
+ icon_state = "corporate_blue"
+ worn_state = "corporate_blue"
+
/obj/item/clothing/under/marine/reporter
name = "combat correspondent uniform"
desc = "A relaxed and robust uniform fit for any potential reporting needs."
diff --git a/code/modules/clothing/under/ties.dm b/code/modules/clothing/under/ties.dm
index 6234bdddf6..c1da290d43 100644
--- a/code/modules/clothing/under/ties.dm
+++ b/code/modules/clothing/under/ties.dm
@@ -79,6 +79,22 @@
name = "red tie"
icon_state = "redtie"
+/obj/item/clothing/accessory/green
+ name = "green tie"
+ icon_state = "greentie"
+
+/obj/item/clothing/accessory/black
+ name = "black tie"
+ icon_state = "blacktie"
+
+/obj/item/clothing/accessory/gold
+ name = "gold tie"
+ icon_state = "goldtie"
+
+/obj/item/clothing/accessory/purple
+ name = "purple tie"
+ icon_state = "purpletie"
+
/obj/item/clothing/accessory/horrible
name = "horrible tie"
desc = "A neosilk clip-on tie. This one is disgusting."
@@ -342,6 +358,11 @@
desc = "An armband, worn by the crew to display which department they're assigned to. This one is white and green."
icon_state = "medgreen"
+/obj/item/clothing/accessory/armband/nurse
+ name = "nurse armband"
+ desc = "An armband, worn by the rookie nurses to display they are still not doctors. This one is dark red."
+ icon_state = "nurse"
+
//patches
/obj/item/clothing/accessory/patch
name = "USCM patch"
diff --git a/code/modules/cm_marines/Donator_Items.dm b/code/modules/cm_marines/Donator_Items.dm
index 6d2f46490d..2bd0fb5021 100644
--- a/code/modules/cm_marines/Donator_Items.dm
+++ b/code/modules/cm_marines/Donator_Items.dm
@@ -1309,8 +1309,8 @@
/obj/item/clothing/shoes/marine/fluff/vintage //CKEY=vintagepalmer
name = "Vintage Sandals"
desc = "Vintage Sandals, suitable for only the highest class of hipster. DONOR ITEM"
- icon_state = "wizard"
- item_state = "wizard"
+ icon_state = "sandals"
+ item_state = "sandals"
/obj/item/clothing/shoes/marine/fluff/feodrich //CKEY=feodrich (UNIQUE)
name = "Doom Shoes"
diff --git a/code/modules/gear_presets/cmb.dm b/code/modules/gear_presets/cmb.dm
index 5786819791..5e620afb2a 100644
--- a/code/modules/gear_presets/cmb.dm
+++ b/code/modules/gear_presets/cmb.dm
@@ -312,7 +312,7 @@
//clothes
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/CMB/ICC, WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/formal, WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/corporate_formal, WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/storage/holster, WEAR_ACCESSORY)
new_human.equip_to_slot_or_del(new /obj/item/weapon/gun/pistol/mod88, WEAR_IN_ACCESSORY)
new_human.equip_to_slot_or_del(new /obj/item/ammo_magazine/pistol/mod88, WEAR_IN_ACCESSORY)
@@ -372,7 +372,7 @@
//clothes
new_human.equip_to_slot_or_del(new headset_type, WEAR_L_EAR)
new_human.equip_to_slot_or_del(new /obj/item/device/flashlight/pen, WEAR_R_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/suspenders, WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/blue, WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/health/ceramic_plate, WEAR_ACCESSORY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest, WEAR_JACKET)
new_human.equip_to_slot_or_del(new /obj/item/device/flashlight, WEAR_J_STORE)
diff --git a/code/modules/gear_presets/corpses.dm b/code/modules/gear_presets/corpses.dm
index de24f1f84f..450758c691 100644
--- a/code/modules/gear_presets/corpses.dm
+++ b/code/modules/gear_presets/corpses.dm
@@ -350,7 +350,7 @@
)
/datum/equipment_preset/corpse/security/liaison/load_gear(mob/living/carbon/human/new_human)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/formal(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/black(new_human), WEAR_BODY)
if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD])
add_ice_colony_survivor_equipment(new_human)
else
diff --git a/code/modules/gear_presets/survivors/corsat/preset_corsat.dm b/code/modules/gear_presets/survivors/corsat/preset_corsat.dm
index f71439b9d7..3b0e275648 100644
--- a/code/modules/gear_presets/survivors/corsat/preset_corsat.dm
+++ b/code/modules/gear_presets/survivors/corsat/preset_corsat.dm
@@ -40,7 +40,7 @@
assignment = "Interstellar Commerce Commission Corporate Liaison"
/datum/equipment_preset/survivor/interstellar_commerce_commission_liason/corsat/load_gear(mob/living/carbon/human/new_human)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/formal(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/corporate_formal(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/CMB/limited(new_human), WEAR_L_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/head/hardhat/white(new_human), WEAR_HEAD)
new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(new_human), WEAR_JACKET)
diff --git a/code/modules/gear_presets/survivors/new_varadero/preset_new_varadero.dm b/code/modules/gear_presets/survivors/new_varadero/preset_new_varadero.dm
index daa3a8ec01..ef6b3ebf6d 100644
--- a/code/modules/gear_presets/survivors/new_varadero/preset_new_varadero.dm
+++ b/code/modules/gear_presets/survivors/new_varadero/preset_new_varadero.dm
@@ -43,7 +43,7 @@
assignment = "Interstellar Commerce Commission Corporate Liaison"
/datum/equipment_preset/survivor/interstellar_commerce_commission_liason/nv/load_gear(mob/living/carbon/human/new_human)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/formal(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/corporate_formal(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/head/hardhat/white(new_human), WEAR_HEAD)
new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/storage/hazardvest/black(new_human), WEAR_JACKET)
new_human.equip_to_slot_or_del(new /obj/item/device/flashlight, WEAR_J_STORE)
diff --git a/code/modules/gear_presets/survivors/shivas_snowball/preset_shivas_snowball.dm b/code/modules/gear_presets/survivors/shivas_snowball/preset_shivas_snowball.dm
index c1dce212d0..9496573401 100644
--- a/code/modules/gear_presets/survivors/shivas_snowball/preset_shivas_snowball.dm
+++ b/code/modules/gear_presets/survivors/shivas_snowball/preset_shivas_snowball.dm
@@ -3,7 +3,7 @@
assignment = "Shivas Snowball Corporate Liaison"
/datum/equipment_preset/survivor/corporate/shiva/load_gear(mob/living/carbon/human/new_human)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/formal(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/black(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/WY(new_human), WEAR_L_EAR)
new_human.equip_to_slot_or_del(new /obj/item/clothing/head/ushanka(new_human), WEAR_HEAD)
new_human.equip_to_slot_or_del(new /obj/item/clothing/mask/rebreather/scarf(new_human), WEAR_FACE)
diff --git a/code/modules/gear_presets/survivors/solaris/preset_solaris.dm b/code/modules/gear_presets/survivors/solaris/preset_solaris.dm
index c71641a82a..49d16be504 100644
--- a/code/modules/gear_presets/survivors/solaris/preset_solaris.dm
+++ b/code/modules/gear_presets/survivors/solaris/preset_solaris.dm
@@ -84,7 +84,7 @@
assignment = "Solaris Ridge Corporate Liaison"
/datum/equipment_preset/survivor/corporate/solaris/load_gear(mob/living/carbon/human/new_human)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/outing/red(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/ivy(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/distress/WY(new_human), WEAR_L_EAR)
if(new_human.disabilities & NEARSIGHTED)
new_human.equip_to_slot_or_del(new /obj/item/clothing/glasses/sunglasses/prescription(new_human), WEAR_EYES)
diff --git a/code/modules/gear_presets/survivors/survivors.dm b/code/modules/gear_presets/survivors/survivors.dm
index 9cb2c29f11..f2378749b4 100644
--- a/code/modules/gear_presets/survivors/survivors.dm
+++ b/code/modules/gear_presets/survivors/survivors.dm
@@ -271,7 +271,7 @@ Everything bellow is a parent used as a base for one or multiple maps.
access = list(ACCESS_CIVILIAN_PUBLIC,ACCESS_CIVILIAN_COMMAND)
/datum/equipment_preset/survivor/interstellar_human_rights_observer/load_gear(mob/living/carbon/human/new_human)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/suspenders(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/brown(new_human), WEAR_BODY)
if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD])
add_ice_colony_survivor_equipment(new_human)
new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(new_human), WEAR_JACKET)
@@ -306,7 +306,7 @@ Everything bellow is a parent used as a base for one or multiple maps.
survivor_variant = CORPORATE_SURVIVOR
/datum/equipment_preset/survivor/corporate/load_gear(mob/living/carbon/human/new_human)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/formal(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/field(new_human), WEAR_BODY)
if(SSmapping.configs[GROUND_MAP].environment_traits[MAP_COLD])
add_ice_colony_survivor_equipment(new_human)
new_human.equip_to_slot_or_del(new /obj/item/clothing/suit/armor/vest(new_human), WEAR_JACKET)
diff --git a/code/modules/gear_presets/uscm_medical.dm b/code/modules/gear_presets/uscm_medical.dm
index b255874829..54f2c71317 100644
--- a/code/modules/gear_presets/uscm_medical.dm
+++ b/code/modules/gear_presets/uscm_medical.dm
@@ -130,7 +130,8 @@
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/doc(new_human), WEAR_L_EAR)
new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/nurse(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/rank/medical/lightblue(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/accessory/armband/nurse(new_human), WEAR_ACCESSORY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/white(new_human), WEAR_FEET)
if(new_human.disabilities & NEARSIGHTED)
diff --git a/code/modules/gear_presets/uscm_ship.dm b/code/modules/gear_presets/uscm_ship.dm
index c574c30bd3..53c171b146 100644
--- a/code/modules/gear_presets/uscm_ship.dm
+++ b/code/modules/gear_presets/uscm_ship.dm
@@ -52,18 +52,18 @@
minimap_icon = "cl"
minimap_background = MINIMAP_ICON_BACKGROUND_CIVILIAN
- utility_under = list(/obj/item/clothing/under/liaison_suit/outing)
+ utility_under = list(/obj/item/clothing/under/liaison_suit/black)
utility_hat = list()
utility_gloves = list()
utility_shoes = list(/obj/item/clothing/shoes/laceup)
- utility_extra = list(/obj/item/clothing/under/liaison_suit/suspenders)
+ utility_extra = list(/obj/item/clothing/under/liaison_suit/blue)
- service_under = list(/obj/item/clothing/under/liaison_suit)
+ service_under = list(/obj/item/clothing/under/liaison_suit/field)
service_over = list()
service_hat = list()
service_shoes = list(/obj/item/clothing/shoes/laceup)
- dress_under = list(/obj/item/clothing/under/liaison_suit/formal)
+ dress_under = list(/obj/item/clothing/under/liaison_suit/corporate_formal)
dress_over = list()
dress_hat = list()
dress_gloves = list(/obj/item/clothing/gloves/marine/dress)
@@ -80,7 +80,7 @@
//back_item = /obj/item/storage/backpack
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/mcl(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/ivy(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK)
diff --git a/code/modules/gear_presets/wo.dm b/code/modules/gear_presets/wo.dm
index acc795dc68..c52d25d255 100644
--- a/code/modules/gear_presets/wo.dm
+++ b/code/modules/gear_presets/wo.dm
@@ -599,7 +599,7 @@
new_human.equip_to_slot_or_del(new /obj/item/clothing/head/fedora(new_human), WEAR_HEAD)
new_human.equip_to_slot_or_del(new /obj/item/device/radio/headset/almayer/mcom(new_human), WEAR_L_EAR)
- new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/suspenders(new_human), WEAR_BODY)
+ new_human.equip_to_slot_or_del(new /obj/item/clothing/under/liaison_suit/black(new_human), WEAR_BODY)
new_human.equip_to_slot_or_del(new /obj/item/clothing/shoes/laceup(new_human), WEAR_FEET)
new_human.equip_to_slot_or_del(new back_item(new_human), WEAR_BACK)
new_human.equip_to_slot_or_del(new /obj/item/device/camera(new_human), WEAR_L_HAND)
diff --git a/code/modules/projectiles/projectile.dm b/code/modules/projectiles/projectile.dm
index cec5d2089e..5c762e2dc1 100644
--- a/code/modules/projectiles/projectile.dm
+++ b/code/modules/projectiles/projectile.dm
@@ -13,8 +13,9 @@
anchored = TRUE //You will not have me, space wind!
flags_atom = NOINTERACT //No real need for this, but whatever. Maybe this flag will do something useful in the future.
mouse_opacity = MOUSE_OPACITY_TRANSPARENT
- invisibility = 100 // We want this thing to be invisible when it drops on a turf because it will be on the user's turf. We then want to make it visible as it travels.
+ alpha = 0 // We want this thing to be transparent when it drops on a turf because it will be on the user's turf. We then want to make it opaque as it travels.
layer = FLY_LAYER
+ animate_movement = NO_STEPS //disables gliding because it fights against what animate() is doing
var/datum/ammo/ammo //The ammo data which holds most of the actual info.
@@ -48,6 +49,13 @@
var/vis_travelled = 0
/// Origin point for tracing and visual updates
var/turf/vis_source
+ var/vis_source_pixel_x = 0
+ var/vis_source_pixel_y = 0
+
+ /// Starting point of projectile before each flight.
+ var/turf/process_start_turf
+ var/process_start_pixel_x = 0
+ var/process_start_pixel_y = 0
var/damage = 0
var/accuracy = 85 //Base projectile accuracy. Can maybe be later taken from the mob if desired.
@@ -229,9 +237,11 @@
p_x = Clamp(p_x, -16, 16)
p_y = Clamp(p_y, -16, 16)
- if(source_turf != vis_source)
+ if(process_start_turf != vis_source)
vis_travelled = 0
- vis_source = source_turf
+ vis_source = process_start_turf || source_turf
+ vis_source_pixel_x = process_start_pixel_x
+ vis_source_pixel_y = process_start_pixel_y
angle = 0 // Stolen from Get_Angle() basically
var/dx = p_x + aim_turf.x * 32 - source_turf.x * 32 // todo account for firer offsets
@@ -248,13 +258,14 @@
else if(dx < 0)
angle += 360
- var/matrix/rotate = matrix() //Change the bullet angle.
- rotate.Turn(angle)
- apply_transform(rotate)
-
/obj/projectile/process(delta_time)
. = PROC_RETURN_SLEEP
+ var/process_start_delta_time = delta_time //easier to take it unaltered than to recalculate it later
+ process_start_turf = get_turf(src) //obj-level vars so update_angle() can use it without passing it through a ton of procs
+ process_start_pixel_x = pixel_x
+ process_start_pixel_y = pixel_y
+
// Keep going as long as we got speed and time
while(speed > 0 && (speed * ((delta_time + time_carry)/10) >= 1))
time_carry -= 1/speed*10
@@ -266,8 +277,72 @@
return PROCESS_KILL
time_carry += delta_time
+
+ animate_flight(process_start_turf, process_start_pixel_x, process_start_pixel_y, process_start_delta_time)
+
return FALSE
+//#define LERP(a, b, t) (a + (b - a) * CLAMP01(t))
+#define LERP_UNCLAMPED(a, b, t) (a + (b - a) * t)
+
+/// Animates the projectile across the process'ed flight.
+/obj/projectile/proc/animate_flight(turf/start_turf, start_pixel_x, start_pixel_y, delta_time)
+ //Get pixelspace coordinates of start and end of visual path
+
+ var/pixel_x_source = vis_source.x * world.icon_size + vis_source_pixel_x
+ var/pixel_y_source = vis_source.y * world.icon_size + vis_source_pixel_y
+
+ var/turf/vis_target = path[path.len]
+ var/pixel_x_target = vis_target.x * world.icon_size + p_x
+ var/pixel_y_target = vis_target.y * world.icon_size + p_y
+
+ //Change the bullet angle to its visual path
+
+ var/vis_angle = get_pixel_angle(x = pixel_x_target - pixel_x_source, y = pixel_y_target - pixel_y_source) //naming vars because the proc takes y then x and that's WEIRD
+ var/matrix/rotate = matrix()
+ rotate.Turn(vis_angle)
+ apply_transform(rotate)
+
+ //Determine apparent position along visual path, then lerp between start and end positions
+
+ var/vis_length = vis_travelled + path.len
+ var/vis_current = vis_travelled + speed * (time_carry * 0.1) //speed * (time_carry * 0.1) for remainder time movement, visually "catching up" to where it should be
+ var/vis_interpolant = vis_current / vis_length
+
+ var/pixel_x_lerped = LERP_UNCLAMPED(pixel_x_source, pixel_x_target, vis_interpolant)
+ var/pixel_y_lerped = LERP_UNCLAMPED(pixel_y_source, pixel_y_target, vis_interpolant)
+
+ //Convert pixelspace to pixel offset relative to current loc
+
+ var/turf/current_turf = get_turf(src)
+ var/pixel_x_rel_new = pixel_x_lerped - current_turf.x * world.icon_size
+ var/pixel_y_rel_new = pixel_y_lerped - current_turf.y * world.icon_size
+
+ //Set pixel offset as from current loc to old position, so it appears to start in the old position
+
+ pixel_x = (start_turf.x - current_turf.x) * world.icon_size + start_pixel_x
+ pixel_y = (start_turf.y - current_turf.y) * world.icon_size + start_pixel_y
+
+ //Determine apparent distance travelled, then lerp for projectile fade-in
+
+ var/dist_current = distance_travelled + speed * (time_carry * 0.1) //speed * (time_carry * 0.1) for remainder time fade-in
+ var/alpha_interpolant = dist_current - 1 //-1 so it transitions from transparent to opaque between dist 1-2
+ var/alpha_new = LERP_UNCLAMPED(0, 255, alpha_interpolant)
+
+ //Animate the visuals from starting position to new position
+
+ if(projectile_flags & PROJECTILE_SHRAPNEL) //there can be a LOT of shrapnel especially from a cluster OB, not important enough for the expense of an animate()
+ alpha = alpha_new
+ pixel_x = pixel_x_rel_new
+ pixel_y = pixel_y_rel_new
+ return
+
+ var/anim_time = delta_time * 0.1
+ animate(src, pixel_x = pixel_x_rel_new, pixel_y = pixel_y_rel_new, alpha = alpha_new, time = anim_time, flags = ANIMATION_END_NOW)
+
+//#undef LERP
+#undef LERP_UNCLAMPED
+
/// Flies the projectile forward one single turf
/obj/projectile/proc/fly()
SHOULD_NOT_SLEEP(TRUE)
@@ -294,8 +369,6 @@
forceMove(next_turf)
distance_travelled++
vis_travelled++
- if(distance_travelled > 1)
- invisibility = 0
// Check we're still flying - in the highly unlikely but apparently possible case
// we hit something through forceMove callbacks that we didn't pick up in scan_a_turf
@@ -320,20 +393,6 @@
p_y *= 2
retarget(aim_turf, keep_angle = TRUE)
- // Nowe we update visual offset by tracing the bullet predicted location against real one
- //
- // Travelled real distance so far
- var/dist = vis_travelled * 32 + speed * (time_carry*10)
- // Compute where we should be
- var/vis_x = vis_source.x * 32 + sin(angle) * dist
- var/vis_y = vis_source.y * 32 + cos(angle) * dist
- // Get the difference with where we actually are
- var/dx = vis_x - loc.x * 32
- var/dy = vis_y - loc.y * 32
- // Clamp and set this as pixel offsets
- pixel_x = Clamp(dx, -16, 16)
- pixel_y = Clamp(dy, -16, 16)
-
/obj/projectile/proc/retarget(atom/new_target, keep_angle = FALSE)
var/turf/current_turf = get_turf(src)
path = getline2(current_turf, new_target)
diff --git a/code/modules/vehicles/hardpoints/hardpoint.dm b/code/modules/vehicles/hardpoints/hardpoint.dm
index ee49ebc0ab..acdefca18f 100644
--- a/code/modules/vehicles/hardpoints/hardpoint.dm
+++ b/code/modules/vehicles/hardpoints/hardpoint.dm
@@ -1,22 +1,20 @@
-/*
- Hardpoints are any items that attach to a base vehicle, such as wheels/treads, support systems and guns
-*/
-
+/**
+ * Hardpoints are any items that attach to a base vehicle, such as wheels/treads, support systems and guns
+ */
/obj/item/hardpoint
//------MAIN VARS----------
- // Which slot is this hardpoint in
- // Purely to check for conflicting hardpoints
+ /// Which slot is this hardpoint in. Purely to check for conflicting hardpoints.
var/slot
- // The vehicle this hardpoint is installed on
+ /// The vehicle this hardpoint is installed on.
var/obj/vehicle/multitile/owner
health = 100
w_class = SIZE_LARGE
- // Determines how much of any incoming damage is actually taken
+ /// Determines how much of any incoming damage is actually taken.
var/damage_multiplier = 1
- // Origin coords of the hardpoint relative to the vehicle
+ /// Origin coords of the hardpoint relative to the vehicle.
var/list/origins = list(0, 0)
var/list/buff_multipliers
@@ -32,13 +30,13 @@
var/disp_icon //This also differentiates tank vs apc vs other
var/disp_icon_state
- // List of pixel offsets for each direction
+ /// List of pixel offsets for each direction.
var/list/px_offsets
- //visual layer of hardpoint when on vehicle
+ /// Visual layer of hardpoint when on vehicle.
var/hdpt_layer = HDPT_LAYER_WHEELS
- // List of offsets for where to place the muzzle flash for each direction
+ /// List of offsets for where to place the muzzle flash for each direction.
var/list/muzzle_flash_pos = list(
"1" = list(0, 0),
"2" = list(0, 0),
@@ -54,33 +52,23 @@
var/const_mz_offset_y = 0
//------SOUNDS VARS----------
- // Sounds to play when the module activated/fired
+ /// Sounds to play when the module activated/fired.
var/list/activation_sounds
//------INTERACTION VARS----------
- //which seat can use this module
+ /// Which seat can use this module.
var/allowed_seat = VEHICLE_GUNNER
- //Cooldown on use of the hardpoint
- var/cooldown = 100
- var/next_use = 0
-
- //whether hardpoint has activatable ability like shooting or zooming
+ /// Whether hardpoint has activatable ability like shooting or zooming.
var/activatable = 0
- //used to prevent welder click spam
+ /// Used to prevent welder click spam.
var/being_repaired = FALSE
- //current user. We can have only one user at a time. Better never change that
- var/user
-
- //Accuracy of the hardpoint. (which is, in fact, a scatter. Need to change this system)
- var/accuracy = 1
-
- // The firing arc of this hardpoint
+ /// The firing arc of this hardpoint.
var/firing_arc = 0 //in degrees. 0 skips whole arc of fire check
// Muzzleflash
@@ -91,17 +79,53 @@
//------AMMUNITION VARS----------
- //Currently loaded ammo that we shoot from
+ /// Currently loaded ammo that we shoot from.
var/obj/item/ammo_magazine/hardpoint/ammo
- //spare magazines that we can reload from
+ /// Spare magazines that we can reload from.
var/list/backup_clips
- //maximum amount of spare mags
+ /// Maximum amount of spare mags.
var/max_clips = 0
/// An assoc list in the format list(/datum/element/bullet_trait_to_give = list(...args))
- /// that will be given to a projectile fired from the hardpoint
+ /// that will be given to a projectile fired from the hardpoint.
var/list/list/traits_to_give
+ /// How much the bullet scatters when fired, in degrees.
+ var/scatter = 0
+ /// How many bullets the gun fired while burst firing/auto firing.
+ var/shots_fired = 0
+ /// Delay before a new firing sequence can start.
+ COOLDOWN_DECLARE(fire_cooldown)
+
+ // Firemodes.
+ /// Current selected firemode of the gun.
+ var/gun_firemode = GUN_FIREMODE_SEMIAUTO
+ /// List of allowed firemodes.
+ var/list/gun_firemode_list = list(
+ GUN_FIREMODE_SEMIAUTO,
+ )
+
+ // Semi-auto and full-auto.
+ /// For regular shots, how long to wait before firing again. Use modify_fire_delay and set_fire_delay instead of modifying this on the fly
+ var/fire_delay = 0
+ /// The multiplier for how much slower this should fire in automatic mode. 1 is normal, 1.2 is 20% slower, 2 is 100% slower, etc. Protected due to it never needing to be edited.
+ var/autofire_slow_mult = 1
+ /// If the gun is currently auto firing.
+ var/auto_firing = FALSE
+
+ // Burst fire.
+ /// How many shots can the weapon shoot in burst? Anything less than 2 and you cannot toggle burst. Use modify_burst_amount and set_burst_amount instead of modifying this
+ var/burst_amount = 1
+ /// The delay in between shots. Lower = less delay = faster. Use modify_burst_delay and set_burst_delay instead of modifying this
+ var/burst_delay = 1
+ /// When burst-firing, this number is extra time before the weapon can fire again.
+ var/extra_delay = 0
+ /// If the gun is currently burst firing.
+ var/burst_firing = FALSE
+
+ /// Currently selected target to fire at. Set with set_target().
+ var/atom/target
+
//-----------------------------
//------GENERAL PROCS----------
//-----------------------------
@@ -109,6 +133,7 @@
/obj/item/hardpoint/Initialize()
. = ..()
set_bullet_traits()
+ AddComponent(/datum/component/automatedfire/autofire, fire_delay, burst_delay, burst_amount, gun_firemode, autofire_slow_mult, CALLBACK(src, PROC_REF(set_burst_firing)), CALLBACK(src, PROC_REF(reset_fire)), CALLBACK(src, PROC_REF(fire_wrapper)), callback_set_firing = CALLBACK(src, PROC_REF(set_auto_firing)))
/obj/item/hardpoint/Destroy()
if(owner)
@@ -117,7 +142,7 @@
owner = null
QDEL_NULL_LIST(backup_clips)
QDEL_NULL(ammo)
-
+ set_target(null)
return ..()
/obj/item/hardpoint/ex_act(severity)
@@ -166,37 +191,64 @@
/obj/item/hardpoint/proc/get_integrity_percent()
return 100.0*health/initial(health)
-/obj/item/hardpoint/proc/on_install(obj/vehicle/multitile/V)
- apply_buff(V)
- return
+/// Apply hardpoint effects to vehicle and self.
+/obj/item/hardpoint/proc/on_install(obj/vehicle/multitile/vehicle)
+ if(!vehicle) //in loose holder
+ return
+ RegisterSignal(vehicle, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES, PROC_REF(recalculate_hardpoint_bonuses))
+ apply_buff(vehicle)
-/obj/item/hardpoint/proc/on_uninstall(obj/vehicle/multitile/V)
- remove_buff(V)
- return
+/// Remove hardpoint effects from vehicle and self.
+/obj/item/hardpoint/proc/on_uninstall(obj/vehicle/multitile/vehicle)
+ if(!vehicle) //in loose holder
+ return
+ UnregisterSignal(vehicle, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES)
+ remove_buff(vehicle)
+ //resetting values like set_gun_config_values() would be tidy, but unnecessary as it gets recalc'd on install anyway
-//applying passive buffs like damage type resistance, speed, accuracy, cooldowns
-/obj/item/hardpoint/proc/apply_buff(obj/vehicle/multitile/V)
+/// Applying passive buffs like damage type resistance, speed, accuracy, cooldowns.
+/obj/item/hardpoint/proc/apply_buff(obj/vehicle/multitile/vehicle)
if(buff_applied)
return
if(LAZYLEN(type_multipliers))
for(var/type in type_multipliers)
- V.dmg_multipliers[type] *= LAZYACCESS(type_multipliers, type)
+ vehicle.dmg_multipliers[type] *= LAZYACCESS(type_multipliers, type)
if(LAZYLEN(buff_multipliers))
for(var/type in buff_multipliers)
- V.misc_multipliers[type] *= LAZYACCESS(buff_multipliers, type)
+ vehicle.misc_multipliers[type] *= LAZYACCESS(buff_multipliers, type)
buff_applied = TRUE
+ SEND_SIGNAL(vehicle, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES)
-//removing buffs
-/obj/item/hardpoint/proc/remove_buff(obj/vehicle/multitile/V)
+/// Removing passive buffs like damage type resistance, speed, accuracy, cooldowns.
+/obj/item/hardpoint/proc/remove_buff(obj/vehicle/multitile/vehicle)
if(!buff_applied)
return
if(LAZYLEN(type_multipliers))
for(var/type in type_multipliers)
- V.dmg_multipliers[type] *= 1 / LAZYACCESS(type_multipliers, type)
+ vehicle.dmg_multipliers[type] *= 1 / LAZYACCESS(type_multipliers, type)
if(LAZYLEN(buff_multipliers))
for(var/type in buff_multipliers)
- V.misc_multipliers[type] *= 1 / LAZYACCESS(buff_multipliers, type)
+ vehicle.misc_multipliers[type] *= 1 / LAZYACCESS(buff_multipliers, type)
buff_applied = FALSE
+ SEND_SIGNAL(vehicle, COMSIG_GUN_RECALCULATE_ATTACHMENT_BONUSES)
+
+/// Recalculates hardpoint values based on vehicle modifiers.
+/obj/item/hardpoint/proc/recalculate_hardpoint_bonuses()
+ scatter = initial(scatter) / owner.misc_multipliers["accuracy"]
+ var/cooldown_mult = owner.misc_multipliers["cooldown"]
+ set_fire_delay(initial(fire_delay) * cooldown_mult)
+ set_burst_delay(initial(burst_delay) * cooldown_mult)
+ extra_delay = initial(extra_delay) * cooldown_mult
+
+/// Setter for fire_delay.
+/obj/item/hardpoint/proc/set_fire_delay(value)
+ fire_delay = value
+ SEND_SIGNAL(src, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, fire_delay)
+
+/// Setter for burst_delay.
+/obj/item/hardpoint/proc/set_burst_delay(value)
+ burst_delay = value
+ SEND_SIGNAL(src, COMSIG_GUN_BURST_SHOT_DELAY_MODIFIED, burst_delay)
//this proc called on each move of vehicle
/obj/item/hardpoint/proc/on_move(turf/old, turf/new_turf, move_dir)
@@ -253,13 +305,12 @@
return data
-// Traces backwards from the gun origin to the vehicle to check for obstacles between the vehicle and the muzzle
-/obj/item/hardpoint/proc/clear_los(atom/A)
-
+/// Traces backwards from the gun origin to the vehicle to check for obstacles between the vehicle and the muzzle.
+/obj/item/hardpoint/proc/clear_los()
if(origins[1] == 0 && origins[2] == 0) //skipping check for modules we don't need this
return TRUE
- var/turf/muzzle_turf = locate(owner.x + origins[1], owner.y + origins[2], owner.z)
+ var/turf/muzzle_turf = get_origin_turf()
var/turf/checking_turf = muzzle_turf
while(!(owner in checking_turf))
@@ -268,24 +319,24 @@
return FALSE
// Ensure that we can pass over all objects in the turf
- for(var/obj/O in checking_turf)
+ for(var/obj/object in checking_turf)
// Since vehicles are multitile the
- if(O == owner)
+ if(object == owner)
continue
// Non-dense objects are irrelevant
- if(!O.density)
+ if(!object.density)
continue
// Make sure we can pass object from all directions
- if(!(O.pass_flags.flags_can_pass_all & PASS_OVER_THROW_ITEM))
- if(!(O.flags_atom & ON_BORDER))
+ if(!HAS_FLAG(object.pass_flags.flags_can_pass_all, PASS_OVER_THROW_ITEM))
+ if(!HAS_FLAG(object.flags_atom, ON_BORDER))
return FALSE
//If we're behind the object, check the behind pass flags
- else if(dir == O.dir && !(O.pass_flags.flags_can_pass_behind & PASS_OVER_THROW_ITEM))
+ else if(dir == object.dir && !HAS_FLAG(object.pass_flags.flags_can_pass_behind, PASS_OVER_THROW_ITEM))
return FALSE
//If we're in front, check front pass flags
- else if(dir == turn(O.dir, 180) && !(O.pass_flags.flags_can_pass_front & PASS_OVER_THROW_ITEM))
+ else if(dir == turn(object.dir, 180) && !HAS_FLAG(object.pass_flags.flags_can_pass_front, PASS_OVER_THROW_ITEM))
return FALSE
// Trace back towards the vehicle
@@ -297,47 +348,6 @@
//------INTERACTION PROCS----------
//-----------------------------
-//If the hardpoint can be activated by current user
-/obj/item/hardpoint/proc/can_activate(mob/user, atom/A)
- if(!owner)
- return
-
- var/seat = owner.get_mob_seat(user)
- if(!seat)
- return
-
- if(seat != allowed_seat)
- to_chat(user, SPAN_WARNING("Only [allowed_seat] can use [name]."))
- return
-
- if(health <= 0)
- to_chat(user, SPAN_WARNING("\The [name] is broken!"))
- return FALSE
-
- if(world.time < next_use)
- if(cooldown >= 20) //filter out guns with high firerate to prevent message spam.
- to_chat(user, SPAN_WARNING("You need to wait [SPAN_HELPFUL((next_use - world.time) / 10)] seconds before [name] can be used again."))
- return FALSE
-
- if(ammo && ammo.current_rounds <= 0)
- to_chat(user, SPAN_WARNING("\The [name] is out of ammo! Magazines: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]"))
- return FALSE
-
- if(!in_firing_arc(A))
- to_chat(user, SPAN_WARNING("The target is not within your firing arc!"))
- return FALSE
-
- if(!clear_los(A))
- to_chat(user, SPAN_WARNING("You don't have a clear line of sight to the target!"))
- return FALSE
-
- return TRUE
-
-//Called when you want to activate the hardpoint, by default firing a gun
-//This can also be used for some type of temporary buff or toggling mode, up to you
-/obj/item/hardpoint/proc/activate(mob/user, atom/A)
- fire(user, A)
-
/obj/item/hardpoint/proc/deactivate()
return
@@ -490,76 +500,201 @@
user.visible_message(SPAN_NOTICE("[user] stops repairing \the [name]."), SPAN_NOTICE("You stop repairing \the [name]. The integrity of the module is at [SPAN_HELPFUL(round(get_integrity_percent()))]%."))
return
-//determines whether something is in firing arc of a hardpoint
-/obj/item/hardpoint/proc/in_firing_arc(atom/A)
- if(!owner)
- return FALSE
+/// Setter proc for the automatic firing flag.
+/obj/item/hardpoint/proc/set_auto_firing(auto = FALSE)
+ if(auto_firing != auto)
+ auto_firing = auto
+ if(!auto_firing) //end-of-fire, show changed ammo
+ display_ammo()
+
+/// Setter proc for the burst firing flag.
+/obj/item/hardpoint/proc/set_burst_firing(burst = FALSE)
+ if(burst_firing != burst)
+ burst_firing = burst
+ if(!burst_firing) //end-of-fire, show changed ammo
+ display_ammo()
+
+/// Clean all firing references.
+/obj/item/hardpoint/proc/reset_fire()
+ shots_fired = 0
+ set_target(null)
+ set_auto_firing(FALSE) //on abnormal exits automatic fire doesn't call set_auto_firing()
+
+/// Set the target and take care of hard delete.
+/obj/item/hardpoint/proc/set_target(atom/object)
+ if(object == target || object == loc)
+ return
+ if(target)
+ UnregisterSignal(target, COMSIG_PARENT_QDELETING)
+ target = object
+ if(target)
+ RegisterSignal(target, COMSIG_PARENT_QDELETING, PROC_REF(clean_target))
+
+/// Set the target to its turf, so we keep shooting even when it was qdeled.
+/obj/item/hardpoint/proc/clean_target()
+ SIGNAL_HANDLER
+ target = get_turf(target)
+
+/// Print how much ammo is left to chat.
+/obj/item/hardpoint/proc/display_ammo(mob/user)
+ if(!user)
+ user = owner.get_seat_mob(allowed_seat)
+ if(!user)
+ return
- if(!firing_arc)
- return TRUE
+ if(ammo)
+ to_chat(user, SPAN_WARNING("[name] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]"))
- var/turf/T = get_turf(A)
- if(!T)
- return FALSE
+/// Reset variables used in firing and remove the gun from the autofire system.
+/obj/item/hardpoint/proc/stop_fire(datum/source, atom/object, turf/location, control, params)
+ SEND_SIGNAL(src, COMSIG_GUN_STOP_FIRE)
+ if(auto_firing)
+ reset_fire() //automatic fire doesn't reset itself from COMSIG_GUN_STOP_FIRE
- var/dx = T.x - (owner.x + origins[1]/2)
- var/dy = T.y - (owner.y + origins[2]/2)
-
- var/deg = 0
- switch(dir)
- if(EAST)
- deg = 0
- if(NORTH)
- deg = -90
- if(WEST)
- deg = 180
- if(SOUTH)
- deg = 90
-
- var/nx = dx * cos(deg) - dy * sin(deg)
- var/ny = dx * sin(deg) + dy * cos(deg)
- if(nx == 0)
- return firing_arc >= 90
-
- var/angle = arctan(ny/nx)
- if(nx < 0)
- angle += 180
-
- return abs(angle) <= (firing_arc/2)
-
-//doing last preparation before actually firing gun
-/obj/item/hardpoint/proc/fire(mob/user, atom/A)
- if(!ammo) //Prevents a runtime
+/// Update the target if you dragged your mouse.
+/obj/item/hardpoint/proc/change_target(datum/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params)
+ set_target(get_turf_on_clickcatcher(over_object, source, params))
+
+/// Check if the gun can fire and add it to bucket autofire system if needed, or just fire the gun if not.
+/obj/item/hardpoint/proc/start_fire(datum/source, atom/object, turf/location, control, params)
+ if(istype(object, /atom/movable/screen))
return
- if(ammo.current_rounds <= 0)
+
+ if(QDELETED(object))
return
- next_use = world.time + cooldown * owner.misc_multipliers["cooldown"]
- if(!prob((accuracy * 100) / owner.misc_multipliers["accuracy"]))
- A = get_step(get_turf(A), pick(cardinal))
+ if(!auto_firing && !burst_firing && !COOLDOWN_FINISHED(src, fire_cooldown))
+ if(max(fire_delay, burst_delay + extra_delay) >= 2.0 SECONDS) //filter out guns with high firerate to prevent message spam.
+ to_chat(source, SPAN_WARNING("You need to wait [SPAN_HELPFUL(COOLDOWN_SECONDSLEFT(src, fire_cooldown))] seconds before [name] can be used again."))
+ return
- if(LAZYLEN(activation_sounds))
- playsound(get_turf(src), pick(activation_sounds), 60, 1)
+ set_target(get_turf_on_clickcatcher(object, source, params))
- fire_projectile(user, A)
+ if(gun_firemode == GUN_FIREMODE_SEMIAUTO)
+ var/fire_return = try_fire(object, source, params)
+ //end-of-fire, show ammo (if changed)
+ if(fire_return == AUTOFIRE_CONTINUE)
+ reset_fire()
+ display_ammo(source)
+ else
+ SEND_SIGNAL(src, COMSIG_GUN_FIRE)
+
+/// Wrapper proc for the autofire system to ensure the important args aren't null.
+/obj/item/hardpoint/proc/fire_wrapper(atom/target, mob/living/user, params)
+ SHOULD_NOT_OVERRIDE(TRUE)
+ if(!target)
+ target = src.target
+ if(!user)
+ user = owner.get_seat_mob(allowed_seat)
+ if(!target || !user)
+ return NONE
+
+ return try_fire(target, user, params)
+
+/// Tests if firing should be interrupted, otherwise fires.
+/obj/item/hardpoint/proc/try_fire(atom/target, mob/living/user, params)
+ if(health <= 0)
+ to_chat(user, SPAN_WARNING("\The [name] is broken!"))
+ return NONE
- to_chat(user, SPAN_WARNING("[name] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]"))
+ if(ammo && ammo.current_rounds <= 0)
+ click_empty(user)
+ return NONE
-//finally firing the gun
-/obj/item/hardpoint/proc/fire_projectile(mob/user, atom/A)
- set waitfor = 0
+ if(!in_firing_arc(target))
+ to_chat(user, SPAN_WARNING("The target is not within your firing arc!"))
+ return NONE
- var/turf/origin_turf = get_turf(src)
- origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z)
+ if(!clear_los())
+ to_chat(user, SPAN_WARNING("The muzzle is obstructed!"))
+ return NONE
- var/obj/projectile/P = generate_bullet(user, origin_turf)
- SEND_SIGNAL(P, COMSIG_BULLET_USER_EFFECTS, user)
- P.fire_at(A, user, src, P.ammo.max_range, P.ammo.shell_speed)
+ return handle_fire(target, user, params)
- if(use_muzzle_flash)
- muzzle_flash(Get_Angle(origin_turf, A))
+/// Actually fires the gun, sets up the projectile and fires it.
+/obj/item/hardpoint/proc/handle_fire(atom/target, mob/living/user, params)
+ var/turf/origin_turf = get_origin_turf()
+ var/obj/projectile/projectile_to_fire = generate_bullet(user, origin_turf)
ammo.current_rounds--
+ SEND_SIGNAL(projectile_to_fire, COMSIG_BULLET_USER_EFFECTS, user)
+
+ // turf-targeted projectiles are fired without scatter, because proc would raytrace them further away
+ var/ammo_flags = projectile_to_fire.ammo.flags_ammo_behavior | projectile_to_fire.projectile_override_flags
+ if(!HAS_FLAG(ammo_flags, AMMO_HITS_TARGET_TURF) && !HAS_FLAG(ammo_flags, AMMO_EXPLOSIVE)) //AMMO_EXPLOSIVE is also a turf-targeted projectile
+ projectile_to_fire.scatter = scatter
+ target = simulate_scatter(projectile_to_fire, target, origin_turf, get_turf(target), user)
+
+ INVOKE_ASYNC(projectile_to_fire, TYPE_PROC_REF(/obj/projectile, fire_at), target, user, src, projectile_to_fire.ammo.max_range, projectile_to_fire.ammo.shell_speed)
+ projectile_to_fire = null
+
+ shots_fired++
+ play_firing_sounds()
+ if(use_muzzle_flash)
+ muzzle_flash(Get_Angle(origin_turf, target))
+
+ set_fire_cooldown(gun_firemode)
+
+ return AUTOFIRE_CONTINUE
+
+/// Start cooldown to respect delay of firemode.
+/obj/item/hardpoint/proc/set_fire_cooldown(firemode)
+ var/cooldown_time = 0
+ switch(firemode)
+ if(GUN_FIREMODE_SEMIAUTO)
+ cooldown_time = fire_delay
+ if(GUN_FIREMODE_BURSTFIRE)
+ cooldown_time = burst_delay + extra_delay
+ if(GUN_FIREMODE_AUTOMATIC)
+ cooldown_time = fire_delay
+ COOLDOWN_START(src, fire_cooldown, cooldown_time)
+
+/// Adjust target based on random scatter angle.
+/obj/item/hardpoint/proc/simulate_scatter(obj/projectile/projectile_to_fire, atom/target, turf/curloc, turf/targloc)
+ var/fire_angle = Get_Angle(curloc, targloc)
+ var/total_scatter_angle = projectile_to_fire.scatter
+
+ //Not if the gun doesn't scatter at all, or negative scatter.
+ if(total_scatter_angle > 0)
+ fire_angle += rand(-total_scatter_angle, total_scatter_angle)
+ target = get_angle_target_turf(curloc, fire_angle, 30)
+
+ return target
+
+/// Get turf at hardpoint origin offset, used as the muzzle.
+/obj/item/hardpoint/proc/get_origin_turf()
+ return get_offset_target_turf(get_turf(src), origins[1], origins[2])
+
+/// Plays 'click' noise and announced to chat. Usually called when weapon empty.
+/obj/item/hardpoint/proc/click_empty(mob/user)
+ playsound(src, 'sound/weapons/gun_empty.ogg', 25, 1, 5)
+ if(user)
+ to_chat(user, SPAN_WARNING("*click*"))
+
+/// Selects and plays a firing sound from the list.
+/obj/item/hardpoint/proc/play_firing_sounds()
+ if(LAZYLEN(activation_sounds))
+ playsound(get_turf(src), pick(activation_sounds), 60, 1)
+
+/// Determines whether something is in firing arc of a hardpoint.
+/obj/item/hardpoint/proc/in_firing_arc(atom/target)
+ if(!firing_arc || !ISINRANGE_EX(firing_arc, 0, 360))
+ return TRUE
+
+ var/turf/muzzle_turf = get_origin_turf()
+ var/turf/target_turf = get_turf(target)
+
+ //same tile angle returns EAST, returning FALSE to ensure consistency
+ if(muzzle_turf == target_turf)
+ return FALSE
+
+ var/angle_diff = SIMPLIFY_DEGREES(dir2angle(dir) - get_angle(muzzle_turf, target_turf))
+ if(angle_diff < -180)
+ angle_diff += 360
+ else if(angle_diff > 180)
+ angle_diff -= 360
+
+ return abs(angle_diff) <= (firing_arc * 0.5)
//-----------------------------
//------ICON PROCS----------
diff --git a/code/modules/vehicles/hardpoints/holder/holder.dm b/code/modules/vehicles/hardpoints/holder/holder.dm
index b14e078a39..fc8e849d10 100644
--- a/code/modules/vehicles/hardpoints/holder/holder.dm
+++ b/code/modules/vehicles/hardpoints/holder/holder.dm
@@ -43,10 +43,21 @@
for(var/obj/item/hardpoint/H in hardpoints)
H.take_damage(damage)
-/obj/item/hardpoint/holder/on_install(obj/vehicle/multitile/V)
- for(var/obj/item/hardpoint/HP in hardpoints)
- HP.owner = V
- return
+/obj/item/hardpoint/holder/on_install(obj/vehicle/multitile/vehicle)
+ ..()
+ if(!vehicle) //in loose holder
+ return
+ for(var/obj/item/hardpoint/hardpoint in hardpoints)
+ hardpoint.owner = vehicle
+ hardpoint.on_install(vehicle)
+
+/obj/item/hardpoint/holder/on_uninstall(obj/vehicle/multitile/vehicle)
+ if(!vehicle) //in loose holder
+ return
+ for(var/obj/item/hardpoint/hardpoint in hardpoints)
+ hardpoint.on_uninstall(vehicle)
+ hardpoint.owner = null
+ ..()
/obj/item/hardpoint/holder/proc/can_install(obj/item/hardpoint/H)
// Can only have 1 hardpoint of each slot type
@@ -121,16 +132,17 @@
H.forceMove(src)
LAZYADD(hardpoints, H)
+ H.on_install(owner)
H.rotate(turning_angle(H.dir, dir))
/obj/item/hardpoint/holder/proc/remove_hardpoint(obj/item/hardpoint/H, turf/uninstall_to)
if(!hardpoints)
return
- hardpoints -= H
H.forceMove(uninstall_to ? uninstall_to : get_turf(src))
+ H.on_uninstall(owner)
H.reset_rotation()
-
+ hardpoints -= H
H.owner = null
if(H.health <= 0)
diff --git a/code/modules/vehicles/hardpoints/holder/tank_turret.dm b/code/modules/vehicles/hardpoints/holder/tank_turret.dm
index 27ab6c9540..896628e609 100644
--- a/code/modules/vehicles/hardpoints/holder/tank_turret.dm
+++ b/code/modules/vehicles/hardpoints/holder/tank_turret.dm
@@ -13,8 +13,6 @@
density = TRUE //come on, it's huge
activatable = TRUE
- cooldown = 150
- accuracy = 0.8
ammo = new /obj/item/ammo_magazine/hardpoint/turret_smoke
max_clips = 2
@@ -60,6 +58,15 @@
// Used during the windup
var/rotating = FALSE
+ scatter = 4
+ gun_firemode = GUN_FIREMODE_BURSTFIRE
+ gun_firemode_list = list(
+ GUN_FIREMODE_BURSTFIRE,
+ )
+ burst_amount = 2
+ burst_delay = 1.0 SECONDS
+ extra_delay = 13.0 SECONDS
+
/obj/item/hardpoint/holder/tank_turret/update_icon()
var/broken = (health <= 0)
icon_state = "tank_turret_[broken]"
@@ -182,12 +189,7 @@
user.client.pixel_x = -1 * AM.view_tile_offset * 32
user.client.pixel_y = 0
-/obj/item/hardpoint/holder/tank_turret/fire(mob/user, atom/A)
- if(ammo.current_rounds <= 0)
- return
-
- next_use = world.time + cooldown
-
+/obj/item/hardpoint/holder/tank_turret/try_fire(atom/target, mob/living/user, params)
var/turf/L
var/turf/R
switch(owner.dir)
@@ -204,26 +206,14 @@
L = locate(owner.x - 4, owner.y + 2, owner.z)
R = locate(owner.x - 4, owner.y - 2, owner.z)
- if(LAZYLEN(activation_sounds))
- playsound(get_turf(src), pick(activation_sounds), 60, 1)
- fire_projectile(user, L)
+ if(shots_fired)
+ target = R
+ else
+ target = L
- sleep(10)
+ return ..()
- if(LAZYLEN(activation_sounds))
- playsound(get_turf(src), pick(activation_sounds), 60, 1)
- fire_projectile(user, R)
-
- to_chat(user, SPAN_WARNING("Smoke Screen uses left: [SPAN_HELPFUL(ammo ? ammo.current_rounds / 2 : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds / 2 : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]"))
-
-/obj/item/hardpoint/holder/tank_turret/fire_projectile(mob/user, atom/A)
- set waitfor = 0
-
- var/turf/origin_turf = get_turf(src)
- origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z)
+/obj/item/hardpoint/holder/tank_turret/get_origin_turf()
+ var/origin_turf = ..()
origin_turf = get_step(get_step(origin_turf, owner.dir), owner.dir) //this should get us tile in front of tank to prevent grenade being stuck under us.
-
- var/obj/projectile/P = generate_bullet(user, origin_turf)
- SEND_SIGNAL(P, COMSIG_BULLET_USER_EFFECTS, owner.seats[VEHICLE_GUNNER])
- P.fire_at(A, owner.seats[VEHICLE_GUNNER], src, get_dist(origin_turf, A) + 1, P.ammo.shell_speed)
- ammo.current_rounds--
+ return origin_turf
diff --git a/code/modules/vehicles/hardpoints/primary/autocannon.dm b/code/modules/vehicles/hardpoints/primary/autocannon.dm
index df9224011b..b6dc2cedc6 100644
--- a/code/modules/vehicles/hardpoints/primary/autocannon.dm
+++ b/code/modules/vehicles/hardpoints/primary/autocannon.dm
@@ -8,8 +8,6 @@
activation_sounds = list('sound/weapons/vehicles/autocannon_fire.ogg')
health = 500
- cooldown = 7
- accuracy = 0.98
firing_arc = 60
origins = list(0, -3)
@@ -23,3 +21,10 @@
"4" = list(32, 0),
"8" = list(-32, 0)
)
+
+ scatter = 1
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ gun_firemode_list = list(
+ GUN_FIREMODE_AUTOMATIC,
+ )
+ fire_delay = 0.7 SECONDS
diff --git a/code/modules/vehicles/hardpoints/primary/dual_cannon.dm b/code/modules/vehicles/hardpoints/primary/dual_cannon.dm
index d33fc1d628..b76e6ad5cf 100644
--- a/code/modules/vehicles/hardpoints/primary/dual_cannon.dm
+++ b/code/modules/vehicles/hardpoints/primary/dual_cannon.dm
@@ -12,10 +12,7 @@
damage_multiplier = 0.2
health = 500
- cooldown = 7
- accuracy = 0.98
firing_arc = 60
- var/burst_amount = 2
origins = list(0, -2)
@@ -35,27 +32,15 @@
"8" = list(14, 9)
)
+ scatter = 1
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ gun_firemode_list = list(
+ GUN_FIREMODE_AUTOMATIC,
+ )
+ fire_delay = 0.3 SECONDS
+
/obj/item/hardpoint/primary/dualcannon/set_bullet_traits()
..()
LAZYADD(traits_to_give, list(
BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff)
))
-
-/obj/item/hardpoint/primary/dualcannon/fire(mob/user, atom/A)
- if(ammo.current_rounds <= 0)
- return
-
- next_use = world.time + cooldown * owner.misc_multipliers["cooldown"]
-
- for(var/bullets_fired = 1, bullets_fired <= burst_amount, bullets_fired++)
- var/atom/T = A
- if(!prob((accuracy * 100) / owner.misc_multipliers["accuracy"]))
- T = get_step(get_turf(A), pick(cardinal))
- if(LAZYLEN(activation_sounds))
- playsound(get_turf(src), pick(activation_sounds), 60, 1)
- fire_projectile(user, T)
- if(ammo.current_rounds <= 0)
- break
- if(bullets_fired < burst_amount) //we need to sleep only if there are more bullets to shoot in the burst
- sleep(3)
- to_chat(user, SPAN_WARNING("[src] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]"))
diff --git a/code/modules/vehicles/hardpoints/primary/flamer.dm b/code/modules/vehicles/hardpoints/primary/flamer.dm
index 929842df23..13beee9dd2 100644
--- a/code/modules/vehicles/hardpoints/primary/flamer.dm
+++ b/code/modules/vehicles/hardpoints/primary/flamer.dm
@@ -8,8 +8,6 @@
activation_sounds = list('sound/weapons/vehicles/flamethrower.ogg')
health = 400
- cooldown = 20
- accuracy = 0.75
firing_arc = 90
origins = list(0, -3)
@@ -26,36 +24,19 @@
use_muzzle_flash = FALSE
+ scatter = 5
+ fire_delay = 2.0 SECONDS
+
/obj/item/hardpoint/primary/flamer/set_bullet_traits()
..()
LAZYADD(traits_to_give, list(
BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff)
))
-/obj/item/hardpoint/primary/flamer/can_activate(mob/user, atom/A)
- if(!..())
- return FALSE
-
- var/turf/origin_turf = get_turf(src)
- origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z)
- if(origin_turf == get_turf(A))
- return FALSE
-
- return TRUE
-
-/obj/item/hardpoint/primary/flamer/fire_projectile(mob/user, atom/A)
- set waitfor = 0
-
- var/turf/origin_turf = get_turf(src)
- origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z)
-
- var/range = get_dist(origin_turf, A) + 1
-
- var/obj/projectile/P = generate_bullet(user, origin_turf)
- SEND_SIGNAL(P, COMSIG_BULLET_USER_EFFECTS, owner.seats[VEHICLE_GUNNER])
- P.fire_at(A, owner.seats[VEHICLE_GUNNER], src, range < P.ammo.max_range ? range : P.ammo.max_range, P.ammo.shell_speed)
-
- if(use_muzzle_flash)
- muzzle_flash(Get_Angle(owner, A))
+/obj/item/hardpoint/primary/flamer/try_fire(target, user, params)
+ var/turf/origin_turf = get_origin_turf()
+ if(origin_turf == get_turf(target))
+ to_chat(user, SPAN_WARNING("The target is too close."))
+ return NONE
- ammo.current_rounds--
+ return ..()
diff --git a/code/modules/vehicles/hardpoints/primary/ltb.dm b/code/modules/vehicles/hardpoints/primary/ltb.dm
index 7c663dc27f..19b5c7e7b9 100644
--- a/code/modules/vehicles/hardpoints/primary/ltb.dm
+++ b/code/modules/vehicles/hardpoints/primary/ltb.dm
@@ -8,8 +8,6 @@
activation_sounds = list('sound/weapons/vehicles/cannon_fire1.ogg', 'sound/weapons/vehicles/cannon_fire2.ogg')
health = 500
- cooldown = 200
- accuracy = 0.97
firing_arc = 60
origins = list(0, -3)
@@ -30,3 +28,6 @@
"4" = list(89, -4),
"8" = list(-89, -4)
)
+
+ scatter = 2
+ fire_delay = 20.0 SECONDS
diff --git a/code/modules/vehicles/hardpoints/primary/minigun.dm b/code/modules/vehicles/hardpoints/primary/minigun.dm
index c6158f1a3b..3acf37eec2 100644
--- a/code/modules/vehicles/hardpoints/primary/minigun.dm
+++ b/code/modules/vehicles/hardpoints/primary/minigun.dm
@@ -7,8 +7,6 @@
disp_icon_state = "ltaaap_minigun"
health = 350
- cooldown = 8
- accuracy = 0.6
firing_arc = 90
origins = list(0, -3)
@@ -30,46 +28,58 @@
"8" = list(-77, 0)
)
- //changed minigun mechanic so instead of having lowered cooldown with each shot it now has increased burst size.
- //While it's still spammy, user doesn't have to click as fast as possible anymore and has margin of 2 seconds before minigun will start slowing down
-
- var/chained_shots = 1 //how many quick succession shots we've fired, 1 by default
- var/last_shot_time = 0 //when was last shot fired, after 3 seconds we stop barrel
- var/list/chain_bursts = list(1, 1, 2, 2, 3, 3, 3, 4, 4, 4) //how many shots per click we do
+ scatter = 7
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ gun_firemode_list = list(
+ GUN_FIREMODE_AUTOMATIC,
+ )
+ fire_delay = 0.8 SECONDS //base fire rate, modified by stage_delay_mult
+ activation_sounds = list('sound/weapons/gun_minigun.ogg')
+ /// Active firing time to reach max spin_stage.
+ var/spinup_time = 8 SECONDS
+ /// Grace period before losing spin_stage.
+ var/spindown_grace_time = 2 SECONDS
+ COOLDOWN_DECLARE(spindown_grace_cooldown)
+ /// Cooldown time to reach min spin_stage.
+ var/spindown_time = 3 SECONDS
+ /// Index of stage_rate.
+ var/spin_stage = 1
+ /// Shots fired per fire_delay at a particular spin_stage.
+ var/list/stage_rate = list(1, 1, 2, 2, 3, 3, 3, 4, 4, 4, 5)
+ /// Fire delay multiplier for current spin_stage.
+ var/stage_delay_mult = 1
+ /// When it was last fired, related to world.time.
+ var/last_fired = 0
-/obj/item/hardpoint/primary/minigun/fire(mob/user, atom/A)
+/obj/item/hardpoint/primary/minigun/set_fire_delay(value)
+ fire_delay = value
+ SEND_SIGNAL(src, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, fire_delay * stage_delay_mult)
- var/S = 'sound/weapons/vehicles/minigun_stop.ogg'
- //check how much time since last shot. 2 seconds are grace period before minigun starts to lose rotation momentum
- var/t = world.time - last_shot_time - 2 SECONDS
- t = round(t / 10)
- if(t > 0)
- chained_shots = max(chained_shots - t * 3, 1) //we lose 3 chained_shots per second
- else
- if(chained_shots < 11)
- chained_shots++
- S = 'sound/weapons/vehicles/minigun_loop.ogg'
+/obj/item/hardpoint/primary/minigun/set_fire_cooldown()
+ calculate_stage_delay_mult() //needs to check grace_cooldown before refreshed
+ last_fired = world.time
+ COOLDOWN_START(src, spindown_grace_cooldown, spindown_grace_time)
+ COOLDOWN_START(src, fire_cooldown, fire_delay * stage_delay_mult)
- if(chained_shots == 1)
- playsound(get_turf(src), 'sound/weapons/vehicles/minigun_start.ogg', 40, 1)
+/obj/item/hardpoint/primary/minigun/proc/calculate_stage_delay_mult()
+ var/stage_rate_len = stage_rate.len
+ var/delta_time = world.time - last_fired
- next_use = world.time + cooldown * owner.misc_multipliers["cooldown"]
-
- //how many rounds we will shoot in this burst
- if(chained_shots > LAZYLEN(chain_bursts)) //5 shots at maximum rotation
- t = 5
+ var/old_spin_stage = spin_stage
+ if(auto_firing || burst_firing) //spinup if continuing fire
+ var/delta_stage = delta_time * (stage_rate_len - 1)
+ spin_stage += delta_stage / spinup_time
+ else if(COOLDOWN_FINISHED(src, spindown_grace_cooldown)) //spindown if initiating fire after grace
+ var/delta_stage = (delta_time - spindown_grace_time) * (stage_rate_len - 1)
+ spin_stage -= delta_stage / spindown_time
else
- t = LAZYACCESS(chain_bursts, chained_shots)
- for(var/i = 1; i <= t; i++)
- var/atom/T = A
- if(!prob((accuracy * 100) / owner.misc_multipliers["accuracy"]))
- T = get_step(get_turf(T), pick(cardinal))
- fire_projectile(user, T)
- if(ammo.current_rounds <= 0)
- break
- sleep(2)
- to_chat(user, SPAN_WARNING("[src] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]"))
+ return
+ spin_stage = Clamp(spin_stage, 1, stage_rate_len)
+
+ var/old_stage_rate = stage_rate[Floor(old_spin_stage)]
+ var/new_stage_rate = stage_rate[Floor(spin_stage)]
- playsound(get_turf(src), S, 40, 1)
- last_shot_time = world.time
+ if(old_stage_rate != new_stage_rate)
+ stage_delay_mult = 1 / new_stage_rate
+ SEND_SIGNAL(src, COMSIG_GUN_AUTOFIREDELAY_MODIFIED, fire_delay * stage_delay_mult)
diff --git a/code/modules/vehicles/hardpoints/secondary/cupola.dm b/code/modules/vehicles/hardpoints/secondary/cupola.dm
index f1f8f23435..f259d6ea26 100644
--- a/code/modules/vehicles/hardpoints/secondary/cupola.dm
+++ b/code/modules/vehicles/hardpoints/secondary/cupola.dm
@@ -8,10 +8,7 @@
activation_sounds = list('sound/weapons/gun_smartgun1.ogg', 'sound/weapons/gun_smartgun2.ogg', 'sound/weapons/gun_smartgun3.ogg', 'sound/weapons/gun_smartgun4.ogg')
health = 350
- cooldown = 15
- accuracy = 0.9
firing_arc = 120
- var/burst_amount = 3
origins = list(0, -2)
@@ -25,27 +22,17 @@
"8" = list(-5, 7)
)
+ scatter = 3
+ gun_firemode = GUN_FIREMODE_BURSTFIRE
+ gun_firemode_list = list(
+ GUN_FIREMODE_BURSTFIRE,
+ )
+ burst_amount = 3
+ burst_delay = 0.3 SECONDS
+ extra_delay = 0.6 SECONDS
+
/obj/item/hardpoint/secondary/m56cupola/set_bullet_traits()
..()
LAZYADD(traits_to_give, list(
BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff)
))
-
-/obj/item/hardpoint/secondary/m56cupola/fire(mob/user, atom/A)
- if(ammo.current_rounds <= 0)
- return
-
- next_use = world.time + cooldown * owner.misc_multipliers["cooldown"]
-
- for(var/bullets_fired = 1, bullets_fired <= burst_amount, bullets_fired++)
- var/atom/T = A
- if(!prob((accuracy * 100) / owner.misc_multipliers["accuracy"]))
- T = get_step(get_turf(A), pick(cardinal))
- if(LAZYLEN(activation_sounds))
- playsound(get_turf(src), pick(activation_sounds), 60, 1)
- fire_projectile(user, T)
- if(ammo.current_rounds <= 0)
- break
- if(bullets_fired < burst_amount) //we need to sleep only if there are more bullets to shoot in the burst
- sleep(3)
- to_chat(user, SPAN_WARNING("[src] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]"))
diff --git a/code/modules/vehicles/hardpoints/secondary/flamer.dm b/code/modules/vehicles/hardpoints/secondary/flamer.dm
index 10f7453d8c..5557cfb24e 100644
--- a/code/modules/vehicles/hardpoints/secondary/flamer.dm
+++ b/code/modules/vehicles/hardpoints/secondary/flamer.dm
@@ -8,8 +8,6 @@
activation_sounds = list('sound/weapons/vehicles/flamethrower.ogg')
health = 300
- cooldown = 30
- accuracy = 0.68
firing_arc = 120
origins = list(0, -2)
@@ -28,31 +26,20 @@
"8" = list(-3, 18)
)
-/obj/item/hardpoint/secondary/small_flamer/fire_projectile(mob/user, atom/A)
- set waitfor = 0
-
- var/turf/origin_turf = get_turf(src)
- origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z)
- var/list/turf/turfs = getline2(origin_turf, A)
- var/distance = 0
- var/turf/prev_T
-
- for(var/turf/T in turfs)
- if(T == loc)
- prev_T = T
- continue
- if(!ammo.current_rounds) break
- if(distance >= max_range) break
- if(prev_T && LinkBlocked(prev_T, T))
- break
- ammo.current_rounds--
- flame_turf(T, user)
- distance++
- prev_T = T
- sleep(1)
-
-/obj/item/hardpoint/secondary/small_flamer/proc/flame_turf(turf/T, mob/user)
- if(!istype(T)) return
-
- if(!locate(/obj/flamer_fire) in T) // No stacking flames!
- new/obj/flamer_fire(T, create_cause_data(initial(name), user))
+ scatter = 6
+ fire_delay = 3.0 SECONDS
+
+/obj/item/hardpoint/secondary/small_flamer/handle_fire(atom/target, mob/living/user, params)
+ var/turf/origin_turf = get_origin_turf()
+
+ var/distance = get_dist(origin_turf, get_turf(target))
+ var/fire_amount = min(ammo.current_rounds, distance+1, max_range)
+ ammo.current_rounds -= fire_amount
+
+ new /obj/flamer_fire(origin_turf, create_cause_data(initial(name), user), null, fire_amount, null, FLAMESHAPE_LINE, target, CALLBACK(src, PROC_REF(display_ammo), user))
+
+ play_firing_sounds()
+
+ COOLDOWN_START(src, fire_cooldown, fire_delay)
+
+ return AUTOFIRE_CONTINUE
diff --git a/code/modules/vehicles/hardpoints/secondary/frontal_cannon.dm b/code/modules/vehicles/hardpoints/secondary/frontal_cannon.dm
index c7600059d9..f80a1e81af 100644
--- a/code/modules/vehicles/hardpoints/secondary/frontal_cannon.dm
+++ b/code/modules/vehicles/hardpoints/secondary/frontal_cannon.dm
@@ -11,10 +11,7 @@
damage_multiplier = 0.11
health = 350
- cooldown = 16
- accuracy = 0.8
firing_arc = 120
- var/burst_amount = 4
origins = list(0, -2)
@@ -34,27 +31,15 @@
"8" = list(-62, -26)
)
+ scatter = 4
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ gun_firemode_list = list(
+ GUN_FIREMODE_AUTOMATIC,
+ )
+ fire_delay = 0.3 SECONDS
+
/obj/item/hardpoint/secondary/frontalcannon/set_bullet_traits()
..()
LAZYADD(traits_to_give, list(
BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff)
))
-
-/obj/item/hardpoint/secondary/frontalcannon/fire(mob/user, atom/A)
- if(ammo.current_rounds <= 0)
- return
-
- next_use = world.time + cooldown * owner.misc_multipliers["cooldown"]
-
- for(var/bullets_fired = 1, bullets_fired <= burst_amount, bullets_fired++)
- var/atom/T = A
- if(!prob((accuracy * 100) / owner.misc_multipliers["accuracy"]))
- T = get_step(get_turf(A), pick(cardinal))
- if(LAZYLEN(activation_sounds))
- playsound(get_turf(src), pick(activation_sounds), 60, 1)
- fire_projectile(user, T)
- if(ammo.current_rounds <= 0)
- break
- if(bullets_fired < burst_amount) //we need to sleep only if there are more bullets to shoot in the burst
- sleep(3)
- to_chat(user, SPAN_WARNING("[src] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)] | Mags: [SPAN_HELPFUL(LAZYLEN(backup_clips))]/[SPAN_HELPFUL(max_clips)]"))
diff --git a/code/modules/vehicles/hardpoints/secondary/grenade_launcher.dm b/code/modules/vehicles/hardpoints/secondary/grenade_launcher.dm
index 8151a1ee50..efd151e93c 100644
--- a/code/modules/vehicles/hardpoints/secondary/grenade_launcher.dm
+++ b/code/modules/vehicles/hardpoints/secondary/grenade_launcher.dm
@@ -8,8 +8,6 @@
activation_sounds = list('sound/weapons/gun_m92_attachable.ogg')
health = 500
- cooldown = 30
- accuracy = 0.4
firing_arc = 90
var/max_range = 7
@@ -27,40 +25,19 @@
"8" = list(-6, 17)
)
+ scatter = 10
+ fire_delay = 3.0 SECONDS
+
/obj/item/hardpoint/secondary/grenade_launcher/set_bullet_traits()
..()
LAZYADD(traits_to_give, list(
BULLET_TRAIT_ENTRY(/datum/element/bullet_trait_iff)
))
-/obj/item/hardpoint/secondary/grenade_launcher/can_activate(mob/user, atom/A)
- if(!..())
- return FALSE
-
- var/turf/origin_turf = get_turf(src)
- origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z)
- if(get_dist(origin_turf, A) < 1)
- to_chat(usr, SPAN_WARNING("The target is too close."))
- return FALSE
-
- return TRUE
-
-/obj/item/hardpoint/secondary/grenade_launcher/fire_projectile(mob/user, atom/A)
- set waitfor = 0
-
- var/turf/origin_turf = get_turf(src)
- origin_turf = locate(origin_turf.x + origins[1], origin_turf.y + origins[2], origin_turf.z)
-
- //getting distance between supposed target and tank center.
- var/range = get_dist(origin_turf, A) + 1 //otherwise nade falls one tile shorter
- if(range > max_range)
- range = max_range
-
- var/obj/projectile/P = generate_bullet(user, origin_turf)
- SEND_SIGNAL(P, COMSIG_BULLET_USER_EFFECTS, owner.seats[VEHICLE_GUNNER])
- P.fire_at(A, owner.seats[VEHICLE_GUNNER], src, P.ammo.max_range, P.ammo.shell_speed)
-
- if(use_muzzle_flash)
- muzzle_flash(Get_Angle(owner, A))
+/obj/item/hardpoint/secondary/grenade_launcher/try_fire(mob/user, atom/A)
+ var/turf/origin_turf = get_origin_turf()
+ if(origin_turf == get_turf(A))
+ to_chat(user, SPAN_WARNING("The target is too close."))
+ return NONE
- ammo.current_rounds--
+ return ..()
diff --git a/code/modules/vehicles/hardpoints/secondary/tow.dm b/code/modules/vehicles/hardpoints/secondary/tow.dm
index 4bdbc6f417..7c58f7970c 100644
--- a/code/modules/vehicles/hardpoints/secondary/tow.dm
+++ b/code/modules/vehicles/hardpoints/secondary/tow.dm
@@ -7,8 +7,6 @@
disp_icon_state = "towlauncher"
health = 500
- cooldown = 150
- accuracy = 0.8
firing_arc = 60
origins = list(0, -2)
@@ -29,3 +27,7 @@
"4" = list(5, -8),
"8" = list(-5, 10)
)
+
+ scatter = 4
+ fire_delay = 15.0 SECONDS
+
diff --git a/code/modules/vehicles/hardpoints/special/firing_port_weapon.dm b/code/modules/vehicles/hardpoints/special/firing_port_weapon.dm
index 9310556ee9..780c195f00 100644
--- a/code/modules/vehicles/hardpoints/special/firing_port_weapon.dm
+++ b/code/modules/vehicles/hardpoints/special/firing_port_weapon.dm
@@ -10,10 +10,7 @@
activation_sounds = list('sound/weapons/gun_smartgun1.ogg', 'sound/weapons/gun_smartgun2.ogg', 'sound/weapons/gun_smartgun3.ogg', 'sound/weapons/gun_smartgun4.ogg')
health = 100
- cooldown = 10
- accuracy = 0.9
firing_arc = 120
- var/burst_amount = 3
//FPWs reload automatically
var/reloading = FALSE
var/reload_time = 10 SECONDS
@@ -30,6 +27,13 @@
underlayer_north_muzzleflash = TRUE
+ scatter = 3
+ gun_firemode = GUN_FIREMODE_AUTOMATIC
+ gun_firemode_list = list(
+ GUN_FIREMODE_AUTOMATIC,
+ )
+ fire_delay = 0.3 SECONDS
+
/obj/item/hardpoint/special/firing_port_weapon/set_bullet_traits()
..()
LAZYADD(traits_to_give, list(
@@ -49,46 +53,6 @@
return data
-
-/obj/item/hardpoint/special/firing_port_weapon/can_activate(mob/user, atom/A)
- if(!owner)
- return FALSE
-
- var/seat = owner.get_mob_seat(user)
- if(!seat)
- return FALSE
-
- if(seat != allowed_seat)
- to_chat(user, SPAN_WARNING("Only [allowed_seat] can use [name]."))
- return FALSE
-
- //FPW stop working at 50% hull
- if(owner.health < initial(owner.health) * 0.5)
- to_chat(user, SPAN_WARNING("\The [owner]'s hull is too damaged!"))
- return FALSE
-
- if(world.time < next_use)
- if(cooldown >= 20) //filter out guns with high firerate to prevent message spam.
- to_chat(user, SPAN_WARNING("You need to wait [SPAN_HELPFUL((next_use - world.time) / 10)] seconds before [name] can be used again."))
- return FALSE
-
- if(reloading)
- to_chat(user, SPAN_NOTICE("\The [name] is reloading. Wait [SPAN_HELPFUL("[((reload_time_started + reload_time - world.time) / 10)]")] seconds."))
- return FALSE
-
- if(ammo && ammo.current_rounds <= 0)
- if(reloading)
- to_chat(user, SPAN_WARNING("\The [name] is out of ammo! You have to wait [(reload_time_started + reload_time - world.time) / 10] seconds before it reloads!"))
- else
- start_auto_reload(user)
- return FALSE
-
- if(!in_firing_arc(A))
- to_chat(user, SPAN_WARNING("The target is not within your firing arc!"))
- return FALSE
-
- return TRUE
-
/obj/item/hardpoint/special/firing_port_weapon/reload(mob/user)
if(!ammo)
ammo = new /obj/item/ammo_magazine/hardpoint/firing_port_weapon
@@ -116,27 +80,32 @@
to_chat(user, SPAN_NOTICE("\The [name] reloads automatically."))
return FALSE
+/obj/item/hardpoint/special/firing_port_weapon/try_fire(atom/target, mob/living/user, params)
+ if(!owner)
+ return NONE
+
+ //FPW stop working at 50% hull
+ if(owner.health < initial(owner.health) * 0.5)
+ to_chat(user, SPAN_WARNING("\The [owner]'s hull is too damaged!"))
+ return NONE
-/obj/item/hardpoint/special/firing_port_weapon/fire(mob/user, atom/A)
if(user.get_active_hand())
to_chat(user, SPAN_WARNING("You need a free hand to use \the [name]."))
- return
+ return NONE
- if(ammo.current_rounds <= 0)
- start_auto_reload(user)
- return
+ if(reloading)
+ to_chat(user, SPAN_NOTICE("\The [name] is reloading. Wait [SPAN_HELPFUL("[((reload_time_started + reload_time - world.time) / 10)]")] seconds."))
+ return NONE
+
+ if(ammo && ammo.current_rounds <= 0)
+ if(reloading)
+ to_chat(user, SPAN_WARNING("\The [name] is out of ammo! You have to wait [(reload_time_started + reload_time - world.time) / 10] seconds before it reloads!"))
+ else
+ start_auto_reload(user)
+ return NONE
+
+ if(!in_firing_arc(target))
+ to_chat(user, SPAN_WARNING("The target is not within your firing arc!"))
+ return NONE
- next_use = world.time + cooldown * owner.misc_multipliers["cooldown"]
-
- for(var/bullets_fired = 1, bullets_fired <= burst_amount, bullets_fired++)
- var/atom/T = A
- if(!prob((accuracy * 100) / owner.misc_multipliers["accuracy"]))
- T = get_step(get_turf(A), pick(cardinal))
- if(LAZYLEN(activation_sounds))
- playsound(get_turf(src), pick(activation_sounds), 60, 1)
- fire_projectile(user, T)
- if(ammo.current_rounds <= 0)
- break
- if(bullets_fired < burst_amount) //we need to sleep only if there are more bullets to shoot in the burst
- sleep(3)
- to_chat(user, SPAN_WARNING("[src] Ammo: [SPAN_HELPFUL(ammo ? ammo.current_rounds : 0)]/[SPAN_HELPFUL(ammo ? ammo.max_rounds : 0)]"))
+ return handle_fire(target, user, params)
diff --git a/code/modules/vehicles/hardpoints/support/artillery.dm b/code/modules/vehicles/hardpoints/support/artillery.dm
index 441817107e..62f977ad32 100644
--- a/code/modules/vehicles/hardpoints/support/artillery.dm
+++ b/code/modules/vehicles/hardpoints/support/artillery.dm
@@ -14,7 +14,7 @@
var/view_buff = 10 //This way you can VV for more or less fun
var/view_tile_offset = 7
-/obj/item/hardpoint/support/artillery_module/activate(mob/user, atom/A)
+/obj/item/hardpoint/support/artillery_module/handle_fire(atom/target, mob/living/user, params)
if(!user.client)
return
@@ -62,8 +62,9 @@
user.client.pixel_y = 0
is_active = FALSE
-/obj/item/hardpoint/support/artillery_module/can_activate()
+/obj/item/hardpoint/support/artillery_module/try_fire(target, user, params)
if(health <= 0)
to_chat(usr, SPAN_WARNING("\The [src] is broken!"))
- return FALSE
- return TRUE
+ return NONE
+
+ return handle_fire(target, user, params)
diff --git a/code/modules/vehicles/hardpoints/support/flare.dm b/code/modules/vehicles/hardpoints/support/flare.dm
index 2cee40064f..186b6bbaf5 100644
--- a/code/modules/vehicles/hardpoints/support/flare.dm
+++ b/code/modules/vehicles/hardpoints/support/flare.dm
@@ -13,8 +13,6 @@
activatable = TRUE
health = 500
- cooldown = 30
- accuracy = 0.7
firing_arc = 120
origins = list(0, -2)
@@ -35,6 +33,9 @@
"8" = list(14, -6)
)
+ scatter = 6
+ fire_delay = 3.0 SECONDS
+
/obj/item/hardpoint/support/flare_launcher/set_bullet_traits()
..()
LAZYADD(traits_to_give, list(
diff --git a/code/modules/vehicles/interior/interactable/seats.dm b/code/modules/vehicles/interior/interactable/seats.dm
index 2984adda91..017b9e6b58 100644
--- a/code/modules/vehicles/interior/interactable/seats.dm
+++ b/code/modules/vehicles/interior/interactable/seats.dm
@@ -40,8 +40,8 @@
return
if(QDELETED(buckled_mob))
- vehicle.set_seated_mob(seat, null)
M.unset_interaction()
+ vehicle.set_seated_mob(seat, null)
if(M.client)
M.client.change_view(world_view_size, vehicle)
M.client.pixel_x = 0
@@ -174,8 +174,8 @@
return
if(QDELETED(buckled_mob))
- vehicle.set_seated_mob(seat, null)
M.unset_interaction()
+ vehicle.set_seated_mob(seat, null)
if(M.client)
M.client.change_view(world_view_size, vehicle)
M.client.pixel_x = 0
@@ -252,8 +252,8 @@
return
if(QDELETED(buckled_mob))
- vehicle.set_seated_mob(seat, null)
M.unset_interaction()
+ vehicle.set_seated_mob(seat, null)
if(M.client)
M.client.change_view(world_view_size, vehicle)
M.client.pixel_x = 0
diff --git a/code/modules/vehicles/multitile/multitile.dm b/code/modules/vehicles/multitile/multitile.dm
index 3eb03c5cb2..d86555d5b0 100644
--- a/code/modules/vehicles/multitile/multitile.dm
+++ b/code/modules/vehicles/multitile/multitile.dm
@@ -342,15 +342,24 @@
M.reset_view(src)
give_action(M, /datum/action/human_action/vehicle_unbuckle)
+/// Get crewmember of seat.
/obj/vehicle/multitile/proc/get_seat_mob(seat)
return seats[seat]
+/// Get seat of crewmember.
/obj/vehicle/multitile/proc/get_mob_seat(mob/M)
for(var/seat in seats)
if(seats[seat] == M)
return seat
return null
+/// Get active hardpoint of crewmember.
+/obj/vehicle/multitile/proc/get_mob_hp(mob/crew)
+ var/seat = get_mob_seat(crew)
+ if(seat)
+ return active_hp[seat]
+ return null
+
/obj/vehicle/multitile/proc/get_passengers()
if(interior)
return interior.get_passengers()
diff --git a/code/modules/vehicles/multitile/multitile_hardpoints.dm b/code/modules/vehicles/multitile/multitile_hardpoints.dm
index b8edba78da..949cc29b80 100644
--- a/code/modules/vehicles/multitile/multitile_hardpoints.dm
+++ b/code/modules/vehicles/multitile/multitile_hardpoints.dm
@@ -234,47 +234,3 @@
qdel(old)
update_icon()
-
-//proc that fires non selected weaponry
-/obj/vehicle/multitile/proc/shoot_other_weapon(mob/living/carbon/human/M, seat, atom/A)
-
- if(!istype(M))
- return
-
- var/list/usable_hps = get_hardpoints_with_ammo(seat)
- for(var/obj/item/hardpoint/HP in usable_hps)
- if(HP == active_hp[seat] || HP.slot != HDPT_PRIMARY && HP.slot != HDPT_SECONDARY)
- usable_hps.Remove(HP)
-
- if(!LAZYLEN(usable_hps))
- to_chat(M, SPAN_WARNING("No other working weapons detected."))
- return
-
- for(var/obj/item/hardpoint/HP in usable_hps)
- if(!HP.can_activate(M, A))
- return
- HP.activate(M, A)
- break
- return
-
-//proc that activates support module if it can be activated and you meet requirements
-/obj/vehicle/multitile/proc/activate_support_module(mob/living/carbon/human/M, seat, atom/A)
-
- if(!istype(M))
- return
-
- var/list/usable_hps = get_activatable_hardpoints(seat)
- for(var/obj/item/hardpoint/HP in usable_hps)
- if(HP.slot != HDPT_SUPPORT)
- usable_hps.Remove(HP)
-
- if(!LAZYLEN(usable_hps))
- to_chat(M, SPAN_WARNING("No activatable support modules detected."))
- return
-
- for(var/obj/item/hardpoint/HP in usable_hps)
- if(!HP.can_activate(M, A))
- return
- HP.activate(M, A)
- break
- return
diff --git a/code/modules/vehicles/multitile/multitile_interaction.dm b/code/modules/vehicles/multitile/multitile_interaction.dm
index c4f1ed2d3d..466db72102 100644
--- a/code/modules/vehicles/multitile/multitile_interaction.dm
+++ b/code/modules/vehicles/multitile/multitile_interaction.dm
@@ -337,80 +337,61 @@
healthcheck()
-/obj/vehicle/multitile/handle_click(mob/living/user, atom/A, list/mods)
-
- var/seat
- for(var/vehicle_seat in seats)
- if(seats[vehicle_seat] == user)
- seat = vehicle_seat
- break
-
- if(istype(A, /atom/movable/screen) || !seat)
+/obj/vehicle/multitile/on_set_interaction(mob/user)
+ RegisterSignal(user, COMSIG_MOB_MOUSEDOWN, PROC_REF(crew_mousedown))
+ RegisterSignal(user, COMSIG_MOB_MOUSEDRAG, PROC_REF(crew_mousedrag))
+ RegisterSignal(user, COMSIG_MOB_MOUSEUP, PROC_REF(crew_mouseup))
+
+/obj/vehicle/multitile/on_unset_interaction(mob/user)
+ UnregisterSignal(user, list(COMSIG_MOB_MOUSEUP, COMSIG_MOB_MOUSEDOWN, COMSIG_MOB_MOUSEDRAG))
+
+ var/obj/item/hardpoint/hardpoint = get_mob_hp(user)
+ if(hardpoint)
+ SEND_SIGNAL(hardpoint, COMSIG_GUN_INTERRUPT_FIRE) //abort fire when crew leaves
+
+/// Relays crew mouse release to active hardpoint.
+/obj/vehicle/multitile/proc/crew_mouseup(datum/source, atom/object, turf/location, control, params)
+ SIGNAL_HANDLER
+ var/obj/item/hardpoint/hardpoint = get_mob_hp(source)
+ if(!hardpoint)
return
- if(seat == VEHICLE_DRIVER)
- if(mods["shift"] && !mods["alt"])
- A.examine(user)
- return
-
- if(mods["ctrl"] && !mods["alt"])
- activate_horn()
- return
-
- var/obj/item/hardpoint/HP = active_hp[seat]
- if(!HP)
- to_chat(user, SPAN_WARNING("Please select an active hardpoint first."))
- return
-
- if(!HP.can_activate(user, A))
- return
-
- HP.activate(user, A)
-
- if(seat == VEHICLE_GUNNER)
- if(mods["shift"] && !mods["middle"])
- if(vehicle_flags & VEHICLE_TOGGLE_SHIFT_CLICK_GUNNER)
- shoot_other_weapon(user, seat, A)
- else
- A.examine(user)
- return
- if(mods["middle"] && !mods["shift"])
- if(!(vehicle_flags & VEHICLE_TOGGLE_SHIFT_CLICK_GUNNER))
- shoot_other_weapon(user, seat, A)
- return
- if(mods["alt"])
- toggle_gyrostabilizer()
- return
- if(mods["ctrl"])
- activate_support_module(user, seat, A)
- return
+ hardpoint.stop_fire(source, object, location, control, params)
- var/obj/item/hardpoint/HP = active_hp[seat]
- if(!HP)
- to_chat(user, SPAN_WARNING("Please select an active hardpoint first."))
- return
+/// Relays crew mouse movement to active hardpoint.
+/obj/vehicle/multitile/proc/crew_mousedrag(datum/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params)
+ SIGNAL_HANDLER
+ var/obj/item/hardpoint/hardpoint = get_mob_hp(source)
+ if(!hardpoint)
+ return
- if(!HP.can_activate(user, A))
- return
+ hardpoint.change_target(source, src_object, over_object, src_location, over_location, src_control, over_control, params)
- HP.activate(user, A)
+/// Checks for special control keybinds, else relays crew mouse press to active hardpoint.
+/obj/vehicle/multitile/proc/crew_mousedown(datum/source, atom/object, turf/location, control, params)
+ SIGNAL_HANDLER
- if(seat == VEHICLE_SUPPORT_GUNNER_ONE || seat == VEHICLE_SUPPORT_GUNNER_TWO)
- if(mods["shift"])
- A.examine(user)
- return
- if(mods["middle"] || mods["alt"] || mods["ctrl"])
- return
+ var/list/modifiers = params2list(params)
+ if(modifiers[SHIFT_CLICK] || modifiers[MIDDLE_CLICK] || modifiers[RIGHT_CLICK]) //don't step on examine, point, etc
+ return
- var/obj/item/hardpoint/HP = active_hp[seat]
- if(!HP)
- to_chat(user, SPAN_WARNING("Please select an active hardpoint first."))
- return
+ var/seat = get_mob_seat(source)
+ switch(seat)
+ if(VEHICLE_DRIVER)
+ if(modifiers[LEFT_CLICK] && modifiers[CTRL_CLICK])
+ activate_horn()
+ return
+ if(VEHICLE_GUNNER)
+ if(modifiers[LEFT_CLICK] && modifiers[ALT_CLICK])
+ toggle_gyrostabilizer()
+ return
- if(!HP.can_activate(user, A))
- return
+ var/obj/item/hardpoint/hardpoint = get_mob_hp(source)
+ if(!hardpoint)
+ to_chat(source, SPAN_WARNING("Please select an active hardpoint first."))
+ return
- HP.activate(user, A)
+ hardpoint.start_fire(source, object, location, control, params)
/obj/vehicle/multitile/proc/handle_player_entrance(mob/M)
if(!M || M.client == null) return
diff --git a/code/modules/vehicles/multitile/multitile_verbs.dm b/code/modules/vehicles/multitile/multitile_verbs.dm
index c7dd29bbf0..3801cd2e17 100644
--- a/code/modules/vehicles/multitile/multitile_verbs.dm
+++ b/code/modules/vehicles/multitile/multitile_verbs.dm
@@ -30,6 +30,10 @@
if(!HP)
return
+ var/obj/item/hardpoint/old_HP = V.active_hp[seat]
+ if(old_HP)
+ SEND_SIGNAL(old_HP, COMSIG_GUN_INTERRUPT_FIRE) //stop fire when switching away from HP
+
V.active_hp[seat] = HP
var/msg = "You select \the [HP]."
if(HP.ammo)
@@ -66,6 +70,10 @@
if(!HP)
return
+ var/obj/item/hardpoint/old_HP = V.active_hp[seat]
+ if(old_HP)
+ SEND_SIGNAL(old_HP, COMSIG_GUN_INTERRUPT_FIRE) //stop fire when switching away from HP
+
V.active_hp[seat] = HP
var/msg = "You select \the [HP]."
if(HP.ammo)
@@ -225,10 +233,7 @@
3. \"G: Toggle Turret Gyrostabilizer\" - toggles Turret Gyrostabilizer allowing it to keep current direction ignoring hull turning. (Exists only on vehicles with rotating turret, e.g. M34A2 Longstreet Light Tank)
\
Support Gunner verbs:
1. \"Reload Firing Port Weapon\" - initiates automated reloading process for M56 FPW. Requires a confirmation.
\
Driver shortcuts:
1. \"CTRL + Click\" - activates vehicle horn.
\
- Gunner shortcuts:
1. \"ALT + Click\" - toggles Turret Gyrostabilizer. (Exists only on vehicles with rotating turret, e.g. M34A2 Longstreet Light Tank)
\
- 2. \"CTRL + Click\" - activates not destroyed activatable support module.
\
- 3. \"Middle Mouse Button Click (MMB)\" - default shortcut to shoot currently not selected weapon if possible. Won't work if SHIFT + Click firing is toggled ON.
\
- 4. \"SHIFT + Click\" - examines target as usual, unless \"G: Toggle Middle/Shift Clicking\" verb was used to toggle SHIFT + Click firing ON. In this case, it will fire currently not selected weapon if possible.
"
+ Gunner shortcuts:
1. \"ALT + Click\" - toggles Turret Gyrostabilizer. (Exists only on vehicles with rotating turret, e.g. M34A2 Longstreet Light Tank)
"
show_browser(user, dat, "Vehicle Controls Guide", "vehicle_help", "size=900x500")
onclose(user, "vehicle_help")
diff --git a/icons/mob/humans/onmob/feet.dmi b/icons/mob/humans/onmob/feet.dmi
index 17b4073c74..e0611d5b7e 100644
Binary files a/icons/mob/humans/onmob/feet.dmi and b/icons/mob/humans/onmob/feet.dmi differ
diff --git a/icons/mob/humans/onmob/hands.dmi b/icons/mob/humans/onmob/hands.dmi
index d8fc38fff8..437da5250e 100644
Binary files a/icons/mob/humans/onmob/hands.dmi and b/icons/mob/humans/onmob/hands.dmi differ
diff --git a/icons/mob/humans/onmob/head_0.dmi b/icons/mob/humans/onmob/head_0.dmi
index 51cad85586..b4475e9a8a 100644
Binary files a/icons/mob/humans/onmob/head_0.dmi and b/icons/mob/humans/onmob/head_0.dmi differ
diff --git a/icons/mob/humans/onmob/suit_0.dmi b/icons/mob/humans/onmob/suit_0.dmi
index d0f816e2b7..1a5e66ba66 100644
Binary files a/icons/mob/humans/onmob/suit_0.dmi and b/icons/mob/humans/onmob/suit_0.dmi differ
diff --git a/icons/mob/humans/onmob/suit_1.dmi b/icons/mob/humans/onmob/suit_1.dmi
index 636bbf8b9d..c05e998cb1 100644
Binary files a/icons/mob/humans/onmob/suit_1.dmi and b/icons/mob/humans/onmob/suit_1.dmi differ
diff --git a/icons/mob/humans/onmob/ties.dmi b/icons/mob/humans/onmob/ties.dmi
index 8f9940f639..844c0e98a1 100644
Binary files a/icons/mob/humans/onmob/ties.dmi and b/icons/mob/humans/onmob/ties.dmi differ
diff --git a/icons/mob/humans/onmob/uniform_0.dmi b/icons/mob/humans/onmob/uniform_0.dmi
index 40305b9413..fd6e4a335f 100644
Binary files a/icons/mob/humans/onmob/uniform_0.dmi and b/icons/mob/humans/onmob/uniform_0.dmi differ
diff --git a/icons/mob/humans/onmob/uniform_1.dmi b/icons/mob/humans/onmob/uniform_1.dmi
index ae84c1a1b9..5cbf84ee36 100644
Binary files a/icons/mob/humans/onmob/uniform_1.dmi and b/icons/mob/humans/onmob/uniform_1.dmi differ
diff --git a/icons/obj/items/clothing/cm_suits.dmi b/icons/obj/items/clothing/cm_suits.dmi
index 162d66a2f0..85cd95d5e5 100644
Binary files a/icons/obj/items/clothing/cm_suits.dmi and b/icons/obj/items/clothing/cm_suits.dmi differ
diff --git a/icons/obj/items/clothing/hats.dmi b/icons/obj/items/clothing/hats.dmi
index a6a0e6fb90..e94b17f2da 100644
Binary files a/icons/obj/items/clothing/hats.dmi and b/icons/obj/items/clothing/hats.dmi differ
diff --git a/icons/obj/items/clothing/shoes.dmi b/icons/obj/items/clothing/shoes.dmi
index 4d99b2ea4b..c4e01786e5 100644
Binary files a/icons/obj/items/clothing/shoes.dmi and b/icons/obj/items/clothing/shoes.dmi differ
diff --git a/icons/obj/items/clothing/suits.dmi b/icons/obj/items/clothing/suits.dmi
index 10fbfff30d..e74c16d703 100644
Binary files a/icons/obj/items/clothing/suits.dmi and b/icons/obj/items/clothing/suits.dmi differ
diff --git a/icons/obj/items/clothing/ties.dmi b/icons/obj/items/clothing/ties.dmi
index b02ff9c253..f29883cc87 100644
Binary files a/icons/obj/items/clothing/ties.dmi and b/icons/obj/items/clothing/ties.dmi differ
diff --git a/icons/obj/items/clothing/uniforms.dmi b/icons/obj/items/clothing/uniforms.dmi
index f05eb3671f..26fb112ea0 100644
Binary files a/icons/obj/items/clothing/uniforms.dmi and b/icons/obj/items/clothing/uniforms.dmi differ