Merge pull request #10892 from kevinz000/small_guncode_refactor

Small guncode refactor but it works
This commit is contained in:
Ghom
2020-02-07 23:13:21 +01:00
committed by GitHub
9 changed files with 238 additions and 150 deletions
@@ -191,7 +191,7 @@
else if(istype(I, /obj/item/gun/energy))
var/obj/item/gun/energy/EG = I
if(EG.cell?.charge < EG.cell.maxcharge)
var/obj/item/ammo_casing/energy/S = EG.ammo_type[EG.select]
var/obj/item/ammo_casing/energy/S = EG.ammo_type[EG.current_firemode_index]
EG.cell.give(S.e_cost * coeff)
if(!EG.chambered)
EG.recharge_newshot(TRUE)
@@ -197,8 +197,6 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca
return 0
return ..()
/mob/living/simple_animal/hostile/mimic/copy/ranged
var/obj/item/gun/TrueGun = null
var/obj/item/gun/magic/Zapstick
@@ -229,14 +227,13 @@ GLOBAL_LIST_INIT(protected_objects, list(/obj/structure/table, /obj/structure/ca
casingtype = initial(M.ammo_type)
if(istype(G, /obj/item/gun/energy))
Zapgun = G
var/selectfiresetting = Zapgun.select
var/obj/item/ammo_casing/energy/E = Zapgun.ammo_type[selectfiresetting]
var/obj/item/ammo_casing/energy/E = Zapgun.ammo_type[Zapgun.current_firemode_index]
projectiletype = initial(E.projectile_type)
/mob/living/simple_animal/hostile/mimic/copy/ranged/OpenFire(the_target)
if(Zapgun)
if(Zapgun.cell)
var/obj/item/ammo_casing/energy/shot = Zapgun.ammo_type[Zapgun.select]
var/obj/item/ammo_casing/energy/shot = Zapgun.ammo_type[Zapgun.current_firemode_index]
if(Zapgun.cell.charge >= shot.e_cost)
Zapgun.cell.use(shot.e_cost)
Zapgun.update_icon()
@@ -12,4 +12,4 @@
/obj/item/ammo_casing/energy/plasma/weak
projectile_type = /obj/item/projectile/plasma/weak
e_cost = 100
e_cost = 100
+77 -66
View File
@@ -28,10 +28,19 @@
trigger_guard = TRIGGER_GUARD_NORMAL //trigger guard on the weapon, hulks can't fire them with their big meaty fingers
var/sawn_desc = null //description change if weapon is sawn-off
var/sawn_off = FALSE
var/burst_size = 1 //how large a burst is
var/fire_delay = 0 //rate of fire for burst firing and semi auto
var/firing_burst = 0 //Prevent the weapon from firing again while already firing
var/semicd = 0 //cooldown handler
/// Weapon is burst fire if this is above 1
var/burst_size = 1
/// The time between shots in burst.
var/burst_shot_delay = 3
/// The time between firing actions, this means between bursts if this is burst weapon. The reason this is 0 is because you are still, by default, limited by clickdelay.
var/fire_delay = 0
/// Last world.time this was fired
var/last_fire = 0
/// Currently firing, whether or not it's a burst or not.
var/firing = FALSE
/// Used in gun-in-mouth execution/suicide and similar, while TRUE nothing should work on this like firing or modification and so on and so forth.
var/busy_action = FALSE
var/weapon_weight = WEAPON_LIGHT //currently only used for inaccuracy
var/spread = 0 //Spread induced by the gun itself.
var/burst_spread = 0 //Spread induced by the gun itself during burst fire per iteration. Only checked if spread is 0.
@@ -117,13 +126,12 @@
to_chat(user, "<span class='danger'>*click*</span>")
playsound(src, "gun_dry_fire", 30, 1)
/obj/item/gun/proc/shoot_live_shot(mob/living/user as mob|obj, pointblank = 0, mob/pbtarget = null, message = 1)
if(recoil)
shake_camera(user, recoil + 1, recoil)
if(isliving(user)) //CIT CHANGE - makes gun recoil cause staminaloss
user.adjustStaminaLossBuffered(getstamcost(user)*(firing_burst && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
user.adjustStaminaLossBuffered(getstamcost(user)*(firing && burst_size >= 2 ? 1/burst_size : 1)) //CIT CHANGE - ditto
if(suppressed)
playsound(user, fire_sound, 10, 1)
@@ -143,9 +151,12 @@
/obj/item/gun/afterattack(atom/target, mob/living/user, flag, params)
. = ..()
process_afterattack(target, user, flag, params)
/obj/item/gun/proc/process_afterattack(atom/target, mob/living/user, flag, params)
if(!target)
return
if(firing_burst)
if(firing)
return
if(flag) //It's adjacent, is the user, or is on the user's person
if(target in user.contents) //can't shoot stuff inside us.
@@ -169,7 +180,6 @@
handle_suicide(user, target, params)
return
//Exclude lasertag guns from the TRAIT_CLUMSY check.
if(clumsy_check)
if(istype(user))
@@ -201,8 +211,6 @@
process_fire(target, user, TRUE, params, null, bonus_spread)
/obj/item/gun/can_trigger_gun(mob/living/user)
. = ..()
if(!.)
@@ -227,54 +235,29 @@
/obj/item/gun/proc/recharge_newshot()
return
/obj/item/gun/proc/process_burst(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
if(!user || !firing_burst)
firing_burst = FALSE
return FALSE
if(!issilicon(user))
if(iteration > 1 && !(user.is_holding(src))) //for burst firing
firing_burst = FALSE
return FALSE
if(chambered && chambered.BB)
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
if(chambered.harmful) // Is the bullet chambered harmful?
to_chat(user, "<span class='notice'> [src] is lethally chambered! You don't want to risk harming anyone...</span>")
return
if(randomspread)
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread), 1)
else //Smart spread
sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread), 1)
before_firing(target,user)
if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd, src))
shoot_with_empty_chamber(user)
firing_burst = FALSE
return FALSE
else
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
shoot_live_shot(user, 1, target, message)
else
shoot_live_shot(user, 0, target, message)
if (iteration >= burst_size)
firing_burst = FALSE
else
shoot_with_empty_chamber(user)
firing_burst = FALSE
return FALSE
process_chamber()
update_icon()
return TRUE
/obj/item/gun/proc/on_cooldown()
return busy_action || firing || (last_fire + fire_delay > world.time)
/obj/item/gun/proc/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
add_fingerprint(user)
if(semicd)
if(on_cooldown())
return
firing = TRUE
. = do_fire(target, user, message, params, zone_override, bonus_spread)
firing = FALSE
last_fire = world.time
if(user)
user.update_inv_hands()
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
/obj/item/gun/proc/do_fire(atom/target, mob/living/user, message = TRUE, params, zone_override = "", bonus_spread = 0)
var/sprd = 0
var/randomized_gun_spread = 0
var/rand_spr = rand()
if(spread)
randomized_gun_spread = rand(0, spread)
randomized_gun_spread = rand(0, spread)
else if(burst_size > 1 && burst_spread)
randomized_gun_spread = rand(0, burst_spread)
if(HAS_TRAIT(user, TRAIT_POOR_AIM)) //nice shootin' tex
@@ -282,9 +265,12 @@
var/randomized_bonus_spread = rand(0, bonus_spread)
if(burst_size > 1)
firing_burst = TRUE
for(var/i = 1 to burst_size)
addtimer(CALLBACK(src, .proc/process_burst, user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i), fire_delay * (i - 1))
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, 1)
for(var/i in 2 to burst_size)
sleep(burst_shot_delay)
if(QDELETED(src))
break
do_burst_shot(user, target, message, params, zone_override, sprd, randomized_gun_spread, randomized_bonus_spread, rand_spr, i)
else
if(chambered)
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread))
@@ -302,21 +288,46 @@
return
process_chamber()
update_icon()
semicd = TRUE
addtimer(CALLBACK(src, .proc/reset_semicd), fire_delay)
if(user)
user.update_inv_hands()
SEND_SIGNAL(user, COMSIG_LIVING_GUN_PROCESS_FIRE, target, params, zone_override)
SSblackbox.record_feedback("tally", "gun_fired", 1, type)
return TRUE
/obj/item/gun/update_icon()
..()
/obj/item/gun/proc/reset_semicd()
semicd = FALSE
/obj/item/gun/proc/do_burst_shot(mob/living/user, atom/target, message = TRUE, params=null, zone_override = "", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
if(!user || !firing)
firing = FALSE
return FALSE
if(!issilicon(user))
if(iteration > 1 && !(user.is_holding(src))) //for burst firing
firing = FALSE
return FALSE
if(chambered && chambered.BB)
if(HAS_TRAIT(user, TRAIT_PACIFISM)) // If the user has the pacifist trait, then they won't be able to fire [src] if the round chambered inside of [src] is lethal.
if(chambered.harmful) // Is the bullet chambered harmful?
to_chat(user, "<span class='notice'> [src] is lethally chambered! You don't want to risk harming anyone...</span>")
return
if(randomspread)
sprd = round((rand() - 0.5) * DUALWIELD_PENALTY_EXTRA_MULTIPLIER * (randomized_gun_spread + randomized_bonus_spread), 1)
else //Smart spread
sprd = round((((rand_spr/burst_size) * iteration) - (0.5 + (rand_spr * 0.25))) * (randomized_gun_spread + randomized_bonus_spread), 1)
before_firing(target,user)
if(!chambered.fire_casing(target, user, params, ,suppressed, zone_override, sprd, src))
shoot_with_empty_chamber(user)
firing = FALSE
return FALSE
else
if(get_dist(user, target) <= 1) //Making sure whether the target is in vicinity for the pointblank shot
shoot_live_shot(user, 1, target, message)
else
shoot_live_shot(user, 0, target, message)
if (iteration >= burst_size)
firing = FALSE
else
shoot_with_empty_chamber(user)
firing = FALSE
return FALSE
process_chamber()
update_icon()
return TRUE
/obj/item/gun/attack(mob/M as mob, mob/user)
if(user.a_intent == INTENT_HARM) //Flogging
@@ -437,7 +448,7 @@
if(!ishuman(user) || !ishuman(target))
return
if(semicd)
if(on_cooldown())
return
if(user == target)
@@ -447,7 +458,7 @@
target.visible_message("<span class='warning'>[user] points [src] at [target]'s head, ready to pull the trigger...</span>", \
"<span class='userdanger'>[user] points [src] at your head, ready to pull the trigger...</span>")
semicd = TRUE
busy_action = TRUE
if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
if(user)
@@ -455,10 +466,10 @@
user.visible_message("<span class='notice'>[user] decided not to shoot.</span>")
else if(target && target.Adjacent(user))
target.visible_message("<span class='notice'>[user] has decided to spare [target]</span>", "<span class='notice'>[user] has decided to spare your life!</span>")
semicd = FALSE
busy_action = FALSE
return
semicd = FALSE
busy_action = FALSE
target.visible_message("<span class='warning'>[user] pulls the trigger!</span>", "<span class='userdanger'>[user] pulls the trigger!</span>")
@@ -5,7 +5,7 @@
var/automatic_burst_overlay = TRUE
can_suppress = TRUE
burst_size = 3
fire_delay = 2
burst_shot_delay = 2
actions_types = list(/datum/action/item_action/toggle_firemode)
/obj/item/gun/ballistic/automatic/proto
@@ -77,11 +77,9 @@
/obj/item/gun/ballistic/automatic/proc/enable_burst()
burst_size = initial(burst_size)
fire_delay = initial(fire_delay)
/obj/item/gun/ballistic/automatic/proc/disable_burst()
burst_size = 1
fire_delay = 0
/obj/item/gun/ballistic/automatic/can_shoot()
return get_ammo()
@@ -100,7 +98,7 @@
item_state = "c20r"
mag_type = /obj/item/ammo_box/magazine/smgm45
fire_sound = 'sound/weapons/gunshot_smg.ogg'
fire_delay = 2
burst_shot_delay = 2
burst_size = 2
pin = /obj/item/firing_pin/implant/pindicate
can_bayonet = TRUE
@@ -130,7 +128,7 @@
mag_type = /obj/item/ammo_box/magazine/wt550m9
can_suppress = FALSE
burst_size = 2
fire_delay = 1
burst_shot_delay = 1
can_bayonet = TRUE
knife_x_offset = 25
knife_y_offset = 12
@@ -165,7 +163,7 @@
can_suppress = FALSE
var/obj/item/gun/ballistic/revolver/grenadelauncher/underbarrel
burst_size = 3
fire_delay = 2
burst_shot_delay = 2
pin = /obj/item/firing_pin/implant/pindicate
/obj/item/gun/ballistic/automatic/m90/Initialize()
@@ -212,7 +210,6 @@
if(0)
select = 1
burst_size = initial(burst_size)
fire_delay = initial(fire_delay)
to_chat(user, "<span class='notice'>You switch to [burst_size]-rnd burst.</span>")
if(1)
select = 2
@@ -220,7 +217,6 @@
if(2)
select = 0
burst_size = 1
fire_delay = 0
to_chat(user, "<span class='notice'>You switch to semi-auto.</span>")
playsound(user, 'sound/weapons/empty.ogg', 100, 1)
update_icon()
@@ -237,7 +233,7 @@
fire_sound = 'sound/weapons/gunshot_smg.ogg'
can_suppress = FALSE
burst_size = 4
fire_delay = 1
burst_shot_delay = 1
/obj/item/gun/ballistic/automatic/ar
name = "\improper NT-ARG 'Boarder'"
@@ -249,7 +245,7 @@
fire_sound = 'sound/weapons/gunshot_smg.ogg'
can_suppress = FALSE
burst_size = 3
fire_delay = 1
burst_shot_delay = 1
// Bulldog shotgun //
@@ -264,7 +260,6 @@
fire_sound = 'sound/weapons/gunshot.ogg'
can_suppress = FALSE
burst_size = 1
fire_delay = 0
pin = /obj/item/firing_pin/implant/pindicate
actions_types = list()
@@ -301,7 +296,7 @@
var/cover_open = FALSE
can_suppress = FALSE
burst_size = 3
fire_delay = 1
burst_shot_delay = 1
spread = 7
pin = /obj/item/firing_pin/implant/pindicate
@@ -421,7 +416,7 @@
mag_type = /obj/item/ammo_box/magazine/recharge
fire_delay = 2
can_suppress = FALSE
burst_size = 0
burst_size = 1
actions_types = list()
fire_sound = 'sound/weapons/laser.ogg'
casing_ejector = FALSE
+134 -37
View File
@@ -1,3 +1,16 @@
/*
* Energy guns that draw from a cell to fire.
*
* This is a bit weird but this is how it currently works:
* When switching shots, it clears the chamber, and loads the correct energy ammo casing if there is enough energy to fire it.
* If there's no projectile in the casing, it creates it now.
* Otherwise the chamber stays null.
* After firing, it actually deducts the energy and then clears the chamber and does the above again.
* It detects if a successful fire is done by checking if the chambered energy ammo casing still has its projectile intact.
*
* It might be good in the future to move away from ammo casinsgs and instead use a datum-firemode system, but that would make handling firing,
* which the casing does as of now, a little interesting to implement.
*/
/obj/item/gun/energy
icon_state = "energy"
name = "energy gun"
@@ -7,8 +20,10 @@
var/obj/item/stock_parts/cell/cell //What type of power cell this uses
var/cell_type = /obj/item/stock_parts/cell
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.
/// = TRUE/FALSE decides if the user can switch to it of their own accord
var/list/ammo_type = list(/obj/item/ammo_casing/energy = TRUE)
/// The index of the ammo_types/firemodes which we're using right now
var/current_firemode_index = 1
var/can_charge = 1 //Can it be charged in a recharger?
var/automatic_charge_overlays = TRUE //Do we handle overlays with base update_icon()?
var/charge_sections = 4
@@ -21,6 +36,9 @@
var/use_cyborg_cell = FALSE //whether the gun drains the cyborg user's cell instead, not to be confused with EGUN_SELFCHARGE_BORG
var/dead_cell = FALSE //set to true so the gun is given an empty cell
/// SET THIS TO TRUE IF YOU OVERRIDE altafterattack() or ANY right click action! If this is FALSE, the gun will show in examine its default right click behavior, which is to switch modes.
var/right_click_overridden = FALSE
/obj/item/gun/energy/emp_act(severity)
. = ..()
if(!(. & EMP_PROTECT_CONTENTS))
@@ -46,16 +64,6 @@
START_PROCESSING(SSobj, src)
update_icon()
/obj/item/gun/energy/proc/update_ammo_types()
var/obj/item/ammo_casing/energy/shot
for (var/i = 1, i <= ammo_type.len, i++)
var/shottype = ammo_type[i]
shot = new shottype(src)
ammo_type[i] = shot
shot = ammo_type[select]
fire_sound = shot.fire_sound
fire_delay = shot.delay
/obj/item/gun/energy/Destroy()
if(flags_1 & INITIALIZED_1)
QDEL_NULL(cell)
@@ -63,6 +71,11 @@
STOP_PROCESSING(SSobj, src)
return ..()
/obj/item/gun/energy/examine(mob/user)
. = ..()
if(!right_click_overridden)
. += "<span class='notice'>Right click in combat mode to switch modes.</span>"
/obj/item/gun/energy/process()
if(selfcharge && cell?.charge < cell.maxcharge)
charge_tick++
@@ -83,13 +96,14 @@
recharge_newshot(TRUE)
update_icon()
/obj/item/gun/energy/attack_self(mob/living/user as mob)
if(ammo_type.len > 1)
// ATTACK SELF IGNORING PARENT RETURN VALUE
/obj/item/gun/energy/attack_self(mob/living/user)
. = ..()
if(can_select_fire(user))
select_fire(user)
update_icon()
/obj/item/gun/energy/can_shoot()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
return !QDELETED(cell) ? (cell.charge >= shot.e_cost) : FALSE
/obj/item/gun/energy/recharge_newshot(no_cyborg_drain)
@@ -99,11 +113,11 @@
if(iscyborg(loc))
var/mob/living/silicon/robot/R = loc
if(R.cell)
var/obj/item/ammo_casing/energy/shot = ammo_type[select] //Necessary to find cost of shot
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index] //Necessary to find cost of shot
if(R.cell.use(shot.e_cost)) //Take power from the borg...
cell.give(shot.e_cost) //... to recharge the shot
if(!chambered)
var/obj/item/ammo_casing/energy/AC = ammo_type[select]
var/obj/item/ammo_casing/energy/AC = ammo_type[current_firemode_index]
if(cell.charge >= AC.e_cost) //if there's enough power in the cell cell...
chambered = AC //...prepare a new shot based on the current ammo type selected
if(!chambered.BB)
@@ -116,29 +130,104 @@
chambered = null //either way, released the prepared shot
recharge_newshot() //try to charge a new shot
/obj/item/gun/energy/process_fire(atom/target, mob/living/user, message = TRUE, params = null, zone_override = "", bonus_spread = 0)
/obj/item/gun/energy/do_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 ..()
/obj/item/gun/energy/process_burst(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
/obj/item/gun/energy/do_burst_shot(mob/living/user, atom/target, message = TRUE, params = null, zone_override="", sprd = 0, randomized_gun_spread = 0, randomized_bonus_spread = 0, rand_spr = 0, iteration = 0)
if(!chambered && can_shoot())
process_chamber() // Ditto.
return ..()
/obj/item/gun/energy/proc/select_fire(mob/living/user)
select++
if (select > ammo_type.len)
select = 1
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
fire_sound = shot.fire_sound
fire_delay = shot.delay
if (shot.select_name)
to_chat(user, "<span class='notice'>[src] is now set to [shot.select_name].</span>")
chambered = null
recharge_newshot(TRUE)
// Firemodes/Ammotypes
/obj/item/gun/energy/proc/update_ammo_types()
var/obj/item/ammo_casing/energy/C
for(var/i in 1 to length(ammo_type))
var/v = ammo_type[i]
var/user_can_select = ammo_type[v]
if(istype(v, /obj/item/ammo_casing/energy)) //already set
ammo_type[v] = isnull(user_can_select)? TRUE : user_can_select
else
C = new v //if you put non energycasing/type stuff in here you deserve the runtime
ammo_type[i] = C
ammo_type[C] = isnull(user_can_select)? TRUE : user_can_select
set_firemode_index(initial(current_firemode_index))
/obj/item/gun/energy/proc/set_firemode_index(index, mob/user_for_feedback)
chambered = null //unchamber whatever we have chambered
if(index > length(ammo_type))
index = 1
else if(index < 1)
index = length(ammo_type)
var/obj/item/ammo_casing/energy/C = ammo_type[index] //energy weapons should not have no casings, if it does you deserve the runtime.
current_firemode_index = index
fire_sound = C.fire_sound
fire_delay = C.delay
if(user_for_feedback)
to_chat(user_for_feedback, "<span class='notice'>[src] is now set to [C.select_name || C].</span>")
post_set_firemode()
update_icon(TRUE)
return
/obj/item/gun/energy/proc/post_set_firemode(recharge_newshot = TRUE)
if(recharge_newshot)
recharge_newshot(TRUE)
/obj/item/gun/energy/proc/set_firemode_to_next(mob/user_for_feedback)
return set_firemode_index(++current_firemode_index, user_for_feedback)
/obj/item/gun/energy/proc/set_firemode_to_prev(mob/user_for_feedback)
return set_firemode_index(--current_firemode_index, user_for_feedback)
/obj/item/gun/energy/proc/get_firemode_index(casing_type)
var/obj/item/ammo_casing/energy/E = locate(casing_type) in ammo_type
if(E)
return ammo_type.Find(E)
/obj/item/gun/energy/proc/set_firemode_to_type(casing_type)
var/index = get_firemode_index(casing_type)
if(index)
set_firemode_index(index)
/// This is the proc used in general for when a user switches firemodes. Just goes to next firemode by default.
/obj/item/gun/energy/proc/select_fire(mob/living/user)
return user_set_firemode_to_next(user)
/obj/item/gun/energy/proc/can_select_fire(mob/living/user)
return TRUE
#define INCREMENT_OR_WRAP(i) i = (i >= length(ammo_type))? 1 : (i + 1)
#define DECREMENT_OR_WRAP(i) i = (i <= 1)? length(ammo_type) : (i - 1)
#define IS_VALID_INDEX(i) (ammo_type[ammo_type[i]])
/obj/item/gun/energy/proc/user_set_firemode_to_next(mob/user_for_feedback)
var/current_index = current_firemode_index
var/new_index = current_index
INCREMENT_OR_WRAP(new_index)
if(!IS_VALID_INDEX(new_index))
var/initial_index = new_index
while(!IS_VALID_INDEX(new_index) && (new_index != initial_index))
new_index = INCREMENT_OR_WRAP(new_index)
if(initial_index == new_index) //cycled through without finding another
new_index = current_index
set_firemode_index(new_index, user_for_feedback)
/obj/item/gun/energy/proc/user_set_firemode_to_prev(mob/user_for_feedback)
var/current_index = current_firemode_index
var/new_index = current_index
DECREMENT_OR_WRAP(new_index)
if(!IS_VALID_INDEX(new_index))
var/initial_index = new_index
while(!IS_VALID_INDEX(new_index) && (new_index != initial_index))
new_index = DECREMENT_OR_WRAP(new_index)
if(initial_index == new_index) //cycled through without finding another
new_index = current_index
set_firemode_index(new_index, user_for_feedback)
#undef INCREMENT_OR_WRAP
#undef DECREMENT_OR_WRAP
#undef IS_VALID_INDEX
/obj/item/gun/energy/update_icon(force_update)
if(QDELETED(src))
@@ -158,7 +247,7 @@
if(!initial(item_state))
itemState = icon_state
if (modifystate)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
add_overlay("[icon_state]_[shot.select_name]")
iconState += "_[shot.select_name]"
if(itemState)
@@ -177,6 +266,9 @@
if(itemState)
itemState += "[ratio]"
item_state = itemState
if(ismob(loc)) //forces inhands to update
var/mob/M = loc
M.update_inv_hands()
/obj/item/gun/energy/suicide_act(mob/living/user)
if (istype(user) && can_shoot() && can_trigger_gun(user) && user.get_bodypart(BODY_ZONE_HEAD))
@@ -186,7 +278,7 @@
user.visible_message("<span class='suicide'>[user] melts [user.p_their()] face off with [src]!</span>")
playsound(loc, fire_sound, 50, 1, -1)
playsound(src, 'sound/weapons/dink.ogg', 30, 1)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
cell.use(shot.e_cost)
update_icon()
return(FIRELOSS)
@@ -208,13 +300,12 @@
STOP_PROCESSING(SSobj, src)
. = ..()
/obj/item/gun/energy/ignition_effect(atom/A, mob/living/user)
if(!can_shoot() || !ammo_type[select])
if(!can_shoot() || !ammo_type[current_firemode_index])
shoot_with_empty_chamber()
. = ""
else
var/obj/item/ammo_casing/energy/E = ammo_type[select]
var/obj/item/ammo_casing/energy/E = ammo_type[current_firemode_index]
var/obj/item/projectile/energy/BB = E.BB
if(!BB)
. = ""
@@ -236,3 +327,9 @@
playsound(user, BB.hitsound, 50, 1)
cell.use(E.e_cost)
. = "<span class='danger'>[user] casually lights their [A.name] with [src]. Damn.</span>"
/obj/item/gun/energy/altafterattack(atom/target, mob/user, proximity_flags, params)
if(!right_click_overridden)
select_fire(user)
return TRUE
return ..()
@@ -202,7 +202,7 @@
if(!ishuman(user) || !ishuman(target))
return
if(semicd)
if(on_cooldown())
return
if(user == target)
@@ -212,7 +212,7 @@
target.visible_message("<span class='warning'>[user] points [src] at [target]'s head, ready to pull the trigger...</span>", \
"<span class='userdanger'>[user] points [src] at your head, ready to pull the trigger...</span>")
semicd = TRUE
busy_action = TRUE
if(!bypass_timer && (!do_mob(user, target, 120) || user.zone_selected != BODY_ZONE_PRECISE_MOUTH))
if(user)
@@ -220,10 +220,10 @@
user.visible_message("<span class='notice'>[user] decided not to shoot.</span>")
else if(target && target.Adjacent(user))
target.visible_message("<span class='notice'>[user] has decided to spare [target]</span>", "<span class='notice'>[user] has decided to spare your life!</span>")
semicd = FALSE
busy_action = FALSE
return
semicd = FALSE
busy_action = FALSE
target.visible_message("<span class='warning'>[user] pulls the trigger!</span>", "<span class='userdanger'>[user] pulls the trigger!</span>")
@@ -36,7 +36,7 @@
/obj/item/gun/energy/decloner/update_icon()
..()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
if(!QDELETED(cell) && (cell.charge > shot.e_cost))
add_overlay("decloner_spin")
@@ -185,7 +185,7 @@
var/atmos_link = FALSE
/obj/item/gun/energy/wormhole_projector/update_icon()
icon_state = "[initial(icon_state)][select]"
icon_state = "[initial(icon_state)][current_firemode_index]"
item_state = icon_state
/obj/item/gun/energy/wormhole_projector/update_ammo_types()
@@ -320,7 +320,7 @@
/obj/item/gun/energy/emitter/update_icon()
..()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
if(!QDELETED(cell) && (cell.charge > shot.e_cost))
add_overlay("emitter_carbine_empty")
else
@@ -46,34 +46,22 @@
cell.use(shot.e_cost)//... drain the cell cell
chambered = 0 //either way, released the prepared shot
/obj/item/gun/energy/pumpaction/select_fire(mob/living/user) //makes it so that it doesn't rack itself when changing firing modes unless already racked
select++
if (select > ammo_type.len)
select = 1
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
fire_sound = shot.fire_sound
fire_delay = shot.delay
if (shot.select_name)
to_chat(user, "<span class='notice'>[src] is now set to [shot.select_name].</span>")
if(chambered)
chambered = 0
recharge_newshot(1)
update_icon()
if(ismob(loc)) //forces inhands to update
var/mob/M = loc
M.update_inv_hands()
return
/obj/item/gun/energy/pumpaction/post_set_firemode()
var/has_shot = chambered
. = ..(recharge_newshot = FALSE)
if(has_shot)
recharge_newshot(TRUE)
/obj/item/gun/energy/pumpaction/update_icon() //adds racked indicators
..()
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
if(chambered)
add_overlay("[icon_state]_rack_[shot.select_name]")
else
add_overlay("[icon_state]_rack_empty")
/obj/item/gun/energy/pumpaction/proc/pump(mob/M) //pumping proc. Checks if the gun is empty and plays a different sound if it is.
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
if(cell.charge < shot.e_cost)
playsound(M, 'sound/weapons/laserPumpEmpty.ogg', 100, 1) //Ends with three beeps made from highly processed knife honing noises
else
@@ -102,7 +90,7 @@
/obj/item/gun/energy/pumpaction/worn_overlays(isinhands, icon_file, style_flags = NONE) //ammo counter for inhands
. = ..()
var/ratio = CEILING((cell.charge / cell.maxcharge) * charge_sections, 1)
var/obj/item/ammo_casing/energy/shot = ammo_type[select]
var/obj/item/ammo_casing/energy/shot = ammo_type[current_firemode_index]
if(isinhands)
if(cell.charge < shot.e_cost)
var/mutable_appearance/ammo_inhand = mutable_appearance(icon_file, "[item_state]_empty")