diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 29785a2c075..4d730af7449 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -763,7 +763,7 @@ About the new airlock wires panel:
return
if(ishuman(user))
var/mob/living/carbon/human/H = user
-
+
if(H.getBrainLoss() >= 50)
if(prob(40) && src.density)
playsound(src.loc, 'sound/effects/bang.ogg', 25, 1)
@@ -777,7 +777,7 @@ About the new airlock wires panel:
else
user.visible_message("[user] headbutts the airlock. Good thing they're wearing a helmet.")
return
-
+
if(H.species.can_shred(H))
if(!src.density)
@@ -876,8 +876,34 @@ About the new airlock wires panel:
return 1
+
+/obj/machinery/door/airlock/proc/CreateAssembly()
+ var/obj/structure/door_assembly/da = new assembly_type(src.loc)
+ if (istype(da, /obj/structure/door_assembly/multi_tile))
+ da.set_dir(src.dir)
+
+ da.anchored = 1
+ if(mineral)
+ da.glass = mineral
+ else if(glass && !da.glass)
+ da.glass = 1
+ da.state = 1
+ da.created_name = src.name
+ da.update_state()
+ if(operating == -1 || (stat & BROKEN))
+ new /obj/item/weapon/circuitboard/broken(src.loc)
+ operating = 0
+ else
+ if (!electronics) create_electronics()
+ electronics.forceMove(src.loc)
+ electronics = null
+ qdel(src)
+
+
+/obj/machinery/door/airlock/proc/CanChainsaw(var/obj/item/weapon/material/twohanded/chainsaw/ChainSawVar)
+ return (ChainSawVar.powered && density)
+
/obj/machinery/door/airlock/attackby(C as obj, mob/user as mob)
- //world << text("airlock attackby src [] obj [] mob []", src, C, user)
if(!istype(usr, /mob/living/silicon))
if(src.isElectrified())
if(src.shock(user, 75))
@@ -928,28 +954,7 @@ About the new airlock wires panel:
user.visible_message("[user] removes the electronics from the airlock assembly.", "You start to remove electronics from the airlock assembly.")
if(do_after(user,40))
user << "You removed the airlock electronics!"
-
- var/obj/structure/door_assembly/da = new assembly_type(src.loc)
- if (istype(da, /obj/structure/door_assembly/multi_tile))
- da.set_dir(src.dir)
-
- da.anchored = 1
- if(mineral)
- da.glass = mineral
- //else if(glass)
- else if(glass && !da.glass)
- da.glass = 1
- da.state = 1
- da.created_name = src.name
- da.update_state()
- if(operating == -1 || (stat & BROKEN))
- new /obj/item/weapon/circuitboard/broken(src.loc)
- operating = 0
- else
- if (!electronics) create_electronics()
- electronics.loc = src.loc
- electronics = null
- qdel(src)
+ CreateAssembly()
return
else if(arePowerSystemsOn())
user << "The airlock's motors resist your efforts to force it."
@@ -960,7 +965,6 @@ About the new airlock wires panel:
open(1)
else
close(1)
-
else if(istype(C, /obj/item/weapon/material/twohanded/fireaxe) && !arePowerSystemsOn())
if(locked)
user << "The airlock's bolts prevent it from being forced."
@@ -988,11 +992,70 @@ About the new airlock wires panel:
open(1)
else
close(1)
+ else if(density && istype(C, /obj/item/weapon/material/twohanded/chainsaw))
+ var/obj/item/weapon/material/twohanded/chainsaw/ChainSawVar = C
+ if(!ChainSawVar.wielded)
+ user << "Cutting the airlock requires the strength of two hands."
+ else if(ChainSawVar.cutting)
+ user << "You are already cutting an airlock open."
+ else if(!ChainSawVar.powered)
+ user << "The [C] needs to be on in order to open this door."
+ else if(bracer) //Has a magnetic lock
+ user << "The bracer needs to be removed in order to cut through this door."
+ else if(!arePowerSystemsOn())
+ ChainSawVar.cutting = 1
+ user.visible_message(\
+ "[user.name] starts cutting the control pannel of the airlock with the [C]!",\
+ "You start cutting the airlock control panel...",\
+ "You hear a loud buzzing sound and metal grinding on metal..."\
+ )
+ if(do_after(user, ChainSawVar.opendelay SECONDS, act_target = user, extra_checks = CALLBACK(src, .proc/CanChainsaw, C)))
+ user.visible_message(\
+ "[user.name] finishes cutting the control pannel of the airlock with the [C].",\
+ "You finish cutting the airlock control panel.",\
+ "You hear a metal clank and some sparks."\
+ )
+ set_broken()
+ sleep(1 SECONDS)
+ CreateAssembly()
+ ChainSawVar.cutting = 0
+ take_damage(50)
+ else if(locked)
+ ChainSawVar.cutting = 1
+ user.visible_message(\
+ "[user.name] starts cutting below the airlock with the [C]!",\
+ "You start cutting below the airlock...",\
+ "You hear a loud buzzing sound and metal grinding on metal..."\
+ )
+ if(do_after(user, ChainSawVar.opendelay SECONDS, act_target = user, extra_checks = CALLBACK(src, .proc/CanChainsaw, C)))
+ user.visible_message(\
+ "[user.name] finishes cutting below the airlock with the [C].",\
+ "You finish cutting below the airlock.",\
+ "You hear a metal clank and some sparks."\
+ )
+ unlock(1)
+ ChainSawVar.cutting = 0
+ take_damage(50)
+ else
+ ChainSawVar.cutting = 1
+ user.visible_message(\
+ "[user.name] starts cutting between the airlock with the [C]!",\
+ "You start cutting between the airlock...",\
+ "You hear a loud buzzing sound and metal grinding on metal..."\
+ )
+ if(do_after(user, ChainSawVar.opendelay SECONDS, act_target = user, extra_checks = CALLBACK(src, .proc/CanChainsaw, C)))
+ user.visible_message(\
+ "[user.name] finishes cutting between the airlock.",\
+ "You finish cutting between the airlock.",\
+ "You hear a metal clank and some sparks."\
+ )
+ open(1)
+ take_damage(50)
+ ChainSawVar.cutting = 0
else
..()
return
-
/obj/machinery/door/airlock/phoron/attackby(C as obj, mob/user as mob)
if(C)
ignite(is_hot(C))
@@ -1123,10 +1186,6 @@ About the new airlock wires panel:
for(var/turf/turf in locs)
for(var/atom/movable/AM in turf)
if(AM.blocks_airlock())
-// if(world.time > next_beep_at)
-
-// playsound(src.loc, 'sound/machines/buzz-two.ogg', 50, 0)
-// next_beep_at = world.time + SecondsToTicks(10)
close_door_in(6)
return
for(var/turf/turf in locs)
diff --git a/code/game/objects/items/weapons/material/twohanded.dm b/code/game/objects/items/weapons/material/twohanded.dm
index aad0b587fdf..345b0a9b33a 100644
--- a/code/game/objects/items/weapons/material/twohanded.dm
+++ b/code/game/objects/items/weapons/material/twohanded.dm
@@ -277,3 +277,194 @@
for(var/obj/item/organ/external/head/H in src)
H.loc = user.loc
qdel(src)
+
+// Chainsaws!
+
+/obj/item/weapon/material/twohanded/chainsaw
+ name = "chainsaw"
+ icon_state = "chainsaw_off"
+ base_icon = "chainsaw_off"
+ flags = CONDUCT
+ force = 10
+ force_wielded = 20
+ throwforce = 7
+ w_class = 4
+ sharp = 1
+ edge = 1
+ origin_tech = list(TECH_COMBAT = 5)
+ attack_verb = list("chopped", "sliced", "shredded", "slashed", "cut", "ripped")
+ hitsound = "sound/weapons/bladeslice.ogg"
+ can_embed = 0
+ applies_material_colour = 0
+ default_material = "steel"
+ var/opendelay = 30 // How long it takes to perform a door opening action with this chainsaw, in seconds.
+ var/max_fuel = 300 // The maximum amount of fuel the chainsaw stores.
+ var/fuel_cost = 1 // Multiplier for fuel cost.
+
+ var/cutting = 0 //Ignore
+ var/powered = 0 //Ignore
+
+/obj/item/weapon/material/twohanded/chainsaw/op //For events or whatever
+ name = "bloody chainsaw"
+ opendelay = 5
+ max_fuel = 1000
+ fuel_cost = 0.5
+
+/obj/item/weapon/material/twohanded/chainsaw/Initialize()
+ . = ..()
+ create_reagents(max_fuel)
+
+/obj/item/weapon/material/twohanded/chainsaw/proc/PowerUp()
+ var/turf/T = get_turf(src)
+ T.audible_message(span("notice", "\The [src] rumbles to life."))
+ playsound(src, "sound/weapons/chainsawstart.ogg", 25, 0, 30)
+ force = 20
+ force_wielded = 40
+ throwforce = 20
+ icon_state = "chainsaw_on"
+ base_icon = "chainsaw_on"
+ slot_flags = null
+ START_PROCESSING(SSfast_process, src)
+ powered = 1
+ update_held_icon()
+
+/obj/item/weapon/material/twohanded/chainsaw/proc/PowerDown()
+ var/turf/T = get_turf(src)
+ T.audible_message(span("notice", "\The [src] slowly powers down."))
+ force = initial(force)
+ force_wielded = initial(force_wielded)
+ throwforce = initial(throwforce)
+ hitsound = initial(hitsound)
+ icon_state = initial(icon_state)
+ base_icon = initial(base_icon)
+ slot_flags = initial(slot_flags)
+ STOP_PROCESSING(SSfast_process, src)
+ powered = 0
+ update_held_icon()
+
+/obj/item/weapon/material/twohanded/chainsaw/Destroy()
+ STOP_PROCESSING(SSfast_process, src)
+ return ..()
+
+/obj/item/weapon/material/twohanded/chainsaw/proc/RemoveFuel(var/amount = 1)
+ amount = amount * fuel_cost
+ reagents.remove_reagent("fuel", Clamp(amount,0,reagents.get_reagent_amount("fuel")))
+ if(reagents.get_reagent_amount("fuel") <= 0)
+ powered = 0
+ PowerDown()
+
+/obj/item/weapon/material/twohanded/chainsaw/process()
+ //TickRate is 0.1
+ var/FuelToRemove = 0.1 //0.1 Every 0.1 seconds
+
+ if(cutting)
+ FuelToRemove = 1
+ playsound(loc, 'sound/weapons/chainsawloop2.ogg', 25, 0, 30)
+ spark(src, 3, alldirs)
+ eyecheck(loc)
+ else
+ playsound(loc, 'sound/weapons/chainsawloop.ogg', 25, 0, 30)
+
+ RemoveFuel(FuelToRemove)
+
+/obj/item/weapon/material/twohanded/chainsaw/examine(mob/user)
+ if(..(user, 1))
+ user << "A heavy-duty chainsaw meant for cutting wood. Contains [round(reagents.total_volume)] unit\s of fuel."
+
+/obj/item/weapon/material/twohanded/chainsaw/afterattack(obj/O as obj, mob/user as mob, proximity)
+ if(!proximity) return
+ if (istype(O, /obj/structure/reagent_dispensers/fueltank) && get_dist(src,O) <= 1 && !powered)
+ O.reagents.trans_to_obj(src, max_fuel)
+ user << "[src] refueled"
+ playsound(loc, 'sound/effects/refill.ogg', 50, 1, -6)
+ return
+ else if(powered)
+ playsound(loc, "sound/weapons/chainsword.ogg", 25, 0, 30)
+ RemoveFuel(3)
+ user.setClickCooldown(DEFAULT_ATTACK_COOLDOWN) //No sound spam
+
+ . = ..()
+
+/obj/item/weapon/material/twohanded/chainsaw/proc/eyecheck(mob/living/carbon/human/H as mob) //Shamefully copied from the welder. Damage values multiplied by 0.1
+
+ if (!istype(H))
+ return 1
+
+ var/obj/item/organ/eyes/E = H.get_eyes()
+ if(!E)
+ return
+ var/safety = H.eyecheck()
+ if(H.status_flags & GODMODE)
+ return
+ switch(safety)
+ if(FLASH_PROTECTION_MODERATE)
+ H << "Your eyes sting a little."
+ E.damage += rand(1, 2)*0.1
+ if(E.damage > 12)
+ H.eye_blurry += rand(3,6)*0.1
+ if(FLASH_PROTECTION_NONE)
+ H << "Your eyes burn."
+ E.damage += rand(2, 4)*0.1
+ if(E.damage > 10)
+ E.damage += rand(4,10)*0.1
+ if(FLASH_PROTECTION_REDUCED)
+ H << "Your equipment intensify the welder's glow. Your eyes itch and burn severely."
+ H.eye_blurry += rand(12,20)*0.1
+ E.damage += rand(12, 16)*0.1
+ if(safety 10)
+ H << "Your eyes are really starting to hurt. This can't be good for you!"
+
+ if (E.damage >= E.min_broken_damage)
+ H << "You go blind!"
+ H.sdisabilities |= BLIND
+ else if (E.damage >= E.min_bruised_damage)
+ H << "You go blind!"
+ H.eye_blind = 5
+ H.eye_blurry = 5
+ H.disabilities |= NEARSIGHTED
+ addtimer(CALLBACK(H, /mob/.proc/reset_nearsighted), 100)
+
+/obj/item/weapon/material/twohanded/chainsaw/AltClick(mob/user as mob)
+
+ if(powered)
+ PowerDown(user)
+ else if(!wielded)
+ user << "You need to hold this with two hands to turn this on."
+ else if(reagents.get_reagent_amount("fuel") <= 0)
+ user.visible_message(\
+ "[user] pulls the cord on the [src], but nothing happens.",\
+ "You pull the cord on the [src], but nothing happens.",\
+ "You hear a cord being pulled."\
+ )
+ else
+ var/max = rand(3,6)
+ for(var/i in 1 to max)
+ user.visible_message(\
+ "[user] pulls the cord on the [src]...",\
+ "You pull the cord on the [src]...",\
+ "You hear a cord being pulled and an engine sputtering..."\
+ )
+ if(i == max)
+ PowerUp(user)
+ else
+ playsound(loc, 'sound/weapons/chainsawpull.ogg', 50, 0, 15)
+ if(!do_after(user, 2 SECONDS, act_target = user))
+ break
+
+
+
+/obj/item/weapon/material/twohanded/chainsaw/pre_attack(var/mob/living/target, var/mob/living/user)
+ if(istype(target) && wielded && powered)
+ cleave(user, target)
+ ..()
+
+/obj/item/weapon/material/twohanded/chainsaw/update_icon()
+ // Just an override.
+
+/obj/item/weapon/material/twohanded/chainsaw/verb/toggle_power()
+ set name = "Toggle power"
+ set category = "Object"
+ set src in usr
+
+ AltClick(usr)
\ No newline at end of file
diff --git a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
index 86db98a3e68..96cb4d1db17 100644
--- a/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
+++ b/code/game/objects/structures/crates_lockers/closets/secure/secure_closets.dm
@@ -67,6 +67,9 @@
else
user << "Access Denied"
+/obj/structure/closet/secure_closet/proc/CanChainsaw(var/obj/item/weapon/material/twohanded/chainsaw/ChainSawVar)
+ return (ChainSawVar.powered && !opened && !broken)
+
/obj/structure/closet/secure_closet/attackby(obj/item/weapon/W as obj, mob/user as mob)
if(opened)
if(istype(W, /obj/item/weapon/grab))
@@ -137,7 +140,24 @@
wrenched = 1
anchored = 1
else if(!opened)
- if(istype(W, /obj/item/weapon/melee/energy/blade))//Attempt to cut open locker if locked
+ if(!broken && istype(W,/obj/item/weapon/material/twohanded/chainsaw))
+ var/obj/item/weapon/material/twohanded/chainsaw/ChainSawVar = W
+ ChainSawVar.cutting = 1
+ user.visible_message(\
+ "[user.name] starts cutting the [src] with the [W]!",\
+ "You start cutting the [src]...",\
+ "You hear a loud buzzing sound and metal grinding on metal..."\
+ )
+ if(do_after(user, ChainSawVar.opendelay SECONDS, act_target = user, extra_checks = CALLBACK(src, .proc/CanChainsaw, W)))
+ user.visible_message(\
+ "[user.name] finishes cutting open the [src] with the [W].",\
+ "You finish cutting open the [src].",\
+ "You hear a metal clank and some sparks."\
+ )
+ emag_act(INFINITY, user, "The locker has been sliced open by [user] with \an [W]!", "You hear metal being sliced and sparks flying.")
+ spark(src, 5)
+ ChainSawVar.cutting = 0
+ else if(istype(W, /obj/item/weapon/melee/energy/blade))//Attempt to cut open locker if locked
if(emag_act(INFINITY, user, "The locker has been sliced open by [user] with \an [W]!", "You hear metal being sliced and sparks flying."))
spark(src, 5)
playsound(loc, 'sound/weapons/blade1.ogg', 50, 1)
@@ -245,3 +265,4 @@
var/obj/structure/bigDelivery/BD = loc
BD.unwrap()
open()
+
diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm
index d17026eaef4..10905378d62 100644
--- a/code/game/objects/structures/door_assembly.dm
+++ b/code/game/objects/structures/door_assembly.dm
@@ -301,10 +301,39 @@
new path(src.loc, src)
qdel(src)
+ else if(istype(W, /obj/item/weapon/material/twohanded/chainsaw))
+ var/obj/item/weapon/material/twohanded/chainsaw/ChainSawVar = W
+ if(!ChainSawVar.wielded)
+ user << "Cutting the airlock requires the strength of two hands."
+ else if(ChainSawVar.cutting)
+ user << "You are already cutting an airlock open."
+ else if(!ChainSawVar.powered)
+ user << "The [W] needs to be on in order to open this door."
+ else
+ ChainSawVar.cutting = 1
+ user.visible_message(\
+ "[user.name] starts cutting the rest of the airlock with the [W]!",\
+ "You start cutting the rest of the airlock...",\
+ "You hear a loud buzzing sound and metal grinding on metal..."\
+ )
+ if(do_after(user, ChainSawVar.opendelay SECONDS, act_target = user, extra_checks = CALLBACK(src, .proc/CanChainsaw, W)))
+ user.visible_message(\
+ "[user.name] finishes cutting the airlock with the [W].",\
+ "You finish cutting the airlock.",\
+ "You hear a metal clank and some sparks."\
+ )
+ new /obj/item/stack/material/steel(src.loc, 2)
+ ChainSawVar.cutting = 0
+ qdel(src)
+ else
+ ChainSawVar.cutting = 0
else
..()
update_state()
+/obj/structure/door_assembly/proc/CanChainsaw(var/obj/item/weapon/material/twohanded/chainsaw/ChainSawVar)
+ return (ChainSawVar.powered)
+
/obj/structure/door_assembly/proc/update_state()
icon_state = "door_as_[glass == 1 ? "g" : ""][istext(glass) ? glass : base_icon_state][state]"
name = ""
diff --git a/html/changelogs/burgerbb-chainsaw.yml b/html/changelogs/burgerbb-chainsaw.yml
new file mode 100644
index 00000000000..8c776b791e3
--- /dev/null
+++ b/html/changelogs/burgerbb-chainsaw.yml
@@ -0,0 +1,4 @@
+author: BurgerBB
+delete-after: True
+changes:
+ - rscadd: "Added chainsaws, a powerful two-handed weapon that requires welder fuel to operate. Chainsaws can open airlocks and lockers when powered."
diff --git a/icons/mob/items/lefthand.dmi b/icons/mob/items/lefthand.dmi
index 8c8bc1d3130..ee69e8b45b7 100644
Binary files a/icons/mob/items/lefthand.dmi and b/icons/mob/items/lefthand.dmi differ
diff --git a/icons/mob/items/righthand.dmi b/icons/mob/items/righthand.dmi
index f41487fa978..5744342b959 100644
Binary files a/icons/mob/items/righthand.dmi and b/icons/mob/items/righthand.dmi differ
diff --git a/icons/obj/weapons.dmi b/icons/obj/weapons.dmi
index e2b70181890..40916cb5a72 100644
Binary files a/icons/obj/weapons.dmi and b/icons/obj/weapons.dmi differ
diff --git a/sound/weapons/chainsawloop.ogg b/sound/weapons/chainsawloop.ogg
new file mode 100644
index 00000000000..fb93e2544f0
Binary files /dev/null and b/sound/weapons/chainsawloop.ogg differ
diff --git a/sound/weapons/chainsawloop2.ogg b/sound/weapons/chainsawloop2.ogg
new file mode 100644
index 00000000000..1eebea424b3
Binary files /dev/null and b/sound/weapons/chainsawloop2.ogg differ
diff --git a/sound/weapons/chainsawpull.ogg b/sound/weapons/chainsawpull.ogg
new file mode 100644
index 00000000000..1cb3461bed8
Binary files /dev/null and b/sound/weapons/chainsawpull.ogg differ