diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index ad0754c85b21..69886107d61c 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -142,7 +142,7 @@ GLOBAL_LIST_INIT(shove_disarming_types, typecacheof(list(/obj/item/gun))) #define EXPLODE_DEVASTATE 1 #define EXPLODE_HEAVY 2 #define EXPLODE_LIGHT 3 -#define EXPLODE_GIB_THRESHOLD 50 //ex_act() with EXPLODE_DEVASTATE severity will gib mobs with less than this much bomb armor +#define EXPLODE_GIB_THRESHOLD 50 //ex_act() with EXPLODE_DEVASTATE severity will gib mobs with less than this much bomb armor #define EMP_HEAVY 1 #define EMP_LIGHT 2 diff --git a/code/__DEFINES/guns.dm b/code/__DEFINES/guns.dm index dba7ce93afaf..17cbab5683d8 100644 --- a/code/__DEFINES/guns.dm +++ b/code/__DEFINES/guns.dm @@ -12,7 +12,8 @@ #define TRIGGER_GUARD_NONE 0 #define TRIGGER_GUARD_NORMAL 1 //Gun bolt types -///The gun has a closed bolt, when resting it's closed, and must be racked to get a bullet from a magazine. see: Every Fucking Videogame Gun Ever +///Gun has a bolt, it stays closed while not cycling. The gun must be racked to have a bullet chambered when a mag is inserted. +/// Example: c20, shotguns, m90 #define BOLT_TYPE_STANDARD 1 ///Gun has a bolt, it is open when ready to fire. The gun can never have a chambered bullet with no magazine, but the bolt stays ready when a mag is removed. /// Example: Some SMGs, the L6 @@ -29,18 +30,6 @@ ///added recoil of sawn off guns #define SAWN_OFF_RECOIL 1 -//ammo box sprite defines -///ammo box will always use provided icon state -#define AMMO_BOX_ONE_SPRITE 0 -///ammo box will have a different state for each bullet; - -#define AMMO_BOX_PER_BULLET 1 -///ammo box will have a different state for full and empty; -max_ammo and -0 -#define AMMO_BOX_FULL_EMPTY 2 - -#define SUPPRESSED_NONE 0 -#define SUPPRESSED_QUIET 1 ///standard suppressed -#define SUPPRESSED_VERY 2 /// no message - //Autofire component /// Compatible firemode is in the gun. Wait until it's held in the user hands. #define AUTOFIRE_STAT_IDLE (1<<0) @@ -54,6 +43,10 @@ #define COMSIG_AUTOFIRE_SHOT "autofire_shot" #define COMPONENT_AUTOFIRE_SHOT_SUCCESS (1<<0) +#define SUPPRESSED_NONE 0 +#define SUPPRESSED_QUIET 1 ///standard suppressed +#define SUPPRESSED_VERY 2 /// no message + #define DUALWIELD_PENALTY_EXTRA_MULTIPLIER 1.6 #define MANUFACTURER_NONE null @@ -72,6 +65,69 @@ #define MANUFACTURER_PGF "the Etherbor Industries emblem" #define MANUFACTURER_IMPORT "Lanchester Import Co." +///////////////// +// ATTACHMENTS // +///////////////// +#define TRAIT_ATTACHABLE "attachable" + +#define COMSIG_ATTACHMENT_ATTACH "attach-attach" +#define COMSIG_ATTACHMENT_DETACH "attach-detach" +#define COMSIG_ATTACHMENT_EXAMINE "attach-examine" +#define COMSIG_ATTACHMENT_EXAMINE_MORE "attach-examine-more" +#define COMSIG_ATTACHMENT_PRE_ATTACK "attach-pre-attack" +#define COMSIG_ATTACHMENT_ATTACK "attach-attacked" +#define COMSIG_ATTACHMENT_UPDATE_OVERLAY "attach-overlay" + +#define COMSIG_ATTACHMENT_TOGGLE "attach-toggle" + +#define COMSIG_ATTACHMENT_GET_SLOT "attach-slot-who" +#define ATTACHMENT_SLOT_MUZZLE "muzzle" +#define ATTACHMENT_SLOT_SCOPE "scope" +#define ATTACHMENT_SLOT_GRIP "grip" +#define ATTACHMENT_SLOT_RAIL "rail" +#define ATTACHMENT_SLOT_STOCK "stock" + +/proc/attachment_slot_to_bflag(slot) + switch(slot) + if(ATTACHMENT_SLOT_MUZZLE) + return (1<<0) + if(ATTACHMENT_SLOT_SCOPE) + return (1<<1) + if(ATTACHMENT_SLOT_GRIP) + return (1<<2) + if(ATTACHMENT_SLOT_RAIL) + return (1<<3) + if(ATTACHMENT_SLOT_STOCK) + return (1<<4) + +/proc/attachment_slot_from_bflag(slot) + switch(slot) + if(1<<0) + return ATTACHMENT_SLOT_MUZZLE + if(1<<1) + return ATTACHMENT_SLOT_SCOPE + if(1<<2) + return ATTACHMENT_SLOT_GRIP + if(1<<3) + return ATTACHMENT_SLOT_RAIL + if(1<<4) + return ATTACHMENT_SLOT_STOCK + +#define ATTACHMENT_DEFAULT_SLOT_AVAILABLE list( \ + ATTACHMENT_SLOT_MUZZLE = 1, \ + ATTACHMENT_SLOT_SCOPE = 1, \ + ATTACHMENT_SLOT_GRIP = 1, \ + ATTACHMENT_SLOT_RAIL = 1, \ + ATTACHMENT_SLOT_STOCK = 1, \ +) + +//attach_features_flags +/// Removable by hand +#define ATTACH_REMOVABLE_HAND (1<<0) +/// Removable via crowbar +#define ATTACH_REMOVABLE_TOOL (1<<1) +#define ATTACH_TOGGLE (1<<2) +#define ATTACH_NO_SPRITE (1<<3) ///////////////// // PROJECTILES // @@ -84,6 +140,18 @@ #define NICE_SHOT_RICOCHET_BONUS 10 //if the shooter has the NICE_SHOT trait and they fire a ricocheting projectile, add this to the ricochet chance and auto aim angle +//ammo box sprite defines +///ammo box will always use provided icon state +#define AMMO_BOX_ONE_SPRITE 0 +///ammo box will have a different state for each bullet; - +#define AMMO_BOX_PER_BULLET 1 +///ammo box will have a different state for full and empty; -max_ammo and -0 +#define AMMO_BOX_FULL_EMPTY 2 + +#define MAG_SIZE_SMALL 1 +#define MAG_SIZE_MEDIUM 2 +#define MAG_SIZE_LARGE 3 + //Projectile Reflect #define REFLECT_NORMAL (1<<0) #define REFLECT_FAKEPROJECTILE (1<<1) @@ -96,3 +164,6 @@ #define FIREMODE_FULLAUTO "auto" #define FIREMODE_OTHER "other" #define FIREMODE_OTHER_TWO "other2" + +#define GUN_LEFTHAND_ICON 'icons/mob/inhands/weapons/guns_lefthand.dmi' +#define GUN_RIGHTHAND_ICON 'icons/mob/inhands/weapons/guns_righthand.dmi' diff --git a/code/__DEFINES/sound.dm b/code/__DEFINES/sound.dm index d4d9807ec0af..1bd23038c600 100644 --- a/code/__DEFINES/sound.dm +++ b/code/__DEFINES/sound.dm @@ -173,3 +173,5 @@ #define SOUND_AREA_LAVALAND SOUND_ENVIRONMENT_MOUNTAINS #define SOUND_AREA_ICEMOON SOUND_ENVIRONMENT_CAVE #define SOUND_AREA_WOODFLOOR SOUND_ENVIRONMENT_CITY + +#define SOUND_EMPTY_MAG 'sound/weapons/empty.ogg' diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 993026c0d5e0..a6f81d8ca4f1 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -366,7 +366,7 @@ return /atom/proc/CtrlShiftClick(mob/user) - SEND_SIGNAL(src, COMSIG_CLICK_CTRL_SHIFT) + SEND_SIGNAL(src, COMSIG_CLICK_CTRL_SHIFT, user) return /* diff --git a/code/datums/action.dm b/code/datums/action.dm index de13fc002dde..cdca8729984f 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -86,9 +86,10 @@ if(owner) UnregisterSignal(owner, COMSIG_PARENT_QDELETING) owner = null - button.moved = FALSE //so the button appears in its normal position when given to another owner. - button.locked = FALSE - button.id = null + if(button) + button.moved = FALSE //so the button appears in its normal position when given to another owner. + button.locked = FALSE + button.id = null /datum/action/proc/Trigger() if(!IsAvailable()) diff --git a/code/datums/components/attachment.dm b/code/datums/components/attachment.dm new file mode 100644 index 000000000000..01e3abedd80b --- /dev/null +++ b/code/datums/components/attachment.dm @@ -0,0 +1,182 @@ +/datum/component/attachment + ///Slot the attachment goes on, also used in descriptions so should be player readable + var/slot + ///various yes no flags associated with attachments. See defines for these: [_DEFINES/guns.dm] + var/attach_features_flags + ///Unused so far, should probally handle it in the parent unless you have a specific reason + var/list/valid_parent_types + var/datum/callback/on_attach + var/datum/callback/on_detach + var/datum/callback/on_toggle + ///Called on the parents preattack + var/datum/callback/on_preattack + ///Unused...Also a little broken.. + var/list/datum/action/actions + ///Generated if the attachment can toggle, sends COMSIG_ATTACHMENT_TOGGLE + var/datum/action/attachment/attachment_toggle_action + +/datum/component/attachment/Initialize( + slot = ATTACHMENT_SLOT_RAIL, + attach_features_flags = ATTACH_REMOVABLE_HAND, + valid_parent_types = list(/obj/item/gun), + datum/callback/on_attach = null, + datum/callback/on_detach = null, + datum/callback/on_toggle = null, + datum/callback/on_preattack = null, + list/signals = null + ) + + if(!isitem(parent)) + return COMPONENT_INCOMPATIBLE + + src.slot = slot + src.attach_features_flags = attach_features_flags + src.valid_parent_types = valid_parent_types + src.on_attach = on_attach + src.on_detach = on_detach + src.on_toggle = on_toggle + src.on_preattack = on_preattack + + ADD_TRAIT(parent, TRAIT_ATTACHABLE, "attachable") + RegisterSignal(parent, COMSIG_ATTACHMENT_ATTACH, PROC_REF(try_attach)) + RegisterSignal(parent, COMSIG_ATTACHMENT_DETACH, PROC_REF(try_detach)) + RegisterSignal(parent, COMSIG_ATTACHMENT_EXAMINE, PROC_REF(handle_examine)) + RegisterSignal(parent, COMSIG_ATTACHMENT_EXAMINE_MORE, PROC_REF(handle_examine_more)) + if(attach_features_flags & ATTACH_TOGGLE) + RegisterSignal(parent, COMSIG_ATTACHMENT_TOGGLE, PROC_REF(try_toggle)) + attachment_toggle_action = new /datum/action/attachment(parent) + RegisterSignal(parent, COMSIG_ATTACHMENT_PRE_ATTACK, PROC_REF(relay_pre_attack)) + RegisterSignal(parent, COMSIG_ATTACHMENT_UPDATE_OVERLAY, PROC_REF(update_overlays)) + RegisterSignal(parent, COMSIG_ATTACHMENT_GET_SLOT, PROC_REF(send_slot)) + + for(var/signal in signals) + RegisterSignal(parent, signal, signals[signal]) + +/datum/component/attachment/Destroy(force, silent) + REMOVE_TRAIT(parent, TRAIT_ATTACHABLE, "attachable") + if(actions && length(actions)) + var/obj/item/gun/parent = src.parent + parent.actions -= actions + QDEL_LIST(actions) + qdel(attachment_toggle_action) + return ..() + +/datum/component/attachment/proc/try_toggle(obj/item/parent, obj/item/holder, mob/user) + SIGNAL_HANDLER + if(attach_features_flags & ATTACH_TOGGLE) + INVOKE_ASYNC(src, PROC_REF(do_toggle), parent, holder, user) + holder.update_icon() + attachment_toggle_action.UpdateButtonIcon() + +/datum/component/attachment/proc/do_toggle(obj/item/parent, obj/item/holder, mob/user) + if(on_toggle) + on_toggle.Invoke(holder, user) + return TRUE + + parent.attack_self(user) + return TRUE + +/datum/component/attachment/proc/update_overlays(obj/item/parent, list/overlays, list/offset) + if(!(attach_features_flags & ATTACH_NO_SPRITE)) + overlays += mutable_appearance(parent.icon, "[parent.icon_state]-attached") + +/datum/component/attachment/proc/try_attach(obj/item/parent, obj/item/holder, mob/user, bypass_checks) + SIGNAL_HANDLER + + if(!bypass_checks) + if(!parent.Adjacent(user) || (length(valid_parent_types) && (holder.type in valid_parent_types))) + return FALSE + + if(on_attach && !on_attach.Invoke(holder, user)) + return FALSE + + parent.forceMove(holder) + + if(attach_features_flags & ATTACH_TOGGLE) + holder.actions += list(attachment_toggle_action) + attachment_toggle_action.gun = holder + attachment_toggle_action.Grant(user) + + return TRUE + +/datum/component/attachment/proc/try_detach(obj/item/parent, obj/item/holder, mob/user) + SIGNAL_HANDLER + + if(!parent.Adjacent(user) || (valid_parent_types && (holder.type in valid_parent_types))) + return FALSE + + if(on_attach && !on_detach.Invoke(holder, user)) + return FALSE + + if(attach_features_flags & ATTACH_TOGGLE) + holder.actions -= list(attachment_toggle_action) + attachment_toggle_action.gun = null + attachment_toggle_action.Remove(user) + + if(user.can_put_in_hand(parent)) + user.put_in_hand(parent) + return TRUE + + parent.forceMove(holder.drop_location()) + return TRUE + +/datum/component/attachment/proc/handle_examine(obj/item/parent, mob/user, list/examine_list) + SIGNAL_HANDLER + +/datum/component/attachment/proc/handle_examine_more(obj/item/parent, mob/user, list/examine_list) + SIGNAL_HANDLER + +/datum/component/attachment/proc/relay_pre_attack(obj/item/parent, obj/item/gun, atom/target_atom, mob/user, params) + SIGNAL_HANDLER_DOES_SLEEP + + if(on_preattack) + return on_preattack.Invoke(gun, target_atom, user, params) + +/datum/component/attachment/proc/send_slot(obj/item/parent) + SIGNAL_HANDLER + return attachment_slot_to_bflag(slot) + +/datum/action/attachment + name = "Toggle Attachment" + check_flags = AB_CHECK_HANDS_BLOCKED|AB_CHECK_CONSCIOUS + button_icon_state = null + ///Decides where we send our toggle signal for when pressed + var/obj/item/gun/gun = null + +/datum/action/attachment/New(Target) + ..() + name = "Toggle [target.name]" + button.name = name + icon_icon = target.icon + button_icon_state = target.icon_state + +/datum/action/attachment/Destroy() + . = ..() + gun = null + +/datum/action/attachment/Trigger() + ..() + SEND_SIGNAL(target, COMSIG_ATTACHMENT_TOGGLE, gun, owner) + +/datum/action/attachment/UpdateButtonIcon() + icon_icon = target.icon + button_icon_state = target.icon_state + ..() + +//Copied from item action.. +/datum/action/attachment/ApplyIcon(atom/movable/screen/movable/action_button/current_button, force) + if(button_icon && button_icon_state) + // If set, use the custom icon that we set instead + // of the item appearence + ..() + else if((target && current_button.appearance_cache != target.appearance) || force) //replace with /ref comparison if this is not valid. + var/obj/item/I = target + var/old_layer = I.layer + var/old_plane = I.plane + I.layer = FLOAT_LAYER //AAAH + I.plane = FLOAT_PLANE //^ what that guy said + current_button.cut_overlays() + current_button.add_overlay(I) + I.layer = old_layer + I.plane = old_plane + current_button.appearance_cache = I.appearance diff --git a/code/datums/components/attachment_holder.dm b/code/datums/components/attachment_holder.dm new file mode 100644 index 000000000000..82968a17604b --- /dev/null +++ b/code/datums/components/attachment_holder.dm @@ -0,0 +1,188 @@ +/datum/component/attachment_holder + dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS + + ///List of things you can attach to the parent + var/list/valid_types = null + ///How many slots a parent can hold of any one slot + var/list/slot_room = null + ///Icon offsets, should match the sprite itself so just find the position where it should attach + var/list/slot_offsets = null + var/list/obj/item/attachments = list() + +/datum/component/attachment_holder/Initialize( + list/slot_room = null, + list/valid_types = null, + list/slot_offsets = null, + list/default_attachments = null + ) + + if(!isgun(parent)) + return COMPONENT_INCOMPATIBLE + var/obj/item/gun/parent_gun = parent + + src.slot_room = slot_room + src.valid_types = valid_types + src.slot_offsets = slot_offsets + + RegisterSignal(parent, COMSIG_PARENT_ATTACKBY, PROC_REF(handle_attack)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE, PROC_REF(handle_examine)) + RegisterSignal(parent, COMSIG_PARENT_EXAMINE_MORE, PROC_REF(handle_examine_more)) + RegisterSignal(parent, COMSIG_PARENT_QDELETING, PROC_REF(handle_qdel)) + RegisterSignal(parent, COMSIG_ITEM_PRE_ATTACK, PROC_REF(handle_item_pre_attack)) + RegisterSignal(parent, COMSIG_CLICK_CTRL_SHIFT, PROC_REF(handle_ctrl_shift_click)) + RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(handle_alt_click)) + RegisterSignal(parent, COMSIG_ATOM_UPDATE_OVERLAYS, PROC_REF(handle_overlays)) + + if(length(default_attachments)) + for(var/attachment in default_attachments) + var/obj/item/attachment/new_attachment = new attachment(parent_gun.loc) + INVOKE_ASYNC(src, PROC_REF(do_attach), new_attachment, null, TRUE) + +/datum/component/attachment_holder/proc/handle_overlays(obj/item/parent, list/overlays) + SIGNAL_HANDLER + + for(var/obj/item/attachment/attach as anything in attachments) + var/slot = SEND_SIGNAL(attach, COMSIG_ATTACHMENT_GET_SLOT) + slot = attachment_slot_from_bflag(slot) + var/list/attach_overlays = list() + SEND_SIGNAL(attach, COMSIG_ATTACHMENT_UPDATE_OVERLAY, attach_overlays) + for(var/mutable_appearance/overlay as anything in attach_overlays) + if(slot_offsets && slot_offsets[slot]) + var/matrix/overlay_matrix = new + overlay_matrix.Translate(slot_offsets[slot]["x"] - attach.pixel_shift_x, slot_offsets[slot]["y"] - attach.pixel_shift_y) + overlay.transform = overlay_matrix + overlays += overlay + +/datum/component/attachment_holder/proc/handle_qdel() + SIGNAL_HANDLER + qdel(src) + +/datum/component/attachment_holder/Destroy(force, silent) + QDEL_LIST(attachments) + attachments = null + return ..() + +/datum/component/attachment_holder/proc/attachments_to_list(only_toggles = FALSE) + . = list() + for(var/obj/item/attachment/attach as anything in attachments) + if(attach.name in .) + stack_trace("two attachments with same name; this shouldn't happen and will cause failures") + continue + if(only_toggles && !(attach.attach_features_flags & ATTACH_TOGGLE)) + continue + .[attach.name] = attach + +/datum/component/attachment_holder/proc/handle_ctrl_shift_click(obj/item/parent, mob/user) + SIGNAL_HANDLER + + INVOKE_ASYNC(src, PROC_REF(do_attachment_radial), parent, user) + +/datum/component/attachment_holder/proc/handle_alt_click(obj/item/parent, mob/user) + SIGNAL_HANDLER + + INVOKE_ASYNC(src, PROC_REF(handle_detach), parent, user) + +/datum/component/attachment_holder/proc/do_attachment_radial(obj/item/parent, mob/user) + var/list/attachments_as_list = attachments_to_list(TRUE) + var/selection = show_radial_menu(user, parent, attachments_as_list) + var/obj/item/attach = attachments_as_list[selection] + if(!attach) + return + SEND_SIGNAL(attach, COMSIG_ATTACHMENT_TOGGLE, parent, user) + +/datum/component/attachment_holder/proc/handle_examine(obj/item/parent, mob/user, list/examine_list) + if(length(attachments)) + examine_list += span_notice("It has [length(attachments)] attachment\s.") + for(var/obj/item/attach as anything in attachments) + SEND_SIGNAL(attach, COMSIG_ATTACHMENT_EXAMINE, user, examine_list) + +/datum/component/attachment_holder/proc/handle_examine_more(obj/item/parent, mob/user, list/examine_list) + for(var/key in slot_room) + if(slot_room[key]) + examine_list += span_notice("It has [slot_room[key]] slot\s free for [key] attachments.") + if(length(attachments)) + examine_list += span_notice("It has the following attachments:") + for(var/obj/item/attach as anything in attachments) + examine_list += span_notice("\t- [attach.name]") + if(length(valid_types)) + examine_list += span_notice("It can accept:") + for(var/obj/attach_type as anything in valid_types) + examine_list += span_notice("\t- [initial(attach_type.name)]") + for(var/obj/item/attach as anything in attachments) + SEND_SIGNAL(attach, COMSIG_ATTACHMENT_EXAMINE_MORE, user, examine_list) + +/datum/component/attachment_holder/proc/do_attach(obj/item/attachment, mob/user, bypass_checks) + var/slot = SEND_SIGNAL(attachment, COMSIG_ATTACHMENT_GET_SLOT) + slot = attachment_slot_from_bflag(slot) + if(!(attachment.type in valid_types)) + to_chat(user, span_notice("[attachment] is not a valid attachment for this [parent]!")) + return + if(!slot_room[slot]) + to_chat(user, span_notice("[parent] does not contain room for [attachment]!")) + return + slot_room[slot]-- + . = SEND_SIGNAL(attachment, COMSIG_ATTACHMENT_ATTACH, parent, user, bypass_checks) + if(.) + attachments += attachment + var/atom/parent = src.parent + parent.update_icon() + +/datum/component/attachment_holder/proc/do_detach(obj/item/attachment, mob/user) + var/slot = SEND_SIGNAL(attachment, COMSIG_ATTACHMENT_GET_SLOT) + slot = attachment_slot_from_bflag(slot) + if(slot in slot_room) + slot_room[slot]++ + . = SEND_SIGNAL(attachment, COMSIG_ATTACHMENT_DETACH, parent, user) + if(.) + attachments -= attachment + var/atom/parent = src.parent + parent.update_icon() + +/datum/component/attachment_holder/proc/handle_detach(obj/item/parent, mob/user, obj/item/tool) + var/list/tool_list = list() + var/list/hand_list = list() + for(var/obj/item/attachment/attach as anything in attachments) + if(attach.attach_features_flags & ATTACH_REMOVABLE_TOOL) + tool_list[attach.name] = attach + if(attach.attach_features_flags & ATTACH_REMOVABLE_HAND) + hand_list[attach.name] = attach + if(tool) + if(!length(tool_list)) + return + var/selected = tgui_input_list(user, "Select Attachment", "Detach", tool_list) + if(!parent.Adjacent(user) || !selected || !tool || !tool.use_tool(parent, user, 2 SECONDS * tool.toolspeed)) + return + do_detach(tool_list[selected], user) + else + if(!length(hand_list)) + return + var/selected = tgui_input_list(user, "Select Attachment", "Detach", hand_list) + if(do_after(user, 2 SECONDS, parent)) + do_detach(hand_list[selected], user) + + +/datum/component/attachment_holder/proc/handle_attack(obj/item/parent, obj/item/item, mob/user) + SIGNAL_HANDLER + + if(!user.Adjacent(parent)) + return + + if(item.tool_behaviour == TOOL_CROWBAR && length(attachments)) + INVOKE_ASYNC(src, PROC_REF(handle_detach), parent, user, item) + return TRUE + + if(HAS_TRAIT(item, TRAIT_ATTACHABLE)) + INVOKE_ASYNC(src, PROC_REF(do_attach), item, user) + return TRUE + + for(var/obj/item/attach as anything in attachments) + if(SEND_SIGNAL(attach, COMSIG_ATTACHMENT_ATTACK, parent, item, user)) + parent.update_icon() + return TRUE + +/datum/component/attachment_holder/proc/handle_item_pre_attack(obj/item/parent, atom/target_atom, mob/user, params) + SIGNAL_HANDLER + + for(var/obj/item/attach as anything in attachments) + if(SEND_SIGNAL(attach, COMSIG_ATTACHMENT_PRE_ATTACK, parent, target_atom, user, params)) + return TRUE diff --git a/code/datums/wires/mines.dm b/code/datums/wires/mines.dm index 4c856cf99d3f..91e0ac816189 100644 --- a/code/datums/wires/mines.dm +++ b/code/datums/wires/mines.dm @@ -28,7 +28,7 @@ if(WIRE_PIN) if(ourmine.clicked == TRUE) holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] You hear something inside \the [ourmine] click softly.")) - playsound(ourmine, 'sound/weapons/empty.ogg', 30, TRUE) + playsound(ourmine, SOUND_EMPTY_MAG, 30, TRUE) ourmine.clicked = FALSE else holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s detonation pad shifts slightly. Nothing happens.")) @@ -61,7 +61,7 @@ ourmine.dud = TRUE if(ourmine.clicked == TRUE) holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] You hear something inside \the [ourmine] shift out of place.")) - playsound(ourmine, 'sound/weapons/empty.ogg', 30, TRUE) + playsound(ourmine, SOUND_EMPTY_MAG, 30, TRUE) ourmine.clicked = FALSE else holder.visible_message(span_notice("[icon2html(ourmine, viewers(holder))] \The [ourmine]'s detonation pad goes loose.")) diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm index 4a16a6f9b249..b0b40ea0877e 100644 --- a/code/game/mecha/equipment/weapons/weapons.dm +++ b/code/game/mecha/equipment/weapons/weapons.dm @@ -6,7 +6,7 @@ var/fire_sound var/projectiles_per_shot = 1 var/variance = 0 - var/randomspread = 0 //use random spread for machineguns, instead of shotgun scatter + var/randomspread = FALSE //use random spread for machineguns, instead of shotgun scatter var/projectile_delay = 0 var/firing_effect_type = /obj/effect/temp_visual/dir_setting/firing_effect //the visual effect appearing when the weapon is fired. var/kickback = TRUE //Will using this weapon in no grav push mecha back. @@ -137,8 +137,8 @@ desc = "A device that shoots resonant plasma bursts at extreme velocity. The blasts are capable of crushing rock and demolishing solid obstacles." icon_state = "mecha_plasmacutter" item_state = "plasmacutter" - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON energy_drain = 30 projectile = /obj/projectile/plasma/adv/mech fire_sound = 'sound/weapons/plasma_cutter.ogg' @@ -347,7 +347,7 @@ projectiles_cache_max = 1200 projectiles_per_shot = 3 variance = 6 - randomspread = 1 + randomspread = TRUE projectile_delay = 2 harmful = TRUE ammo_type = "lmg" diff --git a/code/game/objects/items/attachments/_attachment.dm b/code/game/objects/items/attachments/_attachment.dm new file mode 100644 index 000000000000..a6c25ec8cdf3 --- /dev/null +++ b/code/game/objects/items/attachments/_attachment.dm @@ -0,0 +1,99 @@ +///Most of the logic of attachments is held within the component which allows you to add other items as attachments in theory +/obj/item/attachment + name = "broken attachment" + desc = "alert coders" + icon = 'icons/obj/guns/attachments.dmi' + + //Slot the attachment goes on, also used in descriptions so should be player readable + var/slot = ATTACHMENT_SLOT_RAIL + ///various yes no flags associated with attachments. See defines for these: [_DEFINES/guns.dm] + var/attach_features_flags = ATTACH_REMOVABLE_HAND + ///See attachment component + var/list/valid_parents = list() + ///Unused.. but could hold extra callbacks I assume? + var/list/signals = list() + ///Component that handles most of the logic of attachments + var/datum/component/attachment/attachment_comp + + ///If the attachment is on or off + var/toggled = FALSE + var/toggle_on_sound = 'sound/items/flashlight_on.ogg' + var/toggle_off_sound = 'sound/items/flashlight_off.ogg' + + ///Determines the amount of pixels to move the icon state for the overlay. in the x direction + var/pixel_shift_x = 16 + ///Determines the amount of pixels to move the icon state for the overlay. in the y direction + var/pixel_shift_y = 16 + + //Toggle modifers are handled seperatly + ///Modifier applied to the parent + var/spread_mod = 0 + ///Modifier applied to the parent + var/spread_unwielded_mod = 0 + ///Modifier applied to the parent, deciseconds + var/wield_delay = 0 + ///Modifier applied to the parent + var/size_mod = 0 + +/obj/item/attachment/Initialize() + . = ..() + attachment_comp = AddComponent( \ + /datum/component/attachment, \ + slot, \ + attach_features_flags, \ + valid_parents, \ + CALLBACK(src, PROC_REF(apply_attachment)), \ + CALLBACK(src, PROC_REF(remove_attachment)), \ + CALLBACK(src, PROC_REF(toggle_attachment)), \ + CALLBACK(src, PROC_REF(on_preattack)), \ + signals) + +/obj/item/attachment/Destroy() + qdel(attachment_comp) + attachment_comp = null + . = ..() + +/obj/item/attachment/proc/toggle_attachment(obj/item/gun/gun, mob/user) + SHOULD_CALL_PARENT(TRUE) + + playsound(user, toggled ? toggle_on_sound : toggle_off_sound, 40, TRUE) + toggled = !toggled + icon_state = "[initial(icon_state)][toggled ? "-on" : ""]" + +/// Checks if a user should be allowed to attach this attachment to the given parent +/obj/item/attachment/proc/apply_attachment(obj/item/gun/gun, mob/user) + SHOULD_CALL_PARENT(TRUE) + + if(toggled) + to_chat(user, span_warning("You cannot attach [src] while it is active!")) + return FALSE + + apply_modifiers(gun, user, TRUE) + playsound(src.loc, 'sound/weapons/gun/pistol/mag_insert_alt.ogg', 75, 1) + return TRUE + +/obj/item/attachment/proc/remove_attachment(obj/item/gun/gun, mob/user) + SHOULD_CALL_PARENT(TRUE) + + if(toggled) + toggle_attachment(gun, user) + + apply_modifiers(gun, user, FALSE) + playsound(src.loc, 'sound/weapons/gun/pistol/mag_release_alt.ogg', 75, 1) + return TRUE + +/obj/item/attachment/proc/on_preattack(obj/item/gun/gun, atom/target, mob/user, list/params) + return FALSE + +///Handles the modifiers to the parent gun +/obj/item/attachment/proc/apply_modifiers(obj/item/gun/gun, mob/user, attaching) + if(attaching) + gun.spread += spread_mod + gun.spread_unwielded += spread_unwielded_mod + gun.wield_delay += wield_delay + gun.w_class += size_mod + else + gun.spread -= spread_mod + gun.spread_unwielded -= spread_unwielded_mod + gun.wield_delay -= wield_delay + gun.w_class -= size_mod diff --git a/code/game/objects/items/attachments/bayonet.dm b/code/game/objects/items/attachments/bayonet.dm new file mode 100644 index 000000000000..6b1961f4b693 --- /dev/null +++ b/code/game/objects/items/attachments/bayonet.dm @@ -0,0 +1,22 @@ +/obj/item/attachment/bayonet + name = "bayonet" + desc = "Stabby-Stabby" + icon_state = "bayonet" + force = 15 + throwforce = 10 + pickup_sound = 'sound/items/handling/knife1_pickup.ogg' + drop_sound = 'sound/items/handling/knife3_drop.ogg' + hitsound = 'sound/weapons/bladeslice.ogg' + attack_verb = list("slashed", "stabbed", "sliced", "torn", "ripped", "diced", "cut") + sharpness = IS_SHARP_ACCURATE + + pixel_shift_x = 1 + pixel_shift_y = 4 + spread_mod = 1 + wield_delay = 0.1 SECONDS + +/obj/item/attachment/bayonet/on_preattack(obj/item/gun/gun, atom/target, mob/living/user, list/params) + if(user.a_intent == INTENT_HARM && user.CanReach(target, src, TRUE)) + melee_attack_chain(user, target, params) + return COMPONENT_NO_ATTACK + diff --git a/code/game/objects/items/attachments/laser_sight.dm b/code/game/objects/items/attachments/laser_sight.dm new file mode 100644 index 000000000000..082da1153de5 --- /dev/null +++ b/code/game/objects/items/attachments/laser_sight.dm @@ -0,0 +1,23 @@ +/obj/item/attachment/laser_sight + name = "laser sight" + desc = "Designed to be rail-mounted on a compatible firearm to provide increased accuracy and decreased spread." + icon_state = "laserpointer" + + attach_features_flags = ATTACH_REMOVABLE_HAND|ATTACH_TOGGLE + pixel_shift_x = 1 + pixel_shift_y = 4 + wield_delay = 0.1 SECONDS + +/obj/item/attachment/laser_sight/toggle_attachment(obj/item/gun/gun, mob/user) + . = ..() + + if(toggled) + gun.spread -= 3 + gun.spread_unwielded -= 3 + gun.wield_delay -= 0.3 SECONDS + else + gun.spread += 3 + gun.spread_unwielded += 3 + gun.wield_delay += 0.3 SECONDS + + playsound(user, toggled ? 'sound/weapons/magin.ogg' : 'sound/weapons/magout.ogg', 40, TRUE) diff --git a/code/game/objects/items/attachments/rail_light.dm b/code/game/objects/items/attachments/rail_light.dm new file mode 100644 index 000000000000..0cfbe9661e9e --- /dev/null +++ b/code/game/objects/items/attachments/rail_light.dm @@ -0,0 +1,33 @@ +/obj/item/attachment/rail_light + name = "rail light" + desc = "A flashlight made to be mounted on a firearm." + icon_state = "raillight" + light_color = COLOR_LIGHT_ORANGE + light_system = MOVABLE_LIGHT_DIRECTIONAL + light_range = 4 + light_power = 0.8 + light_on = FALSE + + attach_features_flags = ATTACH_REMOVABLE_HAND|ATTACH_TOGGLE + pixel_shift_x = 1 + pixel_shift_y = 4 + wield_delay = 0.1 SECONDS + +/obj/item/attachment/rail_light/toggle_attachment(obj/item/gun/gun, mob/user) + . = ..() + set_light_on(toggled) + update_icon() + +/obj/item/attachment/rail_light/apply_attachment(obj/item/gun/gun, mob/user) + . = ..() + if(!.) + return + + set_light_flags(light_flags | LIGHT_ATTACHED) + +/obj/item/attachment/rail_light/remove_attachment(obj/item/gun/gun, mob/user) + . = ..() + if(!.) + return + + set_light_flags(light_flags & ~LIGHT_ATTACHED) diff --git a/code/game/objects/items/attachments/silencer.dm b/code/game/objects/items/attachments/silencer.dm new file mode 100644 index 000000000000..31cf3fc15b36 --- /dev/null +++ b/code/game/objects/items/attachments/silencer.dm @@ -0,0 +1,19 @@ +/obj/item/attachment/silencer + name = "suppressor" + desc = "An attachment for the barrel of a firearm. Muffles the gunshot and muzzle flash." + icon_state = "silencer" + + slot = ATTACHMENT_SLOT_MUZZLE + pixel_shift_x = 1 + pixel_shift_y = 2 + spread_mod = -1 + size_mod = 1 + +/obj/item/attachment/silencer/apply_attachment(obj/item/gun/gun, mob/user) + . = ..() + gun.suppressed = TRUE + +/obj/item/attachment/silencer/remove_attachment(obj/item/gun/gun, mob/user) + . = ..() + gun.suppressed = FALSE + return TRUE diff --git a/code/game/objects/items/attachments/stock.dm b/code/game/objects/items/attachments/stock.dm new file mode 100644 index 000000000000..1fe286c14296 --- /dev/null +++ b/code/game/objects/items/attachments/stock.dm @@ -0,0 +1,40 @@ +/obj/item/attachment/foldable_stock + name = "folding stock" + desc = "A folding stock that can be attached to certain weapons to improve stability and decreases recoil." + icon_state = "skm-carbine-stock" + slot = ATTACHMENT_SLOT_STOCK + attach_features_flags = ATTACH_TOGGLE + + pixel_shift_x = 17 + pixel_shift_y = 18 + + var/toggled_slowdown = 0.10 + var/toggled_wield_delay = -0.4 SECONDS + var/toggled_recoil_bonus = -2 + var/toggled_spread_bonus = -5 + +/obj/item/attachment/foldable_stock/toggle_attachment(obj/item/gun/gun, mob/user) + . = ..() + + if(toggled) + to_chat(user, span_notice("You unfold the stock on the [src].")) + gun.w_class += 1 + gun.wield_delay += toggled_wield_delay + gun.wield_slowdown += toggled_slowdown + gun.recoil += toggled_recoil_bonus + gun.spread += toggled_spread_bonus + else + to_chat(user, span_notice("You fold the stock on the [src].")) + gun.w_class -= 1 + gun.wield_delay -= toggled_wield_delay + gun.wield_slowdown -= toggled_slowdown + gun.recoil -= toggled_recoil_bonus + gun.spread -= toggled_spread_bonus + + if(gun.wielded) + user.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/gun, multiplicative_slowdown = gun.wield_slowdown) + + playsound(src, SOUND_EMPTY_MAG, 100, 1) + +/obj/item/attachment/foldable_stock/inteq + icon_state = "skm-inteqsmg-stock" diff --git a/code/game/objects/items/devices/multitool.dm b/code/game/objects/items/devices/multitool.dm index dca088c1be2e..204371ca0e51 100644 --- a/code/game/objects/items/devices/multitool.dm +++ b/code/game/objects/items/devices/multitool.dm @@ -28,7 +28,7 @@ custom_materials = list(/datum/material/iron=50, /datum/material/glass=20) custom_premium_price = 450 toolspeed = 1 - usesound = 'sound/weapons/empty.ogg' + usesound = SOUND_EMPTY_MAG var/obj/machinery/buffer // simple machine buffer for device linkage var/mode = 0 diff --git a/code/game/objects/items/pneumaticCannon.dm b/code/game/objects/items/pneumaticCannon.dm index 060e59f0f5de..5108a8713633 100644 --- a/code/game/objects/items/pneumaticCannon.dm +++ b/code/game/objects/items/pneumaticCannon.dm @@ -11,8 +11,8 @@ icon = 'icons/obj/pneumaticCannon.dmi' icon_state = "pneumaticCannon" item_state = "bulldog" - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 60, "acid" = 50) var/maxWeightClass = 20 //The max weight of items that can fit into the cannon var/loadedWeightClass = 0 //The weight of items currently in the cannon diff --git a/code/game/objects/items/storage/backpack.dm b/code/game/objects/items/storage/backpack.dm index 5d87b42b78e5..92123969a4cd 100644 --- a/code/game/objects/items/storage/backpack.dm +++ b/code/game/objects/items/storage/backpack.dm @@ -624,7 +624,7 @@ new /obj/item/ammo_box/magazine/smgm45(src) new /obj/item/ammo_box/magazine/smgm45(src) new /obj/item/gun/ballistic/automatic/smg/c20r(src) - new /obj/item/suppressor/specialoffer(src) + new /obj/item/attachment/silencer(src) /obj/item/storage/backpack/duffelbag/syndie/bulldogbundle desc = "A large duffel bag containing a Bulldog, some drums, and a pair of thermal imaging glasses." diff --git a/code/game/objects/items/storage/briefcase.dm b/code/game/objects/items/storage/briefcase.dm index f55613dd4d21..64a3a11cf327 100644 --- a/code/game/objects/items/storage/briefcase.dm +++ b/code/game/objects/items/storage/briefcase.dm @@ -47,5 +47,5 @@ new /obj/item/clothing/under/syndicate/sniper(src) new /obj/item/ammo_box/magazine/sniper_rounds/soporific(src) new /obj/item/ammo_box/magazine/sniper_rounds/soporific(src) - new /obj/item/suppressor/specialoffer(src) + new /obj/item/attachment/silencer(src) diff --git a/code/game/objects/items/storage/uplink_kits.dm b/code/game/objects/items/storage/uplink_kits.dm index bfbc4679af88..f34aae9e6f82 100644 --- a/code/game/objects/items/storage/uplink_kits.dm +++ b/code/game/objects/items/storage/uplink_kits.dm @@ -120,7 +120,7 @@ switch (pickweight(list( "bond" = 2, "ninja" = 1, "darklord" = 1, "white_whale_holy_grail" = 2, "mad_scientist" = 2, "bee" = 1, "mr_freeze" = 2, "made_man"= 1))) if("bond") new /obj/item/gun/ballistic/automatic/pistol/syndicate(src) - new /obj/item/suppressor(src) + new /obj/item/attachment/silencer(src) new /obj/item/ammo_box/magazine/m10mm(src) new /obj/item/ammo_box/magazine/m10mm(src) new /obj/item/clothing/under/chameleon(src) diff --git a/code/game/objects/items/toys.dm b/code/game/objects/items/toys.dm index b1dfb479b66c..5ce082d79dc9 100644 --- a/code/game/objects/items/toys.dm +++ b/code/game/objects/items/toys.dm @@ -187,8 +187,8 @@ icon = 'icons/obj/guns/projectile.dmi' icon_state = "revolver" item_state = "gun" - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BELT w_class = WEIGHT_CLASS_NORMAL diff --git a/code/modules/cargo/blackmarket/blackmarket_items/tools.dm b/code/modules/cargo/blackmarket/blackmarket_items/tools.dm index 384886ac30d3..d24cbf68171d 100644 --- a/code/modules/cargo/blackmarket/blackmarket_items/tools.dm +++ b/code/modules/cargo/blackmarket/blackmarket_items/tools.dm @@ -125,7 +125,7 @@ /datum/blackmarket_item/tool/suppressor name = "Suppressor" desc = "A suppressor, for when you to keep your murder on the down low." - item = /obj/item/suppressor + item = /obj/item/attachment/silencer price_min = 100 price_max = 700 diff --git a/code/modules/cargo/packs/gun.dm b/code/modules/cargo/packs/gun.dm index 1d71b2799026..7ac296f09398 100644 --- a/code/modules/cargo/packs/gun.dm +++ b/code/modules/cargo/packs/gun.dm @@ -189,3 +189,31 @@ cost = 5000 contains = list(/obj/item/storage/guncase/skm) crate_name = "auto rifle crate" + +/datum/supply_pack/gun/attachment/rail_light + name = "Tactical Rail Light Crate" + desc = "Contains a single rail light to be mounted on a firearm." + cost = 250 + contains = list(/obj/item/attachment/rail_light) + crate_name = "rail light crate" + +/datum/supply_pack/gun/attachment/laser_sight + name = "Laser Sight Crate" + desc = "Contains a single rail light to be mounted on a firearm." + cost = 250 + contains = list(/obj/item/attachment/laser_sight) + crate_name = "laser sight crate" + +/datum/supply_pack/gun/attachment/bayonet + name = "Bayonet Crate" + desc = "Contains a single bayonet to be mounted on a firearm." + cost = 250 + contains = list(/obj/item/attachment/bayonet) + crate_name = "bayonet crate" + +/datum/supply_pack/gun/attachment/silencer + name = "Suppressor Crate" + desc = "Contains a single suppressor to be mounted on a firearm." + cost = 250 + contains = list(/obj/item/attachment/silencer) + crate_name = "silencer crate" diff --git a/code/modules/flufftext/Hallucination.dm b/code/modules/flufftext/Hallucination.dm index ced086e1dfc6..4774ea852424 100644 --- a/code/modules/flufftext/Hallucination.dm +++ b/code/modules/flufftext/Hallucination.dm @@ -476,15 +476,15 @@ GLOBAL_LIST_INIT(hallucination_list, list( A = image(image_file,H,"dualsaberred1", layer=ABOVE_MOB_LAYER) if("taser") if(side == "right") - image_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + image_file = GUN_RIGHTHAND_ICON else - image_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' + image_file = GUN_LEFTHAND_ICON A = image(image_file,H,"advtaserstun4", layer=ABOVE_MOB_LAYER) if("ebow") if(side == "right") - image_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + image_file = GUN_RIGHTHAND_ICON else - image_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' + image_file = GUN_LEFTHAND_ICON A = image(image_file,H,"crossbow", layer=ABOVE_MOB_LAYER) if("baton") if(side == "right") diff --git a/code/modules/mining/equipment/kinetic_crusher.dm b/code/modules/mining/equipment/kinetic_crusher.dm index 030e592d80cd..b6073d4c86a2 100644 --- a/code/modules/mining/equipment/kinetic_crusher.dm +++ b/code/modules/mining/equipment/kinetic_crusher.dm @@ -113,7 +113,7 @@ /obj/item/kinetic_crusher/ui_action_click(mob/user, actiontype) set_light_on(!light_on) - playsound(user, 'sound/weapons/empty.ogg', 100, TRUE) + playsound(user, SOUND_EMPTY_MAG, 100, TRUE) update_appearance() diff --git a/code/modules/mining/lavaland/necropolis_chests.dm b/code/modules/mining/lavaland/necropolis_chests.dm index 268413ef203c..e48f4d5af5aa 100644 --- a/code/modules/mining/lavaland/necropolis_chests.dm +++ b/code/modules/mining/lavaland/necropolis_chests.dm @@ -869,8 +869,8 @@ name = "Slowpoke" desc = "The work of a truly genius gunsmith, altered and \"improved\" by a truly deranged Nanotrasen scientist, using components from a kinetic accelerator and beam rifle. Draw, partner!" icon = 'icons/obj/guns/energy.dmi' - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON icon_state = "spur" item_state = "spur" selfcharge = 1 diff --git a/code/modules/mob/living/carbon/human/human_defense.dm b/code/modules/mob/living/carbon/human/human_defense.dm index 1cb061ff9fd9..64dfdfde91ce 100644 --- a/code/modules/mob/living/carbon/human/human_defense.dm +++ b/code/modules/mob/living/carbon/human/human_defense.dm @@ -501,6 +501,10 @@ else if(!(flags & SHOCK_NOGLOVES)) //This gets the siemens_coeff for all non tesla shocks if(gloves) siemens_coeff *= gloves.siemens_coefficient + //If it doesnt have physiology its prob still initializing. + if(!physiology) + . = ..() + return siemens_coeff *= physiology.siemens_coeff siemens_coeff *= dna.species.siemens_coeff . = ..() diff --git a/code/modules/mob/living/simple_animal/hostile/megafauna/codename_claw.dm b/code/modules/mob/living/simple_animal/hostile/megafauna/codename_claw.dm index 3a4506b62562..a762a9298279 100644 --- a/code/modules/mob/living/simple_animal/hostile/megafauna/codename_claw.dm +++ b/code/modules/mob/living/simple_animal/hostile/megafauna/codename_claw.dm @@ -232,7 +232,6 @@ projectiletype = /obj/projectile/tentacle projectilesound = 'sound/effects/splat.ogg' Shoot(target) - /////TENTACLE END /////STING ATTACK diff --git a/code/modules/projectiles/ammunition/_ammunition.dm b/code/modules/projectiles/ammunition/_ammunition.dm index 26597a64f33b..b216296cfe8d 100644 --- a/code/modules/projectiles/ammunition/_ammunition.dm +++ b/code/modules/projectiles/ammunition/_ammunition.dm @@ -32,7 +32,7 @@ var/pellets = 1 //Pellets for spreadshot var/variance = 0 //Variance for inaccuracy fundamental to the casing - var/randomspread = 0 //Randomspread for automatics + var/randomspread = FALSE //Randomspread for automatics var/delay = 0 //Delay for energy weapons var/click_cooldown_override = 0 //Override this to make your gun have a faster fire rate, in tenths of a second. 4 is the default gun cooldown. diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index b92b79e0009f..707f4805afe3 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -4,6 +4,8 @@ icon = 'icons/obj/guns/projectile.dmi' icon_state = "flatgun" item_state = "gun" + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BELT custom_materials = list(/datum/material/iron=2000) @@ -16,101 +18,185 @@ attack_verb = list("struck", "hit", "bashed") pickup_sound = 'sound/items/handling/gun_pickup.ogg' drop_sound = 'sound/items/handling/gun_drop.ogg' + //trigger guard on the weapon, hulks can't fire them with their big meaty fingers + trigger_guard = TRIGGER_GUARD_NORMAL - /// The manufacturer of this weapon. For flavor mostly. If none, this will not show. + ///The manufacturer of this weapon. For flavor mostly. If none, this will not show. var/manufacturer = MANUFACTURER_NONE +/* + * Muzzle +*/ + ///Effect for the muzzle flash of the gun. + var/obj/effect/muzzle_flash/muzzle_flash + ///Icon state of the muzzle flash effect. + var/muzzleflash_iconstate + ///Brightness of the muzzle flash effect. + var/muzzle_flash_lum = 3 + ///Color of the muzzle flash effect. + var/muzzle_flash_color = COLOR_VERY_SOFT_YELLOW + +/* + * Firing +*/ var/fire_sound = 'sound/weapons/gun/pistol/shot.ogg' var/vary_fire_sound = TRUE var/fire_sound_volume = 50 var/dry_fire_sound = 'sound/weapons/gun/general/dry_fire.ogg' - ///Text showed when attempting to fire with no round or empty round. var/dry_fire_text = "click" - ///whether or not a message is displayed when fired - var/suppressed = null - var/can_suppress = FALSE + +/* + * Reloading +*/ + var/obj/item/ammo_casing/chambered = null + ///Whether the gun can be tacloaded by slapping a fresh magazine directly on it + var/tac_reloads = TRUE + ///If we have the 'snowflake mechanic,' how long should it take to reload? + var/tactical_reload_delay = 1 SECONDS + +//BALLISTIC + ///Compatible magazines with the gun + var/mag_type = /obj/item/ammo_box/magazine/m10mm //Removes the need for max_ammo and caliber info + ///Whether the gun alarms when empty or not. + var/empty_alarm = FALSE + ///Do we eject the magazine upon runing out of ammo? + var/empty_autoeject = FALSE + ///Whether the gun supports multiple special mag types + var/special_mags = FALSE + + ///Actual magazine currently contained within the gun + var/obj/item/ammo_box/magazine/magazine + ///whether the gun ejects the chambered casing + var/casing_ejector = TRUE + ///Whether the gun has an internal magazine or a detatchable one. Overridden by BOLT_TYPE_NO_BOLT. + var/internal_magazine = FALSE + + ///Phrasing of the magazine in examine and notification messages; ex: magazine, box, etx + var/magazine_wording = "magazine" + ///Phrasing of the cartridge in examine and notification messages; ex: bullet, shell, dart, etc. + var/cartridge_wording = "bullet" + + ///sound when inserting magazine + var/load_sound = 'sound/weapons/gun/general/magazine_insert_full.ogg' + ///sound when inserting an empty magazine + var/load_empty_sound = 'sound/weapons/gun/general/magazine_insert_empty.ogg' + ///volume of loading sound + var/load_sound_volume = 40 + ///whether loading sound should vary + var/load_sound_vary = TRUE + ///Sound of ejecting a magazine + var/eject_sound = 'sound/weapons/gun/general/magazine_remove_full.ogg' + ///sound of ejecting an empty magazine + var/eject_empty_sound = 'sound/weapons/gun/general/magazine_remove_empty.ogg' + ///volume of ejecting a magazine + var/eject_sound_volume = 40 + ///whether eject sound should vary + var/eject_sound_vary = TRUE + +//ENERGY + //What type of power cell this uses + var/obj/item/stock_parts/cell/gun/cell + var/cell_type = /obj/item/stock_parts/cell/gun + //Can it be charged in a recharger? + var/can_charge = TRUE + var/selfcharge = FALSE + var/charge_tick = 0 + var/charge_delay = 4 + //whether the gun's cell drains the cyborg user's cell to recharge + var/use_cyborg_cell = FALSE + ///Used for large and small cells + var/mag_size = MAG_SIZE_MEDIUM + //Time it takes to unscrew the cell + var/unscrewing_time = 2 SECONDS + + ///if the gun's cell cannot be replaced + var/internal_cell = FALSE + + var/list/ammo_type = list(/obj/item/ammo_casing/energy) + //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next. + var/select = 1 + +/* + * Operation +*/ + //whether or not a message is displayed when fired + var/suppressed = FALSE var/suppressed_sound = 'sound/weapons/gun/general/heavy_shot_suppressed.ogg' var/suppressed_volume = 60 - var/can_unsuppress = TRUE - var/obj/item/ammo_casing/chambered = null - ///trigger guard on the weapon. Used for hulk mutations and ashies. I honestly dont know how usefult his is, id avoid touching it - trigger_guard = TRIGGER_GUARD_NORMAL - ///Set the description of the gun to this when sawed off - var/sawn_desc = null - ///This triggers some sprite behavior in shotguns and prevents further sawoff, note that can_be_sawn_off is on gun/ballistic and not here, wtf. - var/sawn_off = FALSE - /// how many shots per burst, Ex: most machine pistols, M90, some ARs are 3rnd burst, while others like the GAR and laser minigun are 2 round burst. - var/burst_size = 3 - ///The rate of fire when firing in a burst. Not the delay between bursts - var/burst_delay = 0.15 SECONDS - ///The rate of fire when firing full auto and semi auto, and between bursts; for bursts its fire delay + burst_delay after every burst - var/fire_delay = 0.2 SECONDS + //true if the gun is wielded via twohanded component, shouldnt affect anything else + var/wielded = FALSE + //true if the gun is wielded after delay, should affects accuracy + var/wielded_fully = FALSE + ///Slowdown for wielding + var/wield_slowdown = 0.1 + ///How long between wielding and firing in tenths of seconds + var/wield_delay = 0.4 SECONDS + ///Storing value for above + var/wield_time = 0 - /// after initializing, we set the firemode to this - var/default_firemode = FIREMODE_SEMIAUTO - ///Firemode index, due to code shit this is the currently selected firemode - var/firemode_index - /// Our firemodes, subtract and add to this list as needed. NOTE that the autofire component is given on init when FIREMODE_FULLAUTO is here. - var/list/gun_firemodes = list(FIREMODE_SEMIAUTO, FIREMODE_BURST, FIREMODE_FULLAUTO, FIREMODE_OTHER, FIREMODE_OTHER_TWO) - /// A acoc list that determines the names of firemodes. Use if you wanna be weird and set the name of say, FIREMODE_OTHER to "Underbarrel grenade launcher" for example. - var/list/gun_firenames = list(FIREMODE_SEMIAUTO = "single", FIREMODE_BURST = "burst fire", FIREMODE_FULLAUTO = "full auto", FIREMODE_OTHER = "misc. fire", FIREMODE_OTHER_TWO = "very misc. fire") - ///BASICALLY: the little button you select firing modes from? this is jsut the prefix of the icon state of that. For example, if we set it as "laser", the fire select will use "laser_single" and so on. - var/fire_select_icon_state_prefix = "" - ///If true, we put "safety_" before fire_select_icon_state_prefix's prefix. ex. "safety_laser_single" - var/adjust_fire_select_icon_state_on_safety = FALSE +// BALLISTIC + ///Whether the gun has to be racked each shot or not. + var/semi_auto = TRUE + ///The bolt type of the gun, affects quite a bit of functionality, see gun.dm in defines for bolt types: BOLT_TYPE_STANDARD; BOLT_TYPE_LOCKING; BOLT_TYPE_OPEN; BOLT_TYPE_NO_BOLT + var/bolt_type = BOLT_TYPE_STANDARD + ///Used for locking bolt and open bolt guns. Set a bit differently for the two but prevents firing when true for both. + var/bolt_locked = FALSE + ///Phrasing of the bolt in examine and notification messages; ex: bolt, slide, etc. + var/bolt_wording = "bolt" + ///length between individual racks + var/rack_delay = 5 + ///time of the most recent rack, used for cooldown purposes + var/recent_rack = 0 + + ///Whether the gun can be sawn off by sawing tools + var/can_be_sawn_off = FALSE + //description change if weapon is sawn-off + var/sawn_desc = null + var/sawn_off = FALSE - ///Are we firing a burst? If so, dont fire again until burst is done - var/currently_firing_burst = FALSE - ///This prevents gun from firing until the coodown is done, affected by lag - var/current_cooldown = 0 - ///affects if you can fire it unwielded or even dual wield it. LIGHT means dual wield allowed, HEAVY and higher means you have to wield to fire + ///sound of racking + var/rack_sound = 'sound/weapons/gun/general/bolt_rack.ogg' + ///volume of racking + var/rack_sound_volume = 60 + ///whether racking sound should vary + var/rack_sound_vary = TRUE + ///sound of when the bolt is locked back manually + var/lock_back_sound = 'sound/weapons/gun/general/slide_lock_1.ogg' + ///volume of lock back + var/lock_back_sound_volume = 60 + ///whether lock back varies + var/lock_back_sound_vary = TRUE + + ///sound of dropping the bolt or releasing a slide + var/bolt_drop_sound = 'sound/weapons/gun/general/bolt_drop.ogg' + ///volume of bolt drop/slide release + var/bolt_drop_sound_volume = 60 + ///empty alarm sound (if enabled) + var/empty_alarm_sound = 'sound/weapons/gun/general/empty_alarm.ogg' + ///empty alarm volume sound + var/empty_alarm_volume = 70 + ///whether empty alarm sound varies + var/empty_alarm_vary = TRUE + +/* + * Stats +*/ var/weapon_weight = WEAPON_LIGHT - ///If dual wielding, add this to the spread - var/dual_wield_spread = 24 - /// ???, no clue what this is. Original desc: //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once. - var/randomspread = 1 - - ///Alters projectile damage multiplicatively based on this value. Use it for "better" or "worse" weapons that use the same ammo. + //Alters projectile damage multiplicatively based on this value. Use it for "better" or "worse" weapons that use the same ammo. var/projectile_damage_multiplier = 1 - - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' - - var/list/attachment_options = list() //This.. works for now.. gun refactor soon - - 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/kitchen/knife/bayonet - var/knife_x_offset = 0 - var/knife_y_offset = 0 - - 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/zoomable = FALSE //whether the gun generates a Zoom action on creation - var/zoomed = FALSE //Zoom toggle - var/zoom_amt = 3 //Distance in TURFs to move the user's screen forward (the "zoom" effect) - var/zoom_out_amt = 0 - var/datum/action/toggle_scope_zoom/azoom - + //Speed someone can be flung if its point blank var/pb_knockback = 0 - var/wielded = FALSE // true if the gun is wielded via twohanded component, shouldnt affect anything else - - var/wielded_fully = FALSE // true if the gun is wielded after delay, should affects accuracy - + //Set to 0 for shotguns. This is used for weapons that don't fire all their bullets at once. + var/randomspread = TRUE ///How much the bullet scatters when fired while wielded. var/spread = 4 ///How much the bullet scatters when fired while unwielded. var/spread_unwielded = 12 + //additional spread when dual wielding + var/dual_wield_spread = 24 + ///Screen shake when the weapon is fired while wielded. var/recoil = 0 @@ -121,43 +207,126 @@ ///this is how much deviation the gun recoil can have, recoil pushes the screen towards the reverse angle you shot + some deviation which this is the max. var/recoil_deviation = 22.5 - ///Slowdown for wielding - var/wield_slowdown = 0.1 - ///How long between wielding and firing in tenths of seconds - var/wield_delay = 0.4 SECONDS - ///Storing value for above - var/wield_time = 0 + /// how many shots per burst, Ex: most machine pistols, M90, some ARs are 3rnd burst, while others like the GAR and laser minigun are 2 round burst. + var/burst_size = 3 + ///The rate of fire when firing in a burst. Not the delay between bursts + var/burst_delay = 0.15 SECONDS + ///The rate of fire when firing full auto and semi auto, and between bursts; for bursts its fire delay + burst_delay after every burst + var/fire_delay = 0.2 SECONDS + //Prevent the weapon from firing again while already firing + var/firing_burst = 0 - ///Effect for the muzzle flash of the gun. - var/obj/effect/muzzle_flash/muzzle_flash - ///Icon state of the muzzle flash effect. - var/muzzleflash_iconstate - ///Brightness of the muzzle flash effect. - var/muzzle_flash_lum = 3 - ///Color of the muzzle flash effect. - var/muzzle_flash_color = COLOR_VERY_SOFT_YELLOW +/* + * Overlay +*/ + ///Used for positioning ammo count overlay on sprite + var/ammo_x_offset = 0 + var/ammo_y_offset = 0 - //gun saftey +//BALLISTIC + ///Whether the sprite has a visible magazine or not + var/mag_display = FALSE + ///Whether the sprite has a visible ammo display or not + var/mag_display_ammo = FALSE + ///Whether the sprite has a visible indicator for being empty or not. + var/empty_indicator = FALSE + ///Whether the sprite has a visible magazine or not + var/show_magazine_on_sprite = FALSE + ///Whether the sprite has a visible ammo display or not + var/show_magazine_on_sprite_ammo = FALSE + ///Whether the gun supports multiple special mag types + var/unique_mag_sprites_for_variants = FALSE + +//ENERGY + //Do we handle overlays with base update_appearance()? + var/automatic_charge_overlays = TRUE + var/charge_sections = 4 + //if this gun uses a stateful charge bar for more detail + var/shaded_charge = FALSE + //Modifies WHOS state //im SOMEWHAT this is wether or not the overlay changes based on the ammo type selected + var/modifystate = TRUE + +/* + * Attachment +*/ + ///The types of attachments allowed, a list of types. SUBTYPES OF AN ALLOWED TYPE ARE ALSO ALLOWED + var/list/valid_attachments = list() + ///Reference to our attachment holder to prevent subtypes having to call GetComponent + var/datum/component/attachment_holder/attachment_holder + ///Number of attachments that can fit on a given slot + var/list/slot_available = ATTACHMENT_DEFAULT_SLOT_AVAILABLE + ///Offsets for the slots on this gun. should be indexed by SLOT and then by X/Y + var/list/slot_offsets = list() + +/* + * Zooming +*/ + ///Whether the gun generates a Zoom action on creation + var/zoomable = FALSE + //Zoom toggle + var/zoomed = FALSE + ///Distance in TURFs to move the user's screen forward (the "zoom" effect) + var/zoom_amt = 3 + var/zoom_out_amt = 0 + var/datum/action/toggle_scope_zoom/azoom + +/* + * Safety +*/ ///Does this gun have a saftey and thus can toggle it? var/has_safety = FALSE ///If the saftey on? If so, we can't fire the weapon var/safety = FALSE - ///The wording of safety. Useful for guns that have a non-standard safety system, like a revolver var/safety_wording = "safety" +/* + * Spawn Info (Stuff that becomes useless onces the gun is spawned, mostly here for mappers) +*/ + ///Attachments spawned on initialization. Should also be in valid attachments or it SHOULD(once i add that) fail + var/list/default_attachments = list() + +//BALLISTIC + ///Whether the gun will spawn loaded with a magazine + var/spawnwithmagazine = TRUE + +//ENERGY + //set to true so the gun is given an empty cell + var/dead_cell = FALSE + +// Need to sort + ///trigger guard on the weapon. Used for hulk mutations and ashies. I honestly dont know how usefult his is, id avoid touching it + trigger_guard = TRIGGER_GUARD_NORMAL + + /// after initializing, we set the firemode to this + var/default_firemode = FIREMODE_SEMIAUTO + ///Firemode index, due to code shit this is the currently selected firemode + var/firemode_index + /// Our firemodes, subtract and add to this list as needed. NOTE that the autofire component is given on init when FIREMODE_FULLAUTO is here. + var/list/gun_firemodes = list(FIREMODE_SEMIAUTO, FIREMODE_BURST, FIREMODE_FULLAUTO, FIREMODE_OTHER, FIREMODE_OTHER_TWO) + /// A acoc list that determines the names of firemodes. Use if you wanna be weird and set the name of say, FIREMODE_OTHER to "Underbarrel grenade launcher" for example. + var/list/gun_firenames = list(FIREMODE_SEMIAUTO = "single", FIREMODE_BURST = "burst fire", FIREMODE_FULLAUTO = "full auto", FIREMODE_OTHER = "misc. fire", FIREMODE_OTHER_TWO = "very misc. fire") + ///BASICALLY: the little button you select firing modes from? this is jsut the prefix of the icon state of that. For example, if we set it as "laser", the fire select will use "laser_single" and so on. + var/fire_select_icon_state_prefix = "" + ///If true, we put "safety_" before fire_select_icon_state_prefix's prefix. ex. "safety_laser_single" + var/adjust_fire_select_icon_state_on_safety = FALSE + + ///Are we firing a burst? If so, dont fire again until burst is done + var/currently_firing_burst = FALSE + ///This prevents gun from firing until the coodown is done, affected by lag + var/current_cooldown = 0 + /obj/item/gun/Initialize() . = ..() RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield)) RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield)) - if(gun_light) - alight = new(src) muzzle_flash = new(src, muzzleflash_iconstate) build_zooming() build_firemodes() /obj/item/gun/ComponentInitialize() . = ..() + attachment_holder = AddComponent(/datum/component/attachment_holder, slot_available, valid_attachments, slot_offsets, default_attachments) AddComponent(/datum/component/two_handed) /// triggered on wield of two handed item @@ -196,16 +365,10 @@ user.remove_movespeed_modifier(/datum/movespeed_modifier/gun) /obj/item/gun/Destroy() - if(gun_light) - QDEL_NULL(gun_light) - if(bayonet) - QDEL_NULL(bayonet) if(chambered) //Not all guns are chambered (EMP'ed energy guns etc) QDEL_NULL(chambered) if(azoom) QDEL_NULL(azoom) - if(isatom(suppressed)) //SUPPRESSED IS USED AS BOTH A TRUE/FALSE AND AS A REF, WHAT THE FUCKKKKKKKKKKKKKKKKK - QDEL_NULL(suppressed) if(muzzle_flash) QDEL_NULL(muzzle_flash) return ..() @@ -213,36 +376,17 @@ /obj/item/gun/handle_atom_del(atom/A) if(A == chambered) chambered = null - update_appearance() - if(A == bayonet) - clear_bayonet() - if(A == gun_light) - clear_gunlight() + update_icon() return ..() /obj/item/gun/examine(mob/user) . = ..() - 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." - if(has_safety) . += "The safety is [safety ? "ON" : "OFF"]. Ctrl-Click to toggle the safety." if(manufacturer) . += "It has [manufacturer] engraved on it." - /obj/item/gun/equipped(mob/living/user, slot) . = ..() if(zoomed && user.get_active_held_item() != src) @@ -250,48 +394,8 @@ /obj/item/gun/attack(mob/M as mob, mob/user) if(user.a_intent == INTENT_HARM) //Flogging - if(bayonet) - M.attackby(bayonet, user) - return - else - return ..() - return - -/obj/item/gun/attack_obj(obj/O, mob/user) - if(user.a_intent == INTENT_HARM) - if(bayonet) - O.attackby(bayonet, user) - return - return ..() - -/obj/item/gun/attackby(obj/item/I, mob/user, params) - if(user.a_intent == INTENT_HARM) - 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, "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/kitchen/knife)) - var/obj/item/kitchen/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. - return ..() - if(!user.transferItemToLoc(I, src)) - return - to_chat(user, "You attach [K] to [src]'s bayonet lug.") - bayonet = K - update_appearance() - - else return ..() + return //called after the gun has successfully fired its chambered ammo. /obj/item/gun/proc/process_chamber(atom/shooter) @@ -513,6 +617,7 @@ /obj/item/gun/proc/reset_current_cooldown() current_cooldown = FALSE + /obj/item/gun/proc/shoot_with_empty_chamber(mob/living/user as mob|obj) if(!safety) to_chat(user, "*[dry_fire_text]*") @@ -600,116 +705,6 @@ update_appearance() - -/obj/item/gun/screwdriver_act(mob/living/user, obj/item/I) - . = ..() - if(.) - return - if(!user.canUseTopic(src, BE_CLOSE, FALSE, NO_TK)) - return - attachment_options = list() - get_gun_attachments() - if(LAZYLEN(attachment_options) == 1) - remove_gun_attachments(user, I, attachment_options[1]) - else if (LAZYLEN(attachment_options)) - var/picked_option = show_radial_menu(user, src, attachment_options, radius = 38, require_near = TRUE) - remove_gun_attachments(user, I, picked_option) - -/obj/item/gun/proc/get_gun_attachments() - if(can_flashlight && gun_light) - attachment_options += list("Light" = image(icon = gun_light.icon, icon_state = gun_light.icon_state)) - if(can_bayonet && bayonet) - attachment_options += list("Knife" = image(icon = bayonet.icon, icon_state = bayonet.icon_state)) - -/obj/item/gun/proc/remove_gun_attachments(mob/living/user, obj/item/I, picked_option) - if(picked_option == "Light") - return remove_gun_attachment(user, I, gun_light, "unscrewed") - else if(picked_option == "Knife") - return remove_gun_attachment(user, I, bayonet, "unfix") - -/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, "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)) - gun_light.set_light_flags(gun_light.light_flags & ~LIGHT_ATTACHED) - if(gun_light.loc != get_turf(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, "You toggle the gunlight [gun_light.on ? "on":"off"].") - - playsound(user, gun_light.on ? gun_light.toggle_on_sound : gun_light.toggle_off_sound, 40, TRUE) - update_gunlight() - -/obj/item/gun/proc/update_gunlight() - update_appearance() - for(var/X in actions) - var/datum/action/A = X - A.UpdateButtonIcon() - /obj/item/gun/attack_hand(mob/user) . = ..() update_appearance() @@ -730,27 +725,6 @@ /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. - if(bayonet.icon_state in icon_states('icons/obj/guns/bayonets.dmi')) //Snowflake state? - state = bayonet.icon_state - var/icon/bayonet_icons = 'icons/obj/guns/bayonets.dmi' - knife_overlay = mutable_appearance(bayonet_icons, state) - knife_overlay.pixel_x = knife_x_offset - knife_overlay.pixel_y = knife_y_offset - . += knife_overlay - if(ismob(loc) && has_safety) var/mutable_appearance/safety_overlay safety_overlay = mutable_appearance('icons/obj/guns/safety.dmi') @@ -987,10 +961,7 @@ flash_loc.vis_contents -= muzzle_flash muzzle_flash.applied = FALSE -///////////// -// ZOOMING // -///////////// - +//I need to refactor this into an attachment /datum/action/toggle_scope_zoom name = "Toggle Scope" check_flags = AB_CHECK_CONSCIOUS|AB_CHECK_HANDS_BLOCKED|AB_CHECK_IMMOBILE|AB_CHECK_LYING diff --git a/code/modules/projectiles/guns/ballistic.dm b/code/modules/projectiles/guns/ballistic.dm index a4247898d59d..7c75d8fe9f56 100644 --- a/code/modules/projectiles/guns/ballistic.dm +++ b/code/modules/projectiles/guns/ballistic.dm @@ -13,90 +13,26 @@ has_safety = TRUE safety = TRUE - ///sound when inserting magazine - var/load_sound = 'sound/weapons/gun/general/magazine_insert_full.ogg' - ///sound when inserting an empty magazine - var/load_empty_sound = 'sound/weapons/gun/general/magazine_insert_empty.ogg' - ///volume of loading sound - var/load_sound_volume = 40 - ///whether loading sound should vary - var/load_sound_vary = TRUE - ///sound of racking - var/rack_sound = 'sound/weapons/gun/general/bolt_rack.ogg' - ///volume of racking - var/rack_sound_volume = 60 - ///whether racking sound should vary - var/rack_sound_vary = TRUE - ///sound of when the bolt is locked back manually - var/lock_back_sound = 'sound/weapons/gun/general/slide_lock_1.ogg' - ///volume of lock back - var/lock_back_sound_volume = 60 - ///whether lock back varies - var/lock_back_sound_vary = TRUE - ///Sound of ejecting a magazine - var/eject_sound = 'sound/weapons/gun/general/magazine_remove_full.ogg' - ///sound of ejecting an empty magazine - var/eject_empty_sound = 'sound/weapons/gun/general/magazine_remove_empty.ogg' - ///volume of ejecting a magazine - var/eject_sound_volume = 40 - ///whether eject sound should vary - var/eject_sound_vary = TRUE - ///sound of dropping the bolt or releasing a slide - var/bolt_drop_sound = 'sound/weapons/gun/general/bolt_drop.ogg' - ///volume of bolt drop/slide release - var/bolt_drop_sound_volume = 60 - ///empty alarm sound (if enabled) - var/empty_alarm_sound = 'sound/weapons/gun/general/empty_alarm.ogg' - ///empty alarm volume sound - var/empty_alarm_volume = 70 - ///whether empty alarm sound varies - var/empty_alarm_vary = TRUE - - ///Whether the gun will spawn loaded with a magazine - var/spawnwithmagazine = TRUE - ///Compatible magazines with the gun - var/mag_type = /obj/item/ammo_box/magazine/m10mm //Removes the need for max_ammo and caliber info - ///Whether the sprite has a visible magazine or not - var/show_magazine_on_sprite = FALSE - ///Whether the sprite has a visible ammo display or not - var/show_magazine_on_sprite_ammo = FALSE - ///Whether the sprite has a visible indicator for being empty or not. - var/empty_indicator = FALSE - ///Whether the gun alarms when empty or not. - var/empty_alarm = FALSE - ///Do we eject the magazine upon runing out of ammo? - var/empty_autoeject = FALSE - ///Whether the gun supports multiple special mag types - var/unique_mag_sprites_for_variants = FALSE - ///The bolt type of the gun, affects quite a bit of functionality, see combat.dm defines for bolt types: BOLT_TYPE_STANDARD; BOLT_TYPE_LOCKING; BOLT_TYPE_OPEN; BOLT_TYPE_NO_BOLT - var/bolt_type = BOLT_TYPE_STANDARD - ///Used for locking bolt and open bolt guns. Set a bit differently for the two but prevents firing when true for both. - var/bolt_locked = FALSE - ///Whether the gun has to be racked each shot or not. - var/semi_auto = TRUE - ///Actual magazine currently contained within the gun - var/obj/item/ammo_box/magazine/magazine - ///whether the gun ejects the chambered casing - var/casing_ejector = TRUE - ///Whether the gun has an internal magazine or a detatchable one. Overridden by BOLT_TYPE_NO_BOLT. - var/internal_magazine = FALSE - ///Phrasing of the bolt in examine and notification messages; ex: bolt, slide, etc. - var/bolt_wording = "bolt" - ///Phrasing of the magazine in examine and notification messages; ex: magazine, box, etx - var/magazine_wording = "magazine" - ///Phrasing of the cartridge in examine and notification messages; ex: bullet, shell, dart, etc. - var/cartridge_wording = "bullet" - ///length between individual racks - var/rack_delay = 5 - ///time of the most recent rack, used for cooldown purposes - var/recent_rack = 0 - ///Whether the gun can be sawn off by sawing tools - var/can_be_sawn_off = FALSE - - ///Whether the gun can be tacloaded by slapping a fresh magazine directly on it - var/tac_reloads = TRUE //Snowflake mechanic no more. - ///If we have the 'snowflake mechanic,' how long should it take to reload? - var/tactical_reload_delay = 1 SECONDS + valid_attachments = list( + /obj/item/attachment/silencer, + /obj/item/attachment/laser_sight, + /obj/item/attachment/rail_light, + /obj/item/attachment/bayonet + ) + slot_available = list( + ATTACHMENT_SLOT_MUZZLE = 1, + ATTACHMENT_SLOT_RAIL = 1 + ) + slot_offsets = list( + ATTACHMENT_SLOT_MUZZLE = list( + "x" = 26, + "y" = 20, + ), + ATTACHMENT_SLOT_RAIL = list( + "x" = 19, + "y" = 18, + ) + ) /obj/item/gun/ballistic/Initialize() . = ..() @@ -123,8 +59,6 @@ . += "[icon_state]_bolt[bolt_locked ? "_locked" : ""]" if (bolt_type == BOLT_TYPE_OPEN && bolt_locked) . += "[icon_state]_bolt" - if (suppressed) - . += "[icon_state]_suppressor" if (magazine) if (unique_mag_sprites_for_variants) . += "[icon_state]_mag_[magazine.base_icon_state]" @@ -203,12 +137,12 @@ update_appearance() ///Handles all the logic needed for magazine insertion -/obj/item/gun/ballistic/proc/insert_magazine(mob/user, obj/item/ammo_box/magazine/AM, display_message = TRUE) - if(!istype(AM, mag_type)) - to_chat(user, "\The [AM] doesn't seem to fit into \the [src]...") +/obj/item/gun/ballistic/proc/insert_magazine(mob/user, obj/item/ammo_box/magazine/inserted_mag, display_message = TRUE) + if(!istype(inserted_mag, mag_type)) + to_chat(user, "\The [inserted_mag] doesn't seem to fit into \the [src]...") return FALSE - if(user.transferItemToLoc(AM, src)) - magazine = AM + if(user.transferItemToLoc(inserted_mag, src)) + magazine = inserted_mag if (display_message) to_chat(user, "You load a new [magazine_wording] into \the [src].") if (magazine.ammo_count()) @@ -287,48 +221,11 @@ A.update_appearance() update_appearance() return - if(istype(A, /obj/item/suppressor)) - var/obj/item/suppressor/S = A - if(!can_suppress) - to_chat(user, "You can't seem to figure out how to fit [S] on [src]!") - return - if(!user.is_holding(src)) - to_chat(user, "You need be holding [src] to fit [S] to it!") - return - if(suppressed) - to_chat(user, "[src] already has a suppressor!") - return - if(user.transferItemToLoc(A, src)) - to_chat(user, "You screw \the [S] onto \the [src].") - install_suppressor(A) - return if (can_be_sawn_off) if (sawoff(user, A)) return return FALSE -///Installs a new suppressor, assumes that the suppressor is already in the contents of src -/obj/item/gun/ballistic/proc/install_suppressor(obj/item/suppressor/S) - suppressed = S - w_class += S.w_class //so pistols do not fit in pockets when suppressed - update_appearance() - -/obj/item/gun/ballistic/AltClick(mob/user) - if (unique_reskin && !current_skin && user.canUseTopic(src, BE_CLOSE, NO_DEXTERITY)) - reskin_obj(user) - return - if(loc == user) - if(suppressed && can_unsuppress) - var/obj/item/suppressor/S = suppressed - if(!user.is_holding(src)) - return ..() - to_chat(user, "You unscrew \the [suppressed] from \the [src].") - user.put_in_hands(suppressed) - w_class -= S.w_class - suppressed = null - update_appearance() - return - ///Prefire empty checks for the bolt drop /obj/item/gun/ballistic/proc/prefire_empty_checks() if (!chambered && !get_ammo()) @@ -402,9 +299,7 @@ . += "It does not seem to have a round chambered." if (bolt_locked) . += "The [bolt_wording] is locked back and needs to be released before firing." - if (suppressed) - . += "It has a suppressor attached that can be removed with alt+click." - . += "You can [bolt_wording] [src] by pressing the unique action key. By default, this is space" + . += "You can [bolt_wording] [src] by pressing the unqiue action key. By default, this is space" ///Gets the number of bullets in the gun /obj/item/gun/ballistic/proc/get_ammo(countchambered = TRUE) @@ -437,9 +332,6 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( if(sawn_off) to_chat(user, "\The [src] is already shortened!") return - if(bayonet) - to_chat(user, "You cannot saw-off \the [src] with \the [bayonet] attached!") - return user.changeNext_move(CLICK_CD_MELEE) user.visible_message("[user] begins to shorten \the [src].", "You begin to shorten \the [src]...") @@ -470,16 +362,3 @@ GLOBAL_LIST_INIT(gun_saw_types, typecacheof(list( if(AC.BB) process_fire(user, user, FALSE) . = TRUE - - -/obj/item/suppressor - name = "suppressor" - desc = "A syndicate small-arms suppressor for maximum espionage." - icon = 'icons/obj/guns/projectile.dmi' - icon_state = "suppressor" - w_class = WEIGHT_CLASS_TINY - - -/obj/item/suppressor/specialoffer - name = "cheap suppressor" - desc = "A foreign knock-off suppressor, it feels flimsy, cheap, and brittle. Still fits most weapons." diff --git a/code/modules/projectiles/guns/ballistic/assault.dm b/code/modules/projectiles/guns/ballistic/assault.dm index 3f649994827e..ce500cda930b 100644 --- a/code/modules/projectiles/guns/ballistic/assault.dm +++ b/code/modules/projectiles/guns/ballistic/assault.dm @@ -164,7 +164,6 @@ icon_state = "e40" item_state = "e40" mag_type = /obj/item/ammo_box/magazine/e40 - can_suppress = FALSE var/obj/item/gun/energy/laser/e40_laser_secondary/secondary fire_select_icon_state_prefix = "e40_" diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm index 2fea717c28a0..769ea9e7f57e 100644 --- a/code/modules/projectiles/guns/ballistic/automatic.dm +++ b/code/modules/projectiles/guns/ballistic/automatic.dm @@ -1,7 +1,6 @@ /obj/item/gun/ballistic/automatic w_class = WEIGHT_CLASS_NORMAL - can_suppress = TRUE gun_firemodes = list(FIREMODE_SEMIAUTO) default_firemode = FIREMODE_SEMIAUTO @@ -33,8 +32,6 @@ mag_type = /obj/item/ammo_box/magazine/m10mm/rifle fire_delay = 0.5 SECONDS burst_size = 1 - can_unsuppress = TRUE - can_suppress = TRUE w_class = WEIGHT_CLASS_HUGE slot_flags = ITEM_SLOT_BACK show_magazine_on_sprite = TRUE @@ -48,7 +45,6 @@ item_state = "arg" mag_type = /obj/item/ammo_box/magazine/recharge fire_delay = 0.2 SECONDS - can_suppress = FALSE burst_size = 0 fire_sound = 'sound/weapons/laser.ogg' casing_ejector = FALSE @@ -59,8 +55,6 @@ icon_state = "ZipPistol" item_state = "ZipPistol" mag_type = /obj/item/ammo_box/magazine/zip_ammo_9mm - can_suppress = FALSE actions_types = list() - can_bayonet = FALSE show_magazine_on_sprite = TRUE weapon_weight = WEAPON_LIGHT diff --git a/code/modules/projectiles/guns/ballistic/gauss.dm b/code/modules/projectiles/guns/ballistic/gauss.dm index 12264a3ccd8f..3fdc2e55dadd 100644 --- a/code/modules/projectiles/guns/ballistic/gauss.dm +++ b/code/modules/projectiles/guns/ballistic/gauss.dm @@ -11,7 +11,6 @@ mag_type = /obj/item/ammo_box/magazine/gauss fire_sound = 'sound/weapons/gun/gauss/magrifle.ogg' load_sound = 'sound/weapons/gun/gauss/rifle_reload.ogg' - can_suppress = FALSE burst_size = 1 fire_delay = 0.3 SECONDS spread = 0 diff --git a/code/modules/projectiles/guns/ballistic/hmg.dm b/code/modules/projectiles/guns/ballistic/hmg.dm index 79977249dd31..8a3e68b9a6ec 100644 --- a/code/modules/projectiles/guns/ballistic/hmg.dm +++ b/code/modules/projectiles/guns/ballistic/hmg.dm @@ -163,7 +163,6 @@ base_icon_state = "l6" mag_type = /obj/item/ammo_box/magazine/mm712x82 - can_suppress = FALSE spread = 7 fire_delay = 0.1 SECONDS @@ -236,8 +235,6 @@ fire_select_icon_state_prefix = "caseless_" - can_suppress = FALSE - can_bayonet = FALSE show_magazine_on_sprite = TRUE w_class = WEIGHT_CLASS_BULKY manufacturer = MANUFACTURER_SOLARARMORIES diff --git a/code/modules/projectiles/guns/ballistic/launchers.dm b/code/modules/projectiles/guns/ballistic/launchers.dm index d82f2dbd1250..f18f97cd0f4f 100644 --- a/code/modules/projectiles/guns/ballistic/launchers.dm +++ b/code/modules/projectiles/guns/ballistic/launchers.dm @@ -55,7 +55,6 @@ fire_sound = 'sound/weapons/gun/general/rocket_launch.ogg' load_sound = 'sound/weapons/gun/general/rocket_load.ogg' w_class = WEIGHT_CLASS_BULKY - can_suppress = FALSE burst_size = 1 fire_delay = 0.4 SECONDS casing_ejector = FALSE diff --git a/code/modules/projectiles/guns/ballistic/pistol.dm b/code/modules/projectiles/guns/ballistic/pistol.dm index 347f4950382e..b2416462da39 100644 --- a/code/modules/projectiles/guns/ballistic/pistol.dm +++ b/code/modules/projectiles/guns/ballistic/pistol.dm @@ -1,5 +1,4 @@ /obj/item/gun/ballistic/automatic/pistol - can_suppress = TRUE bolt_type = BOLT_TYPE_LOCKING vary_fire_sound = FALSE @@ -67,7 +66,6 @@ EMPTY_GUN_HELPER(automatic/pistol/syndicate) mob_overlay_icon = 'icons/obj/guns/manufacturer/hunterspride/onmob.dmi' mag_type = /obj/item/ammo_box/magazine/m45 - can_suppress = FALSE fire_sound = 'sound/weapons/gun/pistol/candor.ogg' rack_sound = 'sound/weapons/gun/pistol/candor_cocked.ogg' lock_back_sound = 'sound/weapons/gun/pistol/slide_lock.ogg' @@ -106,7 +104,7 @@ EMPTY_GUN_HELPER(automatic/pistol/candor/factory) icon_state = "deagle" force = 14 mag_type = /obj/item/ammo_box/magazine/m50 - can_suppress = FALSE + mag_display = TRUE show_magazine_on_sprite = TRUE fire_sound = 'sound/weapons/gun/pistol/deagle.ogg' rack_sound = 'sound/weapons/gun/pistol/rack.ogg' @@ -166,7 +164,6 @@ EMPTY_GUN_HELPER(automatic/pistol/candor/factory) gun_firemodes = list(FIREMODE_SEMIAUTO, FIREMODE_BURST) default_firemode = FIREMODE_SEMIAUTO - /obj/item/gun/ballistic/automatic/pistol/commander name = "\improper Commander" desc = "A classic handgun in a tasteful black and stainless steel color scheme. An enamel Nanotrasen logo is set into the grips. Chambered in 9mm." @@ -178,7 +175,6 @@ EMPTY_GUN_HELPER(automatic/pistol/candor/factory) w_class = WEIGHT_CLASS_NORMAL mag_type = /obj/item/ammo_box/magazine/co9mm - can_suppress = FALSE manufacturer = MANUFACTURER_NANOTRASEN fire_sound = 'sound/weapons/gun/pistol/commander.ogg' load_sound = 'sound/weapons/gun/pistol/mag_insert.ogg' @@ -216,7 +212,6 @@ EMPTY_GUN_HELPER(automatic/pistol/commander/inteq) w_class = WEIGHT_CLASS_NORMAL mag_type = /obj/item/ammo_box/magazine/co9mm - can_suppress = FALSE var/funnysounds = TRUE var/cooldown = 0 load_sound = 'sound/weapons/gun/pistol/mag_insert.ogg' @@ -256,6 +251,7 @@ EMPTY_GUN_HELPER(automatic/pistol/commander/inteq) to_chat(user, "You toggle [src]'s vox audio functions.") /obj/item/gun/ballistic/automatic/pistol/commissar/AltClick(mob/user) + . = ..() if(!user.canUseTopic(src, BE_CLOSE, ismonkey(user))) return if((cooldown < world.time - 200) && funnysounds) @@ -327,7 +323,6 @@ EMPTY_GUN_HELPER(automatic/pistol/commander/inteq) w_class = WEIGHT_CLASS_NORMAL mag_type = /obj/item/ammo_box/magazine/disposable custom_materials = list(/datum/material/plastic=2000) - can_suppress = FALSE manufacturer = MANUFACTURER_NONE has_safety = FALSE //thing barely costs anything, why would it have a safety? safety = FALSE @@ -410,7 +405,6 @@ EMPTY_GUN_HELPER(automatic/pistol/commander/inteq) w_class = WEIGHT_CLASS_TINY mag_type = /obj/item/ammo_box/magazine/m22lr - can_suppress = FALSE fire_sound = 'sound/weapons/gun/pistol/himehabu.ogg' load_sound = 'sound/weapons/gun/pistol/mag_insert_alt.ogg' diff --git a/code/modules/projectiles/guns/ballistic/rifle.dm b/code/modules/projectiles/guns/ballistic/rifle.dm index 4cf82a445fb3..1e7724c5c9fa 100644 --- a/code/modules/projectiles/guns/ballistic/rifle.dm +++ b/code/modules/projectiles/guns/ballistic/rifle.dm @@ -99,7 +99,6 @@ if(.) spread = 24 spread_unwielded = 30 - can_bayonet = FALSE item_state = "illestren_sawn" mob_overlay_state = item_state weapon_weight = WEAPON_MEDIUM //you can fire it onehanded, makes it worse than worse than useless onehanded, but you can diff --git a/code/modules/projectiles/guns/ballistic/shotgun.dm b/code/modules/projectiles/guns/ballistic/shotgun.dm index 692c09a45f42..1f15f8d01689 100644 --- a/code/modules/projectiles/guns/ballistic/shotgun.dm +++ b/code/modules/projectiles/guns/ballistic/shotgun.dm @@ -78,7 +78,7 @@ fire_delay = 0.05 SECONDS //slamfire rack_delay = 0.2 SECONDS - can_be_sawn_off = TRUE + can_be_sawn_off = TRUE /obj/item/gun/ballistic/shotgun/brimstone/sawoff(mob/user) @@ -111,7 +111,7 @@ mag_type = /obj/item/ammo_box/magazine/internal/shot/riot sawn_desc = "Come with me if you want to live." - can_be_sawn_off = TRUE + can_be_sawn_off = TRUE rack_sound = 'sound/weapons/gun/shotgun/rack_alt.ogg' fire_delay = 0.1 SECONDS @@ -141,8 +141,6 @@ recoil = 1 recoil_unwielded = 4 wield_delay = 0.65 SECONDS - -/obj/item/gun/ballistic/shotgun/automatic manufacturer = MANUFACTURER_NANOTRASEN /obj/item/gun/ballistic/shotgun/automatic/shoot_live_shot(mob/living/user) @@ -232,7 +230,6 @@ weapon_weight = WEAPON_MEDIUM mag_type = /obj/item/ammo_box/magazine/m12g - can_suppress = FALSE burst_size = 1 fire_delay = 0.4 SECONDS // this NEEDS the old delay. fire_sound = 'sound/weapons/gun/shotgun/bulldog.ogg' @@ -332,7 +329,7 @@ EMPTY_GUN_HELPER(shotgun/bulldog/inteq) "Stained Green" = "dshotgun_green" ) semi_auto = TRUE - can_be_sawn_off = TRUE + can_be_sawn_off = TRUE bolt_type = BOLT_TYPE_NO_BOLT pb_knockback = 3 // it's a super shotgun! manufacturer = MANUFACTURER_HUNTERSPRIDE @@ -452,8 +449,8 @@ EMPTY_GUN_HELPER(shotgun/bulldog/inteq) name = "improvised shotgun" desc = "A length of pipe and miscellaneous bits of scrap fashioned into a rudimentary single-shot shotgun." icon = 'icons/obj/guns/projectile.dmi' - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON mob_overlay_icon = null base_icon_state = "ishotgun" @@ -519,7 +516,7 @@ EMPTY_GUN_HELPER(shotgun/bulldog/inteq) mag_type = /obj/item/ammo_box/magazine/internal/shot/com/compact/compact w_class = WEIGHT_CLASS_SMALL sawn_desc = "You know, this isn't funny anymore." - can_be_sawn_off = TRUE + can_be_sawn_off = TRUE /obj/item/gun/ballistic/shotgun/automatic/combat/compact/compact/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0) if(prob(0 + (magazine.ammo_count() * 20))) //minimum probability of 20, maximum of 60 @@ -542,7 +539,7 @@ EMPTY_GUN_HELPER(shotgun/bulldog/inteq) mag_type = /obj/item/ammo_box/magazine/internal/shot/com/compact/compact/compact w_class = WEIGHT_CLASS_TINY sawn_desc = "Sigh. This is a trigger attached to a bullet." - can_be_sawn_off = TRUE + can_be_sawn_off = TRUE /obj/item/gun/ballistic/shotgun/automatic/combat/compact/compact/compact/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0) if(prob(50)) //It's going to blow up. @@ -636,7 +633,7 @@ EMPTY_GUN_HELPER(shotgun/bulldog/inteq) rack_sound = 'sound/weapons/gun/rifle/skm_cocked.ogg' bolt_wording = "lever" cartridge_wording = "bullet" - can_be_sawn_off = TRUE + can_be_sawn_off = TRUE wield_slowdown = 0.5 wield_delay = 0.65 SECONDS @@ -765,15 +762,12 @@ EMPTY_GUN_HELPER(shotgun/bulldog/inteq) inhand_y_dimension = 32 mag_type = /obj/item/ammo_box/magazine/internal/shot/beacon fire_sound = 'sound/weapons/gun/revolver/shot_hunting.ogg' - can_be_sawn_off=TRUE w_class = WEIGHT_CLASS_BULKY weapon_weight = WEAPON_MEDIUM force = 10 - flags_1 = CONDUCT_1 - slot_flags = ITEM_SLOT_BACK obj_flags = UNIQUE_RENAME semi_auto = TRUE - can_be_sawn_off = TRUE + can_be_sawn_off = TRUE pb_knockback = 3 wield_slowdown = 0.7 spread_unwielded = 15 diff --git a/code/modules/projectiles/guns/ballistic/smg.dm b/code/modules/projectiles/guns/ballistic/smg.dm index 96d4e7d922db..2cb68fc09176 100644 --- a/code/modules/projectiles/guns/ballistic/smg.dm +++ b/code/modules/projectiles/guns/ballistic/smg.dm @@ -50,10 +50,6 @@ item_state = "c20r" mag_type = /obj/item/ammo_box/magazine/smgm45 - can_bayonet = TRUE - can_suppress = FALSE - knife_x_offset = 26 - knife_y_offset = 12 show_magazine_on_sprite = TRUE show_magazine_on_sprite_ammo = TRUE empty_indicator = TRUE @@ -68,7 +64,6 @@ EMPTY_GUN_HELPER(automatic/smg/c20r) /obj/item/gun/ballistic/automatic/smg/c20r/cobra name = "\improper Cobra 20" desc = "An older model of SMG manufactured by Scarborough Arms, a predecessor to the military C-20 series. Chambered in .45. " - can_bayonet = FALSE icon_state = "cobra20" item_state = "cobra20" @@ -90,11 +85,7 @@ EMPTY_GUN_HELPER(automatic/smg/c20r) icon_state = "wt550" item_state = "arg" mag_type = /obj/item/ammo_box/magazine/wt550m9 - can_suppress = FALSE actions_types = list() - can_bayonet = TRUE - knife_x_offset = 25 - knife_y_offset = 12 show_magazine_on_sprite = TRUE show_magazine_on_sprite_ammo = TRUE empty_indicator = TRUE @@ -158,7 +149,6 @@ EMPTY_GUN_HELPER(automatic/smg/c20r) item_state = "m90" mag_type = /obj/item/ammo_box/magazine/m556 - can_suppress = FALSE gun_firenames = list(FIREMODE_SEMIAUTO = "single", FIREMODE_BURST = "burst fire", FIREMODE_FULLAUTO = "full auto", FIREMODE_OTHER = "underbarrel grenade launcher") gun_firemodes = list(FIREMODE_SEMIAUTO, FIREMODE_BURST, FIREMODE_OTHER) default_firemode = FIREMODE_SEMIAUTO @@ -241,7 +231,6 @@ EMPTY_GUN_HELPER(automatic/smg/c20r) icon_state = "firestorm" item_state = "firestorm" mag_type = /obj/item/ammo_box/magazine/c45_firestorm_mag - can_suppress = FALSE unique_mag_sprites_for_variants = TRUE burst_size = 1 actions_types = list() @@ -315,11 +304,9 @@ EMPTY_GUN_HELPER(automatic/smg/cm5) eject_empty_sound = 'sound/weapons/gun/rifle/skm_unload.ogg' weapon_weight = WEAPON_MEDIUM - w_class = WEIGHT_CLASS_BULKY + w_class = WEIGHT_CLASS_NORMAL mag_type = /obj/item/ammo_box/magazine/skm_545_39 - actions_types = list(/datum/action/item_action/fold_stock) //once again, ideally an attatchment in the future - recoil = 2 recoil_unwielded = 6 @@ -329,76 +316,35 @@ EMPTY_GUN_HELPER(automatic/smg/cm5) wield_delay = 0.6 SECONDS wield_slowdown = 0.35 - ///is the bipod deployed? - var/stock_folded = FALSE - - ///we add these two values to recoi/spread when we have the bipod deployed - var/stock_recoil_bonus = -2 - var/stock_spread_bonus = -5 - - var/folded_slowdown = 0.6 - var/folded_wield_delay = 0.6 SECONDS - - var/unfolded_slowdown = 0.35 - var/unfolded_wield_delay = 0.2 SECONDS - -/obj/item/gun/ballistic/automatic/smg/skm_carbine/ComponentInitialize() - . = ..() - AddElement(/datum/element/update_icon_updates_onmob) - -/datum/action/item_action/fold_stock - name = "Fold/Unfold stock" - desc = "Fold or unfold the stock for easier storage." - -/obj/item/gun/ballistic/automatic/smg/skm_carbine/ui_action_click(mob/user, action) - if(!istype(action, /datum/action/item_action/fold_stock)) - return ..() - fold(user) - - -/obj/item/gun/ballistic/automatic/smg/skm_carbine/proc/fold(mob/user) - if(stock_folded) - to_chat(user, "You unfold the stock on the [src].") - w_class = WEIGHT_CLASS_BULKY - wield_delay = folded_wield_delay - wield_slowdown = folded_slowdown - else - to_chat(user, "You fold the stock on the [src].") - w_class = WEIGHT_CLASS_NORMAL - wield_delay = unfolded_wield_delay - wield_slowdown = unfolded_slowdown - - if(wielded) - user.add_or_update_variable_movespeed_modifier(/datum/movespeed_modifier/gun, multiplicative_slowdown = wield_slowdown) - - stock_folded = !stock_folded - playsound(src, 'sound/weapons/empty.ogg', 100, 1) - update_appearance() - - -/obj/item/gun/ballistic/automatic/smg/skm_carbine/calculate_recoil(mob/user, recoil_bonus = 0) - var/total_recoil = recoil_bonus - if(!stock_folded) - total_recoil += stock_recoil_bonus - - return ..(user, total_recoil) - -/obj/item/gun/ballistic/automatic/smg/skm_carbine/calculate_spread(mob/user, bonus_spread) - var/total_spread = bonus_spread - - if(!stock_folded) - total_spread += stock_spread_bonus - - return ..(user, total_spread) - -/obj/item/gun/ballistic/automatic/smg/skm_carbine/update_icon_state() - . = ..() - item_state = "[initial(item_state)][stock_folded ? "_nostock" : ""]" - mob_overlay_state = "[initial(item_state)][stock_folded ? "_nostock" : ""]" - -/obj/item/gun/ballistic/automatic/smg/skm_carbine/update_overlays() - . = ..() - . += "[base_icon_state || initial(icon_state)][stock_folded ? "_nostock" : "_stock"]" + valid_attachments = list( + /obj/item/attachment/silencer, + /obj/item/attachment/laser_sight, + /obj/item/attachment/rail_light, + /obj/item/attachment/bayonet, + /obj/item/attachment/foldable_stock + ) + + slot_available = list( + ATTACHMENT_SLOT_MUZZLE = 1, + ATTACHMENT_SLOT_RAIL = 1, + ATTACHMENT_SLOT_STOCK = 1 + ) + slot_offsets = list( + ATTACHMENT_SLOT_MUZZLE = list( + "x" = 26, + "y" = 20, + ), + ATTACHMENT_SLOT_RAIL = list( + "x" = 19, + "y" = 18, + ), + ATTACHMENT_SLOT_STOCK = list( + "x" = 11, + "y" = 20, + ) + ) + + default_attachments = list(/obj/item/attachment/foldable_stock) /obj/item/gun/ballistic/automatic/smg/skm_carbine/inteq name = "\improper SKM-44v Mongrel" @@ -426,16 +372,16 @@ EMPTY_GUN_HELPER(automatic/smg/cm5) recoil = 0 recoil_unwielded = 4 - stock_spread_bonus = -4 - stock_recoil_bonus = -1 - wield_delay = 0.4 SECONDS - folded_slowdown = 0.15 - folded_wield_delay = 0.2 SECONDS - - unfolded_slowdown = 0.35 - unfolded_wield_delay = 0.4 SECONDS + valid_attachments = list( + /obj/item/attachment/silencer, + /obj/item/attachment/laser_sight, + /obj/item/attachment/rail_light, + /obj/item/attachment/bayonet, + /obj/item/attachment/foldable_stock/inteq + ) + default_attachments = list(/obj/item/attachment/foldable_stock/inteq) /obj/item/gun/ballistic/automatic/smg/skm_carbine/inteq/proto name = "\improper Nanotrasen Saber SMG" @@ -447,4 +393,3 @@ EMPTY_GUN_HELPER(automatic/smg/cm5) bolt_type = BOLT_TYPE_LOCKING show_magazine_on_sprite = TRUE manufacturer = MANUFACTURER_NANOTRASEN_OLD - diff --git a/code/modules/projectiles/guns/ballistic/toy.dm b/code/modules/projectiles/guns/ballistic/toy.dm index 160569d3f86c..135a1b2d06b0 100644 --- a/code/modules/projectiles/guns/ballistic/toy.dm +++ b/code/modules/projectiles/guns/ballistic/toy.dm @@ -8,7 +8,6 @@ force = 0 throwforce = 0 burst_size = 3 - can_suppress = TRUE item_flags = NONE casing_ejector = FALSE manufacturer = MANUFACTURER_NANOTRASEN @@ -54,7 +53,6 @@ fire_sound = 'sound/items/syringeproj.ogg' item_flags = NONE casing_ejector = FALSE - can_suppress = FALSE pb_knockback = 0 recoil = -10 //its a toy... recoil_unwielded = -10 @@ -85,7 +83,6 @@ /obj/item/gun/ballistic/automatic/smg/c20r/toy name = "donksoft SMG" desc = "A bullpup two-round burst toy SMG, designated 'C-20r'. Ages 8 and up." - can_suppress = FALSE item_flags = NONE mag_type = /obj/item/ammo_box/magazine/toy/smgm45 fire_sound = 'sound/items/syringeproj.ogg' @@ -105,7 +102,6 @@ name = "donksoft LMG" desc = "A heavily modified toy light machine gun, designated 'L6 SAW'. Ages 8 and up." fire_sound = 'sound/items/syringeproj.ogg' - can_suppress = FALSE item_flags = NONE mag_type = /obj/item/ammo_box/magazine/toy/m762 casing_ejector = FALSE diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm index f3edb62d8942..abe3e3fd7b43 100644 --- a/code/modules/projectiles/guns/energy.dm +++ b/code/modules/projectiles/guns/energy.dm @@ -10,41 +10,31 @@ has_safety = TRUE safety = TRUE + modifystate = FALSE + ammo_x_offset = 2 + gun_firemodes = list(FIREMODE_SEMIAUTO) default_firemode = FIREMODE_SEMIAUTO fire_select_icon_state_prefix = "laser_" - var/obj/item/stock_parts/cell/gun/cell //What type of power cell this uses - var/cell_type = /obj/item/stock_parts/cell/gun - var/modifystate = 0 - var/list/ammo_type = list(/obj/item/ammo_casing/energy) - var/select = 1 //The state of the select fire switch. Determines from the ammo_type list what kind of shot is fired next. - var/can_charge = TRUE //Can it be charged in a recharger? - var/automatic_charge_overlays = TRUE //Do we handle overlays with base update_appearance()? - var/charge_sections = 4 - ammo_x_offset = 2 - var/shaded_charge = FALSE //if this gun uses a stateful charge bar for more detail - var/selfcharge = 0 - var/charge_tick = 0 - var/charge_delay = 4 - var/use_cyborg_cell = FALSE //whether the gun's cell drains the cyborg user's cell to recharge - var/dead_cell = FALSE //set to true so the gun is given an empty cell - - var/internal_cell = FALSE ///if the gun's cell cannot be replaced - var/small_gun = FALSE ///if the gun is small and can only fit the small gun cell - var/big_gun = FALSE ///if the gun is big and can fit the comically large gun cell - var/unscrewing_time = 20 ///Time it takes to unscrew the cell - - ///Whether the gun can be tacloaded by slapping a fresh magazine directly on it - var/tac_reloads = FALSE - ///If we allow tacitcal reloads, how long should it take to reload? - var/tactical_reload_delay = 1.2 SECONDS - - var/load_sound = 'sound/weapons/gun/general/magazine_insert_full.ogg' //Sound when inserting magazine. UPDATE PLEASE - var/eject_sound = 'sound/weapons/gun/general/magazine_remove_full.ogg' //Sound of ejecting a cell. UPDATE PLEASE - var/sound_volume = 40 //Volume of loading/unloading sounds - var/load_sound_vary = TRUE //Should the load/unload sounds vary? + tac_reloads = FALSE + tactical_reload_delay = 1.2 SECONDS + + valid_attachments = list( + /obj/item/attachment/laser_sight, + /obj/item/attachment/rail_light, + /obj/item/attachment/bayonet + ) + slot_available = list( + ATTACHMENT_SLOT_RAIL = 1 + ) + slot_offsets = list( + ATTACHMENT_SLOT_RAIL = list( + "x" = 19, + "y" = 18, + ) + ) /obj/item/gun/energy/emp_act(severity) . = ..() @@ -133,16 +123,16 @@ return ..() /obj/item/gun/energy/proc/insert_cell(mob/user, obj/item/stock_parts/cell/gun/C) - if(small_gun && !istype(C, /obj/item/stock_parts/cell/gun/mini)) + if(mag_size == MAG_SIZE_SMALL && !istype(C, /obj/item/stock_parts/cell/gun/mini)) to_chat(user, span_warning("\The [C] doesn't seem to fit into \the [src]...")) return FALSE - if(!big_gun && istype(C, /obj/item/stock_parts/cell/gun/large)) + if(mag_size == MAG_SIZE_LARGE && !istype(C, /obj/item/stock_parts/cell/gun/large)) to_chat(user, span_warning("\The [C] doesn't seem to fit into \the [src]...")) return FALSE if(user.transferItemToLoc(C, src)) cell = C to_chat(user, span_notice("You load the [C] into \the [src].")) - playsound(src, load_sound, sound_volume, load_sound_vary) + playsound(src, load_sound, load_sound_volume, load_sound_vary) update_appearance() return TRUE else @@ -150,7 +140,7 @@ return FALSE /obj/item/gun/energy/proc/eject_cell(mob/user, obj/item/stock_parts/cell/gun/tac_load = null) - playsound(src, load_sound, sound_volume, load_sound_vary) + playsound(src, load_sound, load_sound_volume, load_sound_vary) cell.forceMove(drop_location()) var/obj/item/stock_parts/cell/gun/old_cell = cell old_cell.update_appearance() @@ -170,17 +160,13 @@ user.put_in_hands(old_cell) update_appearance() -/obj/item/gun/energy/get_gun_attachments() +/obj/item/gun/energy/screwdriver_act(mob/living/user, obj/item/I) if(cell && !internal_cell) - attachment_options += list("Cell" = image(icon = cell.icon, icon_state = cell.icon_state)) - ..() - -/obj/item/gun/energy/remove_gun_attachments(mob/living/user, obj/item/I, picked_option) - if(picked_option == "Cell") - if(I.use_tool(src, user, unscrewing_time, volume=100)) - eject_cell(user, I) - return TRUE - ..() + to_chat(user, span_notice("You begin unscrewing and pulling out the cell...")) + if(I.use_tool(src, user, unscrewing_time, volume = 100)) + to_chat(user, span_notice("You remove the power cell.")) + eject_cell(user) + return ..() /obj/item/gun/energy/can_shoot(visuals) if(safety && !visuals) diff --git a/code/modules/projectiles/guns/energy/energy_gun.dm b/code/modules/projectiles/guns/energy/energy_gun.dm index 6988f1f6cb72..90bfa9a8ead1 100644 --- a/code/modules/projectiles/guns/energy/energy_gun.dm +++ b/code/modules/projectiles/guns/energy/energy_gun.dm @@ -8,11 +8,8 @@ icon_state = "energy" item_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 = 1 - can_flashlight = TRUE + modifystate = TRUE ammo_x_offset = 2 - flight_x_offset = 15 - flight_y_offset = 10 dual_wield_spread = 60 manufacturer = MANUFACTURER_SHARPLITE_NEW @@ -26,25 +23,16 @@ item_state = "gun" w_class = WEIGHT_CLASS_SMALL cell_type = /obj/item/stock_parts/cell/gun/mini - small_gun = TRUE + mag_size = MAG_SIZE_SMALL throwforce = 11 //This is funny, trust me. 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 - wield_delay = 0.2 SECONDS wield_slowdown = 0.15 spread = 2 spread_unwielded = 5 -/obj/item/gun/energy/e_gun/mini/Initialize() - set_gun_light(new /obj/item/flashlight/seclite(src)) - return ..() - /obj/item/gun/energy/e_gun/mini/empty_cell dead_cell = TRUE @@ -108,10 +96,9 @@ desc = "The \"Dynamic Rapid-Apprehension of the Guilty\" net is a revolution in law enforcement technology." icon_state = "dragnet" item_state = "dragnet" - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON ammo_type = list(/obj/item/ammo_casing/energy/net, /obj/item/ammo_casing/energy/trap) - can_flashlight = FALSE ammo_x_offset = 1 /obj/item/gun/energy/e_gun/dragnet/snare @@ -128,7 +115,6 @@ 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 @@ -198,7 +184,7 @@ item_state = "gun" ammo_x_offset = 2 charge_sections = 6 - small_gun = TRUE + mag_size = MAG_SIZE_SMALL wield_delay = 0.2 SECONDS wield_slowdown = 0.15 @@ -242,7 +228,7 @@ inhand_y_dimension = 64 icon_state = "iotshotgun" item_state = "shotgun_combat" - shaded_charge = 1 + shaded_charge = TRUE w_class = WEIGHT_CLASS_BULKY ammo_type = list(/obj/item/ammo_casing/energy/disabler/scatter/ultima, /obj/item/ammo_casing/energy/laser/ultima) var/obj/item/modular_computer/integratedNTOS @@ -257,10 +243,7 @@ mob_overlay_icon = 'icons/obj/guns/manufacturer/eoehoma/onmob.dmi' icon_state = "e11" ammo_type = list(/obj/item/ammo_casing/energy/disabler, /obj/item/ammo_casing/energy/laser/eoehoma) - can_flashlight = TRUE ammo_x_offset = 0 - flight_x_offset = 20 - flight_y_offset = 9 spread = 80 spread_unwielded = 140 dual_wield_spread = 140 diff --git a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm index ac3aa9e3d21a..2ca71649a6f7 100644 --- a/code/modules/projectiles/guns/energy/kinetic_accelerator.dm +++ b/code/modules/projectiles/guns/energy/kinetic_accelerator.dm @@ -8,14 +8,8 @@ item_flags = NONE obj_flags = UNIQUE_RENAME weapon_weight = WEAPON_LIGHT - can_flashlight = TRUE - flight_x_offset = 15 - flight_y_offset = 9 automatic_charge_overlays = FALSE - can_bayonet = TRUE - knife_x_offset = 20 - knife_y_offset = 12 - internal_cell = TRUE + internal_cell = TRUE //prevents you from giving it an OP cell - WS Edit custom_price = 750 w_class = WEIGHT_CLASS_BULKY @@ -28,12 +22,18 @@ var/overheat = FALSE var/mob/holder - var/max_mod_capacity = 100 var/list/modkits = list() var/recharge_timerid + slot_offsets = list( + ATTACHMENT_SLOT_RAIL = list( + "x" = 24, + "y" = 13, + ) + ) + /obj/item/gun/energy/kinetic_accelerator/shoot_with_empty_chamber(mob/living/user) playsound(src, dry_fire_sound, 30, TRUE) //click sound but no to_chat message to cut on spam return diff --git a/code/modules/projectiles/guns/energy/laser.dm b/code/modules/projectiles/guns/energy/laser.dm index c564ae32b4da..eff3d67b2df1 100644 --- a/code/modules/projectiles/guns/energy/laser.dm +++ b/code/modules/projectiles/guns/energy/laser.dm @@ -84,7 +84,7 @@ icon_state = "cshotgun" item_state = "shotgun" desc = "A combat shotgun gutted and refitted with an internal laser system. Can switch between taser and scattered disabler shots." - shaded_charge = 0 + shaded_charge = FALSE ammo_type = list(/obj/item/ammo_casing/energy/disabler/scatter, /obj/item/ammo_casing/energy/electrode) manufacturer = MANUFACTURER_NONE @@ -96,7 +96,7 @@ icon_state = "lasercannon" item_state = "laser" w_class = WEIGHT_CLASS_BULKY - big_gun = TRUE + mag_size = MAG_SIZE_LARGE cell_type = "/obj/item/stock_parts/cell/gun/large" force = 10 flags_1 = CONDUCT_1 @@ -203,7 +203,7 @@ item_state = "gun" ammo_x_offset = 2 charge_sections = 4 - small_gun = TRUE + mag_size = MAG_SIZE_SMALL w_class = WEIGHT_CLASS_NORMAL cell_type = /obj/item/stock_parts/cell/gun/mini ammo_type = list(/obj/item/ammo_casing/energy/lasergun/hitscan) @@ -245,7 +245,7 @@ icon_state = "e50" item_state = "e50" - big_gun = TRUE + mag_size = MAG_SIZE_LARGE cell_type = /obj/item/stock_parts/cell/gun/large ammo_type = list(/obj/item/ammo_casing/energy/laser/eoehoma/e50) weapon_weight = WEAPON_HEAVY diff --git a/code/modules/projectiles/guns/energy/mounted.dm b/code/modules/projectiles/guns/energy/mounted.dm index 4dc5cae77558..cf67db9fd5ae 100644 --- a/code/modules/projectiles/guns/energy/mounted.dm +++ b/code/modules/projectiles/guns/energy/mounted.dm @@ -6,7 +6,6 @@ item_state = "armcannonstun4" 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... diff --git a/code/modules/projectiles/guns/energy/pulse.dm b/code/modules/projectiles/guns/energy/pulse.dm index dfa23e26b468..c2e5b4cb2933 100644 --- a/code/modules/projectiles/guns/energy/pulse.dm +++ b/code/modules/projectiles/guns/energy/pulse.dm @@ -39,11 +39,8 @@ icon_state = "pulse_carbine" item_state = null internal_cell = FALSE - big_gun = TRUE //haha gun go brr + mag_size = MAG_SIZE_LARGE //haha gun go brr cell_type = /obj/item/stock_parts/cell/gun/large - can_flashlight = TRUE - flight_x_offset = 18 - flight_y_offset = 12 ammo_x_offset = 2 charge_sections = 4 diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index 07f0aebaa9a0..09de7690b5ea 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -6,9 +6,8 @@ shaded_charge = FALSE ammo_x_offset = 2 ammo_y_offset = 2 - can_flashlight = FALSE w_class = WEIGHT_CLASS_HUGE - big_gun = TRUE //yes, you can put the comically large cell in it. No, you aren't getting it roundstart. You slut. + mag_size = MAG_SIZE_LARGE //yes, you can put the comically large cell in it. No, you aren't getting it roundstart. You slut. flags_1 = CONDUCT_1 slot_flags = ITEM_SLOT_BACK ammo_type = list(/obj/item/ammo_casing/energy/ion) @@ -28,9 +27,6 @@ slot_flags = ITEM_SLOT_BELT ammo_x_offset = 2 ammo_y_offset = 0 - can_flashlight = TRUE - flight_x_offset = 18 - flight_y_offset = 11 /obj/item/gun/energy/decloner name = "biological demolecularisor" @@ -51,10 +47,10 @@ icon_state = "flora" item_state = "gun" ammo_type = list(/obj/item/ammo_casing/energy/flora/yield, /obj/item/ammo_casing/energy/flora/mut, /obj/item/ammo_casing/energy/flora/revolution) - modifystate = 1 + modifystate = TRUE ammo_x_offset = 1 selfcharge = 1 - shaded_charge = 1 + shaded_charge = TRUE /obj/item/gun/energy/meteorgun name = "meteor gun" @@ -98,7 +94,6 @@ overheat_time = 20 holds_charge = TRUE unique_frequency = TRUE - can_flashlight = FALSE max_mod_capacity = 0 manufacturer = MANUFACTURER_SCARBOROUGH @@ -108,7 +103,7 @@ icon_state = "crossbowlarge" w_class = WEIGHT_CLASS_NORMAL custom_materials = list(/datum/material/iron=4000) - suppressed = null + suppressed = FALSE ammo_type = list(/obj/item/ammo_casing/energy/bolt/large) manufacturer = MANUFACTURER_NONE diff --git a/code/modules/projectiles/guns/energy/stun.dm b/code/modules/projectiles/guns/energy/stun.dm index 168bbdc099dc..e70c46cc76f6 100644 --- a/code/modules/projectiles/guns/energy/stun.dm +++ b/code/modules/projectiles/guns/energy/stun.dm @@ -5,7 +5,6 @@ item_state = null //so the human update icon uses the icon_state instead. ammo_type = list(/obj/item/ammo_casing/energy/electrode) ammo_x_offset = 3 - spread = 2 spread_unwielded = 4 @@ -22,7 +21,6 @@ /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 @@ -37,11 +35,7 @@ item_state = null ammo_type = list(/obj/item/ammo_casing/energy/disabler) ammo_x_offset = 2 - can_flashlight = TRUE - flight_x_offset = 15 - flight_y_offset = 10 manufacturer = MANUFACTURER_SHARPLITE_NEW - spread = 2 spread_unwielded = 4 diff --git a/code/modules/projectiles/guns/misc/beam_rifle.dm b/code/modules/projectiles/guns/misc/beam_rifle.dm index 8b6626bc5e97..b131b03ec148 100644 --- a/code/modules/projectiles/guns/misc/beam_rifle.dm +++ b/code/modules/projectiles/guns/misc/beam_rifle.dm @@ -29,7 +29,7 @@ w_class = WEIGHT_CLASS_BULKY ammo_type = list(/obj/item/ammo_casing/energy/beam_rifle/hitscan) internal_cell = FALSE //prevents you from giving it an OP cell - WS Edit //shut up dumb nerd - big_gun = TRUE + mag_size = MAG_SIZE_LARGE cell_type = "/obj/item/stock_parts/cell/gun/large" canMouseDown = TRUE var/aiming = FALSE diff --git a/code/modules/projectiles/guns/misc/syringe_gun.dm b/code/modules/projectiles/guns/misc/syringe_gun.dm index 84d00b226371..809c15682cd4 100644 --- a/code/modules/projectiles/guns/misc/syringe_gun.dm +++ b/code/modules/projectiles/guns/misc/syringe_gun.dm @@ -80,7 +80,6 @@ w_class = WEIGHT_CLASS_SMALL force = 2 //Also very weak because it's smaller suppressed = TRUE //Softer fire sound - can_unsuppress = FALSE //Permanently silenced /obj/item/gun/syringe/dna name = "modified syringe gun" diff --git a/code/modules/projectiles/guns/powered.dm b/code/modules/projectiles/guns/powered.dm index ac7418748d9b..a9ab2f6365f4 100644 --- a/code/modules/projectiles/guns/powered.dm +++ b/code/modules/projectiles/guns/powered.dm @@ -1,21 +1,6 @@ /obj/item/gun/ballistic/automatic/powered mag_type = /obj/item/ammo_box/magazine/gauss - can_suppress = FALSE - - var/obj/item/stock_parts/cell/cell - var/cell_type = /obj/item/stock_parts/cell/gun - var/charge_sections = 3 - var/empty_battery_sound = FALSE // play empty alarm if no battery - - var/shaded_charge = FALSE //if this gun uses a stateful charge bar for more detail - var/automatic_charge_overlays = TRUE //Do we handle overlays with base update_appearance()? - - var/internal_cell = FALSE ///if the gun's cell cannot be replaced - var/small_gun = FALSE ///if the gun is small and can only fit the small gun cell - var/big_gun = FALSE ///if the gun is big and can fit the comically large gun cell - var/unscrewing_time = 2 SECONDS ///Time it takes to unscrew the cell - var/sound_volume = 40 //Volume of loading/unloading cell sounds - + charge_sections = 3 /obj/item/gun/ballistic/automatic/powered/Initialize() . = ..() @@ -61,24 +46,24 @@ return ..() /obj/item/gun/ballistic/automatic/powered/proc/insert_cell(mob/user, obj/item/stock_parts/cell/gun/C) - if(small_gun && !istype(C, /obj/item/stock_parts/cell/gun/mini)) - to_chat(user, "[C] doesn't seem to fit into [src]...") + if(mag_size == MAG_SIZE_SMALL && !istype(C, /obj/item/stock_parts/cell/gun/mini)) + to_chat(user, "\The [C] doesn't seem to fit into \the [src]...") return FALSE - if(!big_gun && istype(C, /obj/item/stock_parts/cell/gun/large)) - to_chat(user, "[C] doesn't seem to fit into [src]...") + if(mag_size == MAG_SIZE_LARGE && !istype(C, /obj/item/stock_parts/cell/gun/large)) + to_chat(user, "\The [C] doesn't seem to fit into \the [src]...") return FALSE if(user.transferItemToLoc(C, src)) cell = C - to_chat(user, "You load [C] into [src].") - playsound(src, load_sound, sound_volume, load_sound_vary) + to_chat(user, "You load the [C] into \the [src].") + playsound(src, load_sound, load_sound_volume, load_sound_vary) update_appearance() return TRUE else - to_chat(user, "You cannot seem to get [src] out of your hands!") + to_chat(user, "You cannot seem to get \the [src] out of your hands!") return FALSE /obj/item/gun/ballistic/automatic/powered/proc/eject_cell(mob/user, obj/item/stock_parts/cell/gun/tac_load = null) - playsound(src, load_sound, sound_volume, load_sound_vary) + playsound(src, load_sound, load_sound_volume, load_sound_vary) cell.forceMove(drop_location()) var/obj/item/stock_parts/cell/gun/old_cell = cell cell = null @@ -88,7 +73,7 @@ update_appearance() /obj/item/gun/ballistic/automatic/powered/screwdriver_act(mob/living/user, obj/item/I) - if(cell && !internal_cell && !bayonet && (!gun_light || !can_flashlight)) + if(cell && !internal_cell) to_chat(user, "You begin unscrewing and pulling out the cell...") if(I.use_tool(src, user, unscrewing_time, volume=100)) to_chat(user, "You remove the power cell.") diff --git a/code/modules/reagents/reagent_containers/hypospray.dm b/code/modules/reagents/reagent_containers/hypospray.dm index 11cbd03c9787..78326279b6f9 100644 --- a/code/modules/reagents/reagent_containers/hypospray.dm +++ b/code/modules/reagents/reagent_containers/hypospray.dm @@ -395,7 +395,7 @@ to_chat(user, "You remove [vial] from [src].") vial = null update_appearance() - playsound(loc, 'sound/weapons/empty.ogg', 50, 1) + playsound(loc, SOUND_EMPTY_MAG, 50, 1) else to_chat(user, "This hypo isn't loaded!") return diff --git a/code/modules/reagents/reagent_containers/spray.dm b/code/modules/reagents/reagent_containers/spray.dm index 05f68682083c..b4f46e6e4c19 100644 --- a/code/modules/reagents/reagent_containers/spray.dm +++ b/code/modules/reagents/reagent_containers/spray.dm @@ -260,8 +260,8 @@ icon = 'icons/obj/guns/projectile.dmi' icon_state = "chemsprayer" item_state = "chemsprayer" - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON throwforce = 0 w_class = WEIGHT_CLASS_NORMAL stream_mode = 1 @@ -298,8 +298,8 @@ desc = "A utility used to spray large amounts of cleaning reagents in a given area. It regenerates space cleaner by itself but it's unable to be fueled by normal means." icon_state = "chemsprayer_janitor" item_state = "chemsprayer_janitor" - lefthand_file = 'icons/mob/inhands/weapons/guns_lefthand.dmi' - righthand_file = 'icons/mob/inhands/weapons/guns_righthand.dmi' + lefthand_file = GUN_LEFTHAND_ICON + righthand_file = GUN_RIGHTHAND_ICON reagent_flags = NONE list_reagents = list(/datum/reagent/space_cleaner = 1000) volume = 1000 diff --git a/code/modules/research/designs/weapon_designs.dm b/code/modules/research/designs/weapon_designs.dm index 3353dcfb3289..c444336adde5 100644 --- a/code/modules/research/designs/weapon_designs.dm +++ b/code/modules/research/designs/weapon_designs.dm @@ -558,7 +558,7 @@ id = "suppressor" build_type = PROTOLATHE materials = list(/datum/material/iron = 2000, /datum/material/silver = 500) - build_path = /obj/item/suppressor + build_path = /obj/item/attachment/silencer category = list("Weapons") departmental_flags = DEPARTMENTAL_FLAG_SECURITY diff --git a/code/modules/uplink/uplink_items.dm b/code/modules/uplink/uplink_items.dm index 11eb6a4b49e6..9e935611e15f 100644 --- a/code/modules/uplink/uplink_items.dm +++ b/code/modules/uplink/uplink_items.dm @@ -683,7 +683,7 @@ GLOBAL_LIST_INIT(uplink_items, subtypesof(/datum/uplink_item)) /datum/uplink_item/stealthy_weapons/suppressor name = "Suppressor" desc = "This suppressor will silence the shots of the weapon it is attached to for increased stealth and superior ambushing capability. It is compatible with many small ballistic guns including the Stechkin and C-20r, but not revolvers or energy guns." - item = /obj/item/suppressor + item = /obj/item/attachment/silencer cost = 3 surplus = 10 exclude_modes = list(/datum/game_mode/nuclear/clown_ops) diff --git a/icons/obj/guns/48x32guns.dmi b/icons/obj/guns/48x32guns.dmi index cbc495275add..960b9ec448af 100644 Binary files a/icons/obj/guns/48x32guns.dmi and b/icons/obj/guns/48x32guns.dmi differ diff --git a/icons/obj/guns/attachments.dmi b/icons/obj/guns/attachments.dmi new file mode 100644 index 000000000000..29ae084d5759 Binary files /dev/null and b/icons/obj/guns/attachments.dmi differ diff --git a/icons/obj/guns/bayonets.dmi b/icons/obj/guns/bayonets.dmi deleted file mode 100644 index 32b5448b8edc..000000000000 Binary files a/icons/obj/guns/bayonets.dmi and /dev/null differ diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi index e02a7e288cc8..6a32de5b08fb 100644 Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ diff --git a/icons/obj/guns/flashlights.dmi b/icons/obj/guns/flashlights.dmi deleted file mode 100644 index eef6d953f94a..000000000000 Binary files a/icons/obj/guns/flashlights.dmi and /dev/null differ diff --git a/icons/obj/guns/projectile.dmi b/icons/obj/guns/projectile.dmi index 986c2f99692f..ab051d8a21bb 100644 Binary files a/icons/obj/guns/projectile.dmi and b/icons/obj/guns/projectile.dmi differ diff --git a/shiptest.dme b/shiptest.dme index 2b65bc6d6d58..4b8478ffbf1b 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -460,6 +460,8 @@ #include "code\datums\components\anti_magic.dm" #include "code\datums\components\armor_plate.dm" #include "code\datums\components\art.dm" +#include "code\datums\components\attachment.dm" +#include "code\datums\components\attachment_holder.dm" #include "code\datums\components\bandage.dm" #include "code\datums\components\bane.dm" #include "code\datums\components\beetlejuice.dm" @@ -1200,6 +1202,12 @@ #include "code\game\objects\items\vending_items.dm" #include "code\game\objects\items\wayfinding.dm" #include "code\game\objects\items\weaponry.dm" +#include "code\game\objects\items\attachments\_attachment.dm" +#include "code\game\objects\items\attachments\bayonet.dm" +#include "code\game\objects\items\attachments\laser_sight.dm" +#include "code\game\objects\items\attachments\rail_light.dm" +#include "code\game\objects\items\attachments\silencer.dm" +#include "code\game\objects\items\attachments\stock.dm" #include "code\game\objects\items\circuitboards\circuitboard.dm" #include "code\game\objects\items\circuitboards\computer_circuitboards.dm" #include "code\game\objects\items\circuitboards\machine_circuitboards.dm"