Files
Batrachophreno ad2a83db85 Add various additional hints to guns, minor projectiles code cleanup (#21633)
As title. Adds several mechanics/assembly/disassembly hints to several
gun types, and also handles some minor code cleanup where I found
issues. No mechanical changes.
2025-12-23 20:05:54 +00:00

320 lines
10 KiB
Plaintext

/obj/item/gun/energy
name = "energy gun"
desc = "A basic energy-based gun."
icon = 'icons/obj/guns/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
//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)
. = ..()
disable_cell_temp(severity)
queue_icon_update()
/obj/item/gun/energy/proc/disable_cell_temp(var/severity)
set waitfor = FALSE
if(!power_supply)
return
var/mob/M
if(ismob(loc))
M = loc
to_chat(M, SPAN_DANGER("[src] locks up!"))
playsound(M, 'sound/weapons/smg_empty_alarm.ogg', 30)
var/initial_charge = power_supply.charge
power_supply.charge = 0
sleep(severity * 20)
power_supply.give(initial_charge)
update_maptext()
update_icon()
if(M && loc == M)
playsound(M, 'sound/weapons/laser_safetyoff.ogg', 30)
/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/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)