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