From 5a826819eac189fafc057db9141152e6873e2612 Mon Sep 17 00:00:00 2001 From: simb11 <84613249+simb11@users.noreply.github.com> Date: Sun, 22 Sep 2024 08:53:22 +0200 Subject: [PATCH] full auto fire tg edition (#13479) * bbra * l6 saw * smg crate * Update fullauto.dm * del musor * be * small fix * 321 * rnd plasma cutter fix --- code/__DEFINES/combat.dm | 15 + code/__DEFINES/dcs/signals.dm | 8 + code/__DEFINES/subsystem.dm | 1 + code/__DEFINES/traits.dm | 1 + code/__HELPERS/unsorted.dm | 20 ++ code/_onclick/click.dm | 17 + code/controllers/subsystem/fullauto.dm | 5 + code/datums/components/_component.dm | 4 + code/datums/components/fullauto.dm | 290 ++++++++++++++++++ code/datums/uplinks_items.dm | 4 +- .../modes_gameplays/families/outfit.dm | 2 +- code/game/objects/random/random_guns.dm | 4 +- code/modules/cargo/packs.dm | 40 +++ code/modules/client/client_defines.dm | 4 + code/modules/mining/mine_items.dm | 5 +- .../mob/living/carbon/human/human_movement.dm | 3 + .../projectiles/ammunition/magazines.dm | 4 +- code/modules/projectiles/firing.dm | 1 + code/modules/projectiles/gun.dm | 57 +++- .../modules/projectiles/guns/plasma/plasma.dm | 8 +- .../projectiles/guns/projectile/automatic.dm | 85 ++++- .../projectiles/guns/projectile/pistol.dm | 7 + .../modules/projectiles/projectile/bullets.dm | 2 +- code/modules/research/designs.dm | 2 +- code/modules/research/prototipify.dm | 9 +- icons/hud/weapon_pointer.dmi | Bin 0 -> 234 bytes icons/obj/ammo/magazines.dmi | Bin 16720 -> 16690 bytes maps/centcom/centcom.dmm | 6 +- .../space_structures/old_station.dmm | 2 +- taucetistation.dme | 2 + 30 files changed, 566 insertions(+), 42 deletions(-) create mode 100644 code/controllers/subsystem/fullauto.dm create mode 100644 code/datums/components/fullauto.dm create mode 100644 icons/hud/weapon_pointer.dmi diff --git a/code/__DEFINES/combat.dm b/code/__DEFINES/combat.dm index 99add07ecc06..65d55014d2f2 100644 --- a/code/__DEFINES/combat.dm +++ b/code/__DEFINES/combat.dm @@ -112,8 +112,23 @@ #define MOVESET_ROLES "moveset_role" #define MOVESET_QUALITY "moveset_quality" + +//Autofire component +/// Compatible firemode is in the gun. Wait until it's held in the user hands. +#define AUTOFIRE_STAT_IDLE (1<<0) +/// Gun is active and in the user hands. Wait until user does a valid click. +#define AUTOFIRE_STAT_ALERT (1<<1) +/// Gun is shooting. +#define AUTOFIRE_STAT_FIRING (1<<2) + +#define COMSIG_AUTOFIRE_ONMOUSEDOWN "autofire_onmousedown" + #define COMPONENT_AUTOFIRE_ONMOUSEDOWN_BYPASS (1<<0) +#define COMSIG_AUTOFIRE_SHOT "autofire_shot" + #define COMPONENT_AUTOFIRE_SHOT_SUCCESS (1<<0) + //Painkiller effectiveness (for get_painkiller_effect() comparison) #define PAINKILLERS_EFFECT_SLIGHT 0.95 //all painkillers. #define PAINKILLERS_EFFECT_MEDIUM 0.75 //weak painkillers, allow you to ignore minor pain and not see pain() messages. #define PAINKILLERS_EFFECT_HEAVY 0.6 //powerful painkillers, allow you to not see custom_pain() messages. #define PAINKILLERS_EFFECT_VERY_HEAVY 0.5 //very powerful painkillers that does not allow the user to determine the location of the injury. + diff --git a/code/__DEFINES/dcs/signals.dm b/code/__DEFINES/dcs/signals.dm index e6be0a84a9cf..7aeae642e3e5 100644 --- a/code/__DEFINES/dcs/signals.dm +++ b/code/__DEFINES/dcs/signals.dm @@ -424,3 +424,11 @@ #define COMSIG_REMOVE_GENE_DISABILITY "remove_gene_disability" // send this signal to handle disabilities in life for mob/living/carbon/human #define COMSIG_HANDLE_DISABILITIES "handle_disabilities" + +//from base of client/MouseDown(): (/client, object, location, control, params) +#define COMSIG_CLIENT_MOUSEDOWN "client_mousedown" +//from base of client/MouseUp(): (/client, object, location, control, params) +#define COMSIG_CLIENT_MOUSEUP "client_mouseup" + #define COMPONENT_CLIENT_MOUSEUP_INTERCEPT (1<<0) +//from base of client/MouseUp(): (/client, object, location, control, params) +#define COMSIG_CLIENT_MOUSEDRAG "client_mousedrag" diff --git a/code/__DEFINES/subsystem.dm b/code/__DEFINES/subsystem.dm index f9b91ad1fdd6..30133b79d53c 100644 --- a/code/__DEFINES/subsystem.dm +++ b/code/__DEFINES/subsystem.dm @@ -81,6 +81,7 @@ #define SS_PRIORITY_LOW 1 +#define SS_WAIT_FULLAUTO 1 #define SS_WAIT_EXPLOSION 1 #define SS_WAIT_INPUT 1 #define SS_WAIT_DEMO 1 diff --git a/code/__DEFINES/traits.dm b/code/__DEFINES/traits.dm index f5254f82ecef..dbbc836fccaf 100644 --- a/code/__DEFINES/traits.dm +++ b/code/__DEFINES/traits.dm @@ -197,6 +197,7 @@ #define TRAIT_MIMING "miming" #define TRAIT_WILLPOWER_IMPLANT "willpower_implant" #define TRAIT_CAN_LEAP "can_leap" +#define TRAIT_AUTOFIRE_SHOOTS "autofire_shoots" /* * Used for movables that need to be updated, via COMSIG_ENTER_AREA and COMSIG_EXIT_AREA, when transitioning areas. diff --git a/code/__HELPERS/unsorted.dm b/code/__HELPERS/unsorted.dm index 0c3785628578..41209e09c563 100644 --- a/code/__HELPERS/unsorted.dm +++ b/code/__HELPERS/unsorted.dm @@ -1662,3 +1662,23 @@ var/global/list/WALLITEMS = typecacheof(list( location = location.loc if(location && include_turf) //At this point, only the turf is left, provided it exists. . += location + +/proc/parse_caught_click_modifiers(list/modifiers, turf/origin, client/viewing_client) + if(!modifiers) + return null + + var/screen_loc = splittext(LAZYACCESS(modifiers, SCREEN_LOC), ",") + var/list/actual_view = getviewsize(viewing_client ? viewing_client.view : world.view) + var/click_turf_x = splittext(screen_loc[1], ":") + var/click_turf_y = splittext(screen_loc[2], ":") + var/click_turf_z = origin.z + + var/click_turf_px = text2num(click_turf_x[2]) + var/click_turf_py = text2num(click_turf_y[2]) + click_turf_x = origin.x + text2num(click_turf_x[1]) - round(actual_view[1] / 2) - 1 + click_turf_y = origin.y + text2num(click_turf_y[1]) - round(actual_view[2] / 2) - 1 + + var/turf/click_turf = locate(clamp(click_turf_x, 1, world.maxx), clamp(click_turf_y, 1, world.maxy), click_turf_z) + LAZYSET(modifiers, ICON_X, "[(click_turf_px - click_turf.pixel_x) + ((click_turf_x - click_turf.x) * world.icon_size)]") + LAZYSET(modifiers, ICON_Y, "[(click_turf_py - click_turf.pixel_y) + ((click_turf_y - click_turf.y) * world.icon_size)]") + return click_turf diff --git a/code/_onclick/click.dm b/code/_onclick/click.dm index 79e3368daacf..7d0761e32eaa 100644 --- a/code/_onclick/click.dm +++ b/code/_onclick/click.dm @@ -53,6 +53,11 @@ * mob/RangedAttack(atom,params) - used only ranged, only used for tk and laser eyes but could be changed */ /mob/proc/ClickOn( atom/A, params ) + if(client.click_intercept_time) + if(client.click_intercept_time >= world.time) + client.click_intercept_time = 0 //Reset and return. Next click should work, but not this one. + return + client.click_intercept_time = 0 //Just reset. Let's not keep re-checking forever. if(world.time <= next_click) return next_click = world.time + 1 @@ -160,6 +165,18 @@ else RangedAttack(A, params) +/client/MouseDown(datum/object, location, control, params) + SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEDOWN, object, location, control, params) + ..() + +/client/MouseUp(object, location, control, params) + if(SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEUP, object, location, control, params) & COMPONENT_CLIENT_MOUSEUP_INTERCEPT) + click_intercept_time = world.time + +/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params) + SEND_SIGNAL(src, COMSIG_CLIENT_MOUSEDRAG, src_object, over_object, src_location, over_location, src_control, over_control, params) + ..() + // Default behavior: ignore double clicks (don't add normal clicks, as it will do three clicks instead of two with double). /mob/proc/DblClickOn(atom/A, params) return diff --git a/code/controllers/subsystem/fullauto.dm b/code/controllers/subsystem/fullauto.dm new file mode 100644 index 000000000000..856bc49f8e9d --- /dev/null +++ b/code/controllers/subsystem/fullauto.dm @@ -0,0 +1,5 @@ +PROCESSING_SUBSYSTEM_DEF(fullauto) + name = "Fullauto" + flags = SS_NO_INIT | SS_BACKGROUND + priority = SS_PRIORITY_LOW + wait = SS_WAIT_FULLAUTO diff --git a/code/datums/components/_component.dm b/code/datums/components/_component.dm index 2fe896c8820e..52928242093f 100644 --- a/code/datums/components/_component.dm +++ b/code/datums/components/_component.dm @@ -151,6 +151,10 @@ if(!length(signal_procs[target])) signal_procs -= target +/datum/proc/RegisterSignals(datum/target, list/signal_types, proctype, override = FALSE) + for (var/signal_type in signal_types) + RegisterSignal(target, signal_type, proctype, override) + /datum/component/proc/InheritComponent(datum/component/C, i_am_original) return diff --git a/code/datums/components/fullauto.dm b/code/datums/components/fullauto.dm new file mode 100644 index 000000000000..3bd03c5351e2 --- /dev/null +++ b/code/datums/components/fullauto.dm @@ -0,0 +1,290 @@ +#define AUTOFIRE_MOUSEUP 0 +#define AUTOFIRE_MOUSEDOWN 1 + +/datum/component/automatic_fire + var/client/clicker + var/mob/living/shooter + var/atom/target + var/turf/target_loc //For dealing with locking on targets due to BYOND engine limitations (the mouse input only happening when mouse moves). + var/autofire_stat = AUTOFIRE_STAT_IDLE + var/mouse_parameters + /// Time between individual shots. + var/autofire_shot_delay = 0.3 SECONDS + /// This seems hacky but there can be two MouseDown() without a MouseUp() in between if the user holds click and uses alt+tab, printscreen or similar. + var/mouse_status = AUTOFIRE_MOUSEUP + + ///windup autofire vars + ///Whether the delay between shots increases over time, simulating a spooling weapon + var/windup_autofire = FALSE + ///the reduction to shot delay for windup + var/current_windup_reduction = 0 + ///the percentage of autfire_shot_delay that is added to current_windup_reduction + var/windup_autofire_reduction_multiplier = 0.3 + ///How high of a reduction that current_windup_reduction can reach + var/windup_autofire_cap = 0.3 + ///How long it takes for weapons that have spooled-up to reset back to the original firing speed + var/windup_spindown = 3 SECONDS + ///Timer for tracking the spindown reset timings + var/timerid + COOLDOWN_DECLARE(next_shot_cd) + +/datum/component/automatic_fire/Initialize(autofire_shot_delay, windup_autofire, windup_autofire_reduction_multiplier, windup_autofire_cap, windup_spindown) + . = ..() + if(!istype(parent, /obj/item/weapon/gun)) + return COMPONENT_NOT_ATTACHED + var/obj/item/weapon/gun/gun = parent + RegisterSignal(parent, COMSIG_ITEM_EQUIPPED, PROC_REF(wake_up)) + if(autofire_shot_delay) + src.autofire_shot_delay = autofire_shot_delay + if(windup_autofire) + src.windup_autofire = windup_autofire + src.windup_autofire_reduction_multiplier = windup_autofire_reduction_multiplier + src.windup_autofire_cap = windup_autofire_cap + src.windup_spindown = windup_spindown + if(autofire_stat == AUTOFIRE_STAT_IDLE && ismob(gun.loc)) + var/mob/user = gun.loc + wake_up(src, user) + + +/datum/component/automatic_fire/Destroy() + autofire_off() + return ..() + +/datum/component/automatic_fire/process(seconds_per_tick) + if(autofire_stat != AUTOFIRE_STAT_FIRING) + STOP_PROCESSING(SSfullauto, src) + return + process_shot() + +/datum/component/automatic_fire/proc/wake_up(datum/source, mob/user, slot) + SIGNAL_HANDLER + + if(autofire_stat == AUTOFIRE_STAT_ALERT) + return //We've updated the firemode. No need for more. + if(autofire_stat == AUTOFIRE_STAT_FIRING) + stop_autofiring() //Let's stop shooting to avoid issues. + return + if(user.get_active_hand() == parent) + autofire_on(user.client) + +// There is a gun and there is a user wielding it. The component now waits for the mouse click. +/datum/component/automatic_fire/proc/autofire_on(client/usercli) + SIGNAL_HANDLER + + if(autofire_stat != AUTOFIRE_STAT_IDLE) + return + autofire_stat = AUTOFIRE_STAT_ALERT + if(!QDELETED(usercli)) + clicker = usercli + shooter = clicker.mob + RegisterSignal(clicker, COMSIG_CLIENT_MOUSEDOWN, PROC_REF(on_mouse_down)) + if(!QDELETED(shooter)) + RegisterSignal(shooter, COMSIG_LOGOUT, PROC_REF(autofire_off)) + UnregisterSignal(shooter, COMSIG_LOGIN) + RegisterSignals(parent, list(COMSIG_PARENT_QDELETING, COMSIG_ITEM_DROPPED), PROC_REF(autofire_off)) + parent.RegisterSignal(src, COMSIG_AUTOFIRE_ONMOUSEDOWN, TYPE_PROC_REF(/obj/item/weapon/gun, autofire_bypass_check)) + parent.RegisterSignal(parent, COMSIG_AUTOFIRE_SHOT, TYPE_PROC_REF(/obj/item/weapon/gun, do_autofire)) + + + +/datum/component/automatic_fire/proc/autofire_off(datum/source) + SIGNAL_HANDLER + if(autofire_stat == AUTOFIRE_STAT_IDLE) + return + if(autofire_stat == AUTOFIRE_STAT_FIRING) + stop_autofiring() + + autofire_stat = AUTOFIRE_STAT_IDLE + + if(!QDELETED(clicker)) + UnregisterSignal(clicker, list(COMSIG_CLIENT_MOUSEDOWN, COMSIG_CLIENT_MOUSEUP, COMSIG_CLIENT_MOUSEDRAG)) + mouse_status = AUTOFIRE_MOUSEUP //In regards to the component there's no click anymore to care about. + clicker = null + if(!QDELETED(shooter)) + RegisterSignal(shooter, COMSIG_LOGIN, PROC_REF(on_client_login)) + UnregisterSignal(shooter, COMSIG_LOGOUT) + UnregisterSignal(parent, list(COMSIG_PARENT_QDELETING, COMSIG_ITEM_DROPPED)) + shooter = null + parent.UnregisterSignal(parent, COMSIG_AUTOFIRE_SHOT) + parent.UnregisterSignal(src, COMSIG_AUTOFIRE_ONMOUSEDOWN) + +/datum/component/automatic_fire/proc/on_client_login(mob/source) + SIGNAL_HANDLER + if(!source.client) + return + if(source.get_active_hand() == src) + autofire_on(source.client) + +/datum/component/automatic_fire/proc/on_mouse_down(client/source, atom/_target, turf/location, control, params) + SIGNAL_HANDLER + var/list/modifiers = params2list(params) //If they're shift+clicking, for example, let's not have them accidentally shoot. + + if(modifiers[SHIFT_CLICK] || modifiers[MIDDLE_CLICK] || modifiers[RIGHT_CLICK] || modifiers[ALT_CLICK]) + return + if(source.mob.in_throw_mode) + return + if(!isturf(source.mob.loc)) //No firing inside lockers and stuff. + return + if(get_dist(source.mob, _target) < 2) //Adjacent clicking. + return + + if(isnull(location) || istype(_target, /atom/movable/screen)) //Clicking on a screen object. + if(_target.plane != CLICKCATCHER_PLANE) //The clickcatcher is a special case. We want the click to trigger then, under it. + return //If we click and drag on our worn backpack, for example, we want it to open instead. + _target = parse_caught_click_modifiers(modifiers, get_turf(source.eye), source) + params = list2params(modifiers) + if(!_target) + CRASH("Failed to get the turf under clickcatcher") + + if(SEND_SIGNAL(src, COMSIG_AUTOFIRE_ONMOUSEDOWN, source, _target, location, control, params) & COMPONENT_AUTOFIRE_ONMOUSEDOWN_BYPASS) + return + + source.click_intercept_time = world.time //From this point onwards Click() will no longer be triggered. + + if(autofire_stat == (AUTOFIRE_STAT_IDLE)) + CRASH("on_mouse_down() called with [autofire_stat] autofire_stat") + if(autofire_stat == AUTOFIRE_STAT_FIRING) + stop_autofiring() //This can happen if we click and hold and then alt+tab, printscreen or other such action. MouseUp won't be called then and it will keep autofiring. + + target = _target + target_loc = get_turf(target) + mouse_parameters = params + INVOKE_ASYNC(src, PROC_REF(start_autofiring)) + +/datum/component/automatic_fire/proc/start_autofiring() + if(autofire_stat == AUTOFIRE_STAT_FIRING) + return + autofire_stat = AUTOFIRE_STAT_FIRING + + clicker.mouse_override_icon = 'icons/hud/weapon_pointer.dmi' + clicker.mouse_pointer_icon = clicker.mouse_override_icon + + if(mouse_status == AUTOFIRE_MOUSEUP) //See mouse_status definition for the reason for this. + RegisterSignal(clicker, COMSIG_CLIENT_MOUSEUP, PROC_REF(on_mouse_up)) + mouse_status = AUTOFIRE_MOUSEDOWN + + RegisterSignal(shooter, COMSIG_MOB_SWAP_HANDS, PROC_REF(stop_autofiring)) + + if(!istype(parent, /obj/item/weapon/gun)) + var/obj/item/weapon/gun/shoota = parent + if(!shoota.on_autofire_start(shooter)) //This is needed because the minigun has a do_after before firing and signals are async. + stop_autofiring() + return + if(autofire_stat != AUTOFIRE_STAT_FIRING) + return //Things may have changed while on_autofire_start() was being processed, due to do_after's sleep. + + if(!process_shot()) //First shot is processed instantly. + return //If it fails, such as when the gun is empty, then there's no need to schedule a second shot. + + ADD_TRAIT(shooter, TRAIT_AUTOFIRE_SHOOTS, GENERIC_TRAIT) + START_PROCESSING(SSfullauto, src) + RegisterSignal(clicker, COMSIG_CLIENT_MOUSEDRAG, PROC_REF(on_mouse_drag)) + + +/datum/component/automatic_fire/proc/on_mouse_up(datum/source, atom/object, turf/location, control, params) + SIGNAL_HANDLER + UnregisterSignal(clicker, COMSIG_CLIENT_MOUSEUP) + mouse_status = AUTOFIRE_MOUSEUP + if(autofire_stat == AUTOFIRE_STAT_FIRING) + stop_autofiring() + return COMPONENT_CLIENT_MOUSEUP_INTERCEPT + + +/datum/component/automatic_fire/proc/stop_autofiring(datum/source, atom/object, turf/location, control, params) + SIGNAL_HANDLER + if(autofire_stat != AUTOFIRE_STAT_FIRING) + return + STOP_PROCESSING(SSfullauto, src) + autofire_stat = AUTOFIRE_STAT_ALERT + if(clicker) + clicker.mouse_override_icon = null + clicker.mouse_pointer_icon = clicker.mouse_override_icon + UnregisterSignal(clicker, COMSIG_CLIENT_MOUSEDRAG) + if(!QDELETED(shooter)) + UnregisterSignal(shooter, COMSIG_MOB_SWAP_HANDS) + REMOVE_TRAIT(shooter, TRAIT_AUTOFIRE_SHOOTS, GENERIC_TRAIT) + target = null + target_loc = null + mouse_parameters = null + +/datum/component/automatic_fire/proc/on_mouse_drag(client/source, atom/src_object, atom/over_object, turf/src_location, turf/over_location, src_control, over_control, params) + SIGNAL_HANDLER + if(!over_location) //This happens when the mouse is over an inventory or screen object, or on entering deep darkness, for example. + var/list/modifiers = params2list(params) + var/new_target = parse_caught_click_modifiers(modifiers, get_turf(source.eye), source) + params = list2params(modifiers) + mouse_parameters = params + if(!new_target) + if(QDELETED(target)) //No new target acquired, and old one was deleted, get us out of here. + stop_autofiring() + CRASH("on_mouse_drag failed to get the turf under screen object [over_object.type]. Old target was incidentally QDELETED.") + target = get_turf(target) //If previous target wasn't a turf, let's turn it into one to avoid locking onto a potentially moving target. + target_loc = target + CRASH("on_mouse_drag failed to get the turf under screen object [over_object.type]") + target = new_target + target_loc = new_target + return + target = over_object + target_loc = get_turf(over_object) + mouse_parameters = params + + +/datum/component/automatic_fire/proc/process_shot() + if(autofire_stat != AUTOFIRE_STAT_FIRING) + return FALSE + if(!COOLDOWN_FINISHED(src, next_shot_cd)) + return TRUE + if(QDELETED(target) || get_turf(target) != target_loc) //Target moved or got destroyed since we last aimed. + target = target_loc //So we keep firing on the emptied tile until we move our mouse and find a new target. + if(get_dist(shooter, target) <= 0) + target = get_step(shooter, shooter.dir) //Shoot in the direction faced if the mouse is on the same tile as we are. + target_loc = target + shooter.face_atom(target) + var/next_delay = autofire_shot_delay + if(windup_autofire) + next_delay = clamp(next_delay - current_windup_reduction, round(autofire_shot_delay * windup_autofire_cap), autofire_shot_delay) + current_windup_reduction = (current_windup_reduction + round(autofire_shot_delay * windup_autofire_reduction_multiplier)) + timerid = addtimer(CALLBACK(src, PROC_REF(windup_reset), FALSE), windup_spindown, TIMER_UNIQUE|TIMER_OVERRIDE|TIMER_STOPPABLE) + COOLDOWN_START(src, next_shot_cd, next_delay) + if(SEND_SIGNAL(parent, COMSIG_AUTOFIRE_SHOT, target, shooter, mouse_parameters) & COMPONENT_AUTOFIRE_SHOT_SUCCESS) + return TRUE + stop_autofiring() + return FALSE + +/// Reset for our windup, resetting everything back to initial values after a variable set amount of time (determined by var/windup_spindown). +/datum/component/automatic_fire/proc/windup_reset(deltimer) + current_windup_reduction = initial(current_windup_reduction) + if(deltimer && timerid) + deltimer(timerid) + +// Gun procs. + +/obj/item/weapon/gun/proc/on_autofire_start(mob/living/shooter) + if(!ready_to_fire() || shooter.incapacitated()) + return FALSE + if(!can_fire()) + shoot_with_empty_chamber(shooter) + return FALSE + return TRUE + +/obj/item/weapon/gun/proc/autofire_bypass_check(datum/source, client/clicker, atom/target, turf/location, control, params) + SIGNAL_HANDLER + if(clicker.mob.get_active_hand() != src) + return COMPONENT_AUTOFIRE_ONMOUSEDOWN_BYPASS + + +/obj/item/weapon/gun/proc/do_autofire(datum/source, atom/target, mob/living/shooter, params) + SIGNAL_HANDLER + if(!ready_to_fire() || shooter.incapacitated()) + return NONE + if(!can_fire()) + shoot_with_empty_chamber(shooter) + return NONE + INVOKE_ASYNC(src, PROC_REF(do_autofire_shot), source, target, shooter, params) + return COMPONENT_AUTOFIRE_SHOT_SUCCESS //All is well, we can continue shooting. + +/obj/item/weapon/gun/proc/do_autofire_shot(datum/source, atom/target, mob/living/shooter, params) + afterattack(target, shooter, FALSE) + +#undef AUTOFIRE_MOUSEUP +#undef AUTOFIRE_MOUSEDOWN diff --git a/code/datums/uplinks_items.dm b/code/datums/uplinks_items.dm index a1fe5f67feb1..63c8e898c5d6 100644 --- a/code/datums/uplinks_items.dm +++ b/code/datums/uplinks_items.dm @@ -242,7 +242,7 @@ /datum/uplink_item/dangerous/machinegun name = "L6 Squad Automatic Weapon" - desc = "A traditionally constructed machine gun made by AA-2531. This deadly weapon has a massive 50-round magazine of 7.62x51mm ammunition." + desc = "A traditionally constructed machine gun made by AA-2531. This deadly weapon has a massive 100-round magazine of 7.62x51mm ammunition." item = /obj/item/weapon/gun/projectile/automatic/l6_saw cost = 30 uplink_types = list("nuclear") @@ -522,7 +522,7 @@ /datum/uplink_item/ammo/machinegun name = "Ammo-7.62x51mm" - desc = "A 50-round magazine of 7.62x51mm ammunition for use in the L6 SAW machinegun. By the time you need to use this, you'll already be on a pile of corpses." + desc = "A 100-round magazine of 7.62x51mm ammunition for use in the L6 SAW machinegun. By the time you need to use this, you'll already be on a pile of corpses." item = /obj/item/ammo_box/magazine/saw cost = 10 uplink_types = list("nuclear") diff --git a/code/game/gamemodes/modes_gameplays/families/outfit.dm b/code/game/gamemodes/modes_gameplays/families/outfit.dm index 0ade42619f2a..e3b2ed643949 100644 --- a/code/game/gamemodes/modes_gameplays/families/outfit.dm +++ b/code/game/gamemodes/modes_gameplays/families/outfit.dm @@ -65,7 +65,7 @@ head = /obj/item/clothing/head/helmet/laserproof/police shoes = /obj/item/clothing/shoes/boots/combat gloves = /obj/item/clothing/gloves/combat/police - suit_store = /obj/item/weapon/gun/projectile/automatic + suit_store = /obj/item/weapon/gun/projectile/automatic/saber backpack_contents = list( /obj/item/weapon/storage/box/handcuffs = 1, /obj/item/ammo_box/magazine/smg = 3, diff --git a/code/game/objects/random/random_guns.dm b/code/game/objects/random/random_guns.dm index 7742f2589511..af5342398ecb 100644 --- a/code/game/objects/random/random_guns.dm +++ b/code/game/objects/random/random_guns.dm @@ -92,7 +92,7 @@ return pick(\ prob(15);/obj/item/weapon/gun/projectile/shotgun/bolt_action,\ prob(15);/obj/item/weapon/gun/projectile/shotgun/repeater,\ - prob(15);/obj/item/weapon/gun/projectile/automatic,\ + prob(15);/obj/item/weapon/gun/projectile/automatic/saber,\ prob(14);/obj/item/weapon/gun/projectile/automatic/c20r,\ prob(12);/obj/item/weapon/gun/projectile/automatic/mini_uzi,\ prob(10);/obj/item/weapon/gun/projectile/automatic/bar,\ @@ -188,7 +188,7 @@ /obj/item/weapon/gun/projectile/revolver/doublebarrel/dungeon/sawn_off,\ /obj/item/weapon/gun/projectile/revolver,\ /obj/item/weapon/gun/projectile/revolver/detective,\ - /obj/item/weapon/gun/projectile/automatic,\ + /obj/item/weapon/gun/projectile/automatic/saber,\ /obj/item/weapon/gun/projectile/automatic/mini_uzi,\ /obj/item/weapon/gun/projectile/automatic/c20r,\ /obj/item/weapon/gun/projectile/automatic/l13,\ diff --git a/code/modules/cargo/packs.dm b/code/modules/cargo/packs.dm index a737576889b8..ef38f33c5e50 100644 --- a/code/modules/cargo/packs.dm +++ b/code/modules/cargo/packs.dm @@ -174,6 +174,46 @@ var/global/list/all_supply_groups = list("Operations","Security","Hospitality"," access = access_brig group = "Security" +/datum/supply_pack/ballistic/smg + name = ".38 SMG crate" + contains = list(/obj/item/weapon/gun/projectile/automatic/l13, + /obj/item/weapon/gun/projectile/automatic/l13, + /obj/item/weapon/gun/projectile/automatic/l13) + additional_costs = 2300 + crate_type = /obj/structure/closet/crate/secure/weapon + crate_name = ".38 SMG crate" + access = access_brig + group = "Security" + +/datum/supply_pack/ballistic/smg_magazine + name = ".38 magazine" + contains = list(/obj/item/ammo_box/magazine/l13/lethal, + /obj/item/ammo_box/magazine/l13/lethal, + /obj/item/ammo_box/magazine/l13/lethal, + /obj/item/ammo_box/magazine/l13/lethal, + /obj/item/ammo_box/magazine/l13/lethal, + /obj/item/ammo_box/magazine/l13/lethal) + additional_costs = 500 + crate_type = /obj/structure/closet/crate/secure + crate_name = ".38 magazine" + access = access_armory + group = "Security" + +/datum/supply_pack/ballistic/smg_magazine_rubber + name = ".38 magazine (rubber)" + contains = list(/obj/item/ammo_box/magazine/l13, + /obj/item/ammo_box/magazine/l13, + /obj/item/ammo_box/magazine/l13, + /obj/item/ammo_box/magazine/l13, + /obj/item/ammo_box/magazine/l13, + /obj/item/ammo_box/magazine/l13) + additional_costs = 400 + crate_type = /obj/structure/closet/crate/secure + crate_name = ".38 magazine (rubber)" + access = access_brig + group = "Security" + + /datum/supply_pack/ballistic/pistol name = "9mm pistol crate" contains = list(/obj/item/weapon/gun/projectile/automatic/pistol/glock, diff --git a/code/modules/client/client_defines.dm b/code/modules/client/client_defines.dm index 6b470e732a73..8e35c5318c0c 100644 --- a/code/modules/client/client_defines.dm +++ b/code/modules/client/client_defines.dm @@ -75,6 +75,8 @@ var/last_asset_job = 0 var/last_completed_asset_job = 0 + ///Time when the click was intercepted + var/click_intercept_time = 0 ///Amount of keydowns in the last keysend checking interval var/client_keysend_amount = 0 @@ -118,3 +120,5 @@ COOLDOWN_DECLARE(say_slowmode) var/is_in_spawner = FALSE + ///used to override the mouse cursor so it doesnt get reset + var/mouse_override_icon = null diff --git a/code/modules/mining/mine_items.dm b/code/modules/mining/mine_items.dm index ddd9358ab0c7..d1e52bba2bea 100644 --- a/code/modules/mining/mine_items.dm +++ b/code/modules/mining/mine_items.dm @@ -667,7 +667,7 @@ var/global/mining_shuttle_location = 0 // 0 = station 13, 1 = mining station damtype = BURN hitsound = list('sound/weapons/sear.ogg') ammo_type = list(/obj/item/ammo_casing/energy/laser/cutter) - fire_delay = 3 + fire_delay = 0 w_class = SIZE_SMALL //it is smaller than the pickaxe origin_tech = "materials=4;phorontech=3;engineering=3" desc = "The latest self-rechargeable low-power cutter using bursts of hot plasma. You could use it to cut limbs off of xenos! Or, you know, mine stuff." @@ -697,16 +697,15 @@ var/global/mining_shuttle_location = 0 // 0 = station 13, 1 = mining station if((iswallturf(target)) && (prob(destruction_chance))) target.ex_act(EXPLODE_HEAVY) - /obj/item/weapon/gun/energy/laser/cutter/atom_init() . = ..() power_supply.AddComponent(/datum/component/cell_selfrecharge, 50) + AddComponent(/datum/component/automatic_fire, 0.4 SECONDS) /obj/item/weapon/gun/energy/laser/cutter/emag_act(mob/user) if(emagged) return FALSE ammo_type += new /obj/item/ammo_casing/energy/laser/cutter/emagged(src) - fire_delay = 5 origin_tech += ";syndicate=1" emagged = TRUE to_chat(user, "Ошибка: Обнаружен несовместимый модуль. Ошибкаошибкаошибка.") diff --git a/code/modules/mob/living/carbon/human/human_movement.dm b/code/modules/mob/living/carbon/human/human_movement.dm index a5d8a7bf3f34..a186e529b11d 100644 --- a/code/modules/mob/living/carbon/human/human_movement.dm +++ b/code/modules/mob/living/carbon/human/human_movement.dm @@ -136,6 +136,9 @@ if(get_species() == UNATHI && bodytemperature > species.body_temperature) tally -= min((bodytemperature - species.body_temperature) / 10, 1) //will be on the border of heat_level_1 + if(HAS_TRAIT(src, TRAIT_AUTOFIRE_SHOOTS)) // so that you can’t run at full speed and shoot everyone and everything + tally += 0.75 + return (tally + config.human_delay) /mob/living/carbon/human/Process_Spacemove(movement_dir = 0) diff --git a/code/modules/projectiles/ammunition/magazines.dm b/code/modules/projectiles/ammunition/magazines.dm index dc095251e28c..f62b0ef51e59 100644 --- a/code/modules/projectiles/ammunition/magazines.dm +++ b/code/modules/projectiles/ammunition/magazines.dm @@ -331,11 +331,11 @@ origin_tech = "combat=2" ammo_type = /obj/item/ammo_casing/a762 caliber = "a762" - max_ammo = 50 + max_ammo = 100 /obj/item/ammo_box/magazine/saw/update_icon() ..() - icon_state = "[initial(icon_state)]-[round(ammo_count(),10)]" + icon_state = "[initial(icon_state)]-[round(ammo_count(),20)]" /obj/item/ammo_box/magazine/chameleon name = "magazine (.45)" diff --git a/code/modules/projectiles/firing.dm b/code/modules/projectiles/firing.dm index c71ca8829f6d..85549bad2870 100644 --- a/code/modules/projectiles/firing.dm +++ b/code/modules/projectiles/firing.dm @@ -50,6 +50,7 @@ qdel(BB) BB = null return 1 + BB.dispersion += weapon.spread BB.loc = get_turf(src) BB.starting = get_turf(src) BB.current = curloc diff --git a/code/modules/projectiles/gun.dm b/code/modules/projectiles/gun.dm index ed31e7d13761..121f87fe482a 100644 --- a/code/modules/projectiles/gun.dm +++ b/code/modules/projectiles/gun.dm @@ -39,6 +39,11 @@ var/fire_delay = 6 var/last_fired = 0 var/two_hand_weapon = FALSE + var/burst = 1 //burst size + var/burst_delay = 1 //cooldown between burst shots + var/spread_increase = 0 // per shot + var/spread_max = 0 + var/spread = 0 lefthand_file = 'icons/mob/inhands/guns_lefthand.dmi' righthand_file = 'icons/mob/inhands/guns_righthand.dmi' @@ -46,6 +51,12 @@ /datum/action/item_action/hands_free/switch_gun name = "Switch Gun" +/obj/item/weapon/gun/process() + if(spread == 0) + STOP_PROCESSING(SSfastprocess, src) + else + spread = clamp(spread - 0.1, 0, spread_max) + /obj/item/weapon/gun/examine(mob/user) ..() if(two_hand_weapon) @@ -80,12 +91,21 @@ var/skill_recoil_duration = max(DEFAULT_DURATION_RECOIL, apply_skill_bonus(user, recoil, list(/datum/skill/firearms = SKILL_LEVEL_TRAINED), multiplier = -0.5)) if(two_hand_weapon != DESIRABLE_TWOHAND) shake_camera(user, skill_recoil_duration, OPTIMAL_POWER_RECOIL) + if(spread_increase) + spread = clamp(spread + spread_increase, 0, spread_max) + START_PROCESSING(SSfastprocess, src) if(two_hand_weapon == DESIRABLE_TWOHAND) //No OPTIMAL_POWER_RECOIL only for increasing user's motivation to drop other hand if(user.get_inactive_hand()) shake_camera(user, recoil + 2, recoil + 1) + if(spread_increase) + spread = clamp(spread + spread_increase + 1, 0, spread_max) + START_PROCESSING(SSfastprocess, src) else shake_camera(user, skill_recoil_duration, OPTIMAL_POWER_RECOIL) + if(spread_increase) + spread = clamp(spread + spread_increase, 0, spread_max) + START_PROCESSING(SSfastprocess, src) if(silenced) playsound(user, fire_sound, VOL_EFFECTS_MASTER, 30, FALSE, null, -4) @@ -174,25 +194,28 @@ return if (!ready_to_fire()) - if (world.time % 3) //to prevent spam - to_chat(user, "[src] is not ready to fire again!") return - if(chambered) - if(point_blank) - if(!chambered.BB.fake) - user.visible_message(" \The [user] fires \the [src] point blank at [target]!") - chambered.BB.damage *= 1.3 - if(!chambered.fire(src, target, user, params, , silenced)) - shoot_with_empty_chamber(user) - else - shoot_live_shot(user) - user.newtonian_move(get_dir(target, user)) - else - shoot_with_empty_chamber(user) - process_chamber() - update_icon() - update_inv_mob() + user.next_click = world.time + (burst - 1) * burst_delay + for(var/i in 1 to burst) + if(chambered) + if(point_blank) + if(!chambered.BB.fake) + user.visible_message(" \The [user] fires \the [src] point blank at [target]!") + chambered.BB.damage *= 1.3 + if(!chambered.fire(src, target, user, params, , silenced)) + shoot_with_empty_chamber(user) + break + else + shoot_live_shot(user) + user.newtonian_move(get_dir(target, user)) + else + shoot_with_empty_chamber(user) + break + sleep(burst_delay) + process_chamber() + update_icon() + update_inv_mob() /obj/item/weapon/gun/proc/can_fire() return diff --git a/code/modules/projectiles/guns/plasma/plasma.dm b/code/modules/projectiles/guns/plasma/plasma.dm index 0a7761add0a0..a7e256a658e8 100644 --- a/code/modules/projectiles/guns/plasma/plasma.dm +++ b/code/modules/projectiles/guns/plasma/plasma.dm @@ -16,11 +16,12 @@ desc = "Стандартный плазменный карабин типа булл-пап обладающий высокой скорострельностью." icon_state = "plasma10_car" item_state = "plasma10_car" - fire_delay = 2 + fire_delay = 0 origin_tech = "combat=3;magnets=2" fire_sound = 'sound/weapons/guns/plasma10_shot.ogg' recoil = FALSE can_be_holstered = FALSE + var/fullauto = TRUE var/overcharge_fire_sound = 'sound/weapons/guns/plasma10_overcharge_shot.ogg' @@ -40,6 +41,7 @@ icon_state = "plasma104_stg" item_state = "plasma104_stg" origin_tech = "combat=4;magnets=3" + fullauto = FALSE overcharge_fire_sound = 'sound/weapons/guns/plasma10_overcharge_massive_shot.ogg' @@ -55,6 +57,8 @@ /obj/item/weapon/gun/plasma/atom_init() . = ..() + if(fullauto) + AddComponent(/datum/component/automatic_fire, 0.2 SECONDS) magazine = new initial_mag(src) for(var/i in ammo_type) var/path = ammo_type[i] @@ -85,7 +89,7 @@ fire_sound = initial(fire_sound) else shot = ammo_type[PLASMAGUN_OVERCHARGE_TYPE] - fire_delay = 1 + fire_delay = 0 fire_sound = overcharge_fire_sound max_projectile_per_fire = 1 diff --git a/code/modules/projectiles/guns/projectile/automatic.dm b/code/modules/projectiles/guns/projectile/automatic.dm index be0134592d26..48b983faa04e 100644 --- a/code/modules/projectiles/guns/projectile/automatic.dm +++ b/code/modules/projectiles/guns/projectile/automatic.dm @@ -1,6 +1,6 @@ -/obj/item/weapon/gun/projectile/automatic //Hopefully someone will find a way to make these fire in bursts or something. --Superxpdude - name = "submachine gun" - desc = "Легкий, скорострельный пистолет-пулемёт. Использует патроны калибра 9мм." +/obj/item/weapon/gun/projectile/automatic + name = "generic automatic gun" + desc = "О боже, вы не должны были видеть это!" icon_state = "saber" item_state = null w_class = SIZE_SMALL @@ -46,6 +46,17 @@ return install_silencer(I, user, params) return ..() +/obj/item/weapon/gun/projectile/automatic/saber + name = "submachine gun" + desc = "Легкий, скорострельный пистолет-пулемёт. Использует патроны калибра 9мм." + spread_increase = 0.5 + spread_max = 1.5 + fire_delay = 0 + +/obj/item/weapon/gun/projectile/automatic/saber/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.2 SECONDS) + /obj/item/weapon/gun/projectile/automatic/mini_uzi name = "Mac-10" desc = "Легкий и скорострельный пистолет-пулемёт для тех случаев, когда нужно кого-то быстро убить. Использует патроны калибра 9мм." @@ -56,6 +67,13 @@ origin_tech = "combat=5;materials=2;syndicate=8" initial_mag = /obj/item/ammo_box/magazine/mac10 can_be_silenced = TRUE + fire_delay = 0 + spread_increase = 0.25 + spread_max = 2 + +/obj/item/weapon/gun/projectile/automatic/mini_uzi/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.1 SECONDS) /obj/item/weapon/gun/projectile/automatic/c20r name = "C-20r SMG" @@ -70,6 +88,13 @@ should_alarm_when_empty = TRUE can_be_silenced = TRUE has_ammo_counter = TRUE + fire_delay = 0 + spread_increase = 0.25 + spread_max = 1.5 + +/obj/item/weapon/gun/projectile/automatic/c20r/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.2 SECONDS) /obj/item/weapon/gun/projectile/automatic/l6_saw name = "L6 SAW" @@ -83,9 +108,16 @@ has_cover = TRUE two_hand_weapon = ONLY_TWOHAND has_ammo_counter = TRUE + fire_delay = 0 + spread_increase = 0.5 + spread_max = 2 + +/obj/item/weapon/gun/projectile/automatic/l6_saw/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.25 SECONDS) /obj/item/weapon/gun/projectile/automatic/l6_saw/update_icon() - icon_state = "l6[cover_open ? "open" : "closed"][magazine ? CEIL(get_ammo(0) / 12.5) * 25 : "-empty"]" + icon_state = "l6[cover_open ? "open" : "closed"][magazine ? CEIL(get_ammo(0) / 25) * 25 : "-empty"]" item_state = "l6[cover_open ? "open" : "closed"][magazine ? "mag" : "nomag"]" /obj/item/weapon/gun/projectile/automatic/l6_saw/afterattack(atom/target, mob/user, proximity, params) //what I tried to do here is just add a check to see if the cover is open or not and add an icon_state change because I can't figure out how c-20rs do it with overlays @@ -136,6 +168,13 @@ suitable_mags = list(/obj/item/ammo_box/magazine/l13, /obj/item/ammo_box/magazine/l13/lethal) fire_sound = 'sound/weapons/guns/gunshot_l13.ogg' can_be_silenced = TRUE + fire_delay = 0 + spread_increase = 0.25 + spread_max = 1.5 + +/obj/item/weapon/gun/projectile/automatic/l13/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.2 SECONDS) /obj/item/weapon/gun/projectile/automatic/tommygun name = "tommy gun" @@ -149,6 +188,13 @@ initial_mag = /obj/item/ammo_box/magazine/tommygun fire_sound = 'sound/weapons/guns/gunshot_light.ogg' can_be_silenced = TRUE + fire_delay = 0 + spread_increase = 0.25 + spread_max = 2 + +/obj/item/weapon/gun/projectile/automatic/tommygun/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.15 SECONDS) /obj/item/weapon/gun/projectile/automatic/bar name = "Browning M1918" @@ -160,6 +206,13 @@ origin_tech = "combat=5;materials=2" initial_mag = /obj/item/ammo_box/magazine/bar fire_sound = 'sound/weapons/guns/Gunshot2.ogg' + fire_delay = 0 + spread_increase = 0.5 + spread_max = 1 + +/obj/item/weapon/gun/projectile/automatic/bar/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.4 SECONDS) /obj/item/weapon/gun/projectile/automatic/borg name = "Robot SMG" @@ -167,6 +220,8 @@ initial_mag = /obj/item/ammo_box/magazine/borg45 fire_sound = 'sound/weapons/guns/gunshot_medium.ogg' has_ammo_counter = TRUE + burst = 3 + burst_delay = 2 /obj/item/weapon/gun/projectile/automatic/borg/update_icon() return @@ -205,6 +260,13 @@ initial_mag = /obj/item/ammo_box/magazine/a28 suitable_mags = list(/obj/item/ammo_box/magazine/a28, /obj/item/ammo_box/magazine/a28/nonlethal, /obj/item/ammo_box/magazine/a28/incendiary) fire_sound = 'sound/weapons/guns/gunshot_medium.ogg' + fire_delay = 0 + spread_increase = 0.5 + spread_max = 1.5 + +/obj/item/weapon/gun/projectile/automatic/a28/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.25 SECONDS) /obj/item/weapon/gun/projectile/automatic/a74 name = "A74 assault rifle" @@ -217,6 +279,13 @@ item_state = "a74" origin_tech = "combat=5;materials=4;syndicate=6" fire_sound = 'sound/weapons/guns/gunshot_ak74.ogg' + fire_delay = 0 + spread_increase = 0.5 + spread_max = 1.5 + +/obj/item/weapon/gun/projectile/automatic/a74/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.25 SECONDS) /obj/item/weapon/gun/projectile/automatic/a74/krinkov name = "Krinkov" @@ -299,7 +368,10 @@ initial_mag = /obj/item/ammo_box/magazine/m41a w_class = SIZE_SMALL two_hand_weapon = DESIRABLE_TWOHAND - fire_delay = 1 + fire_delay = 3 + burst = 3 + spread_increase = 0.5 + spread_max = 1.5 /obj/item/weapon/gun/projectile/automatic/m41a/process_chamber() return ..(1, 1, 1) @@ -325,10 +397,13 @@ /obj/item/weapon/gun/projectile/automatic/m41a/launcher/proc/toggle_gl(mob/user) using_gl = !using_gl if(using_gl) + spread = 0 + burst = 1 user.visible_message("[user] presses a button, activating their [launcher]!",\ "You activate your [launcher].",\ "You hear an ominous click.") else + burst = 3 user.visible_message("[user] presses a button, deciding to stop the bombings.",\ "You deactivate your [launcher].",\ "You hear a click.") diff --git a/code/modules/projectiles/guns/projectile/pistol.dm b/code/modules/projectiles/guns/projectile/pistol.dm index 1525ed64b7ce..da7b49a15de4 100644 --- a/code/modules/projectiles/guns/projectile/pistol.dm +++ b/code/modules/projectiles/guns/projectile/pistol.dm @@ -65,6 +65,13 @@ initial_mag = /obj/item/ammo_box/magazine/stechkin suitable_mags = list(/obj/item/ammo_box/magazine/stechkin, /obj/item/ammo_box/magazine/stechkin/extended) can_be_silenced = TRUE + fire_delay = 0 + spread_increase = 0.5 + spread_max = 1.5 + +/obj/item/weapon/gun/projectile/automatic/pistol/stechkin/atom_init() + . = ..() + AddComponent(/datum/component/automatic_fire, 0.3 SECONDS) /obj/item/weapon/gun/projectile/automatic/pistol/colt1911 desc = "Дешевая марсианская подделка Colt M1911. Использует менее смертоносные патроны 45-го калибра." diff --git a/code/modules/projectiles/projectile/bullets.dm b/code/modules/projectiles/projectile/bullets.dm index 19f1150e5ca6..ba946827310d 100644 --- a/code/modules/projectiles/projectile/bullets.dm +++ b/code/modules/projectiles/projectile/bullets.dm @@ -238,7 +238,7 @@ proj_act_sound = SOUNDIN_WEAKBULLETACT /obj/item/projectile/bullet/a762 - damage = 50 + damage = 30 embed = 0 /obj/item/projectile/bullet/incendiary diff --git a/code/modules/research/designs.dm b/code/modules/research/designs.dm index ede37b37c08d..d07c41f77cb3 100644 --- a/code/modules/research/designs.dm +++ b/code/modules/research/designs.dm @@ -2083,7 +2083,7 @@ other types of metals and chemistry for reagents). id = "smg" build_type = PROTOLATHE materials = list(MAT_METAL = 8000, MAT_SILVER = 2000, MAT_DIAMOND = 1000) - build_path = /obj/item/weapon/gun/projectile/automatic + build_path = /obj/item/weapon/gun/projectile/automatic/saber category = list("Weapons") /datum/design/msmg9mm diff --git a/code/modules/research/prototipify.dm b/code/modules/research/prototipify.dm index 1983ceecae52..d712c0f0ed61 100644 --- a/code/modules/research/prototipify.dm +++ b/code/modules/research/prototipify.dm @@ -92,12 +92,17 @@ power_supply.maxcharge /= 2 power_supply.charge = power_supply.maxcharge +/obj/item/weapon/gun/energy/laser/cutter/set_prototype_qualities(rel_val=100, mark=0) + if(mark) + power_supply.maxcharge += (mark - 1) * 200 + if(!prob(reliability)) + power_supply.maxcharge /= 2 + power_supply.charge = power_supply.maxcharge + /obj/item/weapon/gun/projectile/automatic/set_prototype_qualities(rel_val=100, mark=0) if(mark) recoil = max(recoil / mark, 0.5) - fire_delay = max(fire_delay / mark, 2) if(!prob(reliability)) - fire_delay *= 2 recoil += 1 /obj/item/weapon/gun/plasma/set_prototype_qualities(rel_val=100, mark=0) diff --git a/icons/hud/weapon_pointer.dmi b/icons/hud/weapon_pointer.dmi new file mode 100644 index 0000000000000000000000000000000000000000..b5070062c0bb6c7a06e95dc52b8cc1631daada63 GIT binary patch literal 234 zcmeAS@N?(olHy`uVBq!ia0vp^4j|0P3?wHke>@jRu?6^qxE?rg;HIQuav+;EP=v80 z$S;_|;n|HeASb;lB%;J6wK%ybv!En1KaYW-Voq>aK~d@VFTn*Lzdq6O*3~+9=6vvm zP=kxc4<6~9_t8AbP;|y;hlO#F@nvH#g*lHV9hnrO5Ugpa?%vsLth#xH#0ldkk9@Sf z&iJ-&m?|3cH|9Va6T?pyNk5zFnyWx7-Lo_BPCrEHL{A4JVaAEj;xc$FCk^t+A d7ta`37=%BFn=Y<3a|bGA@O1TaS?83{1OTnfQ!4-f literal 0 HcmV?d00001 diff --git a/icons/obj/ammo/magazines.dmi b/icons/obj/ammo/magazines.dmi index 7ee6f6754b0eaa14e71812195915e269dc676052..4582c3c2f36dbf8821ef873dfe2b2fce4de746f9 100644 GIT binary patch delta 13551 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 VB;V8@7y|#UT-3c#pk*2Ie*hZptQr6S diff --git a/maps/centcom/centcom.dmm b/maps/centcom/centcom.dmm index c8f3f5f20100..2c6d0b6e89eb 100644 --- a/maps/centcom/centcom.dmm +++ b/maps/centcom/centcom.dmm @@ -14441,13 +14441,13 @@ /area/custom/wizard_station) "aGr" = ( /obj/structure/rack, -/obj/item/weapon/gun/projectile/automatic{ +/obj/item/weapon/gun/projectile/automatic/saber{ pixel_y = 6 }, -/obj/item/weapon/gun/projectile/automatic{ +/obj/item/weapon/gun/projectile/automatic/saber{ pixel_y = 3 }, -/obj/item/weapon/gun/projectile/automatic, +/obj/item/weapon/gun/projectile/automatic/saber, /obj/machinery/camera{ c_tag = "Spec. Ops. Armory North"; network = list("ERT") diff --git a/maps/templates/space_structures/old_station.dmm b/maps/templates/space_structures/old_station.dmm index 72dc11c50b6f..3abc5fe6f605 100644 --- a/maps/templates/space_structures/old_station.dmm +++ b/maps/templates/space_structures/old_station.dmm @@ -6967,7 +6967,7 @@ /area/space_structures/old_station/central) "OZ" = ( /obj/structure/rack, -/obj/item/weapon/gun/projectile/automatic, +/obj/item/weapon/gun/projectile/automatic/saber, /obj/effect/decal/turf_decal/alpha/yellow{ icon_state = "bot" }, diff --git a/taucetistation.dme b/taucetistation.dme index e3766ada9b0d..4cbf3b8f140b 100644 --- a/taucetistation.dme +++ b/taucetistation.dme @@ -240,6 +240,7 @@ #include "code\controllers\subsystem\environment.dm" #include "code\controllers\subsystem\events.dm" #include "code\controllers\subsystem\explosions.dm" +#include "code\controllers\subsystem\fullauto.dm" #include "code\controllers\subsystem\garbage.dm" #include "code\controllers\subsystem\holiday.dm" #include "code\controllers\subsystem\holomaps.dm" @@ -342,6 +343,7 @@ #include "code\datums\components\fishing.dm" #include "code\datums\components\footstep.dm" #include "code\datums\components\forcefield.dm" +#include "code\datums\components\fullauto.dm" #include "code\datums\components\gnawing.dm" #include "code\datums\components\logout_spawner.dm" #include "code\datums\components\magic_item.dm"