diff --git a/.vscode/settings.json b/.vscode/settings.json index 201562aaf7..c7b218b775 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -9,7 +9,7 @@ "**/.pnp.*": true }, "editor.codeActionsOnSave": { - "source.fixAll.eslint": true + "source.fixAll.eslint": "explicit" }, "files.eol": "\n", "files.insertFinalNewline": true, diff --git a/code/__DEFINES/dcs/flags.dm b/code/__DEFINES/dcs/flags.dm index 59d13ef35b..9e185570c5 100644 --- a/code/__DEFINES/dcs/flags.dm +++ b/code/__DEFINES/dcs/flags.dm @@ -4,6 +4,8 @@ #define COMPONENT_INCOMPATIBLE 1 /// Returned in PostTransfer to prevent transfer, similar to `COMPONENT_INCOMPATIBLE` #define COMPONENT_NOTRANSFER 2 +/// Same as COMPONENT_INCOMPATIBLE just it won't error +#define COMPONENT_INCOMPATIBLE_NO_ERROR 3 /// Return value to cancel attaching #define ELEMENT_INCOMPATIBLE 1 diff --git a/code/__DEFINES/dcs/signals/atom/signals_item.dm b/code/__DEFINES/dcs/signals/atom/signals_item.dm index 532437e4a0..96b81129d2 100644 --- a/code/__DEFINES/dcs/signals/atom/signals_item.dm +++ b/code/__DEFINES/dcs/signals/atom/signals_item.dm @@ -15,6 +15,11 @@ ///from base of obj/item/dropped(): (mob/user) #define COMSIG_ITEM_DROPPED "item_drop" + +///from base of /mob/living/carbon/human/equip_to_slot_if_possible : (/obj/item/equipping_item, mob/living/carbon/human/user, slot) +#define COMSIG_ITEM_ATTEMPTING_HUMAN_EQUIP "item_attempting_human_equip" + #define COMPONENT_ITEM_CANCEL_ATTEMPTING_HUMAN_EQUIP (1<<0) + /// From base of /obj/item/proc/equipped(): (mob/user, slot) #define COMSIG_ITEM_EQUIPPED "item_equipped" /// From base of /obj/item/proc/unequipped(): (mob/user, slot) diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index c998bd5525..a99d38796d 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -49,10 +49,15 @@ /datum/component/New(list/raw_args) parent = raw_args[1] var/list/arguments = raw_args.Copy(2) - if(Initialize(arglist(arguments)) == COMPONENT_INCOMPATIBLE) - stack_trace("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]") - qdel(src, TRUE, TRUE) - return + var/returned_value = Initialize(arglist(arguments)) + switch(returned_value) + if(COMPONENT_INCOMPATIBLE) + stack_trace("Incompatible [type] assigned to a [parent.type]! args: [json_encode(arguments)]") + qdel(src, TRUE, TRUE) + return + if(COMPONENT_INCOMPATIBLE_NO_ERROR) + qdel(src, TRUE, TRUE) + return _JoinParent(parent) diff --git a/code/datums/components/attached_headset.dm b/code/datums/components/attached_headset.dm new file mode 100644 index 0000000000..e140af6c8f --- /dev/null +++ b/code/datums/components/attached_headset.dm @@ -0,0 +1,146 @@ +#define DEFAULT_HEADSET_SLOT WEAR_L_EAR +#define ICON_HEADSET_SUFFIX "_hs" + +/datum/component/attached_headset + dupe_mode = COMPONENT_DUPE_UNIQUE + + /// The slot the parent is equipped to that activates the headset + var/parent_activation_slot + + /// The headset that is attached to the parent + var/obj/item/device/radio/headset/headset + + /// The version of our parent that is actually useful + var/obj/item/item_parent + + /// Holds the variables initial icon state before adding the headset + var/parent_initial_icon_state + +/datum/component/attached_headset/Initialize(mob/user, obj/item/device/radio/headset/headset, activation_slot) + . = ..() + + if(!istype(parent, /obj)) + return COMPONENT_INCOMPATIBLE + + item_parent = parent + + if(!icon_exists(item_parent.icon, item_parent.icon_state + "_hs", FALSE)) + if(user) + to_chat(user, SPAN_NOTICE("[headset] doesn't seem to support an integrated headset.")) + return COMPONENT_INCOMPATIBLE_NO_ERROR + + if(!activation_slot) + return COMPONENT_INCOMPATIBLE + + src.headset = headset + parent_activation_slot = activation_slot + + if(user) + user.drop_inv_item_on_ground(headset) + to_chat(user, SPAN_NOTICE("You attach [headset] to [parent].")) + playsound(user, 'sound/effects/gunrustle1.ogg', 20, TRUE) + + headset.moveToNullspace() + + parent_initial_icon_state = item_parent.icon_state + item_parent.icon_state = parent_initial_icon_state + ICON_HEADSET_SUFFIX + +/datum/component/attached_headset/Destroy() + . = ..() + if(!QDELETED(headset) && !headset.loc) + qdel(headset) + + headset = null + + if(parent_initial_icon_state) + item_parent.icon_state = parent_initial_icon_state + + item_parent = null + +/datum/component/attached_headset/RegisterWithParent() + . = ..() + RegisterSignal(parent, COMSIG_ITEM_ATTEMPTING_HUMAN_EQUIP, PROC_REF(on_attempted_equip)) + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(on_equipped)) + RegisterSignal(parent, COMSIG_ITEM_ATTACKED, PROC_REF(attackby)) + RegisterSignal(parent, COMSIG_ITEM_DROPPED, PROC_REF(dropped)) + RegisterSignal(headset, COMSIG_PARENT_QDELETING, PROC_REF(headset_deletion)) + +/datum/component/attached_headset/UnregisterFromParent() + UnregisterSignal(parent, COMSIG_ITEM_ATTEMPTING_HUMAN_EQUIP) + UnregisterSignal(parent, COMSIG_ITEM_EQUIPPED) + UnregisterSignal(parent, COMSIG_ITEM_ATTACKED) + UnregisterSignal(parent, COMSIG_ITEM_DROPPED) + UnregisterSignal(headset, COMSIG_PARENT_QDELETING) + . = ..() + +/datum/component/attached_headset/InheritComponent(datum/component/C, i_am_original) + if(!istype(item_parent.loc, /mob)) + return + + var/mob/user = item_parent.loc + to_chat(user, SPAN_NOTICE("[parent] already has [headset] attached to it. Looks like you could remove it with a screwdriver.")) + +/// Cancels equipping parent if there's a headset already on the left ear +/datum/component/attached_headset/proc/on_attempted_equip(obj/item/equipping_item, mob/living/carbon/human/user, slot) + SIGNAL_HANDLER + + if(slot != parent_activation_slot) + return + + if(user.wear_l_ear || istype(user.wear_r_ear, /obj/item/device/radio/headset)) + to_chat(user, SPAN_NOTICE("[equipping_item] has [headset] attached to it. It can't fit while you're wearing [user.wear_l_ear ? user.wear_l_ear : user.wear_r_ear].")) + return COMPONENT_ITEM_CANCEL_ATTEMPTING_HUMAN_EQUIP + +/// When parent is equipped we check if it's the right slot, if so then we deploy our headset +/datum/component/attached_headset/proc/on_equipped(obj/item/equipping_item, mob/user, slot) + SIGNAL_HANDLER + + if(slot != parent_activation_slot) + return + + if(!user.equip_to_slot_if_possible(headset, DEFAULT_HEADSET_SLOT)) + to_chat(user, SPAN_NOTICE("[headset] breaks off of [equipping_item] due to being unable to fit.")) + headset.forceMove(user.loc) + qdel(src) + return + + headset.flags_item |= NODROP + +/// When parent is dropped we make sure the headset is where it should be +/datum/component/attached_headset/proc/dropped(obj/item/dropped_item, mob/user) + if(!(headset in user)) + if(headset.loc) + qdel(headset) + qdel(src) + stack_trace("An attached headset was not on a mob but somehow not in nullspace.") + return + + headset.flags_item &= ~NODROP + user.drop_inv_item_on_ground(headset) + headset.moveToNullspace() + +/// When attacked by a screwdriver and the parent is in the user's hands then we remove our headset and delete the component +/datum/component/attached_headset/proc/attackby(obj/item/attacked_item, obj/item/attacking_item, mob/user) + SIGNAL_HANDLER + + if(!HAS_TRAIT(attacking_item, TRAIT_TOOL_SCREWDRIVER)) + return + + if(parent != user.r_hand && parent != user.l_hand) + return + + playsound(user, 'sound/items/Screwdriver.ogg', 20, TRUE) + to_chat(user, SPAN_NOTICE("You use [attacking_item] to take [headset] off of [parent].")) + user.put_in_hands(headset) + qdel(src) + + return COMPONENT_CANCEL_ITEM_ATTACK + + +/datum/component/attached_headset/proc/headset_deletion() + SIGNAL_HANDLER + + qdel(src) + +#undef ICON_HEADSET_SUFFIX +#undef DEFAULT_HEADSET_SLOT diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm index 42aa2e13b8..2ac79610ba 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm @@ -73,8 +73,7 @@ list("Marine Combat Boots", round(scale * 15), /obj/item/clothing/shoes/marine/knife, VENDOR_ITEM_REGULAR), list("USCM Uniform", round(scale * 15), /obj/item/clothing/under/marine, VENDOR_ITEM_REGULAR), list("Marine Combat Gloves", round(scale * 15), /obj/item/clothing/gloves/marine, VENDOR_ITEM_REGULAR), - list("M10 Pattern Marine Helmet", round(scale * 15), /obj/item/clothing/head/helmet/marine, VENDOR_ITEM_REGULAR), - list("Marine Radio Headset", round(scale * 15), /obj/item/device/radio/headset/almayer/marine, VENDOR_ITEM_REGULAR), + list("M10 Pattern Marine Helmet with Integrated Headset", round(scale * 15), /obj/item/clothing/head/helmet/marine/attached_headset, VENDOR_ITEM_REGULAR), list("WEBBINGS", -1, null, null), list("Brown Webbing Vest", round(scale * 1.25), /obj/item/clothing/accessory/storage/black_vest/brown_vest, VENDOR_ITEM_REGULAR), diff --git a/code/game/objects/items/devices/radio/headset.dm b/code/game/objects/items/devices/radio/headset.dm index 22d6905159..0832e9b178 100644 --- a/code/game/objects/items/devices/radio/headset.dm +++ b/code/game/objects/items/devices/radio/headset.dm @@ -593,6 +593,11 @@ desc = "A standard marine radio headset. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." frequency = ALPHA_FREQ +/obj/item/device/radio/headset/almayer/marine/lead + name = "marine leader radio headset" + desc = "This is used by a marine squad leader. Channels are as follows: :v - marine command, :j - JTAC. When worn, grants access to Squad Leader tracker. Click tracker with empty hand to open Squad Info window." + initial_keys = list(/obj/item/device/encryptionkey/squadlead) + //############################## ALPHA ############################### /obj/item/device/radio/headset/almayer/marine/alpha name = "marine alpha radio headset" diff --git a/code/game/objects/structures/crates_lockers/closets/job_closets.dm b/code/game/objects/structures/crates_lockers/closets/job_closets.dm index fa1c08b410..bc6f03b526 100644 --- a/code/game/objects/structures/crates_lockers/closets/job_closets.dm +++ b/code/game/objects/structures/crates_lockers/closets/job_closets.dm @@ -88,7 +88,7 @@ new /obj/item/ammo_magazine/rifle/m41aMK1(src) new /obj/item/ammo_magazine/rifle/m41aMK1(src) new /obj/item/ammo_magazine/rifle/m41aMK1(src) - new /obj/item/clothing/head/helmet/marine/leader(src) + new /obj/item/clothing/head/helmet/marine/leader/attached_headset(src) new /obj/item/device/binoculars/range/designator(src) new /obj/item/device/whistle(src) @@ -115,7 +115,7 @@ /obj/structure/closet/secure_closet/squad_sergeant/Initialize() . = ..() - new /obj/item/clothing/head/helmet/marine/rto(src) + //new /obj/item/clothing/head/helmet/marine/rto/attached_headset(src) //add attached_headset version - Morrow new /obj/item/device/binoculars/range/designator(src) new /obj/item/device/whistle(src) @@ -164,13 +164,3 @@ new /obj/item/storage/belt/marine/smartgunner/standard(src) new /obj/item/storage/belt/gun/smartgunner/standard(src) new /obj/item/clothing/glasses/night/m56_goggles/no_nightvision(src) - -/obj/structure/closet/cryo/Initialize() - . = ..() - new /obj/item/clothing/under/marine(src) - new /obj/item/clothing/under/marine(src) - new /obj/item/clothing/shoes/marine/knife(src) - new /obj/item/clothing/shoes/marine/knife(src) - new /obj/item/device/radio/headset/almayer/marine(src) - new /obj/item/device/radio/headset/almayer/marine(src) - new /obj/item/clothing/glasses/night/m56_goggles/no_nightvision(src) diff --git a/code/game/objects/structures/crates_lockers/closets/secure/marine_personal.dm b/code/game/objects/structures/crates_lockers/closets/secure/marine_personal.dm index 4462eda61b..38f6d1b81c 100644 --- a/code/game/objects/structures/crates_lockers/closets/secure/marine_personal.dm +++ b/code/game/objects/structures/crates_lockers/closets/secure/marine_personal.dm @@ -29,4 +29,3 @@ if(has_cryo_gear) new /obj/item/clothing/under/marine(src) new /obj/item/clothing/shoes/marine/knife(src) - new /obj/item/device/radio/headset/almayer/marine(src) diff --git a/code/modules/clothing/head/head.dm b/code/modules/clothing/head/head.dm index 1c9f7ea929..23c47bfdfb 100644 --- a/code/modules/clothing/head/head.dm +++ b/code/modules/clothing/head/head.dm @@ -219,6 +219,7 @@ /obj/item/prop/helmetgarb/helmet_nvg = HAT_GARB_RELAY_ICON_STATE, /obj/item/prop/helmetgarb/helmet_nvg/cosmetic = HAT_GARB_RELAY_ICON_STATE, /obj/item/prop/helmetgarb/helmet_nvg/marsoc = HAT_GARB_RELAY_ICON_STATE, + /obj/item/clothing/head/headset = "headset", /obj/item/clothing/head/headband = "hat_headbandgreen", /obj/item/clothing/head/headband/tan = "hat_headbandtan", /obj/item/clothing/head/headband/red = "hat_headbandred", diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 372c4844d5..8c5bda2190 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -352,7 +352,7 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( /obj/item/clothing/head/helmet/marine name = "\improper M10 pattern marine helmet" - desc = "A standard M10 Pattern Helmet. The inside label, along with washing information, reads, 'The difference between an open-casket and closed-casket funeral. Wear on head for best results.'. There is a built-in camera on the right side." + desc = "A standard M10 Pattern Helmet. The inside label, along with washing information, reads, 'The difference between an open-casket and closed-casket funeral. Wear on head for best results.'. There is a built-in camera on the right side and a slot for a radio earpiece." icon = 'icons/obj/items/clothing/cm_hats.dmi' icon_state = "helmet" item_state = "helmet" @@ -535,6 +535,10 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( return + if(istype(attacking_item, /obj/item/device/radio/headset) && (src == user.l_hand || src == user.r_hand)) + AddComponent(/datum/component/attached_headset, user, attacking_item, WEAR_HEAD) + return + ..() return pockets.attackby(attacking_item, user) @@ -726,6 +730,12 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( button.overlays.Cut() button.overlays += image('icons/obj/items/clothing/helmet_visors.dmi', button, action_icon_state) +/obj/item/clothing/head/helmet/marine/attached_headset/Initialize(mapload, list/new_protection) + . = ..() + + var/obj/item/device/radio/headset/almayer/marine/temp_headset = new() + AddComponent(/datum/component/attached_headset, null, temp_headset, WEAR_HEAD) + /obj/item/clothing/head/helmet/marine/tech name = "\improper M10 technician helmet" desc = "A modified M10 marine helmet for ComTechs. Features a toggleable welding screen for eye protection." @@ -796,6 +806,12 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( armor_bio = CLOTHING_ARMOR_MEDIUMHIGH specialty = "M11 pattern marine" +/obj/item/clothing/head/helmet/marine/leader/attached_headset/Initialize(mapload, list/new_protection) + . = ..() + + var/obj/item/device/radio/headset/almayer/marine/lead/temp_headset = new() + AddComponent(/datum/component/attached_headset, null, temp_headset, WEAR_HEAD) + /obj/item/clothing/head/helmet/marine/rto name = "\improper M12 pattern dust helmet" desc = "An experimental brain-bucket. A dust ruffle hangs from back instead of the standard lobster shell design. Moderately better at deflecting blunt objects at the cost of humiliation, can also hold a second visor optic. But who will be laughing at the memorial? Not you, you'll be busy getting medals for your fantastic leadership." @@ -806,6 +822,14 @@ GLOBAL_LIST_INIT(allowed_helmet_items, list( specialty = "M12 pattern" max_inserted_visors = 2 +/* +/obj/item/clothing/head/helmet/marine/rto/attached_headset/Initialize(mapload, list/new_protection) + . = ..() + + var/obj/item/device/radio/headset/almayer/marine/temp_headset = new() + AddComponent(/datum/component/attached_headset, null, temp_headset, WEAR_HEAD) +*/ + /obj/item/clothing/head/helmet/marine/rto/intel name = "\improper XM12 pattern intelligence helmet" desc = "An experimental brain-bucket. A dust ruffle hangs from back. Moderately better at deflecting blunt objects at the cost of humiliation, can also hold a second visor optic. But who will be laughing at the memorial? Not you, you'll be busy getting medals for your intel work." diff --git a/code/modules/mob/living/carbon/human/human.dm b/code/modules/mob/living/carbon/human/human.dm index f37b1d6a86..3250ea2a71 100644 --- a/code/modules/mob/living/carbon/human/human.dm +++ b/code/modules/mob/living/carbon/human/human.dm @@ -1653,6 +1653,9 @@ if(SEND_SIGNAL(src, COMSIG_HUMAN_ATTEMPTING_EQUIP, equipping_item, slot) & COMPONENT_HUMAN_CANCEL_ATTEMPT_EQUIP) return FALSE + if(SEND_SIGNAL(equipping_item, COMSIG_ITEM_ATTEMPTING_HUMAN_EQUIP, src, slot) & COMPONENT_ITEM_CANCEL_ATTEMPTING_HUMAN_EQUIP) + return FALSE + . = ..() /mob/living/carbon/human/make_dizzy(amount) diff --git a/colonialmarines.dme b/colonialmarines.dme index 9872ffc48e..1df2d0126a 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -381,6 +381,7 @@ #include "code\datums\components\_component.dm" #include "code\datums\components\armor_link.dm" #include "code\datums\components\atom_narrate.dm" +#include "code\datums\components\attached_headset.dm" #include "code\datums\components\bad_leg.dm" #include "code\datums\components\bonus_damage_stack.dm" #include "code\datums\components\cell.dm" diff --git a/icons/mob/humans/onmob/eyes.dmi b/icons/mob/humans/onmob/eyes.dmi index c4d743f61e..424ff594d6 100644 Binary files a/icons/mob/humans/onmob/eyes.dmi and b/icons/mob/humans/onmob/eyes.dmi differ diff --git a/icons/mob/humans/onmob/head_1.dmi b/icons/mob/humans/onmob/head_1.dmi index 139dae66e8..9cd10f4e10 100644 Binary files a/icons/mob/humans/onmob/head_1.dmi and b/icons/mob/humans/onmob/head_1.dmi differ diff --git a/icons/mob/humans/onmob/helmet_garb.dmi b/icons/mob/humans/onmob/helmet_garb.dmi index 6bf64e7eff..65806ca7cc 100644 Binary files a/icons/mob/humans/onmob/helmet_garb.dmi and b/icons/mob/humans/onmob/helmet_garb.dmi differ diff --git a/icons/mob/humans/onmob/suit_1.dmi b/icons/mob/humans/onmob/suit_1.dmi index 5ee10a5942..40075b567b 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/obj/items/clothing/cm_hats.dmi b/icons/obj/items/clothing/cm_hats.dmi index 75c46ae6a7..bb43686861 100644 Binary files a/icons/obj/items/clothing/cm_hats.dmi and b/icons/obj/items/clothing/cm_hats.dmi differ