diff --git a/code/modules/projectiles/guns/misc/blastcannon.dm b/code/modules/projectiles/guns/misc/blastcannon.dm
index b6e4b88f6f8..31b4121b042 100644
--- a/code/modules/projectiles/guns/misc/blastcannon.dm
+++ b/code/modules/projectiles/guns/misc/blastcannon.dm
@@ -1,8 +1,12 @@
+/**
+ * A gun that consumes a TTV to shoot an projectile with equivalent power.
+ *
+ * It's basically an immovable rod launcher.
+ */
/obj/item/gun/blastcannon
name = "pipe gun"
desc = "A pipe welded onto a gun stock, with a mechanical trigger. The pipe has an opening near the top, and there seems to be a spring loaded wheel in the hole."
icon_state = "empty_blastcannon"
- var/icon_state_loaded = "loaded_blastcannon"
inhand_icon_state = "blastcannon_empty"
w_class = WEIGHT_CLASS_NORMAL
force = 10
@@ -10,17 +14,26 @@
item_flags = NONE
clumsy_check = FALSE
randomspread = FALSE
+ /// The icon state used when this is loaded with a bomb.
+ var/icon_state_loaded = "loaded_blastcannon"
- var/hugbox = TRUE
- var/max_power = INFINITY
+ /// The TTV this contains that will be used to create the projectile
+ var/obj/item/transfer_valve/bomb
+ /// Additional volume added to the gasmixture used to calculate the bombs power.
var/reaction_volume_mod = 0
- var/reaction_cycles = 3 //How many times gases react() before calculation. Very finnicky value, do not mess with without good reason.
+ /// Whether the gases are reacted once before calculating the range
var/prereaction = TRUE
+ /// How many times gases react() before calculation. Very finnicky value, do not mess with without good reason.
+ var/reaction_cycles = 3
+ /// The maximum power the blastcannon is capable of reaching
+ var/max_power = INFINITY
+ // For debugging/badminry
+ /// Whether you can fire this without a bomb.
var/bombcheck = TRUE
+ /// The range this defaults to without a bomb for debugging and badminry
var/debug_power = 0
- var/obj/item/transfer_valve/bomb
/obj/item/gun/blastcannon/debug
debug_power = 80
@@ -32,7 +45,8 @@
pin = new
/obj/item/gun/blastcannon/Destroy()
- QDEL_NULL(bomb)
+ if(bomb)
+ QDEL_NULL(bomb)
return ..()
/obj/item/gun/blastcannon/attack_self(mob/user)
@@ -47,34 +61,35 @@
return ..()
/obj/item/gun/blastcannon/update_icon_state()
- if(bomb)
- icon_state = icon_state_loaded
- else
- icon_state = initial(icon_state)
+ . = ..()
+ icon_state = bomb ? icon_state_loaded : initial(icon_state)
-/obj/item/gun/blastcannon/attackby(obj/O, mob/user)
- if(istype(O, /obj/item/transfer_valve))
- var/obj/item/transfer_valve/T = O
- if(!T.tank_one || !T.tank_two)
- to_chat(user, "What good would an incomplete bomb do?")
- return FALSE
- if(!user.transferItemToLoc(T, src))
- to_chat(user, "[T] seems to be stuck to your hand!")
- return FALSE
- user.visible_message("[user] attaches [T] to [src]!")
- bomb = T
- name = "blast cannon"
- desc = "A makeshift device used to concentrate a bomb's blast energy to a narrow wave."
- update_icon()
- return TRUE
- return ..()
+/obj/item/gun/blastcannon/attackby(obj/item/transfer_valve/bomb_to_attach, mob/user)
+ if(!istype(bomb_to_attach))
+ return ..()
-//returns the third value of a bomb blast
+ if(!bomb_to_attach.tank_one || !bomb_to_attach.tank_two)
+ to_chat(user, "What good would an incomplete bomb do?")
+ return FALSE
+ if(!user.transferItemToLoc(bomb_to_attach, src))
+ to_chat(user, "[bomb_to_attach] seems to be stuck to your hand!")
+ return FALSE
+
+ user.visible_message("[user] attaches [bomb_to_attach] to [src]!")
+ bomb = bomb_to_attach
+ name = "blast cannon"
+ desc = "A makeshift device used to concentrate a bomb's blast energy to a narrow wave."
+ update_icon()
+ return TRUE
+
+/// Handles the bomb power calculations
/obj/item/gun/blastcannon/proc/calculate_bomb()
if(!istype(bomb) || !istype(bomb.tank_one) || !istype(bomb.tank_two))
return 0
+
var/datum/gas_mixture/temp = new(max(reaction_volume_mod, 0))
bomb.merge_gases(temp)
+
if(prereaction)
temp.react(src)
var/prereaction_pressure = temp.return_pressure()
@@ -82,19 +97,23 @@
return 0
for(var/i in 1 to reaction_cycles)
temp.react(src)
+
var/pressure = temp.return_pressure()
qdel(temp)
if(pressure < TANK_FRAGMENT_PRESSURE)
return 0
return ((pressure - TANK_FRAGMENT_PRESSURE) / TANK_FRAGMENT_SCALE)
+
/obj/item/gun/blastcannon/afterattack(atom/target, mob/user, flag, params)
if((!bomb && bombcheck) || (!target) || (get_dist(get_turf(target), get_turf(user)) <= 2))
return ..()
- var/power = bomb? calculate_bomb() : debug_power
+
+ var/power = bomb ? calculate_bomb() : debug_power
power = min(power, max_power)
QDEL_NULL(bomb)
update_icon()
+
var/heavy = power * 0.25
var/medium = power * 0.5
var/light = power
@@ -105,12 +124,12 @@
message_admins("Blast wave fired from [ADMIN_VERBOSEJMP(starting)] at [ADMIN_VERBOSEJMP(targturf)] ([target.name]) by [ADMIN_LOOKUPFLW(user)] with power [heavy]/[medium]/[light].")
log_game("Blast wave fired from [AREACOORD(starting)] at [AREACOORD(targturf)] ([target.name]) by [key_name(user)] with power [heavy]/[medium]/[light].")
var/obj/projectile/blastwave/BW = new(loc, heavy, medium, light)
- BW.hugbox = hugbox
BW.preparePixelProjectile(target, get_turf(src), params, 0)
BW.fire()
name = initial(name)
desc = initial(desc)
+/// The projectile used by the blastcannon
/obj/projectile/blastwave
name = "blast wave"
icon_state = "blastwave"
@@ -118,52 +137,38 @@
nodamage = FALSE
movement_type = FLYING
projectile_phasing = ALL // just blows up the turfs lmao
+ /// The maximum distance this will inflict [EXPLODE_DEVASTATE]
var/heavyr = 0
+ /// The maximum distance this will inflict [EXPLODE_HEAVY]
var/mediumr = 0
+ /// The maximum distance this will inflict [EXPLODE_LIGHT]
var/lightr = 0
- var/hugbox = TRUE
- range = 150
-/obj/projectile/blastwave/Initialize(mapload, _h, _m, _l)
- heavyr = _h
- mediumr = _m
- lightr = _l
+/obj/projectile/blastwave/Initialize(mapload, _heavy, _medium, _light)
+ range = max(_heavy, _medium, _light, 0)
+ heavyr = _heavy
+ mediumr = _medium
+ lightr = _light
return ..()
/obj/projectile/blastwave/Range()
- ..()
- var/amount_destruction = EXPLODE_NONE
- var/wallbreak_chance = 0
- if(heavyr)
- amount_destruction = EXPLODE_DEVASTATE
- wallbreak_chance = 99
- else if(mediumr)
- amount_destruction = EXPLODE_HEAVY
- wallbreak_chance = 66
- else if(lightr)
- amount_destruction = EXPLODE_LIGHT
- wallbreak_chance = 33
- if(amount_destruction)
- if(hugbox)
- loc.contents_explosion(EXPLODE_HEAVY, loc)
- if(istype(loc, /turf/closed/wall))
- var/turf/closed/wall/W = loc
- if(prob(wallbreak_chance))
- W.dismantle_wall(TRUE, TRUE)
- else
- switch(amount_destruction)
- if(EXPLODE_DEVASTATE)
- SSexplosions.highturf += loc
- if(EXPLODE_HEAVY)
- SSexplosions.medturf += loc
- if(EXPLODE_LIGHT)
- SSexplosions.lowturf += loc
- else
- qdel(src)
+ . = ..()
+ if(QDELETED(src))
+ return
heavyr = max(heavyr - 1, 0)
mediumr = max(mediumr - 1, 0)
lightr = max(lightr - 1, 0)
+ if(heavyr)
+ SSexplosions.highturf += loc
+ else if(mediumr)
+ SSexplosions.medturf += loc
+ else if(lightr)
+ SSexplosions.lowturf += loc
+ else
+ qdel(src)
+ return
+
/obj/projectile/blastwave/ex_act()
return