diff --git a/code/__DEFINES/dcs/signals/signals_object.dm b/code/__DEFINES/dcs/signals/signals_object.dm index eb95a016d78..f9b34717406 100644 --- a/code/__DEFINES/dcs/signals/signals_object.dm +++ b/code/__DEFINES/dcs/signals/signals_object.dm @@ -116,6 +116,12 @@ #define COMSIG_ITEM_DROPPED "item_drop" ///from base of obj/item/pickup(): (/mob/taker) #define COMSIG_ITEM_PICKUP "item_pickup" + +/// Sebt from obj/item/ui_action_click(): (mob/user, datum/action) +#define COMSIG_ITEM_UI_ACTION_CLICK "item_action_click" + /// Return to prevent the default behavior (attack_selfing) from ocurring. + #define COMPONENT_ACTION_HANDLED (1<<0) + ///from base of mob/living/carbon/attacked_by(): (mob/living/carbon/target, mob/living/user, hit_zone) #define COMSIG_ITEM_ATTACK_ZONE "item_attack_zone" ///from base of obj/item/hit_reaction(): (list/args) diff --git a/code/datums/action.dm b/code/datums/action.dm index 91c6c2c6029..7383aae3708 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -438,6 +438,9 @@ /datum/action/item_action/toggle_helmet name = "Toggle Helmet" +/datum/action/item_action/toggle_seclight + name = "Toggle Seclight" + /datum/action/item_action/toggle_jetpack name = "Toggle Jetpack" diff --git a/code/datums/components/seclight_attachable.dm b/code/datums/components/seclight_attachable.dm new file mode 100644 index 00000000000..ec408401a5c --- /dev/null +++ b/code/datums/components/seclight_attachable.dm @@ -0,0 +1,295 @@ +/** + * Component which allows you to attach a seclight to an item, + * be it a piece of clothing or a tool. + */ +/datum/component/seclite_attachable + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + /// Whether we can remove the light with a screwdriver or not. + var/is_light_removable = TRUE + /// If passed, we wil simply update our item's icon_state when a light is attached. + /// Formatted as parent_base_state-[light_icon-state]-"on" + var/light_icon_state + /// If passed, we will add overlays to the item when a light is attached. + /// This is the icon file it grabs the overlay from. + var/light_overlay_icon + /// The state to take from the light overlay icon if supplied. + var/light_overlay + /// The X offset of our overlay if supplied. + var/overlay_x = 0 + /// The Y offset of our overlay if supplied. + var/overlay_y = 0 + + // Internal vars. + /// A reference to the actual light that's attached. + var/obj/item/flashlight/seclite/light + /// A weakref to the item action we add with the light. + var/datum/weakref/toggle_action_ref + /// Static typecache of all lights we consider seclites (all lights we can attach). + var/static/list/valid_lights = typecacheof(list(/obj/item/flashlight/seclite)) + +/datum/component/seclite_attachable/Initialize( + obj/item/flashlight/seclite/starting_light, + is_light_removable = TRUE, + light_icon_state, + light_overlay_icon, + light_overlay, + overlay_x = 0, + overlay_y = 0, +) + + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + src.is_light_removable = is_light_removable + src.light_icon_state = light_icon_state + src.light_overlay_icon = light_overlay_icon + src.light_overlay = light_overlay + src.overlay_x = overlay_x + src.overlay_y = overlay_y + + if(istype(starting_light)) + add_light(starting_light) + +/datum/component/seclite_attachable/Destroy(force, silent) + if(light) + remove_light() + return ..() + +// Inheriting component allows lights to be added externally to things which already have a mount. +/datum/component/seclite_attachable/InheritComponent( + datum/component/seclite_attachable/new_component, + original, + obj/item/flashlight/seclite/starting_light, + is_light_removable = TRUE, + light_icon_state, + light_overlay_icon, + light_overlay, + overlay_x, + overlay_y, +) + + if(!original) + return + + src.is_light_removable = is_light_removable + + // For the rest of these arguments, default to what already exists + if(light_icon_state) + src.light_icon_state = light_icon_state + if(light_overlay_icon) + src.light_overlay_icon = light_overlay_icon + if(light_overlay) + src.light_overlay = light_overlay + if(overlay_x) + src.overlay_x = overlay_x + if(overlay_x) + src.overlay_y = overlay_y + + if(istype(starting_light)) + add_light(starting_light) + +/datum/component/seclite_attachable/RegisterWithParent() + RegisterSignal(parent, COMSIG_ATOM_DESTRUCTION, .proc/on_parent_deconstructed) + RegisterSignal(parent, COMSIG_ATOM_EXITED, .proc/on_light_exit) + RegisterSignal(parent, COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), .proc/on_screwdriver) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_ICON_STATE, .proc/on_update_icon_state) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, .proc/on_update_overlays) + RegisterSignal(parent, COMSIG_ITEM_UI_ACTION_CLICK, .proc/on_action_click) + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, .proc/on_attackby) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, .proc/on_examine) + RegisterSignal(parent, COMSIG_PARENT_QDELETING, .proc/on_parent_deleted) + +/datum/component/seclite_attachable/UnregisterFromParent() + UnregisterSignal(parent, list( + COMSIG_ATOM_DESTRUCTION, + COMSIG_ATOM_EXITED, + COMSIG_ATOM_TOOL_ACT(TOOL_SCREWDRIVER), + COMSIG_ATOM_UPDATE_ICON_STATE, + COMSIG_ATOM_UPDATE_OVERLAYS, + COMSIG_ITEM_UI_ACTION_CLICK, + COMSIG_PARENT_ATTACKBY, + COMSIG_PARENT_EXAMINE, + COMSIG_PARENT_QDELETING, + )) + +/// Sets a new light as our current light for our parent. +/datum/component/seclite_attachable/proc/add_light(obj/item/flashlight/new_light, mob/attacher) + if(light) + CRASH("[type] tried to add a new light when it already had one.") + + light = new_light + + light.set_light_flags(light.light_flags | LIGHT_ATTACHED) + // We may already exist within in our parent's contents... But if we don't move it over now + if(light.loc != parent) + light.forceMove(parent) + + // We already have an action for the light for some reason? Clean it up + if(toggle_action_ref?.resolve()) + stack_trace("[type] - add_light had an existing toggle action when add_light was called.") + QDEL_NULL(toggle_action_ref) + + // Make a new toggle light item action for our parent + var/obj/item/item_parent = parent + var/datum/action/item_action/toggle_seclight/toggle_action = new(item_parent) + toggle_action_ref = WEAKREF(toggle_action) + if(attacher && item_parent.loc == attacher) + toggle_action.Grant(attacher) + + update_light() + +/// Removes the current light from our parent. +/datum/component/seclite_attachable/proc/remove_light() + // Our action may be linked to our parent, + // but it's really sourced from our light. Get rid of it. + QDEL_NULL(toggle_action_ref) + + // It is possible the light was removed by being deleted. + if(!QDELETED(light)) + UnregisterSignal(light, COMSIG_PARENT_QDELETING) + light.set_light_flags(light.light_flags & ~LIGHT_ATTACHED) + light.update_brightness() + + light = null + update_light() + +/// Toggles the light within on or off. +/// Returns TRUE if there is a light inside, FALSE otherwise. +/datum/component/seclite_attachable/proc/toggle_light(mob/user) + if(!light) + return FALSE + + light.on = !light.on + light.update_brightness() + if(user) + user.balloon_alert(user, "[light.name] toggled [light.on ? "on":"off"]") + + playsound(light, 'sound/weapons/empty.ogg', 100, TRUE) + update_light() + return TRUE + +/// Called after the a light is added, removed, or toggles. +/// Ensures all of our appearances look correct for the new light state. +/datum/component/seclite_attachable/proc/update_light() + var/obj/item/item_parent = parent + item_parent.update_appearance() + item_parent.update_action_buttons() + +/// Signal proc for [COMSIG_ATOM_EXITED] that handles our light being removed or deleted from our parent. +/datum/component/seclite_attachable/proc/on_light_exit(obj/item/source, atom/movable/gone, direction) + SIGNAL_HANDLER + + if(gone == light) + remove_light() + +/// Signal proc for [COMSIG_ATOM_DESTRUCTION] that drops our light to the ground if our parent is deconstructed. +/datum/component/seclite_attachable/proc/on_parent_deconstructed(obj/item/source, disassembled) + SIGNAL_HANDLER + + light.forceMove(source.drop_location()) + +/// Signal proc for [COMSIG_PARENT_QDELETING] that deletes our light if our parent is deleted. +/datum/component/seclite_attachable/proc/on_parent_deleted(obj/item/source) + SIGNAL_HANDLER + + QDEL_NULL(light) + +/// Signal proc for [COMSIG_ITEM_UI_ACTION_CLICK] that toggles our light on and off if our action button is clicked. +/datum/component/seclite_attachable/proc/on_action_click(obj/item/source, mob/user, datum/action) + SIGNAL_HANDLER + + // This isn't OUR action specifically, we don't care. + if(!IS_WEAKREF_OF(action, toggle_action_ref)) + return + + // Toggle light fails = no light attached = shouldn't be possible + if(!toggle_light(user)) + CRASH("[type] - on_action_click somehow both HAD AN ACTION and also HAD A TRIGGERABLE ACTION, without having an attached light.") + + return COMPONENT_ACTION_HANDLED + +/// Signal proc for [COMSIG_PARENT_ATTACKBY] that allows a user to attach a seclite by hitting our parent with it. +/datum/component/seclite_attachable/proc/on_attackby(obj/item/source, obj/item/attacking_item, mob/attacker, params) + SIGNAL_HANDLER + + if(!is_type_in_typecache(attacking_item, valid_lights)) + return + + if(light) + source.balloon_alert(attacker, "already has \a [light]!") + return + + if(!attacker.transferItemToLoc(attacking_item, source)) + return + + add_light(attacking_item, attacker) + source.balloon_alert(attacker, "attached [attacking_item]") + return COMPONENT_NO_AFTERATTACK + +/// Signal proc for [COMSIG_ATOM_TOOL_ACT] via [TOOL_SCREWDRIVER] that removes any attached seclite. +/datum/component/seclite_attachable/proc/on_screwdriver(obj/item/source, mob/user, obj/item/tool) + SIGNAL_HANDLER + + if(!light || !is_light_removable) + return + + INVOKE_ASYNC(src, .proc/unscrew_light, source, user, tool) + return COMPONENT_BLOCK_TOOL_ATTACK + +/// Invoked asyncronously from [proc/on_screwdriver]. Handles removing the light from our parent. +/datum/component/seclite_attachable/proc/unscrew_light(obj/item/source, mob/user, obj/item/tool) + tool?.play_tool_sound(source) + source.balloon_alert(user, "unscrewed [light]") + + var/obj/item/flashlight/seclite/to_remove = light + + // The forcemove here will call exited on the light, and automatically update our references / etc + to_remove.forceMove(source.drop_location()) + if(source.Adjacent(user) && !issilicon(user)) + user.put_in_hands(to_remove) + +/// Signal proc for [COMSIG_PARENT_EXAMINE] that shows our item can have / does have a seclite attached. +/datum/component/seclite_attachable/proc/on_examine(obj/item/source, mob/examiner, list/examine_list) + SIGNAL_HANDLER + + if(light) + examine_list += "It has \a [light] [is_light_removable ? "mounted on it with a few screws" : "permanently mounted on it"]." + else + examine_list += "It has a mounting point for a seclite." + +/// Signal proc for [COMSIG_ATOM_UPDATE_OVERLAYS] that updates our parent with our seclite overlays, if we have some. +/datum/component/seclite_attachable/proc/on_update_overlays(obj/item/source, list/overlays) + SIGNAL_HANDLER + + // No overlays to add, no reason to run + if(!light_overlay || !light_overlay_icon) + return + // No light, nothing to add + if(!light) + return + + var/overlay_state = "[light_overlay][light.on ? "_on":""]" + var/mutable_appearance/flashlight_overlay = mutable_appearance(light_overlay_icon, overlay_state) + flashlight_overlay.pixel_x = overlay_x + flashlight_overlay.pixel_y = overlay_y + overlays += flashlight_overlay + +/// Signal proc for [COMSIG_ATOM_UPDATE_ICON_STATE] that updates our parent's icon state, if we have one. +/datum/component/seclite_attachable/proc/on_update_icon_state(obj/item/source) + SIGNAL_HANDLER + + // No icon state to set, no reason to run + if(!light_icon_state) + return + + // Get the "base icon state" to work on + var/base_state = source.base_icon_state || initial(source.icon_state) + // Updates our icon state based on our light state. + if(light) + source.icon_state = "[base_state]-[light_icon_state][light.on ? "-on":""]" + + // Reset their icon state when if we've got no light. + else if(source.icon_state != base_state) + // Yes, this might mess with other icon state alterations, + // but that's the downside of using icon states over overlays. + source.icon_state = base_state diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index 361fac08566..66bca8c3f3e 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -706,6 +706,9 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e *Checks before we get to here are: mob is alive, mob is not restrained, stunned, asleep, resting, laying, item is on the mob. */ /obj/item/proc/ui_action_click(mob/user, actiontype) + if(SEND_SIGNAL(src, COMSIG_ITEM_UI_ACTION_CLICK, user, actiontype) & COMPONENT_ACTION_HANDLED) + return + attack_self(user) ///This proc determines if and at what an object will reflect energy projectiles if it's in l_hand,r_hand or wear_suit diff --git a/code/modules/clothing/head/helmet.dm b/code/modules/clothing/head/helmet.dm index 73b6b63a896..09c710a3bd6 100644 --- a/code/modules/clothing/head/helmet.dm +++ b/code/modules/clothing/head/helmet.dm @@ -15,77 +15,38 @@ 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/Destroy() - var/obj/item/flashlight/seclite/old_light = set_attached_light(null) - if(old_light) - qdel(old_light) - return ..() - - -/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) - . += span_info("[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/handle_atom_del(atom/A) - if(A == attached_light) - set_attached_light(null) - update_helmlight() - update_appearance() - QDEL_NULL(alight) - qdel(A) - return ..() - - -///Called when attached_light value changes. -/obj/item/clothing/head/helmet/proc/set_attached_light(obj/item/flashlight/seclite/new_attached_light) - if(attached_light == new_attached_light) - return - . = attached_light - attached_light = new_attached_light - if(attached_light) - attached_light.set_light_flags(attached_light.light_flags | LIGHT_ATTACHED) - if(attached_light.loc != src) - attached_light.forceMove(src) - else if(.) - var/obj/item/flashlight/seclite/old_attached_light = . - old_attached_light.set_light_flags(old_attached_light.light_flags & ~LIGHT_ATTACHED) - if(old_attached_light.loc == src) - old_attached_light.forceMove(get_turf(src)) - + AddElement(/datum/element/update_icon_updates_onmob) /obj/item/clothing/head/helmet/sec - can_flashlight = TRUE -/obj/item/clothing/head/helmet/sec/attackby(obj/item/I, mob/user, params) - if(issignaler(I)) - var/obj/item/assembly/signaler/S = I - if(attached_light) //Has a flashlight. Player must remove it, else it will be lost forever. - to_chat(user, span_warning("The mounted flashlight is in the way, remove it first!")) - return +/obj/item/clothing/head/helmet/sec/Initialize(mapload) + . = ..() + AddComponent(/datum/component/seclite_attachable, light_icon_state = "flight") + +/obj/item/clothing/head/helmet/sec/attackby(obj/item/attacking_item, mob/user, params) + if(issignaler(attacking_item)) + var/obj/item/assembly/signaler/attached_signaler = attacking_item + // There's a flashlight in us. Remove it first, or it'll be lost forever! + var/obj/item/flashlight/seclite/blocking_us = locate() in src + if(blocking_us) + to_chat(user, span_warning("[blocking_us] is in the way, remove it first!")) + return TRUE + + if(!attached_signaler.secured) + to_chat(user, span_warning("Secure [attached_signaler] first!")) + return TRUE + + to_chat(user, span_notice("You add [attached_signaler] to [src].")) + + qdel(attached_signaler) + var/obj/item/bot_assembly/secbot/secbot_frame = new(loc) + user.put_in_hands(secbot_frame) + + qdel(src) + return TRUE - if(S.secured) - qdel(S) - var/obj/item/bot_assembly/secbot/A = new - user.put_in_hands(A) - to_chat(user, span_notice("You add the signaler to the helmet.")) - qdel(src) - return return ..() /obj/item/clothing/head/helmet/alt @@ -94,9 +55,12 @@ icon_state = "helmetalt" inhand_icon_state = "helmetalt" armor = list(MELEE = 15, BULLET = 60, LASER = 10, ENERGY = 10, BOMB = 40, BIO = 0, FIRE = 50, ACID = 50, WOUND = 5) - can_flashlight = TRUE dog_fashion = null +/obj/item/clothing/head/helmet/alt/Initialize(mapload) + . = ..() + AddComponent(/datum/component/seclite_attachable, light_icon_state = "flight") + /obj/item/clothing/head/helmet/marine name = "tactical combat helmet" desc = "A tactical black helmet, sealed from outside hazards with a plate of glass and not much else." @@ -106,14 +70,11 @@ min_cold_protection_temperature = SPACE_HELM_MIN_TEMP_PROTECT clothing_flags = STOPSPRESSUREDAMAGE | PLASMAMAN_HELMET_EXEMPT resistance_flags = FIRE_PROOF | ACID_PROOF - can_flashlight = TRUE dog_fashion = null /obj/item/clothing/head/helmet/marine/Initialize(mapload) - set_attached_light(new /obj/item/flashlight/seclite) - update_helmlight() - update_appearance() . = ..() + AddComponent(/datum/component/seclite_attachable, starting_light = new /obj/item/flashlight/seclite(src), light_icon_state = "flight") /obj/item/clothing/head/helmet/marine/security name = "marine heavy helmet" @@ -158,20 +119,27 @@ dog_fashion = null /obj/item/clothing/head/helmet/attack_self(mob/user) - if(can_toggle && !user.incapacitated()) - if(world.time > cooldown + toggle_cooldown) - cooldown = world.time - up = !up - flags_1 ^= visor_flags - flags_inv ^= visor_flags_inv - flags_cover ^= visor_flags_cover - icon_state = "[initial(icon_state)][up ? "up" : ""]" - to_chat(user, span_notice("[up ? alt_toggle_message : toggle_message] \the [src].")) + . = ..() + if(.) + return + if(!can_toggle) + return - user.update_inv_head() - if(iscarbon(user)) - var/mob/living/carbon/C = user - C.head_update(src, forced = 1) + if(user.incapacitated() || world.time <= cooldown + toggle_cooldown) + return + + cooldown = world.time + up = !up + flags_1 ^= visor_flags + flags_inv ^= visor_flags_inv + flags_cover ^= visor_flags_cover + icon_state = "[initial(icon_state)][up ? "up" : ""]" + to_chat(user, span_notice("[up ? alt_toggle_message : toggle_message] \the [src].")) + + user.update_inv_head() + if(iscarbon(user)) + var/mob/living/carbon/carbon_user = user + carbon_user.head_update(src, forced = TRUE) /obj/item/clothing/head/helmet/justice name = "helmet of justice" @@ -405,192 +373,3 @@ material_flags = MATERIAL_EFFECTS | MATERIAL_COLOR | MATERIAL_AFFECT_STATISTICS //Can change color and add prefix flags_inv = HIDEMASK|HIDEEARS|HIDEEYES|HIDEFACE|HIDEHAIR|HIDESNOUT flags_cover = HEADCOVERSEYES | HEADCOVERSMOUTH - -//monkey sentience caps - -/* SKYRAT EDIT REMOVAL - MOVED TO MODULAR -/obj/item/clothing/head/helmet/monkey_sentience - name = "monkey mind magnification helmet" - desc = "A fragile, circuitry embedded helmet for boosting the intelligence of a monkey to a higher level. You see several warning labels..." - - icon_state = "monkeymind" - inhand_icon_state = "monkeymind" - strip_delay = 100 - var/mob/living/carbon/human/magnification = null ///if the helmet is on a valid target (just works like a normal helmet if not (cargo please stop)) - var/polling = FALSE///if the helmet is currently polling for targets (special code for removal) - var/light_colors = 1 ///which icon state color this is (red, blue, yellow) - -/obj/item/clothing/head/helmet/monkey_sentience/Initialize(mapload) - . = ..() - light_colors = rand(1,3) - update_appearance() - -/obj/item/clothing/head/helmet/monkey_sentience/examine(mob/user) - . = ..() - . += span_boldwarning("---WARNING: REMOVAL OF HELMET ON SUBJECT MAY LEAD TO:---") - . += span_warning("BLOOD RAGE") - . += span_warning("BRAIN DEATH") - . += span_warning("PRIMAL GENE ACTIVATION") - . += span_warning("GENETIC MAKEUP MASS SUSCEPTIBILITY") - . += span_boldnotice("Ask your CMO if mind magnification is right for you.") - -/obj/item/clothing/head/helmet/monkey_sentience/update_icon_state() - . = ..() - icon_state = "[initial(icon_state)][light_colors][magnification ? "up" : null]" - -/obj/item/clothing/head/helmet/monkey_sentience/equipped(mob/user, slot) - . = ..() - if(slot != ITEM_SLOT_HEAD) - return - if(!ismonkey(user) || user.ckey) - var/mob/living/something = user - to_chat(something, span_boldnotice("You feel a stabbing pain in the back of your head for a moment.")) - something.apply_damage(5,BRUTE,BODY_ZONE_HEAD,FALSE,FALSE,FALSE) //notably: no damage resist (it's in your helmet), no damage spread (it's in your helmet) - playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE) - return - if(!(GLOB.ghost_role_flags & GHOSTROLE_STATION_SENTIENCE)) - say("ERROR: Central Command has temporarily outlawed monkey sentience helmets in this sector. NEAREST LAWFUL SECTOR: 2.537 million light years away.") - return - magnification = user //this polls ghosts - visible_message(span_warning("[src] powers up!")) - playsound(src, 'sound/machines/ping.ogg', 30, TRUE) - RegisterSignal(magnification, COMSIG_SPECIES_LOSS, .proc/make_fall_off) - polling = TRUE - var/list/candidates = poll_candidates_for_mob("Do you want to play as a mind magnified monkey?", ROLE_SENTIENCE, ROLE_SENTIENCE, 5 SECONDS, magnification, POLL_IGNORE_SENTIENCE_POTION) - polling = FALSE - if(!magnification) - return - if(!candidates.len) - UnregisterSignal(magnification, COMSIG_SPECIES_LOSS) - magnification = null - visible_message(span_notice("[src] falls silent and drops on the floor. Maybe you should try again later?")) - playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE) - user.dropItemToGround(src) - return - var/mob/picked = pick(candidates) - magnification.key = picked.key - playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, FALSE) - to_chat(magnification, span_notice("You're a mind magnified monkey! Protect your helmet with your life- if you lose it, your sentience goes with it!")) - var/policy = get_policy(ROLE_MONKEY_HELMET) - if(policy) - to_chat(magnification, policy) - icon_state = "[icon_state]up" - -/obj/item/clothing/head/helmet/monkey_sentience/Destroy() - disconnect() - return ..() - -/obj/item/clothing/head/helmet/monkey_sentience/proc/disconnect() - if(!magnification) //not put on a viable head - return - if(!polling)//put on a viable head, but taken off after polling finished. - if(magnification.client) - to_chat(magnification, span_userdanger("You feel your flicker of sentience ripped away from you, as everything becomes dim...")) - magnification.ghostize(FALSE) - if(prob(10)) - switch(rand(1,4)) - if(1) //blood rage - magnification.ai_controller.blackboard[BB_MONKEY_AGGRESSIVE] = TRUE - if(2) //brain death - magnification.apply_damage(500,BRAIN,BODY_ZONE_HEAD,FALSE,FALSE,FALSE) - if(3) //primal gene (gorilla) - magnification.gorillize() - if(4) //genetic mass susceptibility (gib) - magnification.gib() - //either used up correctly or taken off before polling finished (punish this by destroying the helmet) - UnregisterSignal(magnification, COMSIG_SPECIES_LOSS) - playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE) - playsound(src, SFX_SPARKS, 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) - visible_message(span_warning("[src] fizzles and breaks apart!")) - magnification = null - new /obj/effect/decal/cleanable/ash/crematorium(drop_location()) //just in case they're in a locker or other containers it needs to use crematorium ash, see the path itself for an explanation - -/obj/item/clothing/head/helmet/monkey_sentience/dropped(mob/user) - . = ..() - if(magnification || polling) - qdel(src)//runs disconnect code - -/obj/item/clothing/head/helmet/monkey_sentience/proc/make_fall_off() - SIGNAL_HANDLER - if(magnification) - visible_message(span_warning("[src] falls off of [magnification]'s head as it changes shape!")) - magnification.dropItemToGround(src) -*/ -//LightToggle - -/obj/item/clothing/head/helmet/ComponentInitialize() - . = ..() - AddElement(/datum/element/update_icon_updates_onmob) - -/obj/item/clothing/head/helmet/update_icon_state() - if(attached_light) - var/state = "[initial(icon_state)]" - if(attached_light.on) - state += "-flight-on" //"helmet-flight-on" // "helmet-cam-flight-on" - else - state += "-flight" //etc. - icon_state = state - return ..() - -/obj/item/clothing/head/helmet/ui_action_click(mob/user, action) - if(istype(action, alight)) - toggle_helmlight() - else - ..() - -/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 && !attached_light) - if(!user.transferItemToLoc(S, src)) - return - to_chat(user, span_notice("You click [S] into place on [src].")) - set_attached_light(S) - update_appearance() - update_helmlight() - alight = new(src) - if(loc == user) - alight.Grant(user) - 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, span_notice("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 = set_attached_light(null) - update_helmlight() - removed_light.update_brightness(user) - update_appearance() - 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(!attached_light) - return - - var/mob/user = usr - if(user.incapacitated()) - return - attached_light.on = !attached_light.on - attached_light.update_brightness() - to_chat(user, span_notice("You toggle the helmet light [attached_light.on ? "on":"off"].")) - - playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) - update_helmlight() - -/obj/item/clothing/head/helmet/proc/update_helmlight() - if(attached_light) - update_appearance() - - update_action_buttons() diff --git a/code/modules/clothing/head/mind_monkey_helmet.dm b/code/modules/clothing/head/mind_monkey_helmet.dm new file mode 100644 index 00000000000..a9fc81ee973 --- /dev/null +++ b/code/modules/clothing/head/mind_monkey_helmet.dm @@ -0,0 +1,110 @@ + +//monkey sentience caps +/* SKYRAT EDIT REMOVAL +/obj/item/clothing/head/helmet/monkey_sentience + name = "monkey mind magnification helmet" + desc = "A fragile, circuitry embedded helmet for boosting the intelligence of a monkey to a higher level. You see several warning labels..." + + icon_state = "monkeymind" + inhand_icon_state = "monkeymind" + strip_delay = 100 + var/mob/living/carbon/human/magnification = null ///if the helmet is on a valid target (just works like a normal helmet if not (cargo please stop)) + var/polling = FALSE///if the helmet is currently polling for targets (special code for removal) + var/light_colors = 1 ///which icon state color this is (red, blue, yellow) + +/obj/item/clothing/head/helmet/monkey_sentience/Initialize(mapload) + . = ..() + light_colors = rand(1,3) + update_appearance() + +/obj/item/clothing/head/helmet/monkey_sentience/examine(mob/user) + . = ..() + . += span_boldwarning("---WARNING: REMOVAL OF HELMET ON SUBJECT MAY LEAD TO:---") + . += span_warning("BLOOD RAGE") + . += span_warning("BRAIN DEATH") + . += span_warning("PRIMAL GENE ACTIVATION") + . += span_warning("GENETIC MAKEUP MASS SUSCEPTIBILITY") + . += span_boldnotice("Ask your CMO if mind magnification is right for you.") + +/obj/item/clothing/head/helmet/monkey_sentience/update_icon_state() + . = ..() + icon_state = "[initial(icon_state)][light_colors][magnification ? "up" : null]" + +/obj/item/clothing/head/helmet/monkey_sentience/equipped(mob/user, slot) + . = ..() + if(slot != ITEM_SLOT_HEAD) + return + if(!ismonkey(user) || user.ckey) + var/mob/living/something = user + to_chat(something, span_boldnotice("You feel a stabbing pain in the back of your head for a moment.")) + something.apply_damage(5,BRUTE,BODY_ZONE_HEAD,FALSE,FALSE,FALSE) //notably: no damage resist (it's in your helmet), no damage spread (it's in your helmet) + playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE) + return + if(!(GLOB.ghost_role_flags & GHOSTROLE_STATION_SENTIENCE)) + say("ERROR: Central Command has temporarily outlawed monkey sentience helmets in this sector. NEAREST LAWFUL SECTOR: 2.537 million light years away.") + return + magnification = user //this polls ghosts + visible_message(span_warning("[src] powers up!")) + playsound(src, 'sound/machines/ping.ogg', 30, TRUE) + RegisterSignal(magnification, COMSIG_SPECIES_LOSS, .proc/make_fall_off) + polling = TRUE + var/list/candidates = poll_candidates_for_mob("Do you want to play as a mind magnified monkey?", ROLE_SENTIENCE, ROLE_SENTIENCE, 5 SECONDS, magnification, POLL_IGNORE_SENTIENCE_POTION) + polling = FALSE + if(!magnification) + return + if(!candidates.len) + UnregisterSignal(magnification, COMSIG_SPECIES_LOSS) + magnification = null + visible_message(span_notice("[src] falls silent and drops on the floor. Maybe you should try again later?")) + playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE) + user.dropItemToGround(src) + return + var/mob/picked = pick(candidates) + magnification.key = picked.key + playsound(src, 'sound/machines/microwave/microwave-end.ogg', 100, FALSE) + to_chat(magnification, span_notice("You're a mind magnified monkey! Protect your helmet with your life- if you lose it, your sentience goes with it!")) + var/policy = get_policy(ROLE_MONKEY_HELMET) + if(policy) + to_chat(magnification, policy) + icon_state = "[icon_state]up" + +/obj/item/clothing/head/helmet/monkey_sentience/Destroy() + disconnect() + return ..() + +/obj/item/clothing/head/helmet/monkey_sentience/proc/disconnect() + if(!magnification) //not put on a viable head + return + if(!polling)//put on a viable head, but taken off after polling finished. + if(magnification.client) + to_chat(magnification, span_userdanger("You feel your flicker of sentience ripped away from you, as everything becomes dim...")) + magnification.ghostize(FALSE) + if(prob(10)) + switch(rand(1,4)) + if(1) //blood rage + magnification.ai_controller.blackboard[BB_MONKEY_AGGRESSIVE] = TRUE + if(2) //brain death + magnification.apply_damage(500,BRAIN,BODY_ZONE_HEAD,FALSE,FALSE,FALSE) + if(3) //primal gene (gorilla) + magnification.gorillize() + if(4) //genetic mass susceptibility (gib) + magnification.gib() + //either used up correctly or taken off before polling finished (punish this by destroying the helmet) + UnregisterSignal(magnification, COMSIG_SPECIES_LOSS) + playsound(src, 'sound/machines/buzz-sigh.ogg', 30, TRUE) + playsound(src, SFX_SPARKS, 100, TRUE, SHORT_RANGE_SOUND_EXTRARANGE) + visible_message(span_warning("[src] fizzles and breaks apart!")) + magnification = null + new /obj/effect/decal/cleanable/ash/crematorium(drop_location()) //just in case they're in a locker or other containers it needs to use crematorium ash, see the path itself for an explanation + +/obj/item/clothing/head/helmet/monkey_sentience/dropped(mob/user) + . = ..() + if(magnification || polling) + qdel(src)//runs disconnect code + +/obj/item/clothing/head/helmet/monkey_sentience/proc/make_fall_off() + SIGNAL_HANDLER + if(magnification) + visible_message(span_warning("[src] falls off of [magnification]'s head as it changes shape!")) + magnification.dropItemToGround(src) +*/ diff --git a/code/modules/mob/living/carbon/human/monkey/monkey.dm b/code/modules/mob/living/carbon/human/monkey/monkey.dm index a4ce98269e5..b0cccf6618d 100644 --- a/code/modules/mob/living/carbon/human/monkey/monkey.dm +++ b/code/modules/mob/living/carbon/human/monkey/monkey.dm @@ -24,10 +24,13 @@ /mob/living/carbon/human/species/monkey/angry/Initialize(mapload) . = ..() if(prob(10)) - var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src) - equip_to_slot_or_del(helmet,ITEM_SLOT_HEAD) - helmet.attack_self(src) // todo encapsulate toggle + INVOKE_ASYNC(src, .proc/give_ape_escape_helmet) +/// Gives our funny monkey an Ape Escape hat reference +/mob/living/carbon/human/species/monkey/angry/proc/give_ape_escape_helmet() + var/obj/item/clothing/head/helmet/justice/escape/helmet = new(src) + equip_to_slot_or_del(helmet, ITEM_SLOT_HEAD) + helmet.attack_self(src) // todo encapsulate toggle GLOBAL_DATUM(the_one_and_only_punpun, /mob/living/carbon/human/species/monkey/punpun) diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index d088324681e..750a28ad32f 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -56,10 +56,6 @@ var/obj/item/firing_pin/pin = /obj/item/firing_pin //standard firing pin for most guns /// True if a gun dosen't need a pin, mostly used for abstract guns like tentacles and meathooks var/pinless = FALSE - var/can_flashlight = FALSE //if a flashlight can be added or removed if it already has one. - var/obj/item/flashlight/seclite/gun_light - var/datum/action/item_action/toggle_gunlight/alight - var/gunlight_state = "flight" var/can_bayonet = FALSE //if a bayonet can be added or removed if it already has one. var/obj/item/knife/bayonet @@ -68,8 +64,6 @@ var/ammo_x_offset = 0 //used for positioning ammo count overlay on sprite var/ammo_y_offset = 0 - var/flight_x_offset = 0 - var/flight_y_offset = 0 var/pb_knockback = 0 @@ -77,14 +71,12 @@ . = ..() if(pin) pin = new pin(src) - if(gun_light) - alight = new(src) + + add_seclight_point() /obj/item/gun/Destroy() if(isobj(pin)) //Can still be the initial path, then we skip QDEL_NULL(pin) - if(gun_light) - QDEL_NULL(gun_light) if(bayonet) QDEL_NULL(bayonet) if(chambered) //Not all guns are chambered (EMP'ed energy guns etc) @@ -93,6 +85,12 @@ QDEL_NULL(suppressed) return ..() +/// Handles adding [the seclite mount component][/datum/component/seclite_attachable] to the gun. +/// If the gun shouldn't have a seclight mount, override this with a return. +/// Or, if a child of a gun with a seclite mount has slightly different behavior or icons, extend this. +/obj/item/gun/proc/add_seclight_point() + return + /obj/item/gun/handle_atom_del(atom/A) if(A == pin) pin = null @@ -101,8 +99,6 @@ update_appearance() if(A == bayonet) clear_bayonet() - if(A == gun_light) - clear_gunlight() if(A == suppressed) clear_suppressor() return ..() @@ -123,13 +119,6 @@ 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. - . += span_info("[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. @@ -417,19 +406,7 @@ /obj/item/gun/attackby(obj/item/I, mob/living/user, params) if(user.combat_mode) return ..() - else if(istype(I, /obj/item/flashlight/seclite)) - if(!can_flashlight) - return ..() - var/obj/item/flashlight/seclite/S = I - if(!gun_light) - if(!user.transferItemToLoc(I, src)) - return - to_chat(user, span_notice("You click [S] into place on [src].")) - set_gun_light(S) - update_gunlight() - alight = new(src) - if(loc == user) - alight.Grant(user) + else if(istype(I, /obj/item/knife)) var/obj/item/knife/K = I if(!can_bayonet || !K.bayonet || bayonet) //ensure the gun has an attachment point available, and that the knife is compatible with it. @@ -449,20 +426,9 @@ 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 = tgui_input_list(user, "Attachment to remove", "Attachment Removal", sort_names(possible_items)) - if(isnull(item_to_remove)) - return - if(!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") + if(bayonet && can_bayonet) //if it has a bayonet, and the bayonet can be removed + return remove_bayonet(user, I) else if(pin && user.is_holding(src)) user.visible_message(span_warning("[user] attempts to remove [pin] from [src] with [I]."), @@ -509,19 +475,15 @@ 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()) +/obj/item/gun/proc/remove_bayonet(mob/living/user, obj/item/tool_item) + tool_item?.play_tool_sound(src) + to_chat(user, span_notice("You unfix [bayonet] from [src].")) + bayonet.forceMove(drop_location()) if(Adjacent(user) && !issilicon(user)) - user.put_in_hands(item_to_remove) + user.put_in_hands(bayonet) - if(item_to_remove == bayonet) - return clear_bayonet() - else if(item_to_remove == gun_light) - return clear_gunlight() + return clear_bayonet() /obj/item/gun/proc/clear_bayonet() if(!bayonet) @@ -530,79 +492,8 @@ 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)) - gun_light.set_light_flags(gun_light.light_flags & ~LIGHT_ATTACHED) - 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) - new_light.set_light_flags(new_light.light_flags | LIGHT_ATTACHED) - if(new_light.loc != src) - new_light.forceMove(src) - - gun_light = new_light - -/obj/item/gun/ui_action_click(mob/user, actiontype) - if(istype(actiontype, alight)) - toggle_gunlight() - else - ..() - -/obj/item/gun/proc/toggle_gunlight() - if(!gun_light) - return - - var/mob/living/carbon/human/user = usr - gun_light.on = !gun_light.on - gun_light.update_brightness() - to_chat(user, span_notice("You toggle the gunlight [gun_light.on ? "on":"off"].")) - - playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) - update_gunlight() - -/obj/item/gun/proc/update_gunlight() - update_appearance() - update_action_buttons() - /obj/item/gun/update_overlays() . = ..() - if(gun_light) - var/mutable_appearance/flashlight_overlay - var/state = "[gunlight_state][gun_light.on? "_on":""]" //Generic state. - if(gun_light.icon_state in icon_states('icons/obj/guns/flashlights.dmi')) //Snowflake state? - state = gun_light.icon_state - flashlight_overlay = mutable_appearance('icons/obj/guns/flashlights.dmi', state) - flashlight_overlay.pixel_x = flight_x_offset - flashlight_overlay.pixel_y = flight_y_offset - . += flashlight_overlay - if(bayonet) var/mutable_appearance/knife_overlay var/state = "bayonet" //Generic state. diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index 59f9e50ec75..ca37127742e 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -59,6 +59,7 @@ START_PROCESSING(SSobj, src) update_appearance() RegisterSignal(src, COMSIG_ITEM_RECHARGED, .proc/instant_recharge) + AddElement(/datum/element/update_icon_updates_onmob) /obj/item/gun/energy/add_weapon_description() AddElement(/datum/element/weapon_description, attached_proc = .proc/add_notes_energy) @@ -92,10 +93,6 @@ return readout.Join("\n") // Sending over the singular string, rather than the whole list -/obj/item/gun/energy/ComponentInitialize() - . = ..() - AddElement(/datum/element/update_icon_updates_onmob) - /obj/item/gun/energy/proc/update_ammo_types() var/obj/item/ammo_casing/energy/shot for (var/i in 1 to ammo_type.len) @@ -219,8 +216,8 @@ if(modifystate) var/obj/item/ammo_casing/energy/shot = ammo_type[select] if(single_shot_type_overlay) - . += "[icon_state]_[shot.select_name]" - overlay_icon_state += "_[shot.select_name]" + . += "[icon_state]_[initial(shot.select_name)]" + overlay_icon_state += "_[initial(shot.select_name)]" var/ratio = get_charge_ratio() if(ratio == 0 && display_empty) diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index 0d2fe725c09..24af32d83c6 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -6,12 +6,16 @@ inhand_icon_state = null //so the human update icon uses the icon_state instead. ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser) modifystate = TRUE - can_flashlight = TRUE ammo_x_offset = 3 - flight_x_offset = 15 - flight_y_offset = 10 dual_wield_spread = 60 +/obj/item/gun/energy/e_gun/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, \ + light_overlay_icon = 'icons/obj/guns/flashlights.dmi', \ + light_overlay = "flight", \ + overlay_x = 15, \ + overlay_y = 10) + /obj/item/gun/energy/e_gun/mini name = "miniature energy gun" desc = "A small, pistol-sized energy gun with a built-in flashlight. It has two settings: disable and kill." @@ -21,15 +25,17 @@ cell_type = /obj/item/stock_parts/cell/mini_egun ammo_x_offset = 2 charge_sections = 3 - can_flashlight = FALSE // Can't attach or detach the flashlight, and override it's icon update - gunlight_state = "mini-light" - flight_x_offset = 19 - flight_y_offset = 13 single_shot_type_overlay = FALSE -/obj/item/gun/energy/e_gun/mini/Initialize(mapload) - set_gun_light(new /obj/item/flashlight/seclite(src)) - return ..() +/obj/item/gun/energy/e_gun/mini/add_seclight_point() + // The mini energy gun's light comes attached but is unremovable. + AddComponent(/datum/component/seclite_attachable, \ + starting_light = new /obj/item/flashlight/seclite(src), \ + is_light_removable = FALSE, \ + light_overlay_icon = 'icons/obj/guns/flashlights.dmi', \ + light_overlay = "mini-light", \ + overlay_x = 19, \ + overlay_y = 13) /obj/item/gun/energy/e_gun/stun name = "tactical energy gun" @@ -76,9 +82,11 @@ ammo_type = list(/obj/item/ammo_casing/energy/net, /obj/item/ammo_casing/energy/trap) modifystate = FALSE w_class = WEIGHT_CLASS_NORMAL - can_flashlight = FALSE ammo_x_offset = 1 +/obj/item/gun/energy/e_gun/dragnet/add_seclight_point() + return + /obj/item/gun/energy/e_gun/dragnet/snare name = "Energy Snare Launcher" desc = "Fires an energy snare that slows the target down." @@ -94,11 +102,13 @@ w_class = WEIGHT_CLASS_HUGE ammo_type = list(/obj/item/ammo_casing/energy/electrode, /obj/item/ammo_casing/energy/laser) weapon_weight = WEAPON_HEAVY - can_flashlight = FALSE trigger_guard = TRIGGER_GUARD_NONE ammo_x_offset = 2 -/obj/item/gun/energy/e_gun/nuclear //ICON OVERRIDEN IN SKYRAT AESTHETICS - SEE MODULE +/obj/item/gun/energy/e_gun/turret/add_seclight_point() + return + +/obj/item/gun/energy/e_gun/nuclear name = "advanced energy gun" desc = "An energy gun with an experimental miniaturized nuclear reactor that automatically charges the internal power cell." icon_state = "nucgun" diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index bcd969f1f82..112a7124435 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -8,9 +8,6 @@ item_flags = NONE obj_flags = UNIQUE_RENAME weapon_weight = WEAPON_LIGHT - can_flashlight = TRUE - flight_x_offset = 15 - flight_y_offset = 9 can_bayonet = TRUE knife_x_offset = 20 knife_y_offset = 12 @@ -18,6 +15,13 @@ var/max_mod_capacity = 100 var/list/modkits = list() +/obj/item/gun/energy/recharge/kinetic_accelerator/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, \ + light_overlay_icon = 'icons/obj/guns/flashlights.dmi', \ + light_overlay = "flight", \ + overlay_x = 15, \ + overlay_y = 9) + /obj/item/gun/energy/recharge/kinetic_accelerator/examine(mob/user) . = ..() if(max_mod_capacity) diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index 45a62a5f8c9..803f4731ba0 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -168,19 +168,23 @@ ammo_type = list(/obj/item/ammo_casing/energy/nanite) shaded_charge = TRUE ammo_x_offset = 1 - can_flashlight = TRUE - flight_x_offset = 15 - flight_y_offset = 9 can_bayonet = TRUE knife_x_offset = 19 knife_y_offset = 13 w_class = WEIGHT_CLASS_NORMAL dual_wield_spread = 10 //as intended by the coders -/obj/item/gun/energy/laser/thermal/ComponentInitialize() +/obj/item/gun/energy/laser/thermal/Initialize(mapload) . = ..() AddElement(/datum/element/empprotection, EMP_PROTECT_SELF|EMP_PROTECT_CONTENTS) +/obj/item/gun/energy/laser/thermal/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, \ + light_overlay_icon = 'icons/obj/guns/flashlights.dmi', \ + light_overlay = "flight", \ + overlay_x = 15, \ + overlay_y = 9) + /obj/item/gun/energy/laser/thermal/inferno //the magma gun name = "inferno pistol" desc = "A modified handcannon with a self-replicating reserve of decommissioned weaponized nanites. Spit globs of molten angry robots into the bad guys. While it doesn't manipulate temperature in of itself, it does cause an violent eruption in anyone who is severely cold." diff --git a/code/modules/projectiles/guns/energy/mounted.dm b/code/modules/projectiles/guns/energy/mounted.dm index fa0b03f3f1c..dba6307ae0b 100644 --- a/code/modules/projectiles/guns/energy/mounted.dm +++ b/code/modules/projectiles/guns/energy/mounted.dm @@ -7,11 +7,10 @@ display_empty = FALSE force = 5 selfcharge = 1 - can_flashlight = FALSE trigger_guard = TRIGGER_GUARD_ALLOW_ALL // Has no trigger at all, uses neural signals instead -/obj/item/gun/energy/e_gun/advtaser/mounted/dropped()//if somebody manages to drop this somehow... - ..() +/obj/item/gun/energy/e_gun/advtaser/mounted/add_seclight_point() + return /obj/item/gun/energy/laser/mounted name = "mounted laser" @@ -23,9 +22,6 @@ selfcharge = 1 trigger_guard = TRIGGER_GUARD_ALLOW_ALL -/obj/item/gun/energy/laser/mounted/dropped() - ..() - /obj/item/gun/energy/laser/mounted/augment icon = 'icons/obj/surgery.dmi' icon_state = "arm_laser" diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index 9f90b69da74..d53edc8a52d 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -40,9 +40,13 @@ worn_icon_state = "gun" inhand_icon_state = null cell_type = "/obj/item/stock_parts/cell/pulse/carbine" - can_flashlight = TRUE - flight_x_offset = 18 - flight_y_offset = 12 + +/obj/item/gun/energy/pulse/carbine/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, \ + light_overlay_icon = 'icons/obj/guns/flashlights.dmi', \ + light_overlay = "flight", \ + overlay_x = 18, \ + overlay_y = 12) /obj/item/gun/energy/pulse/carbine/loyalpin pin = /obj/item/firing_pin/implant/mindshield diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index e050abab313..c06babcfd0b 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -5,13 +5,17 @@ inhand_icon_state = null //so the human update icon uses the icon_state instead. worn_icon_state = null shaded_charge = TRUE - can_flashlight = TRUE w_class = WEIGHT_CLASS_HUGE flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BACK ammo_type = list(/obj/item/ammo_casing/energy/ion) - flight_x_offset = 17 - flight_y_offset = 9 + +/obj/item/gun/energy/ionrifle/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, \ + light_overlay_icon = 'icons/obj/guns/flashlights.dmi', \ + light_overlay = "flight", \ + overlay_x = 17, \ + overlay_y = 9) /obj/item/gun/energy/ionrifle/emp_act(severity) return @@ -22,8 +26,11 @@ icon_state = "ioncarbine" w_class = WEIGHT_CLASS_BULKY slot_flags = ITEM_SLOT_BELT - flight_x_offset = 18 - flight_y_offset = 11 + +/obj/item/gun/energy/ionrifle/carbine/add_seclight_point() + . = ..() + // We use the same overlay as the parent, so we can just let the component inherit the correct offsets here + AddComponent(/datum/component/seclite_attachable, overlay_x = 18, overlay_y = 11) /obj/item/gun/energy/decloner name = "biological demolecularisor" diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index f1edf85c516..4802e8283df 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -16,10 +16,12 @@ /obj/item/gun/energy/e_gun/advtaser/cyborg name = "cyborg taser" desc = "An integrated hybrid taser that draws directly from a cyborg's power cell. The weapon contains a limiter to prevent the cyborg's power cell from overheating." - can_flashlight = FALSE can_charge = FALSE use_cyborg_cell = TRUE +/obj/item/gun/energy/e_gun/advtaser/cyborg/add_seclight_point() + return + /obj/item/gun/energy/e_gun/advtaser/cyborg/emp_act() return @@ -30,11 +32,15 @@ inhand_icon_state = null ammo_type = list(/obj/item/ammo_casing/energy/disabler/skyrat) // SKYRAT EDIT: ammo_type = list(/obj/item/ammo_casing/energy/disabler) ammo_x_offset = 2 - can_flashlight = TRUE - flight_x_offset = 15 - flight_y_offset = 10 cell_type = /obj/item/stock_parts/cell/super // SKYRAT EDIT ADDITION +/obj/item/gun/energy/disabler/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, \ + light_overlay_icon = 'icons/obj/guns/flashlights.dmi', \ + light_overlay = "flight", \ + overlay_x = 15, \ + overlay_y = 10) + /obj/item/gun/energy/disabler/cyborg name = "cyborg disabler" desc = "An integrated disabler that draws from a cyborg's power cell. This weapon contains a limiter to prevent the cyborg's power cell from overheating." diff --git a/modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm b/modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm index aa63398c0b3..ac55e9ccaac 100644 --- a/modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm +++ b/modular_skyrat/master_files/code/modules/projectiles/guns/gun.dm @@ -55,13 +55,7 @@ var/obj/item/firing_pin/pin = /obj/item/firing_pin // standard firing pin for most guns - var/can_flashlight = FALSE // if a flashlight can be added or removed if it already has one. - /// True if a gun dosen't need a pin, mostly used for abstract guns like tentacles and meathooks var/pinless = FALSE - var/obj/item/flashlight/seclite/gun_light - var/datum/action/item_action/toggle_gunlight/alight - var/gunlight_state = "flight" - var/gunlight_icon = 'icons/obj/guns/flashlights.dmi' var/can_bayonet = FALSE // if a bayonet can be added or removed if it already has one. var/bayonet_state = "bayonet" @@ -72,8 +66,6 @@ var/ammo_x_offset = 0 // used for positioning ammo count overlay on sprite var/ammo_y_offset = 0 - var/flight_x_offset = 0 - var/flight_y_offset = 0 // Zooming var/pb_knockback = 0 @@ -111,8 +103,7 @@ if(pin && !pinless) pin = new pin(src) - if(gun_light) - alight = new(src) + add_seclight_point() if(has_gun_safety) safety = TRUE @@ -140,8 +131,6 @@ /obj/item/gun/Destroy() if(isobj(pin)) // Can still be the initial path, then we skip QDEL_NULL(pin) - if(gun_light) - QDEL_NULL(gun_light) if(bayonet) QDEL_NULL(bayonet) if(chambered) // Not all guns are chambered (EMP'ed energy guns etc) @@ -154,6 +143,12 @@ QDEL_NULL(firemode_action) . = ..() +/// Handles adding [the seclite mount component][/datum/component/seclite_attachable] to the gun. +/// If the gun shouldn't have a seclight mount, override this with a return. +/// Or, if a child of a gun with a seclite mount has slightly different behavior or icons, extend this. +/obj/item/gun/proc/add_seclight_point() + return + /obj/item/gun/handle_atom_del(atom/gun_atom) if(gun_atom == pin) pin = null @@ -162,8 +157,6 @@ update_appearance() if(gun_atom == bayonet) clear_bayonet() - if(gun_atom == gun_light) - clear_gunlight() if(gun_atom == suppressed) clear_suppressor() . = ..() @@ -184,13 +177,6 @@ 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. - . += span_info("[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. @@ -550,19 +536,6 @@ /obj/item/gun/attackby(obj/item/attacking_item, mob/living/user, params) if(user.combat_mode) return ..() - else if(istype(attacking_item, /obj/item/flashlight/seclite)) - if(!can_flashlight) - return ..() - var/obj/item/flashlight/seclite/attaching_seclite = attacking_item - if(!gun_light) - if(!user.transferItemToLoc(attacking_item, src)) - return - balloon_alert(user, "[attaching_seclite] attached") - set_gun_light(attaching_seclite) - update_gunlight() - alight = new(src) - if(loc == user) - alight.Grant(user) else if(istype(attacking_item, /obj/item/knife)) var/obj/item/knife/attaching_knife = attacking_item if(!can_bayonet || !attaching_knife.bayonet || bayonet) // ensure the gun has an attachment point available, and that the knife is compatible with it. @@ -582,20 +555,8 @@ 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 = tgui_input_list(user, "Attachment to remove", "Attachment Removal", sort_names(possible_items)) - if(isnull(item_to_remove)) - return - if(user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) - return - return remove_gun_attachment(user, tool, 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, tool, gun_light, "unscrewed") - - else if(bayonet && can_bayonet) // if it has a bayonet, and the bayonet can be removed - return remove_gun_attachment(user, tool, bayonet, "unfix") + if(bayonet && can_bayonet) //if it has a bayonet, and the bayonet can be removed + return remove_bayonet(user, tool) else if(pin && user.is_holding(src)) if(!pin.can_remove) @@ -651,19 +612,15 @@ 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) - balloon_alert(user, "[item_to_remove] removed") - item_to_remove.forceMove(drop_location()) +/obj/item/gun/proc/remove_bayonet(mob/living/user, obj/item/tool_item) + tool_item?.play_tool_sound(src) + to_chat(user, span_notice("You unfix [bayonet] from [src].")) + bayonet.forceMove(drop_location()) if(Adjacent(user) && !issilicon(user)) - user.put_in_hands(item_to_remove) + user.put_in_hands(bayonet) - if(item_to_remove == bayonet) - return clear_bayonet() - else if(item_to_remove == gun_light) - return clear_gunlight() + return clear_bayonet() /obj/item/gun/proc/clear_bayonet() if(!bayonet) @@ -672,84 +629,8 @@ 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)) - gun_light.set_light_flags(gun_light.light_flags & ~LIGHT_ATTACHED) - 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) - new_light.set_light_flags(new_light.light_flags | LIGHT_ATTACHED) - if(new_light.loc != src) - new_light.forceMove(src) - - gun_light = new_light - -/obj/item/gun/ui_action_click(mob/user, actiontype) - if(istype(actiontype, alight)) - toggle_gunlight() - else - ..() - -/obj/item/gun/proc/toggle_gunlight() - if(!gun_light) - return - - var/mob/living/carbon/human/user = usr - gun_light.on = !gun_light.on - gun_light.update_brightness() - balloon_alert(user, "gunlight [gun_light.on ? "on" : "off"]") - - playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) - update_gunlight() - -/obj/item/gun/proc/update_gunlight() - update_appearance() - update_action_buttons() - -/obj/item/gun/pickup(mob/user) - . = ..() - if(w_class > WEIGHT_CLASS_SMALL && !suppressed) - user.visible_message(span_warning("[user] grabs [src]!"), - span_warning("You grab [src]!")) - /obj/item/gun/update_overlays() . = ..() - if(gun_light) - var/mutable_appearance/flashlight_overlay - var/state = "[gunlight_state][gun_light.on? "_on":""]" // Generic state. - if(gun_light.icon_state in icon_states(gunlight_icon)) // Snowflake state? - state = gun_light.icon_state - flashlight_overlay = mutable_appearance(gunlight_icon, state) - flashlight_overlay.pixel_x = flight_x_offset - flashlight_overlay.pixel_y = flight_y_offset - . += flashlight_overlay if(bayonet) var/mutable_appearance/knife_overlay diff --git a/modular_skyrat/modules/ERT_Factions/FTU/code/items.dm b/modular_skyrat/modules/ERT_Factions/FTU/code/items.dm index a62f562fd5b..26936109b20 100644 --- a/modular_skyrat/modules/ERT_Factions/FTU/code/items.dm +++ b/modular_skyrat/modules/ERT_Factions/FTU/code/items.dm @@ -58,7 +58,6 @@ fire_sound = 'modular_skyrat/modules/ERT_Factions/FTU/sound/r37.ogg' emp_damageable = FALSE can_bayonet = FALSE - can_flashlight = TRUE mag_type = /obj/item/ammo_box/magazine/pulse/r37 company_flag = null @@ -95,7 +94,6 @@ fire_sound = 'modular_skyrat/modules/ERT_Factions/FTU/sound/r40.ogg' emp_damageable = FALSE can_bayonet = FALSE - can_flashlight = TRUE mag_type = /obj/item/ammo_box/magazine/pulse/r40 company_flag = null @@ -128,9 +126,11 @@ rack_sound_volume = 110 spread = 1 realistic = TRUE - can_flashlight = FALSE emp_damageable = FALSE +/obj/item/gun/ballistic/automatic/pistol/pdh/pulse/golden_eagle/add_seclight_point() + return + /obj/item/ammo_box/magazine/pulse/mm12/saphe name = "12.7x35mm SAP-HE magnum magazine" icon_state = "50ae" diff --git a/modular_skyrat/modules/black_mesa/code/armor.dm b/modular_skyrat/modules/black_mesa/code/armor.dm index ddbdbb8acdf..3de0cdb9556 100644 --- a/modular_skyrat/modules/black_mesa/code/armor.dm +++ b/modular_skyrat/modules/black_mesa/code/armor.dm @@ -88,7 +88,6 @@ icon = 'modular_skyrat/modules/awaymissions_skyrat/icons/hecucloth.dmi' worn_icon = 'modular_skyrat/modules/awaymissions_skyrat/icons/hecumob.dmi' worn_icon_digi = 'modular_skyrat/modules/awaymissions_skyrat/icons/hecumob_muzzled.dmi' - can_flashlight = FALSE uses_advanced_reskins = TRUE unique_reskin = list( "Basic" = list( diff --git a/modular_skyrat/modules/goofsec/code/sec_clothing_overrides.dm b/modular_skyrat/modules/goofsec/code/sec_clothing_overrides.dm index 521965a0229..733f1034a0d 100644 --- a/modular_skyrat/modules/goofsec/code/sec_clothing_overrides.dm +++ b/modular_skyrat/modules/goofsec/code/sec_clothing_overrides.dm @@ -201,12 +201,6 @@ flags_inv ^= visor_flags_inv flags_cover ^= visor_flags_cover icon_state = "[initial(icon_state)][up ? "up" : ""]" - //Functionally our only change; checks if the attached light is on or off - if(attached_light) - if(attached_light.on) - icon_state += "-flight-on" //"security_helmet-flight-on" // "security_helmetup-flight-on" - else - icon_state += "-flight" //etc. //End of our only change to_chat(user, span_notice("[up ? alt_toggle_message : toggle_message] \the [src].")) @@ -215,12 +209,6 @@ var/mob/living/carbon/C = user C.head_update(src, forced = 1) -/obj/item/clothing/head/helmet/sec/update_icon_state() - . = ..() - if(attached_light) - //This compresses it down nicely. End result is Initial(is the visor toggled)-(is the flashlight on) - icon_state = "[initial(icon_state)][up ? "up" : ""][attached_light.on ? "-flight-on" : "-flight"]" - //Bulletproof Helmet /obj/item/clothing/head/helmet/alt icon = 'modular_skyrat/master_files/icons/obj/clothing/hats.dmi' diff --git a/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm b/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm index 33aefda554b..b05ebf6ae93 100644 --- a/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm +++ b/modular_skyrat/modules/microfusion/code/microfusion_energy_master.dm @@ -9,11 +9,9 @@ icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi' icon_state = "mcr01" bayonet_icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi' - gunlight_icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi' lefthand_file = 'modular_skyrat/modules/microfusion/icons/guns_lefthand.dmi' righthand_file = 'modular_skyrat/modules/microfusion/icons/guns_righthand.dmi' has_gun_safety = TRUE - can_flashlight = FALSE can_bayonet = FALSE w_class = WEIGHT_CLASS_BULKY obj_flags = UNIQUE_RENAME @@ -118,6 +116,9 @@ /obj/item/gun/microfusion/add_weapon_description() AddElement(/datum/element/weapon_description, attached_proc = .proc/add_notes_energy) +/obj/item/gun/microfusion/add_seclight_point() + return + /obj/item/gun/microfusion/Destroy() if(microfusion_lens) QDEL_NULL(microfusion_lens) diff --git a/modular_skyrat/modules/microfusion/code/microfusion_gun_attachments.dm b/modular_skyrat/modules/microfusion/code/microfusion_gun_attachments.dm index 7577538335c..c84fe2e98d9 100644 --- a/modular_skyrat/modules/microfusion/code/microfusion_gun_attachments.dm +++ b/modular_skyrat/modules/microfusion/code/microfusion_gun_attachments.dm @@ -418,15 +418,16 @@ Allows for flashlights bayonets and adds 1 slot to equipment. /obj/item/microfusion_gun_attachment/rail/run_attachment(obj/item/gun/microfusion/microfusion_gun) . = ..() - microfusion_gun.can_flashlight = TRUE + microfusion_gun.AddComponent(/datum/component/seclite_attachable, \ + light_overlay_icon = 'modular_skyrat/modules/microfusion/icons/microfusion_gun40x32.dmi', \ + light_overlay = "flight") microfusion_gun.can_bayonet = TRUE /obj/item/microfusion_gun_attachment/rail/remove_attachment(obj/item/gun/microfusion/microfusion_gun) . = ..() - microfusion_gun.gun_light = initial(microfusion_gun.can_flashlight) - if(microfusion_gun.gun_light) - microfusion_gun.gun_light.forceMove(get_turf(microfusion_gun)) - microfusion_gun.clear_gunlight() + var/component_to_delete = microfusion_gun.GetComponent(/datum/component/seclite_attachable) + if(component_to_delete) + qdel(component_to_delete) microfusion_gun.can_bayonet = initial(microfusion_gun.can_bayonet) if(microfusion_gun.bayonet) microfusion_gun.bayonet.forceMove(get_turf(microfusion_gun)) diff --git a/modular_skyrat/modules/modular_weapons/code/energy.dm b/modular_skyrat/modules/modular_weapons/code/energy.dm index 8d6c6f92355..871218afe76 100644 --- a/modular_skyrat/modules/modular_weapons/code/energy.dm +++ b/modular_skyrat/modules/modular_weapons/code/energy.dm @@ -17,14 +17,11 @@ cell_type = /obj/item/stock_parts/cell/mini_egun ammo_x_offset = 2 charge_sections = 3 - can_flashlight = FALSE // Can't attach or detach the flashlight, and override it's icon update - gunlight_state = "cfa-disabler-light" has_gun_safety = FALSE company_flag = COMPANY_BOLT -/obj/item/gun/energy/disabler/bolt_disabler/Initialize() - set_gun_light(new /obj/item/flashlight/seclite(src)) - return ..() +/obj/item/gun/energy/disabler/bolt_disabler/add_seclight_point() + return /* * CFA PHALANX diff --git a/modular_skyrat/modules/nanotrasen_rep/code/m45a5.dm b/modular_skyrat/modules/nanotrasen_rep/code/m45a5.dm index fbab2ba1925..50f67ba77ea 100644 --- a/modular_skyrat/modules/nanotrasen_rep/code/m45a5.dm +++ b/modular_skyrat/modules/nanotrasen_rep/code/m45a5.dm @@ -15,10 +15,12 @@ recoil = 0 realistic = TRUE dirt_modifier = 0.1 - can_flashlight = TRUE emp_damageable = FALSE fire_sound = 'modular_skyrat/modules/sec_haul/sound/dp_fire.ogg' +/obj/item/gun/ballistic/automatic/pistol/m45a5/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /obj/item/ammo_box/magazine/m45a5 name = "ACA modular magazine" desc = "A magazine able to chamber .460 Rowland Magnun. Made for the M45A5, as it's the only available sidearm with a smart multi-caliber mechanism." diff --git a/modular_skyrat/modules/sec_haul/code/guns/cmg.dm b/modular_skyrat/modules/sec_haul/code/guns/cmg.dm index 5b4a135f4af..5a971724463 100644 --- a/modular_skyrat/modules/sec_haul/code/guns/cmg.dm +++ b/modular_skyrat/modules/sec_haul/code/guns/cmg.dm @@ -15,15 +15,19 @@ fire_delay = 2.5 burst_size = 2 can_bayonet = TRUE - can_flashlight = TRUE knife_x_offset = 26 knife_y_offset = 10 - flight_x_offset = 24 - flight_y_offset = 10 mag_display = TRUE mag_display_ammo = TRUE empty_indicator = TRUE +/obj/item/gun/ballistic/automatic/cmg/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, \ + light_overlay_icon = 'icons/obj/guns/flashlights.dmi', \ + light_overlay = "flight", \ + overlay_x = 24, \ + overlay_y = 10) + /obj/item/ammo_box/magazine/multi_sprite/cmg name = ".45 PDW magazine" icon = 'modular_skyrat/modules/sec_haul/icons/guns/mags.dmi' diff --git a/modular_skyrat/modules/sec_haul/code/guns/guns.dm b/modular_skyrat/modules/sec_haul/code/guns/guns.dm index 710c6c2c8cf..0c06fbb364a 100644 --- a/modular_skyrat/modules/sec_haul/code/guns/guns.dm +++ b/modular_skyrat/modules/sec_haul/code/guns/guns.dm @@ -30,12 +30,14 @@ rack_sound = 'sound/weapons/gun/pistol/rack.ogg' lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg' bolt_drop_sound = 'sound/weapons/gun/pistol/slide_drop.ogg' - can_flashlight = TRUE dirt_modifier = 0.5 emp_damageable = TRUE fire_delay = 1.90 company_flag = COMPANY_CANTALAN +/obj/item/gun/ballistic/automatic/pistol/g17/add_seclight_point() + return + /obj/item/ammo_box/magazine/multi_sprite/g17 name = "\improper GK-17 magazine" desc = "A magazine for the GK-17 handgun, chambered for 9mm Peacekeeper ammo." @@ -75,10 +77,12 @@ spread = 8 mag_display = FALSE mag_display_ammo = FALSE - can_flashlight = TRUE company_flag = COMPANY_CANTALAN dirt_modifier = 0.7 +/obj/item/gun/ballistic/automatic/pistol/g18/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /obj/item/ammo_box/magazine/multi_sprite/g18 name = "\improper GK-18 magazine" desc = "A magazine for the GK-18 machine pistol, chambered for 9mm Peacekeeper." @@ -114,11 +118,14 @@ lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg' bolt_drop_sound = 'sound/weapons/gun/pistol/slide_drop.ogg' realistic = TRUE - can_flashlight = TRUE dirt_modifier = 0.2 emp_damageable = FALSE fire_delay = 0.9 company_flag = null + +/obj/item/gun/ballistic/automatic/pistol/g17/mesa/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /* * PDH 40x32 */ @@ -140,10 +147,12 @@ bolt_drop_sound = 'sound/weapons/gun/pistol/slide_drop.ogg' realistic = TRUE dirt_modifier = 0.3 - can_flashlight = TRUE emp_damageable = TRUE company_flag = COMPANY_ARMADYNE +/obj/item/gun/ballistic/automatic/pistol/pdh/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /obj/item/gun/ballistic/automatic/pistol/pdh/alt name = "\improper PDH-6C 'SOCOM'" desc = "A prestigious 12mm sidearm normally seen in the hands of SolFed special operation units due to its reliable and time-tested design. Now's one of those times that pays to be the strong, silent type." @@ -157,7 +166,6 @@ spread = 1 realistic = TRUE dirt_modifier = 0.1 - can_flashlight = TRUE emp_damageable = FALSE /obj/item/ammo_box/magazine/multi_sprite/pdh @@ -192,7 +200,6 @@ spread = 5 realistic = TRUE dirt_modifier = 0.1 - can_flashlight = TRUE company_flag = COMPANY_ARMADYNE /obj/item/ammo_box/magazine/multi_sprite/pdh_corpo @@ -219,7 +226,6 @@ fire_sound = 'modular_skyrat/modules/sec_haul/sound/pistol_fire.ogg' realistic = TRUE dirt_modifier = 0.6 - can_flashlight = TRUE company_flag = COMPANY_ARMADYNE /obj/item/ammo_box/magazine/multi_sprite/pdh_peacekeeper @@ -264,12 +270,14 @@ lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg' bolt_drop_sound = 'sound/weapons/gun/pistol/slide_drop.ogg' realistic = TRUE - can_flashlight = TRUE dirt_modifier = 0.6 emp_damageable = TRUE fire_delay = 4.20 company_flag = COMPANY_ARMADYNE +/obj/item/gun/ballistic/automatic/pistol/ladon/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /obj/item/ammo_box/magazine/multi_sprite/ladon name = "\improper Ladon magazine" desc = "A magazine for the Ladon pistol, chambered for 10mm Auto." @@ -393,10 +401,13 @@ mag_type = /obj/item/ammo_box/magazine/multi_sprite/firefly can_suppress = FALSE realistic = TRUE - can_flashlight = TRUE emp_damageable = TRUE company_flag = COMPANY_ARMADYNE +/obj/item/gun/ballistic/automatic/pistol/firefly/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + + /obj/item/ammo_box/magazine/multi_sprite/firefly name = "\improper P-92 magazine" desc = "A twelve-round magazine for the P-92 pistol, chambered in 9mm Peacekeeper." @@ -752,7 +763,6 @@ fire_sound = 'modular_skyrat/modules/sec_haul/sound/ltrifle_fire.ogg' emp_damageable = FALSE can_bayonet = TRUE - can_flashlight = TRUE dirt_modifier = 0.1 company_flag = COMPANY_OLDARMS @@ -845,7 +855,6 @@ can_suppress = FALSE can_bayonet = TRUE mag_display = TRUE - can_flashlight = TRUE mag_display_ammo = TRUE actions_types = null realistic = TRUE @@ -860,6 +869,9 @@ . = ..() AddComponent(/datum/component/scope, range_modifier = 1.75) +/obj/item/gun/ballistic/automatic/norwind/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /obj/item/ammo_box/magazine/multi_sprite/norwind name = "\improper Norwind magazine" desc = "An eight-round magazine for the Norwind DMR, chambered for 12mm." @@ -964,9 +976,11 @@ realistic = TRUE fire_sound = 'modular_skyrat/modules/sec_haul/sound/smg_fire.ogg' emp_damageable = TRUE - can_flashlight = TRUE company_flag = COMPANY_BOLT +/obj/item/gun/ballistic/automatic/pcr/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /obj/item/ammo_box/magazine/multi_sprite/pcr name = "\improper PCR-9 magazine" desc = "A thirty-two round magazine for the PCR-9 submachine gun, chambered for 9mm Peacekeeper." @@ -1012,9 +1026,11 @@ fire_sound = 'modular_skyrat/modules/sec_haul/sound/sfrifle_fire.ogg' emp_damageable = TRUE can_bayonet = TRUE - can_flashlight = TRUE company_flag = COMPANY_BOLT +/obj/item/gun/ballistic/automatic/pitbull/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /obj/item/ammo_box/magazine/multi_sprite/pitbull name = "\improper Pitbull magazine" desc = "A twenty-four round magazine for the Pitbull PDW, chambered in 10mm Auto." diff --git a/modular_skyrat/modules/sec_haul/code/guns/pepperball_gun.dm b/modular_skyrat/modules/sec_haul/code/guns/pepperball_gun.dm index e14c2e526b6..dedf0b1007c 100644 --- a/modular_skyrat/modules/sec_haul/code/guns/pepperball_gun.dm +++ b/modular_skyrat/modules/sec_haul/code/guns/pepperball_gun.dm @@ -11,12 +11,14 @@ lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg' bolt_drop_sound = 'sound/weapons/gun/pistol/slide_drop.ogg' realistic = TRUE - can_flashlight = TRUE dirt_modifier = 2 emp_damageable = TRUE fire_sound_volume = 50 company_flag = COMPANY_BOLT +/obj/item/gun/ballistic/automatic/pistol/pepperball/add_seclight_point() + AddComponent(/datum/component/seclite_attachable, light_overlay_icon = 'icons/obj/guns/flashlights.dmi', light_overlay = "flight") + /obj/item/ammo_box/magazine/pepperball name = "pistol magazine (pepperball)" desc = "A gun magazine filled with balls." diff --git a/tgstation.dme b/tgstation.dme index 6a044a550a8..c7553155abb 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -860,6 +860,7 @@ #include "code\datums\components\rot.dm" #include "code\datums\components\rotation.dm" #include "code\datums\components\scope.dm" +#include "code\datums\components\seclight_attachable.dm" #include "code\datums\components\shell.dm" #include "code\datums\components\shielded.dm" #include "code\datums\components\shrink.dm" @@ -2702,6 +2703,7 @@ #include "code\modules\clothing\head\helmet.dm" #include "code\modules\clothing\head\jobs.dm" #include "code\modules\clothing\head\justice.dm" +#include "code\modules\clothing\head\mind_monkey_helmet.dm" #include "code\modules\clothing\head\moth.dm" #include "code\modules\clothing\head\papersack.dm" #include "code\modules\clothing\head\pirate.dm"