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