diff --git a/code/modules/projectiles/guns/ballistic/assault.dm b/code/modules/projectiles/guns/ballistic/assault.dm
index f6da18d86254..2c59adaaa2d0 100644
--- a/code/modules/projectiles/guns/ballistic/assault.dm
+++ b/code/modules/projectiles/guns/ballistic/assault.dm
@@ -180,6 +180,9 @@
/obj/item/gun/ballistic/automatic/assault/e40/process_fire(atom/target, mob/living/user, message, params, zone_override, bonus_spread)
var/current_firemode = gun_firemodes[firemode_index]
if(current_firemode != FIREMODE_OTHER)
+ if(!secondary.latch_closed && prob(65))
+ to_chat(user, span_warning("[src]'s cell falls out!"))
+ secondary.eject_cell()
return ..()
return secondary.process_fire(target, user, message, params, zone_override, bonus_spread)
@@ -198,10 +201,42 @@
/obj/item/gun/ballistic/automatic/assault/e40/attackby(obj/item/attack_obj, mob/user, params)
if(istype(attack_obj, /obj/item/stock_parts/cell/gun))
return secondary.attackby(attack_obj, user, params)
- if(istype(attack_obj, /obj/item/screwdriver))
- return secondary.screwdriver_act(user, attack_obj,)
return ..()
+/obj/item/gun/ballistic/automatic/assault/e40/attack_hand(mob/user)
+ var/current_firemode = gun_firemodes[firemode_index]
+ if(current_firemode == FIREMODE_OTHER && loc == user && user.is_holding(src) && secondary.cell && !secondary.latch_closed)
+ secondary.eject_cell(user)
+ return
+ if(current_firemode == FIREMODE_OTHER && loc == user && user.is_holding(src) && secondary.cell && secondary.latch_closed)
+ to_chat(user, span_warning("The cell retainment clip is latched!"))
+ return
+ return ..()
+
+/obj/item/gun/ballistic/automatic/assault/e40/AltClick(mob/living/user)
+ var/current_firemode = gun_firemodes[firemode_index]
+ if(current_firemode == FIREMODE_OTHER)
+ if(secondary.latch_closed)
+ to_chat(user, span_notice("You start to unlatch the [src]'s power cell retainment clip..."))
+ if(do_after(user, secondary.latch_toggle_delay, src, IGNORE_USER_LOC_CHANGE))
+ to_chat(user, span_notice("You unlatch [src]'s power cell retainment clip " + "OPEN" + "."))
+ playsound(src, 'sound/items/taperecorder/taperecorder_play.ogg', 50, FALSE)
+ secondary.tac_reloads = TRUE
+ secondary.latch_closed = FALSE
+ update_appearance()
+ return
+ else
+ to_chat(user, span_warning("You start to latch the [src]'s power cell retainment clip..."))
+ if (do_after(user, secondary.latch_toggle_delay, src, IGNORE_USER_LOC_CHANGE))
+ to_chat(user, span_notice("You latch [src]'s power cell retainment clip " + "CLOSED" + "."))
+ playsound(src, 'sound/items/taperecorder/taperecorder_close.ogg', 50, FALSE)
+ secondary.tac_reloads = FALSE
+ secondary.latch_closed = TRUE
+ update_appearance()
+ return
+ else
+ return ..()
+
/obj/item/gun/ballistic/automatic/assault/e40/on_wield(obj/item/source, mob/user)
wielded = TRUE
secondary.wielded = TRUE
@@ -241,6 +276,20 @@
. += "[icon_state]_charge[ratio]"
if(secondary.cell)
. += "[icon_state]_cell"
+ if(ismob(loc))
+ var/mutable_appearance/latch_overlay
+ latch_overlay = mutable_appearance('icons/obj/guns/cell_latch.dmi')
+ if(secondary.latch_closed)
+ if(secondary.cell)
+ latch_overlay.icon_state = "latch-on-full"
+ else
+ latch_overlay.icon_state = "latch-on-empty"
+ else
+ if(secondary.cell)
+ latch_overlay.icon_state = "latch-off-full"
+ else
+ latch_overlay.icon_state = "latch-off-empty"
+ . += latch_overlay
/obj/item/gun/ballistic/automatic/assault/e40/toggle_safety(mob/user, silent=FALSE)
@@ -257,6 +306,17 @@
SEND_SIGNAL(src, COMSIG_GUN_SET_AUTOFIRE_SPEED, fire_delay)
SEND_SIGNAL(src, COMSIG_UPDATE_AMMO_HUD)
+/obj/item/gun/ballistic/automatic/assault/e40/examine(mob/user)
+ . = ..()
+ if(!secondary.internal_magazine)
+ . += "The cell retainment latch is [secondary.latch_closed ? "CLOSED" : "OPEN"]. Alt-Click to toggle the latch."
+ var/obj/item/ammo_casing/energy/shot = secondary.ammo_type[select]
+ if(secondary.cell)
+ . += "\The [name]'s cell has [secondary.cell.percent()]% charge remaining."
+ . += "\The [name] has [round(secondary.cell.charge/shot.e_cost)] shots remaining on [shot.select_name] mode."
+ else
+ . += span_notice("\The [name] doesn't seem to have a cell!")
+
//laser
/obj/item/gun/energy/laser/e40_laser_secondary
@@ -268,5 +328,6 @@
fire_delay = 0.2 SECONDS
gun_firemodes = list(FIREMODE_FULLAUTO)
default_firemode = FIREMODE_FULLAUTO
+ latch_toggle_delay = 1.2 SECONDS
spread_unwielded = 20
diff --git a/code/modules/projectiles/guns/energy.dm b/code/modules/projectiles/guns/energy.dm
index 1f595e994902..41147c0e0452 100644
--- a/code/modules/projectiles/guns/energy.dm
+++ b/code/modules/projectiles/guns/energy.dm
@@ -30,6 +30,9 @@
tac_reloads = FALSE
tactical_reload_delay = 1.2 SECONDS
+ var/latch_closed = TRUE
+ var/latch_toggle_delay = 1.0 SECONDS
+
valid_attachments = list(
/obj/item/attachment/laser_sight,
/obj/item/attachment/rail_light,
@@ -128,7 +131,7 @@
if (!internal_magazine && (A.type in (allowed_ammo_types - blacklisted_ammo_types)))
var/obj/item/stock_parts/cell/gun/C = A
if (!cell)
- insert_cell(user, C)
+ return insert_cell(user, C)
else
if (tac_reloads)
eject_cell(user, C)
@@ -136,14 +139,18 @@
return ..()
/obj/item/gun/energy/proc/insert_cell(mob/user, obj/item/stock_parts/cell/gun/C)
- if(user.transferItemToLoc(C, src))
- cell = C
- to_chat(user, span_notice("You load the [C] into \the [src]."))
- playsound(src, load_sound, load_sound_volume, load_sound_vary)
- update_appearance()
- return TRUE
+ if(!latch_closed)
+ if(user.transferItemToLoc(C, src))
+ cell = C
+ to_chat(user, span_notice("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, span_warning("You cannot seem to get \the [src] out of your hands!"))
+ return FALSE
else
- to_chat(user, span_warning("You cannot seem to get \the [src] out of your hands!"))
+ to_chat(user, span_warning("The [src]'s cell retainment clip is latched!"))
return FALSE
/obj/item/gun/energy/proc/eject_cell(mob/user, obj/item/stock_parts/cell/gun/tac_load = null)
@@ -167,13 +174,33 @@
user.put_in_hands(old_cell)
update_appearance()
-/obj/item/gun/energy/screwdriver_act(mob/living/user, obj/item/I)
- if(cell && !internal_magazine)
- 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 ..()
+//special is_type_in_list method to counteract problem with current method
+/obj/item/gun/energy/proc/is_attachment_in_contents_list()
+ for(var/content_item in contents)
+ if(istype(content_item, /obj/item/attachment/))
+ return TRUE
+ return FALSE
+
+/obj/item/gun/energy/AltClick(mob/living/user)
+ if(!internal_magazine && latch_closed)
+ to_chat(user, span_notice("You start to unlatch the [src]'s power cell retainment clip..."))
+ if(do_after(user, latch_toggle_delay, src, IGNORE_USER_LOC_CHANGE))
+ to_chat(user, span_notice("You unlatch the [src]'s power cell retainment clip " + "OPEN" + "."))
+ playsound(src, 'sound/items/taperecorder/taperecorder_play.ogg', 50, FALSE)
+ tac_reloads = TRUE
+ latch_closed = FALSE
+ update_appearance()
+ else if(!internal_magazine && !latch_closed)
+ if(!cell && is_attachment_in_contents_list())
+ return ..() //should bring up the attachment menu if attachments are added. If none are added, it just does leaves the latch open
+ to_chat(user, span_warning("You start to latch the [src]'s power cell retainment clip..."))
+ if (do_after(user, latch_toggle_delay, src, IGNORE_USER_LOC_CHANGE))
+ to_chat(user, span_notice("You latch the [src]'s power cell retainment clip " + "CLOSED" + "."))
+ playsound(src, 'sound/items/taperecorder/taperecorder_close.ogg', 50, FALSE)
+ tac_reloads = FALSE
+ latch_closed = TRUE
+ update_appearance()
+ return
/obj/item/gun/energy/can_shoot(visuals)
if(safety && !visuals)
@@ -213,7 +240,12 @@
/obj/item/gun/energy/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
if(!chambered && can_shoot())
process_chamber() // If the gun was drained and then recharged, load a new shot.
- return ..()
+ ..() //process the gunshot as normal
+ if(!latch_closed && prob(65)) //make the cell slide out if it's fired while the retainment clip is unlatched, with a 65% probability
+ to_chat(user, span_warning("The [src]'s cell falls out!"))
+ eject_cell()
+ return
+
/obj/item/gun/energy/proc/select_fire(mob/living/user)
select++
@@ -252,6 +284,20 @@
var/overlay_icon_state = "[icon_state]_charge"
var/obj/item/ammo_casing/energy/shot = ammo_type[modifystate ? select : 1]
var/ratio = get_charge_ratio()
+ if(ismob(loc) && !internal_magazine)
+ var/mutable_appearance/latch_overlay
+ latch_overlay = mutable_appearance('icons/obj/guns/cell_latch.dmi')
+ if(latch_closed)
+ if(cell)
+ latch_overlay.icon_state = "latch-on-full"
+ else
+ latch_overlay.icon_state = "latch-on-empty"
+ else
+ if(cell)
+ latch_overlay.icon_state = "latch-off-full"
+ else
+ latch_overlay.icon_state = "latch-off-empty"
+ . += latch_overlay
if(cell)
. += "[icon_state]_cell"
if(ratio == 0)
@@ -322,6 +368,8 @@
/obj/item/gun/energy/examine(mob/user)
. = ..()
+ if(!internal_magazine)
+ . += "The cell retainment latch is [latch_closed ? "CLOSED" : "OPEN"]. Alt-Click to toggle the latch."
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
if(ammo_type.len > 1)
. += "You can switch firemodes by pressing the unique action key. By default, this is space"
diff --git a/icons/obj/guns/cell_latch.dmi b/icons/obj/guns/cell_latch.dmi
new file mode 100644
index 000000000000..6372df688776
Binary files /dev/null and b/icons/obj/guns/cell_latch.dmi differ