From 9807a2f9e0f1610a82a5c88c4f286241b0ffba19 Mon Sep 17 00:00:00 2001 From: Linzolle Date: Mon, 29 Nov 2021 17:22:13 -0700 Subject: [PATCH 1/2] pin removal and gun examine things --- .../recipes/recipes_weapon_and_ammo.dm | 16 -- code/modules/projectiles/gun.dm | 192 ++++++++++++++---- 2 files changed, 157 insertions(+), 51 deletions(-) diff --git a/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm index 87ec5cdaab..63972a98aa 100644 --- a/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm +++ b/code/datums/components/crafting/recipes/recipes_weapon_and_ammo.dm @@ -1,19 +1,3 @@ -/datum/crafting_recipe/pin_removal - name = "Pin Removal" - result = /obj/item/gun - reqs = list(/obj/item/gun = 1) - parts = list(/obj/item/gun = 1) - tools = list(TOOL_WELDER, TOOL_SCREWDRIVER, TOOL_WIRECUTTER) - time = 50 - category = CAT_WEAPONRY - subcategory = CAT_OTHER - -/datum/crafting_recipe/pin_removal/check_requirements(mob/user, list/collected_requirements) - var/obj/item/gun/G = collected_requirements[/obj/item/gun][1] - if (G.no_pin_required || !G.pin) - return FALSE - return TRUE - /datum/crafting_recipe/strobeshield name = "Strobe Shield" result = /obj/item/shield/riot/flash diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 06bf298454..2759a8f8d6 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -1,5 +1,6 @@ #define DUALWIELD_PENALTY_EXTRA_MULTIPLIER 1.4 +#define FIRING_PIN_REMOVAL_DELAY 50 /obj/item/gun name = "gun" @@ -115,23 +116,28 @@ QDEL_NULL(chambered) return ..() -/obj/item/gun/CheckParts(list/parts_list) - ..() - var/obj/item/gun/G = locate(/obj/item/gun) in contents - if(G) - G.forceMove(loc) - QDEL_NULL(G.pin) - visible_message("[G] can now fit a new pin, but the old one was destroyed in the process.", null, null, 3) - qdel(src) - /obj/item/gun/examine(mob/user) . = ..() - if(no_pin_required) - return - if(pin) - . += "It has \a [pin] installed." - else - . += "It doesn't have a firing pin installed, and won't fire." + if(!no_pin_required) + if(pin) + . += "It has \a [pin] installed." + . += "[pin] looks like it could be removed with some tools." + else + . += "It doesn't have a firing pin installed, and won't fire." + + if(gun_light) + . += "It has \a [gun_light] [can_flashlight ? "" : "permanently "]mounted on it." + if(can_flashlight) //if it has a light and this is false, the light is permanent. + . += "[gun_light] looks like it can be unscrewed from [src]." + else if(can_flashlight) + . += "It has a mounting point for a seclite." + + if(bayonet) + . += "It has \a [bayonet] [can_bayonet ? "" : "permanently "]affixed to it." + if(can_bayonet) //if it has a bayonet and this is false, the bayonet is permanent. + . += "[bayonet] looks like it can be unscrewed from [src]." + else if(can_bayonet) + . += "It has a bayonet lug on it." /obj/item/gun/equipped(mob/living/user, slot) . = ..() @@ -239,7 +245,7 @@ return if(weapon_weight == WEAPON_HEAVY && user.get_inactive_held_item()) - to_chat(user, "You need both hands free to fire \the [src]!") + to_chat(user, "You need both hands free to fire [src]!") return user.DelayNextAction() @@ -417,12 +423,12 @@ if(!gun_light) if(!user.transferItemToLoc(I, src)) return - to_chat(user, "You click \the [S] into place on \the [src].") + to_chat(user, "You click [S] into place on [src].") if(S.on) set_light(0) - gun_light = S + set_gun_light(S) update_gunlight(user) - alight = new /datum/action/item_action/toggle_gunlight(src) + alight = new(src) if(loc == user) alight.Grant(user) else if(istype(I, /obj/item/kitchen/knife)) @@ -431,27 +437,133 @@ return ..() if(!user.transferItemToLoc(I, src)) return - to_chat(user, "You attach \the [K] to the front of \the [src].") + to_chat(user, "You attach [K] to [src]'s bayonet lug.") bayonet = K update_icon() - else if(I.tool_behaviour == TOOL_SCREWDRIVER) - if(gun_light) - var/obj/item/flashlight/seclite/S = gun_light - to_chat(user, "You unscrew the seclite from \the [src].") - gun_light = null - S.forceMove(get_turf(user)) - update_gunlight(user) - S.update_brightness(user) - QDEL_NULL(alight) - if(bayonet) - to_chat(user, "You unscrew the bayonet from \the [src].") - var/obj/item/kitchen/knife/K = bayonet - K.forceMove(get_turf(user)) - bayonet = null - update_icon() else return ..() +/obj/item/gun/screwdriver_act(mob/living/user, obj/item/I) + . = ..() + if(.) + return + if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + return + if((can_flashlight && gun_light) && (can_bayonet && bayonet)) //give them a choice instead of removing both + var/list/possible_items = list(gun_light, bayonet) + var/obj/item/item_to_remove = input(user, "Select an attachment to remove", "Attachment Removal") as null|obj in possible_items + if(!item_to_remove || !user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + return + return remove_gun_attachment(user, I, item_to_remove) + + else if(gun_light && can_flashlight) //if it has a gun_light and can_flashlight is false, the flashlight is permanently attached. + return remove_gun_attachment(user, I, gun_light, "unscrewed") + + else if(bayonet && can_bayonet) //if it has a bayonet, and the bayonet can be removed + return remove_gun_attachment(user, I, bayonet, "unfix") + + else if(pin && user.is_holding(src)) + user.visible_message(span_warning("[user] attempts to remove [pin] from [src] with [I]."), + span_notice("You attempt to remove [pin] from [src]. (It will take [DisplayTimeText(FIRING_PIN_REMOVAL_DELAY)].)"), null, 3) + if(I.use_tool(src, user, FIRING_PIN_REMOVAL_DELAY, volume = 50)) + if(!pin) //check to see if the pin is still there, or we can spam messages by clicking multiple times during the tool delay + return + user.visible_message(span_notice("[pin] is pried out of [src] by [user], destroying the pin in the process."), + span_warning("You pry [pin] out with [I], destroying the pin in the process."), null, 3) + QDEL_NULL(pin) + return TRUE + +/obj/item/gun/welder_act(mob/living/user, obj/item/I) + . = ..() + if(.) + return + if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + return + if(pin && user.is_holding(src)) + user.visible_message(span_warning("[user] attempts to remove [pin] from [src] with [I]."), + span_notice("You attempt to remove [pin] from [src]. (It will take [DisplayTimeText(FIRING_PIN_REMOVAL_DELAY)].)"), null, 3) + if(I.use_tool(src, user, FIRING_PIN_REMOVAL_DELAY, 5, volume = 50)) + if(!pin) //check to see if the pin is still there, or we can spam messages by clicking multiple times during the tool delay + return + user.visible_message(span_notice("[pin] is spliced out of [src] by [user], melting part of the pin in the process."), + span_warning("You splice [pin] out of [src] with [I], melting part of the pin in the process."), null, 3) + QDEL_NULL(pin) + return TRUE + +/obj/item/gun/wirecutter_act(mob/living/user, obj/item/I) + . = ..() + if(.) + return + if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) + return + if(pin && user.is_holding(src)) + user.visible_message(span_warning("[user] attempts to remove [pin] from [src] with [I]."), + span_notice("You attempt to remove [pin] from [src]. (It will take [DisplayTimeText(FIRING_PIN_REMOVAL_DELAY)].)"), null, 3) + if(I.use_tool(src, user, FIRING_PIN_REMOVAL_DELAY, volume = 50)) + if(!pin) //check to see if the pin is still there, or we can spam messages by clicking multiple times during the tool delay + return + user.visible_message(span_notice("[pin] is ripped out of [src] by [user], mangling the pin in the process."), + span_warning("You rip [pin] out of [src] with [I], mangling the pin in the process."), null, 3) + QDEL_NULL(pin) + return TRUE + +/obj/item/gun/proc/remove_gun_attachment(mob/living/user, obj/item/tool_item, obj/item/item_to_remove, removal_verb) + if(tool_item) + tool_item.play_tool_sound(src) + to_chat(user, span_notice("You [removal_verb ? removal_verb : "remove"] [item_to_remove] from [src].")) + item_to_remove.forceMove(drop_location()) + + if(Adjacent(user) && !issilicon(user)) + user.put_in_hands(item_to_remove) + + if(item_to_remove == bayonet) + return clear_bayonet() + else if(item_to_remove == gun_light) + return clear_gunlight() + +/obj/item/gun/proc/clear_bayonet() + if(!bayonet) + return + bayonet = null + update_appearance() + return TRUE + +/obj/item/gun/proc/clear_gunlight() + if(!gun_light) + return + var/obj/item/flashlight/seclite/removed_light = gun_light + set_gun_light(null) + update_gunlight() + removed_light.update_brightness() + QDEL_NULL(alight) + return TRUE + +/** + * Swaps the gun's seclight, dropping the old seclight if it has not been qdel'd. + * + * Returns the former gun_light that has now been replaced by this proc. + * Arguments: + * * new_light - The new light to attach to the weapon. Can be null, which will mean the old light is removed with no replacement. + */ +/obj/item/gun/proc/set_gun_light(obj/item/flashlight/seclite/new_light) + // Doesn't look like this should ever happen? We're replacing our old light with our old light? + if(gun_light == new_light) + CRASH("Tried to set a new gun light when the old gun light was also the new gun light.") + + . = gun_light + + // If there's an old gun light that isn't being QDELETED, detatch and drop it to the floor. + if(!QDELETED(gun_light)) + if(gun_light.loc == src) + gun_light.forceMove(get_turf(src)) + + // If there's a new gun light to be added, attach and move it to the gun. + if(new_light) + if(new_light.loc != src) + new_light.forceMove(src) + + gun_light = new_light + /obj/item/gun/ui_action_click(mob/user, action) if(istype(action, /datum/action/item_action/toggle_scope_zoom)) zoom(user, user.dir) @@ -606,9 +718,16 @@ user.client.view_size.zoomIn() /obj/item/gun/handle_atom_del(atom/A) + if(A == pin) + pin = null if(A == chambered) chambered = null update_icon() + if(A == bayonet) + clear_bayonet() + if(A == gun_light) + clear_gunlight() + return ..() /obj/item/gun/proc/getinaccuracy(mob/living/user, bonus_spread, stamloss) return 0 // Replacement TBD: Exponential curved aim instability system. @@ -642,3 +761,6 @@ . = recoil if(user && !user.has_gravity()) . = recoil*5 + +#undef FIRING_PIN_REMOVAL_DELAY +#undef DUALWIELD_PENALTY_EXTRA_MULTIPLIER From c2378d3f2663856619d8d823d52acf65939063bf Mon Sep 17 00:00:00 2001 From: Linzolle Date: Mon, 29 Nov 2021 17:40:08 -0700 Subject: [PATCH 2/2] helmet stuff --- code/modules/clothing/clothing.dm | 2 - code/modules/clothing/head/helmet.dm | 110 +++++++++++++++++---------- code/modules/projectiles/gun.dm | 2 +- 3 files changed, 71 insertions(+), 43 deletions(-) diff --git a/code/modules/clothing/clothing.dm b/code/modules/clothing/clothing.dm index 492768a8e0..3beeef91d3 100644 --- a/code/modules/clothing/clothing.dm +++ b/code/modules/clothing/clothing.dm @@ -21,8 +21,6 @@ var/active_sound = null var/toggle_cooldown = null var/cooldown = 0 - var/obj/item/flashlight/F = null - var/can_flashlight = 0 var/blocks_shove_knockdown = FALSE //Whether wearing the clothing item blocks the ability for shove to knock down. diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index de68883a7b..6b698f9619 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -16,17 +16,47 @@ dog_fashion = /datum/dog_fashion/head/helmet + var/can_flashlight = FALSE //if a flashlight can be mounted. if it has a flashlight and this is false, it is permanently attached. + var/obj/item/flashlight/seclite/attached_light + var/datum/action/item_action/toggle_helmet_flashlight/alight + +/obj/item/clothing/head/helmet/Initialize(mapload) + . = ..() + if(attached_light) + alight = new(src) + /obj/item/clothing/head/helmet/ComponentInitialize() . = ..() AddComponent(/datum/component/wearertargeting/earprotection, list(SLOT_HEAD)) +/obj/item/clothing/head/helmet/examine(mob/user) + . = ..() + if(attached_light) + . += "It has \a [attached_light] [can_flashlight ? "" : "permanently "]mounted on it." + if(can_flashlight) + . += "[attached_light] looks like it can be unscrewed from [src]." + else if(can_flashlight) + . += "It has a mounting point for a seclite." + +/obj/item/clothing/head/helmet/Destroy() + QDEL_NULL(attached_light) + return ..() + +/obj/item/clothing/head/helmet/handle_atom_del(atom/A) + if(A == attached_light) + attached_light = null + update_helmlight() + update_icon() + QDEL_NULL(alight) + return ..() + /obj/item/clothing/head/helmet/sec can_flashlight = 1 /obj/item/clothing/head/helmet/sec/attackby(obj/item/I, mob/user, params) if(issignaler(I)) var/obj/item/assembly/signaler/S = I - if(F) //Has a flashlight. Player must remove it, else it will be lost forever. + if(attached_light) //Has a flashlight. Player must remove it, else it will be lost forever. to_chat(user, "The mounted flashlight is in the way, remove it first!") return @@ -280,8 +310,8 @@ /obj/item/clothing/head/helmet/update_icon_state() var/state = "[initial(icon_state)]" - if(F) - if(F.on) + if(attached_light) + if(attached_light.on) state += "-flight-on" //"helmet-flight-on" // "helmet-cam-flight-on" else state += "-flight" //etc. @@ -289,7 +319,7 @@ icon_state = state /obj/item/clothing/head/helmet/ui_action_click(mob/user, action) - if(istype(action, /datum/action/item_action/toggle_helmet_flashlight)) + if(istype(action, alight)) toggle_helmlight() else ..() @@ -297,60 +327,60 @@ /obj/item/clothing/head/helmet/attackby(obj/item/I, mob/user, params) if(istype(I, /obj/item/flashlight/seclite)) var/obj/item/flashlight/seclite/S = I - if(can_flashlight) - if(!F) - if(!user.transferItemToLoc(S, src)) - return - to_chat(user, "You click [S] into place on [src].") - if(S.on) - set_light(0) - F = S - update_icon() - update_helmlight(user) - verbs += /obj/item/clothing/head/helmet/proc/toggle_helmlight - var/datum/action/A = new /datum/action/item_action/toggle_helmet_flashlight(src) - if(loc == user) - A.Grant(user) + if(can_flashlight && !attached_light) + if(!user.transferItemToLoc(S, src)) + return + to_chat(user, "You click [S] into place on [src].") + if(S.on) + set_light(0) + attached_light = S + update_icon() + update_helmlight() + alight = new(src) + if(loc == user) + alight.Grant(user) return - - if(I.tool_behaviour == TOOL_SCREWDRIVER) - if(F) - for(var/obj/item/flashlight/seclite/S in src) - to_chat(user, "You unscrew the seclite from [src].") - F = null - S.forceMove(user.drop_location()) - update_helmlight(user) - S.update_brightness(user) - update_icon() - usr.update_inv_head() - verbs -= /obj/item/clothing/head/helmet/proc/toggle_helmlight - for(var/datum/action/item_action/toggle_helmet_flashlight/THL in actions) - qdel(THL) - return - return ..() +/obj/item/clothing/head/helmet/screwdriver_act(mob/living/user, obj/item/I) + ..() + if(can_flashlight && attached_light) //if it has a light but can_flashlight is false, the light is permanently attached. + I.play_tool_sound(src) + to_chat(user, "You unscrew [attached_light] from [src].") + attached_light.forceMove(drop_location()) + if(Adjacent(user) && !issilicon(user)) + user.put_in_hands(attached_light) + + var/obj/item/flashlight/removed_light = attached_light + attached_light = null + update_helmlight() + removed_light.update_brightness(user) + update_icon() + user.update_inv_head() + QDEL_NULL(alight) + return TRUE + /obj/item/clothing/head/helmet/proc/toggle_helmlight() set name = "Toggle Helmetlight" set category = "Object" set desc = "Click to toggle your helmet's attached flashlight." - if(!F) + if(!attached_light) return var/mob/user = usr if(user.incapacitated()) return - F.on = !F.on - to_chat(user, "You toggle the helmetlight [F.on ? "on":"off"].") + attached_light.on = !attached_light.on + to_chat(user, "You toggle the helmet-light [attached_light.on ? "on":"off"].") playsound(user, 'sound/weapons/empty.ogg', 100, 1) update_helmlight(user) /obj/item/clothing/head/helmet/proc/update_helmlight(mob/user = null) - if(F) - if(F.on) - set_light(F.brightness_on, F.flashlight_power, F.light_color) + if(attached_light) + if(attached_light.on) + set_light(attached_light.brightness_on, attached_light.flashlight_power, attached_light.light_color) else set_light(0) update_icon() diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index 2759a8f8d6..bbd77ad665 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -64,7 +64,7 @@ var/obj/item/firing_pin/pin = /obj/item/firing_pin //standard firing pin for most guns var/no_pin_required = FALSE //whether the gun can be fired without a pin - var/obj/item/flashlight/gun_light + var/obj/item/flashlight/seclite/gun_light var/can_flashlight = FALSE var/gunlight_state = "flight" var/obj/item/kitchen/knife/bayonet