diff --git a/code/modules/projectiles/guns/energy/dueling.dm b/code/modules/projectiles/guns/energy/dueling.dm
new file mode 100644
index 0000000000..cea2fd580d
--- /dev/null
+++ b/code/modules/projectiles/guns/energy/dueling.dm
@@ -0,0 +1,376 @@
+#define DUEL_IDLE 1
+#define DUEL_PREPARATION 2
+#define DUEL_READY 3
+#define DUEL_COUNTDOWN 4
+#define DUEL_FIRING 5
+
+//paper rock scissors
+#define DUEL_SETTING_A "wide"
+#define DUEL_SETTING_B "cone"
+#define DUEL_SETTING_C "pinpoint"
+
+#define DUEL_HUGBOX_NONE 0 //dismember head
+#define DUEL_HUGBOX_LETHAL 1 //200 damage to chest
+#define DUEL_HUGBOX_NONLETHAL 2 //stamcrit
+
+/datum/duel
+ var/obj/item/gun/energy/dueling/gun_A
+ var/obj/item/gun/energy/dueling/gun_B
+ var/state = DUEL_IDLE
+ var/required_distance = 5
+ var/list/confirmations = list()
+ var/list/fired = list()
+ var/countdown_length = 10
+ var/countdown_step = 0
+
+/datum/duel/proc/try_begin()
+ //Check if both guns are held and if so begin.
+ var/mob/living/A = get_duelist(gun_A)
+ var/mob/living/B = get_duelist(gun_B)
+ if(!A || !B)
+ message_duelists("To begin the duel, both participants need to be holding paired dueling pistols.")
+ return
+ begin()
+
+/datum/duel/proc/begin()
+ state = DUEL_PREPARATION
+ confirmations.Cut()
+ fired.Cut()
+ countdown_step = countdown_length
+
+ message_duelists("Set your gun setting and move [required_distance] steps away from your opponent.")
+
+ START_PROCESSING(SSobj,src)
+
+/datum/duel/proc/get_duelist(obj/gun)
+ var/mob/living/G = gun.loc
+ if(!istype(G) || !G.is_holding(gun))
+ return null
+ return G
+
+/datum/duel/proc/message_duelists(message)
+ var/mob/living/LA = get_duelist(gun_A)
+ if(LA)
+ to_chat(LA,message)
+ var/mob/living/LB = get_duelist(gun_B)
+ if(LB)
+ to_chat(LB,message)
+
+/datum/duel/proc/other_gun(obj/item/gun/energy/dueling/G)
+ return G == gun_A ? gun_B : gun_A
+
+/datum/duel/proc/end()
+ message_duelists("Duel finished. Re-engaging safety.")
+ STOP_PROCESSING(SSobj,src)
+ state = DUEL_IDLE
+
+/datum/duel/process()
+ switch(state)
+ if(DUEL_PREPARATION)
+ if(check_positioning())
+ confirm_positioning()
+ else if (!get_duelist(gun_A) && !get_duelist(gun_B))
+ end()
+ if(DUEL_READY)
+ if(!check_positioning())
+ back_to_prep()
+ else if(confirmations.len == 2)
+ confirm_ready()
+ if(DUEL_COUNTDOWN)
+ if(!check_positioning())
+ back_to_prep()
+ else
+ countdown_step()
+ if(DUEL_FIRING)
+ if(check_fired())
+ end()
+
+/datum/duel/proc/back_to_prep()
+ message_duelists("Positions invalid. Please move to valid positions [required_distance] steps aways from each other to continue.")
+ state = DUEL_PREPARATION
+ confirmations.Cut()
+ countdown_step = countdown_length
+
+/datum/duel/proc/confirm_positioning()
+ message_duelists("Position confirmed. Confirm readiness by pulling the trigger once.")
+ state = DUEL_READY
+
+/datum/duel/proc/confirm_ready()
+ message_duelists("Readiness confirmed. Starting countdown. Commence firing at zero mark.")
+ state = DUEL_COUNTDOWN
+
+/datum/duel/proc/countdown_step()
+ countdown_step--
+ if(countdown_step == 0)
+ state = DUEL_FIRING
+ message_duelists("Fire!")
+ else
+ message_duelists("[countdown_step]!")
+
+/datum/duel/proc/check_fired()
+ if(fired.len == 2)
+ return TRUE
+ //Let's say if gun was dropped/stowed the user is finished
+ if(!get_duelist(gun_A))
+ return TRUE
+ if(!get_duelist(gun_B))
+ return TRUE
+ return FALSE
+
+/datum/duel/proc/check_positioning()
+ var/mob/living/A = get_duelist(gun_A)
+ var/mob/living/B = get_duelist(gun_B)
+ if(!A || !B)
+ return FALSE
+ if(!isturf(A.loc) || !isturf(B.loc))
+ return FALSE
+ if(get_dist(A,B) != required_distance)
+ return FALSE
+ for(var/turf/T in getline(get_turf(A),get_turf(B)))
+ if(is_blocked_turf(T,TRUE))
+ return FALSE
+ return TRUE
+
+/obj/item/gun/energy/dueling
+ name = "dueling pistol"
+ desc = "High-tech dueling pistol. Launches chaff and projectile according to preset settings."
+ icon_state = "dueling_pistol"
+ item_state = "gun"
+ ammo_x_offset = 2
+ w_class = WEIGHT_CLASS_SMALL
+ ammo_type = list(/obj/item/ammo_casing/energy/duel)
+ automatic_charge_overlays = FALSE
+ var/unlocked = FALSE
+ var/setting = DUEL_SETTING_A
+ var/datum/duel/duel
+ var/mutable_appearance/setting_overlay
+ var/hugbox = DUEL_HUGBOX_NONE
+
+/obj/item/gun/energy/dueling/hugbox
+ hugbox = DUEL_HUGBOX_LETHAL
+
+/obj/item/gun/energy/dueling/hugbox/stamina
+ hugbox = DUEL_HUGBOX_NONLETHAL
+
+/obj/item/gun/energy/dueling/Initialize()
+ . = ..()
+ setting_overlay = mutable_appearance(icon,setting_iconstate())
+ add_overlay(setting_overlay)
+
+/obj/item/gun/energy/dueling/proc/setting_iconstate()
+ switch(setting)
+ if(DUEL_SETTING_A)
+ return "duel_red"
+ if(DUEL_SETTING_B)
+ return "duel_green"
+ if(DUEL_SETTING_C)
+ return "duel_blue"
+ return "duel_red"
+
+/obj/item/gun/energy/dueling/attack_self(mob/living/user)
+ . = ..()
+ if(duel.state == DUEL_IDLE)
+ duel.try_begin()
+ else
+ toggle_setting(user)
+
+/obj/item/gun/energy/dueling/proc/toggle_setting(mob/living/user)
+ switch(setting)
+ if(DUEL_SETTING_A)
+ setting = DUEL_SETTING_B
+ if(DUEL_SETTING_B)
+ setting = DUEL_SETTING_C
+ if(DUEL_SETTING_C)
+ setting = DUEL_SETTING_A
+ to_chat(user,"You switch [src] setting to [setting] mode.")
+ update_icon()
+
+/obj/item/gun/energy/dueling/update_icon(force_update)
+ . = ..()
+ if(setting_overlay)
+ cut_overlay(setting_overlay)
+ setting_overlay.icon_state = setting_iconstate()
+ add_overlay(setting_overlay)
+
+/obj/item/gun/energy/dueling/Destroy()
+ . = ..()
+ if(duel.gun_A == src)
+ duel.gun_A = null
+ if(duel.gun_B == src)
+ duel.gun_B = null
+ duel = null
+
+/obj/item/gun/energy/dueling/can_trigger_gun(mob/living/user)
+ . = ..()
+ switch(duel.state)
+ if(DUEL_FIRING)
+ return . && !duel.fired[src]
+ if(DUEL_READY)
+ return .
+ else
+ to_chat(user,"[src] is locked. Wait for FIRE signal before shooting.")
+ return FALSE
+
+/obj/item/gun/energy/dueling/proc/is_duelist(mob/living/L)
+ if(!istype(L))
+ return FALSE
+ if(!L.is_holding(duel.other_gun(src)))
+ return FALSE
+ return TRUE
+
+/obj/item/gun/energy/dueling/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
+ if(duel.state == DUEL_READY)
+ duel.confirmations[src] = TRUE
+ to_chat(user,"You confirm your readiness.")
+ return
+ else if(!is_duelist(target)) //I kinda want to leave this out just to see someone shoot a bystander or missing.
+ to_chat(user,"[src] safety system prevents shooting anyone but your designated opponent.")
+ return
+ else
+ duel.fired[src] = TRUE
+ . = ..()
+
+/obj/item/gun/energy/dueling/before_firing(target,user)
+ var/obj/item/ammo_casing/energy/duel/D = chambered
+ D.setting = setting
+ D.hugbox = hugbox
+
+/obj/effect/temp_visual/dueling_chaff
+ icon = 'icons/effects/effects.dmi'
+ icon_state = "shield-old"
+ duration = 30
+ var/setting
+
+/obj/effect/temp_visual/dueling_chaff/update_icon()
+ . = ..()
+ switch(setting)
+ if(DUEL_SETTING_A)
+ color = "red"
+ if(DUEL_SETTING_B)
+ color = "green"
+ if(DUEL_SETTING_C)
+ color = "blue"
+
+//Casing
+
+/obj/item/ammo_casing/energy/duel
+ e_cost = 0
+ projectile_type = /obj/projectile/energy/duel
+ var/setting
+ var/hugbox = DUEL_HUGBOX_NONE
+
+/obj/item/ammo_casing/energy/duel/ready_proj(atom/target, mob/living/user, quiet, zone_override)
+ . = ..()
+ var/obj/projectile/energy/duel/D = BB
+ D.setting = setting
+ D.hugbox = hugbox
+ D.update_icon()
+
+/obj/item/ammo_casing/energy/duel/fire_casing(atom/target, mob/living/user, params, distro, quiet, zone_override, spread, atom/fired_from)
+ . = ..()
+ var/obj/effect/temp_visual/dueling_chaff/C = new(get_turf(user))
+ C.setting = setting
+ D.hugbox = hugbox
+ C.update_icon()
+
+//Projectile
+
+/obj/projectile/energy/duel
+ name = "dueling beam"
+ icon_state = "declone"
+ reflectable = FALSE
+ homing = TRUE
+ var/setting
+ var/hugbox = DUEL_HUGBOX_NONE
+
+/obj/projectile/energy/duel/update_icon()
+ . = ..()
+ switch(setting)
+ if(DUEL_SETTING_A)
+ color = "red"
+ if(DUEL_SETTING_B)
+ color = "green"
+ if(DUEL_SETTING_C)
+ color = "blue"
+
+/obj/projectile/energy/duel/on_hit(atom/target, blocked)
+ . = ..()
+ var/turf/T = get_turf(target)
+ var/obj/effect/temp_visual/dueling_chaff/C = locate() in T
+ if(C)
+ var/counter_setting
+ switch(setting)
+ if(DUEL_SETTING_A)
+ counter_setting = DUEL_SETTING_B
+ if(DUEL_SETTING_B)
+ counter_setting = DUEL_SETTING_C
+ if(DUEL_SETTING_C)
+ counter_setting = DUEL_SETTING_A
+ if(C.setting == counter_setting)
+ return BULLET_ACT_BLOCK
+
+ var/mob/living/L = target
+ if(!istype(target))
+ return BULLET_ACT_BLOCK
+
+ switch(hugbox)
+ if(DUEL_HUGBOX_NONE)
+ var/obj/item/bodypart/B = L.get_bodypart(BODY_ZONE_HEAD)
+ B.dismember()
+ qdel(B)
+ if(DUEL_HUGBOX_LETHAL)
+ L.adjustBruteLoss(180)
+ L.death() //Die, powergamers.
+ if(DUEL_HUGBOX_NONLETHAL)
+ L.adjustStaminaLoss(200, forced = TRUE) //Die, powergamers x 2
+ L.Knockdown(100, override_hardstun = 100) //For good measure.
+
+//Storage case.
+/obj/item/storage/lockbox/dueling
+ name = "dueling pistol case"
+ desc = "Let's solve this like gentlespacemen."
+ icon_state = "medalbox+l"
+ item_state = "syringe_kit"
+ lefthand_file = 'icons/mob/inhands/equipment/medical_lefthand.dmi'
+ righthand_file = 'icons/mob/inhands/equipment/medical_righthand.dmi'
+ w_class = WEIGHT_CLASS_NORMAL
+ req_access = list(ACCESS_CAPTAIN)
+ icon_locked = "medalbox+l"
+ icon_closed = "medalbox"
+ icon_broken = "medalbox+b"
+ var/gun_type = /obj/item/gun/energy/dueling
+
+/obj/item/storage/lockbox/dueling/ComponentInitialize()
+ . = ..()
+ var/datum/component/storage/STR = GetComponent(/datum/component/storage)
+ STR.max_w_class = WEIGHT_CLASS_SMALL
+ STR.max_items = 2
+ STR.set_holdable(list(/obj/item/gun/energy/dueling))
+
+/obj/item/storage/lockbox/dueling/update_icon()
+ cut_overlays()
+ var/locked = SEND_SIGNAL(src, COMSIG_IS_STORAGE_LOCKED)
+ if(locked)
+ icon_state = "medalbox+l"
+ else
+ icon_state = "medalbox"
+ if(open)
+ icon_state += "open"
+ if(broken)
+ icon_state += "+b"
+
+/obj/item/storage/lockbox/dueling/PopulateContents()
+ . = ..()
+ var/obj/item/gun/energy/dueling/gun_A = new gun_type(src)
+ var/obj/item/gun/energy/dueling/gun_B = new gun_type(src)
+ var/datum/duel/D = new
+ gun_A.duel = D
+ gun_B.duel = D
+ D.gun_A = gun_A
+ D.gun_B = gun_B
+
+/obj/item/storage/lockbox/dueling/hugbox
+ gun_type = /obj/item/gun/energy/dueling/hugbox
+
+/obj/item/storage/lockbox/dueling/hugbox/stamina
+ gun_type = /obj/item/gun/energy/dueling/hugbox/stamina
diff --git a/icons/obj/guns/energy.dmi b/icons/obj/guns/energy.dmi
index bba3efc951..c30e8aa6bd 100644
Binary files a/icons/obj/guns/energy.dmi and b/icons/obj/guns/energy.dmi differ
diff --git a/tgstation.dme b/tgstation.dme
index 8fda1f85cb..83c3fd82ed 100755
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -2626,6 +2626,7 @@
#include "code\modules\projectiles\guns\ballistic\revolver.dm"
#include "code\modules\projectiles\guns\ballistic\shotgun.dm"
#include "code\modules\projectiles\guns\ballistic\toy.dm"
+#include "code\modules\projectiles\guns\energy\dueling.dm"
#include "code\modules\projectiles\guns\energy\energy_gun.dm"
#include "code\modules\projectiles\guns\energy\kinetic_accelerator.dm"
#include "code\modules\projectiles\guns\energy\laser.dm"