Files
Aurora.3/code/modules/projectiles/guns/energy.dm
FenodyreeAvandGitHub 28328a717f Modlaser Fixes and material cost tweaks (#22965)
- balance: "Buffs gattling laser modifier charge time from 3 to 2
seconds. It took so long to charge multiple people thought it was
bugged."

This modifier was simply a downgrade, you'd be dead by the time it
fired. Often people handed gattling guns would think they are bugged and
unable to fire. This might help a bit.


- balance: "Tweaks material costs, replacing uranium with silver and
gold. Uranium was previously used everywhere."

Everything used uranium, even things that really didn't make sense. As
uranium spawns on station in engineering and the machinists, this is a
slight nerf.


- bugfix: "Fixed a bug where energy guns would not properly handle
reliability failures when the gun was out of charge."
- bugfix: "Fixed improvement potential calculations for ions and slimes.
You no longer gain improvement shooting monkeys with ions, or for
shooting slimes with lasers."
- bugfix: "Fixed a bug with bluespace capacitors teleporting items in
teleport inhibitor range. This was due to the EMP happening before the
teleport and destroying the inhibitor."
- bugfix: "Fixed Ion modulators not correctly decreasing the number of
shots."
 
Fixes: #22850
2026-08-02 10:19:34 +00:00

344 lines
11 KiB
Plaintext

ABSTRACT_TYPE(/obj/item/gun/energy)
name = "energy gun"
desc = "A basic energy-based gun."
icon = 'icons/obj/guns/faction/nanotrasen_corporation/ecarbine.dmi'
icon_state = "energykill100"
item_state = "energykill100"
fire_sound = 'sound/weapons/Taser.ogg'
fire_sound_text = "laser blast"
update_icon_on_init = TRUE
safetyon_sound = 'sound/weapons/laser_safetyon.ogg'
safetyoff_sound = 'sound/weapons/laser_safetyoff.ogg'
/// Does this gun use the ratio system to modify its icon_state?
var/has_icon_ratio = TRUE
/// Does this gun use the ratio system to paint its item_states?
var/has_item_ratio = TRUE
/// What type of power cell this uses.
var/obj/item/cell/power_supply
/// How much energy is needed to fire.
var/charge_cost = 200
/// Determines the capacity of the weapon's power cell. Specifying a cell_type overrides this value.
var/max_shots = 10
var/cell_type = null
/// Also passed to turrets.
var/projectile_type = /obj/projectile/beam/practice
var/modifystate
/// If set, the icon state will be chosen based on the current charge.
var/charge_meter = 1
/// This list matches with firemode index, used to determine which firemodes get unlocked with what level of authorization.
var/list/required_firemode_auth
///How long the gun is disabled for after an emp, is set in emp_act and counted down in process.
var/emp_disable_time
///Initial charge
var/initial_charge
//self-recharging
/// If set, the weapon will recharge itself.
var/self_recharge = FALSE
/// If set, the weapon will look for an external power source to draw from, otherwise it recharges magically
var/use_external_power = FALSE
var/recharge_time = 4
/// Multiplies by charge cost to determine how much charge should be returned
var/recharge_multiplier = 1
var/charge_tick = 0
/// External power source for the gun. Checked by get_external_power_supply()
var/obj/item/recharger
// Vars passed to turrets
/// If TRUE, allows you to attach the gun on a turret.
var/can_turret = FALSE
/// If null, turret defaults to projectile_type.
var/secondary_projectile_type = null
/// If null, turret defaults to fire_sound.
var/secondary_fire_sound = null
/// If TRUE, allows switching lethal and stun modes.
var/can_switch_modes = FALSE
/// Set of sprites to use for the turret gun.
var/turret_sprite_set = "carbine"
/// Is the gun in lethal (secondary) mode by default?
var/turret_is_lethal = TRUE
/obj/item/gun/energy/mechanics_hints(mob/user, distance, is_adjacent)
. += ..()
. += "This is an energy weapon. Most energy weapons can fire through windows harmlessly. Energy weapons must be recharged once depleted."
if(can_turret)
. += "This weapon can be installed on a turret mount."
/obj/item/gun/energy/feedback_hints(mob/user, distance, is_adjacent)
. += ..()
if(distance > 1)
return
var/shots_remaining = round(power_supply.charge / charge_cost)
. += "It has [shots_remaining] shot\s remaining."
/obj/item/gun/energy/switch_firemodes()
. = ..()
if(.)
update_icon()
/obj/item/gun/energy/emp_act(severity)
. = ..()
if(!power_supply)
return
if(!emp_disable_time)
var/mob/M
if(ismob(loc))
M = loc
if(power_supply.charge > 0)
to_chat(M, SPAN_DANGER("\The [src] locks up as the EMP scrambles it!"))
playsound(M, 'sound/weapons/smg_empty_alarm.ogg', 30)
initial_charge = power_supply.charge
power_supply.charge = 0
SSicon_update.add_to_queue(src)
START_PROCESSING(SSprocessing, src)
emp_disable_time = max(emp_disable_time, 20 / severity)
/obj/item/gun/energy/process(seconds_per_tick)
emp_disable_time = max(0, emp_disable_time - seconds_per_tick)
if (!emp_disable_time)
STOP_PROCESSING(SSprocessing, src)
restore_gun_charge()
/obj/item/gun/energy/proc/restore_gun_charge()
power_supply.give(initial_charge)
var/mob/M
if(ismob(loc))
M = loc
if (power_supply.charge > charge_cost)
playsound(M, 'sound/weapons/laser_safetyoff.ogg', 30)
to_chat(M, SPAN_NOTICE("\The [src] clicks as it resets, ready to fire again!"))
update_maptext()
update_icon()
/obj/item/gun/energy/get_cell()
return power_supply
/obj/item/gun/energy/Initialize()
. = ..()
if(cell_type)
power_supply = new cell_type(src)
else
power_supply = new /obj/item/cell/device/variable(src, max_shots*charge_cost)
update_maptext()
/obj/item/gun/energy/Destroy()
if(recharger)
disconnect()
QDEL_NULL(power_supply)
return ..()
/obj/item/gun/energy/proc/try_recharge()
. = 1
if (!power_supply || power_supply.charge >= power_supply.maxcharge || !self_recharge)
return 0 // check if we actually need to recharge
if (use_external_power)
var/obj/item/cell/external = get_external_power_supply()
if(!external || !external.use(charge_cost)) //Take power from the borg...
return 0
power_supply.give(charge_cost * recharge_multiplier) //... to recharge the shot
update_maptext()
update_icon()
addtimer(CALLBACK(src, PROC_REF(try_recharge)), recharge_time * 2 SECONDS, TIMER_UNIQUE)
/obj/item/gun/energy/handle_reliability_fail(var/mob/user)
if(power_supply && power_supply.charge < charge_cost)
handle_click_empty(user)
return
..()
/obj/item/gun/energy/consume_next_projectile()
if(!power_supply)
return null
if(!ispath(projectile_type))
return null
if(!power_supply.checked_use(charge_cost))
return null
if(self_recharge)
addtimer(CALLBACK(src, PROC_REF(try_recharge)), recharge_time * 2 SECONDS, TIMER_UNIQUE)
return new projectile_type(src)
/obj/item/gun/energy/proc/get_external_power_supply()
if(isrobot(src.loc))
var/mob/living/silicon/robot/R = src.loc
return R.cell
if(isrobot(src.loc.loc)) // for things inside a robot's module
var/mob/living/silicon/robot/R = src.loc.loc
return R.cell
if(recharger)
return recharger.get_cell()
if(istype(src.loc, /obj/item/rig_module))
var/obj/item/rig_module/module = src.loc
if(module.holder && module.holder.wearer)
var/mob/living/carbon/human/H = module.holder.wearer
if(istype(H) && H.back)
var/obj/item/rig/suit = H.back
if(istype(suit))
return suit.cell
if(istype(loc, /obj/item/mecha_equipment))
return loc.get_cell()
return null
/**
* Connects the energy gun to an external power supply
*
* * powersource - the power supply in question. Can either be `/obj/item/rig_module/recharger` or `/obj/item/recharger_backpack`.
*
* Returns `TRUE` if the connection was successful, `FALSE` otherwise
*/
/obj/item/gun/energy/proc/connect(obj/item/powersource)
SHOULD_NOT_SLEEP(TRUE)
//Validate that the type is allowed first of all
if(!is_type_in_list(powersource, list(/obj/item/rig_module/recharger, /obj/item/recharger_backpack)))
stack_trace("Wrong type to connect the energy gun to!")
return FALSE
//If we're already connected with something, we can't connect with something else
if(recharger)
to_chat(usr, SPAN_WARNING("\The [src] is already connected to \the [recharger]!"))
return FALSE
if(istype(powersource, /obj/item/rig_module/recharger))
var/obj/item/rig_module/recharger/rigcharge = powersource
if(!rigcharge.holder || !rigcharge.holder.wearer)
to_chat(usr, SPAN_WARNING("\The [rigcharge] must be installed in a rig and active!"))
return FALSE
to_chat(usr, SPAN_NOTICE("You neatly plug \the [src] into \the [powersource]."))
playsound(get_turf(src), 'sound/machines/click.ogg', 30, 0)
rigcharge.connected = src
recharger = rigcharge.holder
self_recharge = TRUE
use_external_power = TRUE
else if(istype(powersource, /obj/item/recharger_backpack))
var/obj/item/recharger_backpack/back_charge = powersource
if(!ismob(loc))
to_chat(usr, SPAN_WARNING("\The [back_charge] must be worn on the back before a weapon can be connected!"))
return FALSE
to_chat(usr, SPAN_NOTICE("You neatly plug \the [src] into \the [powersource]."))
playsound(get_turf(src), 'sound/machines/click.ogg', 30, 0)
back_charge.connect(src)
recharger = back_charge
self_recharge = TRUE
use_external_power = TRUE
return TRUE
///Disconnects the energy gun from its external power source if one exists.
/obj/item/gun/energy/proc/disconnect()
SHOULD_NOT_SLEEP(TRUE)
if(!recharger)
to_chat(usr, SPAN_WARNING("\The [src] lacks an external power source to disconnect!"))
return
if(istype(recharger, /obj/item/rig))
var/obj/item/rig/rig = recharger
var/obj/item/rig_module/recharger/rigcharger = locate() in rig.installed_modules
to_chat(usr, SPAN_NOTICE("With a snap, \the [src] is disconnected from \the [recharger]."))
playsound(get_turf(src), 'sound/machines/click.ogg', 30, 0)
if(rigcharger.active)
rigcharger.deactivate()
rigcharger.connected = null
else if(istype(recharger, /obj/item/recharger_backpack))
var/obj/item/recharger_backpack/backcharger = recharger
to_chat(usr, SPAN_NOTICE("With a snap, \the [src] is disconnected from \the [recharger]."))
playsound(get_turf(src), 'sound/machines/click.ogg', 30, 0)
backcharger.disconnect(src)
recharger = null
self_recharge = initial(self_recharge)
use_external_power = initial(use_external_power)
/obj/item/gun/energy/mouse_drop_dragged(atom/over, mob/user, src_location, over_location, params)
. = ..()
if(istype(over, /obj/item/rig))
var/obj/item/rig/rig = over
var/obj/item/rig_module/recharger/rigcharge = locate() in rig.installed_modules
if(rigcharge)
connect(rigcharge)
else if(istype(over, /obj/item/recharger_backpack))
var/obj/item/recharger_backpack/backcharge = over
connect(backcharge)
/obj/item/gun/energy/dropped(mob/user)
. = ..()
if(recharger)
disconnect()
/obj/item/gun/energy/update_icon()
if(charge_meter && power_supply && power_supply.maxcharge)
var/ratio = power_supply.charge / power_supply.maxcharge
var/icon_state_ratio = ""
var/item_state_ratio = ""
//make sure that rounding down will not give us the empty state even if we have charge for a shot left.
if(power_supply.charge < charge_cost)
ratio = 0
else
ratio = max(round(ratio, 0.25) * 100, 25)
if(has_icon_ratio)
icon_state_ratio = ratio
if(has_item_ratio)
item_state_ratio = ratio
if(modifystate)
icon_state = "[modifystate][icon_state_ratio]"
item_state = "[modifystate][item_state_ratio]"
else
icon_state = "[initial(icon_state)][icon_state_ratio]"
item_state = "[initial(item_state)][item_state_ratio]"
..()
/obj/item/gun/energy/handle_post_fire()
..()
update_maptext()
/obj/item/gun/energy/get_ammo()
if(!power_supply)
return 0
return round(power_supply.charge / charge_cost)
/obj/item/gun/energy/get_print_info()
. = ""
. += "Max Shots: [initial(max_shots)]<br>"
. += "Recharge Type: [initial(self_recharge) ? "self recharging" : "not self recharging"]<br>"
if(initial(self_recharge))
. += "Recharge Time: [initial(recharge_time)]<br>"
. += "<br><b>Primary Projectile</b><br>"
var/obj/projectile/P = new projectile_type
. += P.get_print_info()
if(secondary_projectile_type)
. += "<br><b>Secondary Projectile</b><br>"
var/obj/projectile/P_second = new secondary_projectile_type
. += P_second.get_print_info()
. += "<br>"
. += ..(FALSE)