diff --git a/code/_onclick/autoclick.dm b/code/_onclick/autoclick.dm
index 1ceeb182ed..7b6e2f108a 100644
--- a/code/_onclick/autoclick.dm
+++ b/code/_onclick/autoclick.dm
@@ -14,7 +14,7 @@
selected_target[1] = null
/client/MouseDrag(src_object,atom/over_object,src_location,over_location,src_control,over_control,params)
- if(selected_target[1] && over_object.IsAutoclickable())
+ if(selected_target[1] && over_object && over_object.IsAutoclickable())
selected_target[1] = over_object
selected_target[2] = params
diff --git a/code/game/gamemodes/gang/gang.dm b/code/game/gamemodes/gang/gang.dm
index ca51e20cc6..bb4bf455dc 100644
--- a/code/game/gamemodes/gang/gang.dm
+++ b/code/game/gamemodes/gang/gang.dm
@@ -332,3 +332,4 @@ GLOBAL_LIST_INIT(gang_outfit_pool, list(/obj/item/clothing/suit/jacket/leather,/
SSticker.station_explosion_cinematic(1,"gang war", null)
SSticker.mode.explosion_in_progress = 0
SSticker.force_ending = TRUE
+
diff --git a/code/game/gamemodes/gang/gang_datum.dm b/code/game/gamemodes/gang/gang_datum.dm
index 075309b9d3..0ff9ef4f2d 100644
--- a/code/game/gamemodes/gang/gang_datum.dm
+++ b/code/game/gamemodes/gang/gang_datum.dm
@@ -28,6 +28,7 @@
var/static/list/boss_items = list(
/datum/gang_item/function/gang_ping,
/datum/gang_item/function/recall,
+
/datum/gang_item/clothing/under,
/datum/gang_item/clothing/suit,
/datum/gang_item/clothing/hat,
@@ -36,21 +37,29 @@
/datum/gang_item/clothing/mask,
/datum/gang_item/clothing/hands,
/datum/gang_item/clothing/belt,
+
/datum/gang_item/weapon/shuriken,
/datum/gang_item/weapon/switchblade,
+ /datum/gang_item/weapon/improvised,
+ /datum/gang_item/weapon/ammo/improvised_ammo,
+ /datum/gang_item/weapon/surplus,
+ /datum/gang_item/weapon/ammo/surplus_ammo,
/datum/gang_item/weapon/pistol,
/datum/gang_item/weapon/ammo/pistol_ammo,
/datum/gang_item/weapon/sniper,
/datum/gang_item/weapon/ammo/sniper_ammo,
+ /datum/gang_item/weapon/machinegun,
/datum/gang_item/weapon/uzi,
/datum/gang_item/weapon/ammo/uzi_ammo,
/datum/gang_item/equipment/sharpener,
/datum/gang_item/equipment/spraycan,
- /datum/gang_item/equipment/c4,
+ /datum/gang_item/equipment/sharpener,
/datum/gang_item/equipment/emp,
+ /datum/gang_item/equipment/c4,
/datum/gang_item/equipment/frag,
- /datum/gang_item/equipment/implant_breaker,
/datum/gang_item/equipment/stimpack,
+ /datum/gang_item/equipment/implant_breaker,
+ /datum/gang_item/equipment/wetwork_boots,
/datum/gang_item/equipment/pen,
/datum/gang_item/equipment/dominator
)
@@ -66,21 +75,29 @@
/datum/gang_item/clothing/mask,
/datum/gang_item/clothing/hands,
/datum/gang_item/clothing/belt,
- /datum/gang_item/weapon/shuriken,
+
+ /datum/gang_item/weapon/shuriken,
/datum/gang_item/weapon/switchblade,
+ /datum/gang_item/weapon/improvised,
+ /datum/gang_item/weapon/ammo/improvised_ammo,
+ /datum/gang_item/weapon/surplus,
+ /datum/gang_item/weapon/ammo/surplus_ammo,
/datum/gang_item/weapon/pistol,
/datum/gang_item/weapon/ammo/pistol_ammo,
/datum/gang_item/weapon/sniper,
/datum/gang_item/weapon/ammo/sniper_ammo,
+ /datum/gang_item/weapon/machinegun,
/datum/gang_item/weapon/uzi,
/datum/gang_item/weapon/ammo/uzi_ammo,
/datum/gang_item/equipment/sharpener,
/datum/gang_item/equipment/spraycan,
- /datum/gang_item/equipment/c4,
+ /datum/gang_item/equipment/sharpener,
/datum/gang_item/equipment/emp,
+ /datum/gang_item/equipment/c4,
/datum/gang_item/equipment/frag,
- /datum/gang_item/equipment/implant_breaker,
/datum/gang_item/equipment/stimpack,
+ /datum/gang_item/equipment/implant_breaker,
+ /datum/gang_item/equipment/wetwork_boots,
)
/datum/gang/New(loc,gangname)
@@ -165,7 +182,6 @@
var/diff = domination_timer - world.time
return diff / 10
-
//////////////////////////////////////////// MESSAGING
@@ -283,4 +299,4 @@
ganghud = new()
/datum/gang/multiverse/income()
- return
\ No newline at end of file
+ return
diff --git a/code/game/gamemodes/gang/gang_items.dm b/code/game/gamemodes/gang/gang_items.dm
index b5237040f1..aec9b040cd 100644
--- a/code/game/gamemodes/gang/gang_items.dm
+++ b/code/game/gamemodes/gang/gang_items.dm
@@ -199,10 +199,34 @@
cost = 5
item_path = /obj/item/weapon/switchblade
+/datum/gang_item/weapon/surplus
+ name = "Surplus Rifle"
+ id = "surplus"
+ cost = 8
+ item_path = /obj/item/weapon/gun/ballistic/automatic/surplus
+
+/datum/gang_item/weapon/ammo/surplus_ammo
+ name = "Surplus Rifle Ammo"
+ id = "surplus_ammo"
+ cost = 5
+ item_path = /obj/item/ammo_box/magazine/m10mm/rifle
+
+/datum/gang_item/weapon/improvised
+ name = "Sawn-Off Improvised Shotgun"
+ id = "sawn"
+ cost = 6
+ item_path = /obj/item/weapon/gun/ballistic/revolver/doublebarrel/improvised/sawn
+
+/datum/gang_item/weapon/ammo/improvised_ammo
+ name = "Box of Buckshot"
+ id = "buckshot"
+ cost = 5
+ item_path = /obj/item/weapon/storage/box/lethalshot
+
/datum/gang_item/weapon/pistol
name = "10mm Pistol"
id = "pistol"
- cost = 25
+ cost = 30
item_path = /obj/item/weapon/gun/ballistic/automatic/pistol
/datum/gang_item/weapon/ammo/pistol_ammo
@@ -223,12 +247,19 @@
cost = 15
item_path = /obj/item/ammo_box/magazine/sniper_rounds
+/datum/gang_item/weapon/machinegun
+ name = "Mounted Machine Gun"
+ id = "MG"
+ cost = 50
+ item_path = /obj/machinery/manned_turret
+ spawn_msg = "The mounted machine gun features enhanced responsiveness. Hold down on the trigger while firing to control where you're shooting."
+
/datum/gang_item/weapon/uzi
name = "Uzi SMG"
id = "uzi"
cost = 60
item_path = /obj/item/weapon/gun/ballistic/automatic/mini_uzi
- id = "uzi"
+
/datum/gang_item/weapon/ammo/uzi_ammo
name = "Uzi Ammo"
@@ -236,8 +267,6 @@
cost = 40
item_path = /obj/item/ammo_box/magazine/uzim9mm
-
-
///////////////////
//EQUIPMENT
///////////////////
@@ -274,13 +303,13 @@
/datum/gang_item/equipment/frag
name = "Fragmentation Grenade"
id = "frag nade"
- cost = 10
+ cost = 18
item_path = /obj/item/weapon/grenade/syndieminibomb/concussion/frag
/datum/gang_item/equipment/stimpack
name = "Black Market Stimulants"
id = "stimpack"
- cost = 15
+ cost = 12
item_path = /obj/item/weapon/reagent_containers/syringe/stimulants
/datum/gang_item/equipment/implant_breaker
@@ -297,6 +326,18 @@
if(spawn_msg)
to_chat(user, spawn_msg)
+/datum/gang_item/equipment/wetwork_boots
+ name = "Wetwork boots"
+ id = "wetwork"
+ cost = 20
+ item_path = /obj/item/clothing/shoes/combat/gang
+
+/obj/item/clothing/shoes/combat/gang
+ name = "Wetwork boots"
+ desc = "A gang's best hitmen are prepared for anything."
+ permeability_coefficient = 0.01
+ flags = NOSLIP
+
/datum/gang_item/equipment/pen
name = "Recruitment Pen"
id = "pen"
@@ -390,4 +431,4 @@
return ..()
/datum/gang_item/equipment/dominator/spawn_item(mob/living/carbon/user, datum/gang/gang, obj/item/device/gangtool/gangtool)
- new item_path(user.loc)
\ No newline at end of file
+ new item_path(user.loc)
diff --git a/code/game/gamemodes/gang/gang_pen.dm b/code/game/gamemodes/gang/gang_pen.dm
index 01b8504e82..d60a3cb57b 100644
--- a/code/game/gamemodes/gang/gang_pen.dm
+++ b/code/game/gamemodes/gang/gang_pen.dm
@@ -66,4 +66,4 @@
cooldown = 0
icon_state = "pen"
var/mob/M = get(src, /mob)
- to_chat(M, "\icon[src] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.")
\ No newline at end of file
+ to_chat(M, "\icon[src] [src][(src.loc == M)?(""):(" in your [src.loc]")] vibrates softly. It is ready to be used again.")
diff --git a/code/game/gamemodes/gang/recaller.dm b/code/game/gamemodes/gang/recaller.dm
index c9fcf3c074..ad2da7b502 100644
--- a/code/game/gamemodes/gang/recaller.dm
+++ b/code/game/gamemodes/gang/recaller.dm
@@ -240,6 +240,7 @@
/obj/item/device/gangtool/spare/lt
promotable = 1
+
///////////// Internal tool used by gang regulars ///////////
/obj/item/device/gangtool/soldier
diff --git a/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index 6bab77fd6f..ae9d485447 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -1,9 +1,9 @@
#define TURRET_STUN 0
#define TURRET_LETHAL 1
-#define POPUP_ANIM_TIME 5
-#define POPDOWN_ANIM_TIME 5 //Be sure to change the icon animation at the same time or it'll look bad
-
+#define POPUP_ANIM_TIME 5
+#define POPDOWN_ANIM_TIME 5 //Be sure to change the icon animation at the same time or it'll look bad
+
/obj/machinery/porta_turret
name = "turret"
icon = 'icons/obj/turrets.dmi'
@@ -87,9 +87,9 @@
if(has_cover)
cover = new /obj/machinery/porta_turret_cover(loc)
cover.parent_turret = src
- underlays += image('icons/obj/turrets.dmi',icon_state = "basedark")
+ underlays += image('icons/obj/turrets.dmi',icon_state = "basedark")
if(!has_cover)
- INVOKE_ASYNC(src, .proc/popUp)
+ INVOKE_ASYNC(src, .proc/popUp)
/obj/machinery/porta_turret/update_icon()
cut_overlays()
@@ -368,10 +368,10 @@
var/list/targets = list()
var/turretview = view(scan_range, base)
for(var/A in turretview)
- var/atom/AA = A
- if(AA.invisibility>SEE_INVISIBLE_LIVING)
- continue
-
+ var/atom/AA = A
+ if(AA.invisibility>SEE_INVISIBLE_LIVING)
+ continue
+
if(check_anomalies)//if it's set to check for simple animals
if(istype(A, /mob/living/simple_animal))
var/mob/living/simple_animal/SA = A
@@ -426,7 +426,7 @@
raising = 1
if(cover)
flick("popup", cover)
- sleep(POPUP_ANIM_TIME)
+ sleep(POPUP_ANIM_TIME)
raising = 0
if(cover)
cover.icon_state = "openTurretCover"
@@ -442,7 +442,7 @@
raising = 1
if(cover)
flick("popdown", cover)
- sleep(POPDOWN_ANIM_TIME)
+ sleep(POPDOWN_ANIM_TIME)
raising = 0
if(cover)
cover.icon_state = "turretCover"
@@ -792,7 +792,7 @@
/obj/item/wallframe/turret_control
name = "turret control frame"
desc = "Used for building turret control panels"
- icon_state = "apc"
+ icon_state = "apc"
result_path = /obj/machinery/turretid
materials = list(MAT_METAL=MINERAL_MATERIAL_AMOUNT)
@@ -921,3 +921,170 @@
on = 0
spawn(100)
on = 1
+
+/////// MANNED TURRET ////////
+
+/obj/machinery/manned_turret
+ name = "machine gun turret"
+ desc = "While the trigger is held down, this gun will redistribute recoil to allow its user to easily shift targets."
+ icon = 'icons/obj/turrets.dmi'
+ icon_state = "machinegun"
+ can_buckle = TRUE
+ density = TRUE
+ max_integrity = 100
+ obj_integrity = 100
+ buckle_lying = 0
+ layer = ABOVE_MOB_LAYER
+ var/view_range = 10
+ var/cooldown = 0
+ var/projectile_type = /obj/item/projectile/bullet/weakbullet3
+ var/rate_of_fire = 1
+ var/number_of_shots = 40
+ var/cooldown_duration = 90
+ var/atom/target
+ var/turf/target_turf
+ var/warned = FALSE
+
+//BUCKLE HOOKS
+
+/obj/machinery/manned_turret/unbuckle_mob(mob/living/buckled_mob,force = 0)
+ playsound(src,'sound/mecha/mechmove01.ogg', 50, 1)
+ for(var/obj/item/I in buckled_mob.held_items)
+ if(istype(I, /obj/item/gun_control))
+ qdel(I)
+ if(istype(buckled_mob))
+ buckled_mob.pixel_x = 0
+ buckled_mob.pixel_y = 0
+ if(buckled_mob.client)
+ buckled_mob.client.change_view(world.view)
+ anchored = FALSE
+ . = ..()
+
+/obj/machinery/manned_turret/user_buckle_mob(mob/living/M, mob/living/carbon/user)
+ if(user.incapacitated() || !istype(user))
+ return
+ M.forceMove(get_turf(src))
+ ..()
+ for(var/V in M.held_items)
+ var/obj/item/I = V
+ if(istype(I))
+ if(M.dropItemToGround(I))
+ var/obj/item/gun_control/TC = new /obj/item/gun_control(src)
+ M.put_in_hands(TC)
+ else //Entries in the list should only ever be items or null, so if it's not an item, we can assume it's an empty hand
+ var/obj/item/gun_control/TC = new /obj/item/gun_control(src)
+ M.put_in_hands(TC)
+ M.pixel_y = 14
+ layer = ABOVE_MOB_LAYER
+ setDir(SOUTH)
+ playsound(src,'sound/mecha/mechmove01.ogg', 50, 1)
+ anchored = TRUE
+ if(user.client)
+ user.client.change_view(view_range)
+
+/obj/item/gun_control
+ name = "turret controls"
+ icon = 'icons/obj/weapons.dmi'
+ icon_state = "offhand"
+ w_class = WEIGHT_CLASS_HUGE
+ flags = ABSTRACT | NODROP
+ resistance_flags = FIRE_PROOF | UNACIDABLE | ACID_PROOF | NOBLUDGEON
+ var/obj/machinery/manned_turret/turret
+
+/obj/item/gun_control/New(obj/machinery/manned_turret/MT)
+ if(MT)
+ turret = MT
+ else
+ qdel(src)
+
+/obj/item/gun_control/CanItemAutoclick()
+ return 1
+
+/obj/item/gun_control/afterattack(atom/targeted_atom, mob/user)
+ ..()
+ var/obj/machinery/manned_turret/E = user.buckled
+ E.setDir(get_dir(E,targeted_atom))
+ user.setDir(E.dir)
+ switch(E.dir)
+ if(NORTH)
+ E.layer = BELOW_MOB_LAYER
+ user.pixel_x = 0
+ user.pixel_y = -14
+ if(NORTHEAST)
+ E.layer = BELOW_MOB_LAYER
+ user.pixel_x = -8
+ user.pixel_y = -4
+ if(EAST)
+ E.layer = ABOVE_MOB_LAYER
+ user.pixel_x = -14
+ user.pixel_y = 0
+ if(SOUTHEAST)
+ E.layer = BELOW_MOB_LAYER
+ user.pixel_x = -8
+ user.pixel_y = 4
+ if(SOUTH)
+ E.layer = ABOVE_MOB_LAYER
+ user.pixel_x = 0
+ user.pixel_y = 14
+ if(SOUTHWEST)
+ E.layer = BELOW_MOB_LAYER
+ user.pixel_x = 8
+ user.pixel_y = 4
+ if(WEST)
+ E.layer = ABOVE_MOB_LAYER
+ user.pixel_x = 14
+ user.pixel_y = 0
+ if(NORTHWEST)
+ E.layer = BELOW_MOB_LAYER
+ user.pixel_x = 8
+ user.pixel_y = -4
+ E.checkfire(targeted_atom, user)
+
+/obj/machinery/manned_turret/proc/checkfire(atom/targeted_atom, mob/user)
+ target = targeted_atom
+ if(target == user || target == get_turf(src))
+ return
+ if(world.time < cooldown)
+ if(!warned && world.time > (cooldown - cooldown_duration + rate_of_fire*number_of_shots)) // To capture the window where one is done firing
+ warned = TRUE
+ playsound(src, 'sound/weapons/sear.ogg', 100, 1)
+ return
+ else
+ cooldown = world.time + cooldown_duration
+ warned = FALSE
+ INVOKE_ASYNC(src, /obj/machinery/manned_turret/.proc/volley)
+
+/obj/machinery/manned_turret/proc/volley()
+ target_turf = get_turf(target)
+ for(var/i in 1 to number_of_shots)
+ addtimer(CALLBACK(src, /obj/machinery/manned_turret/.proc/fire_helper), i*rate_of_fire)
+
+
+/obj/machinery/manned_turret/proc/fire_helper()
+ if(!src)
+ return
+ var/turf/targets_from = get_turf(src)
+ if(QDELETED(target))
+ target = target_turf
+ var/obj/item/projectile/P = new projectile_type(targets_from)
+ P.current = targets_from
+ P.starting = targets_from
+ P.firer = src
+ P.original = target
+ playsound(src, 'sound/weapons/Gunshot_smg.ogg', 75, 1)
+ P.yo = target.y - targets_from.y + rand(-1,1)
+ P.xo = target.x - targets_from.x + rand(-1,1)
+ P.fire()
+
+/obj/machinery/manned_turret/ultimate // Admin-only proof of concept for autoclicker automatics
+ name = "Infinity Gun"
+ view_range = 12
+ projectile_type = /obj/item/projectile/bullet/weakbullet3
+
+
+/obj/machinery/manned_turret/ultimate/checkfire(atom/targeted_atom, mob/user)
+ target = targeted_atom
+ if(target == user || target == get_turf(src))
+ return
+ target_turf = get_turf(target)
+ fire_helper(target_turf)
diff --git a/code/modules/projectiles/boxes_magazines/external_mag.dm b/code/modules/projectiles/boxes_magazines/external_mag.dm
index 11112ec974..72cbc25f12 100644
--- a/code/modules/projectiles/boxes_magazines/external_mag.dm
+++ b/code/modules/projectiles/boxes_magazines/external_mag.dm
@@ -13,6 +13,21 @@
max_ammo = 8
multiple_sprites = 2
+/obj/item/ammo_box/magazine/m10mm/rifle
+ name = "rifle magazine (10mm)"
+ desc = "A well-worn magazine fitted for the surplus rifle."
+ icon_state = "75-8"
+ origin_tech = "combat=2"
+ ammo_type = /obj/item/ammo_casing/c10mm
+ caliber = "10mm"
+ max_ammo = 10
+
+/obj/item/ammo_box/magazine/m10mm/rifle/update_icon()
+ if(ammo_count())
+ icon_state = "75-8"
+ else
+ icon_state = "75-0"
+
/obj/item/ammo_box/magazine/m10mm/fire
name = "pistol magazine (10mm incendiary)"
desc = "A gun magazine. Loaded with rounds which ignite the target."
diff --git a/code/modules/projectiles/guns/ballistic/automatic.dm b/code/modules/projectiles/guns/ballistic/automatic.dm
index 1ffdaf0d29..0235bbe84d 100644
--- a/code/modules/projectiles/guns/ballistic/automatic.dm
+++ b/code/modules/projectiles/guns/ballistic/automatic.dm
@@ -375,8 +375,29 @@
pin = /obj/item/device/firing_pin/implant/pindicate
origin_tech = "combat=7;syndicate=6"
+// Old Semi-Auto Rifle //
+/obj/item/weapon/gun/ballistic/automatic/surplus
+ name = "Surplus Rifle"
+ desc = "One of countless obsolete ballistic rifles that still sees use as a cheap deterrent. Uses 10mm ammo and its bulky frame prevents one-hand firing."
+ origin_tech = "combat=3;materials=2"
+ icon_state = "surplus"
+ item_state = "moistnugget"
+ weapon_weight = WEAPON_HEAVY
+ mag_type = /obj/item/ammo_box/magazine/m10mm/rifle
+ fire_delay = 30
+ burst_size = 1
+ can_unsuppress = 1
+ can_suppress = 1
+ w_class = WEIGHT_CLASS_HUGE
+ slot_flags = SLOT_BACK
+ actions_types = list()
+/obj/item/weapon/gun/ballistic/automatic/surplus/update_icon()
+ if(magazine)
+ icon_state = "surplus"
+ else
+ icon_state = "surplus-e"
// Laser rifle (rechargeable magazine) //
diff --git a/code/modules/projectiles/guns/ballistic/revolver.dm b/code/modules/projectiles/guns/ballistic/revolver.dm
index 6ce52748ec..ac3c56b88a 100644
--- a/code/modules/projectiles/guns/ballistic/revolver.dm
+++ b/code/modules/projectiles/guns/ballistic/revolver.dm
@@ -344,6 +344,15 @@
slung = 0
update_icon()
+/obj/item/weapon/gun/ballistic/revolver/doublebarrel/improvised/sawn
+ name = "sawn-off improvised shotgun"
+ desc = "A single-shot shotgun, better not miss"
+ icon_state = "ishotgun"
+ item_state = "gun"
+ w_class = WEIGHT_CLASS_NORMAL
+ sawn_state = SAWN_OFF
+ slot_flags = SLOT_BELT
+
/obj/item/weapon/gun/ballistic/revolver/reverse //Fires directly at its user... unless the user is a clown, of course.
clumsy_check = 0
diff --git a/icons/obj/turrets.dmi b/icons/obj/turrets.dmi
index c4077b6601..b186c3f224 100644
Binary files a/icons/obj/turrets.dmi and b/icons/obj/turrets.dmi differ