diff --git a/code/__DEFINES/dcs/signals/signals.dm b/code/__DEFINES/dcs/signals/signals.dm index fd56e61f003b..638b5220bc3c 100644 --- a/code/__DEFINES/dcs/signals/signals.dm +++ b/code/__DEFINES/dcs/signals/signals.dm @@ -182,6 +182,8 @@ #define COMSIG_ATOM_CROWBAR_ACT "atom_crowbar_act" ///from base of atom/analyser_act(): (mob/living/user, obj/item/I) #define COMSIG_ATOM_ANALYSER_ACT "atom_analyser_act" +///from base of atom/deconstruct_act(): (mob/living/user, obj/item/I) +#define COMSIG_ATOM_DECONSTRUCT_ACT "atom_deconstruct_act" ///for any tool behaviors: (mob/living/user, obj/item/I, list/recipes) #define COMSIG_ATOM_TOOL_ACT(tooltype) "tool_act_[tooltype]" diff --git a/code/__DEFINES/tools.dm b/code/__DEFINES/tools.dm index 35860ac927f4..eb2696c0afbb 100644 --- a/code/__DEFINES/tools.dm +++ b/code/__DEFINES/tools.dm @@ -15,6 +15,7 @@ #define TOOL_SCALPEL "scalpel" #define TOOL_SAW "saw" #define TOOL_KNIFE "knife" //luv me kuh-nyfe +#define TOOL_DECONSTRUCT "deconstruct" // If delay between the start and the end of tool operation is less than MIN_TOOL_SOUND_DELAY, // tool sound is only played when op is started. If not, it's played twice. diff --git a/code/datums/action.dm b/code/datums/action.dm index fb2d8b5e967f..9bc58c399dd4 100644 --- a/code/datums/action.dm +++ b/code/datums/action.dm @@ -249,6 +249,9 @@ /datum/action/item_action/toggle_mister name = "Toggle Mister" +/datum/action/item_action/toggle_gear_handle + name = "Toggle Gear Handle" + /datum/action/item_action/activate_injector name = "Activate Injector" diff --git a/code/datums/components/twohanded.dm b/code/datums/components/twohanded.dm index 5ba0a368c637..4ede9a6fc168 100644 --- a/code/datums/components/twohanded.dm +++ b/code/datums/components/twohanded.dm @@ -9,8 +9,8 @@ dupe_mode = COMPONENT_DUPE_UNIQUE_PASSARGS // Only one of the component can exist on an item var/wielded = FALSE /// Are we holding the two handed item properly var/force_multiplier = 0 /// The multiplier applied to force when wielded, does not work with force_wielded, and force_unwielded - var/force_wielded = 0 /// The force of the item when weilded - var/force_unwielded = 0 /// The force of the item when unweilded + var/force_wielded = 0 /// The force of the item when wielded + var/force_unwielded = 0 /// The force of the item when unwielded var/wieldsound = FALSE /// Play sound when wielded var/unwieldsound = FALSE /// Play sound when unwielded var/attacksound = FALSE /// Play sound on attack when wielded diff --git a/code/datums/elements/tool_bang.dm b/code/datums/elements/tool_bang.dm new file mode 100644 index 000000000000..bc002e936de4 --- /dev/null +++ b/code/datums/elements/tool_bang.dm @@ -0,0 +1,40 @@ +/** + * Tool bang bespoke element + * + * Bang the user when using this tool + */ +/datum/element/tool_bang + element_flags = ELEMENT_BESPOKE + id_arg_index = 2 + /// Strength of the bang + var/bang_strength + +/datum/element/tool_bang/Attach(datum/target, bang_strength) + . = ..() + if(!isitem(target)) + return ELEMENT_INCOMPATIBLE + + src.bang_strength = bang_strength + + RegisterSignal(target, COMSIG_TOOL_IN_USE, PROC_REF(prob_bang)) + RegisterSignal(target, COMSIG_TOOL_START_USE, PROC_REF(bang)) + +/datum/element/tool_bang/Detach(datum/source, force) + . = ..() + UnregisterSignal(source, list(COMSIG_TOOL_IN_USE, COMSIG_TOOL_START_USE)) + +/datum/element/tool_bang/proc/prob_bang(datum/source, mob/living/user) + SIGNAL_HANDLER + + if(prob(90)) + return + bang(source, user) + +/datum/element/tool_bang/proc/bang(datum/source, mob/living/user) + SIGNAL_HANDLER + + if(user && get_dist(get_turf(source), get_turf(user)) <= 1) + if(istype(user, /mob/living/carbon)) + var/mob/living/carbon/carbon = user + carbon.soundbang_act(min(bang_strength,1), 0, 1, 5) + diff --git a/code/game/atoms.dm b/code/game/atoms.dm index b96e8a53c824..a140ec099085 100644 --- a/code/game/atoms.dm +++ b/code/game/atoms.dm @@ -1282,6 +1282,8 @@ . = welder_act(user, I) if(TOOL_ANALYZER) . = analyzer_act(user, I) + if(TOOL_DECONSTRUCT) + . |= deconstruct_act(user, I) if(. || signal_result & COMPONENT_BLOCK_TOOL_ATTACK) //Either the proc or the signal handled the tool's events in some way. return TRUE @@ -1362,6 +1364,10 @@ /atom/proc/analyzer_act(mob/living/user, obj/item/I) return SEND_SIGNAL(src, COMSIG_ATOM_ANALYSER_ACT, user, I) +///Deconstruct act +/atom/proc/deconstruct_act(mob/living/user, obj/item/I) + return SEND_SIGNAL(src, COMSIG_ATOM_DECONSTRUCT_ACT, user, I) + ///Generate a tag for this atom /atom/proc/GenerateTag() return diff --git a/code/game/machinery/constructable_frame.dm b/code/game/machinery/constructable_frame.dm index f196fc6dc770..a62780aad05a 100644 --- a/code/game/machinery/constructable_frame.dm +++ b/code/game/machinery/constructable_frame.dm @@ -13,14 +13,22 @@ . += "It has \a [circuit] installed." -/obj/structure/frame/deconstruct(disassembled = TRUE) +/obj/structure/frame/deconstruct(disassembled = TRUE, scrapped = FALSE) if(!(flags_1 & NODECONSTRUCT_1)) new /obj/item/stack/sheet/metal(loc, 5) - if(circuit) + if(circuit && !scrapped) circuit.forceMove(loc) circuit = null qdel(src) +/obj/structure/frame/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if(I.use_tool(src, user, 3 SECONDS, volume=0)) + to_chat(user, "You cut apart \the [src].", "You cut apart \the [src].") + deconstruct() + return TRUE /obj/structure/frame/machine name = "machine frame" diff --git a/code/game/machinery/deployable.dm b/code/game/machinery/deployable.dm index 41760633726e..3dedf5887d0c 100644 --- a/code/game/machinery/deployable.dm +++ b/code/game/machinery/deployable.dm @@ -79,6 +79,14 @@ return return ..() +/obj/structure/barricade/wooden/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if (I.use_tool(src, user, 2 SECONDS, volume=0)) + to_chat(user, "You cut apart [src].") + deconstruct() + return TRUE /obj/structure/barricade/wooden/crude name = "crude plank barricade" diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index 4c27a08e64a7..3412321b380b 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -1243,6 +1243,21 @@ return INVOKE_ASYNC(src, (density ? PROC_REF(open) : PROC_REF(close)), 2) +/obj/machinery/door/airlock/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + var/decon_time = 5 SECONDS + if(welded) + decon_time += 5 SECONDS + if(locked) + decon_time += 5 SECONDS + if(seal) + decon_time += 15 SECONDS + if (I.use_tool(src, user, decon_time, volume=100)) + to_chat(user, "You cut open the [src].") + deconstruct(FALSE, user) + return TRUE /obj/machinery/door/airlock/open(forced=0) if(operating || welded || locked || seal || !wires) diff --git a/code/game/mecha/equipment/tools/work_tools.dm b/code/game/mecha/equipment/tools/work_tools.dm index 44c8c6626dae..aa5dbf38c27f 100644 --- a/code/game/mecha/equipment/tools/work_tools.dm +++ b/code/game/mecha/equipment/tools/work_tools.dm @@ -491,6 +491,86 @@ return 1 //WS Edit End - Readded from Smartwire Revert +/obj/item/mecha_parts/mecha_equipment/salvage_saw + name = "109-C Salvage Saw" + desc = "Equipment for cutting open walls and airlocks." + icon_state = "mecha_saw" + equip_cooldown = 5 + energy_drain = 10 + force = 15 + var/dam_force = 30 + harmful = TRUE + tool_behaviour = TOOL_DECONSTRUCT + toolspeed = 0.5 + var/datum/effect_system/spark_spread/spark_system + +/obj/item/mecha_parts/mecha_equipment/salvage_saw/can_attach(obj/mecha/M as obj) + if(..()) + if(istype(M, /obj/mecha/working) || istype(M, /obj/mecha/combat)) + return 1 + return 0 + +/obj/item/mecha_parts/mecha_equipment/salvage_saw/attach() + ..() + toolspeed = 0.5 + return + +/obj/item/mecha_parts/mecha_equipment/salvage_saw/detach() + ..() + toolspeed = 10 //yeah sure, use a mech tool without a mech. see how far that gets you + return ..() + +/obj/item/mecha_parts/mecha_equipment/salvage_saw/action(atom/target) + if(!action_checks(target)) + return + if(isliving(target)) + if(chassis.occupant.a_intent == INTENT_HARM) + var/mob/living/M = target + saw_mob(M, chassis.occupant) + return + else + target.add_overlay(GLOB.cutting_effect) + if(target.deconstruct_act(chassis.occupant, src)) + do_sparks(2, TRUE, src) + chassis.stopped-- + target.cut_overlay(GLOB.cutting_effect) + if(!chassis.stopped) + occupant_message("[src] finishes cutting, allowing movement again.") + +/obj/item/mecha_parts/mecha_equipment/salvage_saw/tool_start_check(user, amount) + if(!chassis.stopped) + occupant_message("[src] begins cutting, locking in place!") + chassis.stopped++ + return TRUE + +/obj/item/mecha_parts/mecha_equipment/salvage_saw/proc/saw_mob(mob/living/target, mob/user) + target.visible_message("[chassis] is sawing [target] with [src]!", \ + "[chassis] is sawing you with [src]!") + if(!do_after_cooldown(target)) + return + log_combat(user, target, "sawed", "[name]", "(INTENT: [uppertext(user.a_intent)]) (DAMTYPE: [uppertext(damtype)])") + if(target.stat == DEAD && target.getBruteLoss() >= 400) + log_combat(user, target, "gibbed", name) + target.gib() + else + var/obj/item/bodypart/target_part = target.get_bodypart(ran_zone(BODY_ZONE_CHEST)) + target.apply_damage(15, BRUTE, BODY_ZONE_CHEST, target.run_armor_check(target_part, "melee")) + + //blood splatters + var/splatter_dir = get_dir(chassis, target) + if(isalien(target)) + new /obj/effect/temp_visual/dir_setting/bloodsplatter/xenosplatter(target.drop_location(), splatter_dir) + else + var/splatter_color = null + if(iscarbon(target)) + var/mob/living/carbon/carbon_target = target + splatter_color = carbon_target.dna.blood_type.color + new /obj/effect/temp_visual/dir_setting/bloodsplatter(target.drop_location(), splatter_dir, splatter_color) + + //organs go everywhere + if(target_part && prob(10)) + target_part.dismember(BRUTE) + //Dunno where else to put this so shrug /obj/item/mecha_parts/mecha_equipment/conversion_kit name = "Exosuit Conversion Kit" diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm index db59620b39fd..eba4801ba56d 100644 --- a/code/game/mecha/mecha.dm +++ b/code/game/mecha/mecha.dm @@ -15,6 +15,7 @@ light_on = FALSE var/ruin_mecha = FALSE //if the mecha starts on a ruin, don't automatically give it a tracking beacon to prevent metagaming. var/can_move = 0 //time of next allowed movement + var/stopped = FALSE var/mob/living/carbon/occupant = null var/step_in = 10 //make a step in step_in/10 sec. var/dir_in = 2//What direction will the mech face when entered/powered on? Defaults to South. @@ -596,6 +597,8 @@ /obj/mecha/proc/domove(direction) if(can_move >= world.time) return 0 + if(stopped) + return 0 if(!Process_Spacemove(direction)) return 0 if(!has_charge(step_energy_drain)) diff --git a/code/game/objects/items.dm b/code/game/objects/items.dm index a1302008cf89..154f6bde143a 100644 --- a/code/game/objects/items.dm +++ b/code/game/objects/items.dm @@ -2,6 +2,10 @@ GLOBAL_DATUM_INIT(fire_overlay, /mutable_appearance, mutable_appearance('icons/e GLOBAL_DATUM_INIT(welding_sparks, /mutable_appearance, mutable_appearance('icons/effects/welding_effect.dmi', "welding_sparks", GASFIRE_LAYER, ABOVE_LIGHTING_PLANE)) +GLOBAL_DATUM_INIT(cutting_effect, /mutable_appearance, mutable_appearance('icons/effects/cutting_effect.dmi', "cutting_effect", GASFIRE_LAYER, ABOVE_LIGHTING_PLANE)) + +GLOBAL_DATUM_INIT(advanced_cutting_effect, /mutable_appearance, mutable_appearance('icons/effects/cutting_effect.dmi', "advanced_cutting_effect", GASFIRE_LAYER, ABOVE_LIGHTING_PLANE)) + GLOBAL_DATUM_INIT(cleaning_bubbles, /mutable_appearance, mutable_appearance('icons/effects/effects.dmi', "bubbles", ABOVE_MOB_LAYER, GAME_PLANE)) GLOBAL_VAR_INIT(rpg_loot_items, FALSE) diff --git a/code/game/objects/items/gear_packs.dm b/code/game/objects/items/gear_packs.dm new file mode 100644 index 000000000000..65db4ffa28c9 --- /dev/null +++ b/code/game/objects/items/gear_packs.dm @@ -0,0 +1,285 @@ +/obj/item/gear_pack + name = "gear pack" + desc = "A large backpack that usually holds things" + icon = 'icons/obj/hydroponics/equipment.dmi' + icon_state = "waterbackpack" + item_state = "waterbackpack" + lefthand_file = 'icons/mob/inhands/equipment/backpack_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi' + w_class = WEIGHT_CLASS_HUGE + slot_flags = ITEM_SLOT_BACK + item_flags = SLOWS_WHILE_IN_HAND + max_integrity = 300 + slowdown = 1 + drag_slowdown = 1 + actions_types = list(/datum/action/item_action/toggle_gear_handle) + max_integrity = 200 + armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 0, "rad" = 0, "fire" = 100, "acid" = 30) + resistance_flags = FIRE_PROOF + var/on = FALSE + var/obj/item/stock_parts/cell/cell + var/preload_cell_type = /obj/item/stock_parts/cell/high + var/powered = FALSE + var/activate_sound = "sparks" + var/obj/item/gear_handle/gear_handle_type = /obj/item/gear_handle + var/obj/item/gear_handle/gear_handle + +/obj/item/gear_pack/get_cell() + return cell + +/obj/item/gear_pack/Initialize() + . = ..() + drag_slowdown = slowdown + gear_handle = new gear_handle_type(src) + cell = new preload_cell_type(src) + update_power() + return + +/obj/item/gear_pack/examine(mob/user) + . = ..() + . += "It is [ on ? "currently" : "not"] active." + if(cell) + . += "A small readout reports [PERCENT(cell.charge / cell.maxcharge)]% charge." + +/obj/item/gear_pack/fire_act(exposed_temperature, exposed_volume) + . = ..() + if(gear_handle?.loc == src) + gear_handle.fire_act(exposed_temperature, exposed_volume) + +/obj/item/gear_pack/extinguish() + . = ..() + if(gear_handle?.loc == src) + gear_handle.extinguish() + +/obj/item/gear_pack/proc/update_power() + if(!QDELETED(cell)) + if(QDELETED(gear_handle) || cell.charge < gear_handle.usecost) + powered = FALSE + else + powered = TRUE + else + powered = FALSE + update_icon() + +/obj/item/gear_pack/update_overlays() + . = ..() + + if(powered) + . += "[initial(icon_state)]-powered" + if(!QDELETED(cell)) + var/ratio = cell.charge / cell.maxcharge + ratio = CEILING(ratio*4, 1) * 25 + . += "[initial(icon_state)]-charge[ratio]" + if(!cell) + . += "[initial(icon_state)]-nocell" + if(!on) + . += "[initial(icon_state)]-attachment" + +/obj/item/gear_pack/CheckParts(list/parts_list) + ..() + cell = locate(/obj/item/stock_parts/cell) in contents + update_power() + +/obj/item/gear_pack/ui_action_click() + toggle_gear_handle() + +//ATTACK HAND IGNORING PARENT RETURN VALUE +/obj/item/gear_pack/attack_hand(mob/user) + if(loc == user) + if(slot_flags == ITEM_SLOT_BACK) + if(user.get_item_by_slot(ITEM_SLOT_BACK) == src) + ui_action_click() + else + to_chat(user, "Put the [src] on your back first!") + + else if(slot_flags == ITEM_SLOT_BELT) + if(user.get_item_by_slot(ITEM_SLOT_BELT) == src) + ui_action_click() + else + to_chat(user, "Strap the [src]'s belt on first!") + return + return ..() + +/obj/item/gear_pack/MouseDrop(obj/over_object) + . = ..() + if(ismob(loc)) + var/mob/M = loc + if(!M.incapacitated() && istype(over_object, /atom/movable/screen/inventory/hand)) + var/atom/movable/screen/inventory/hand/H = over_object + M.putItemFromInventoryInHandIfPossible(src, H.held_index) + +/obj/item/gear_pack/attackby(obj/item/W, mob/user, params) + if(W == gear_handle) + toggle_gear_handle() + else if(istype(W, /obj/item/stock_parts/cell)) + var/obj/item/stock_parts/cell/C = W + if(cell) + to_chat(user, "[src] already has a cell!") + else + if(C.maxcharge < gear_handle.usecost) + to_chat(user, "[src] requires a higher capacity cell.") + return + if(!user.transferItemToLoc(W, src)) + return + cell = W + to_chat(user, "You install a cell in [src].") + update_power() + + else if(W.tool_behaviour == TOOL_SCREWDRIVER) + if(cell) + cell.update_icon() + cell.forceMove(get_turf(src)) + cell = null + to_chat(user, "You remove the cell from [src].") + update_power() + else + return ..() + +/obj/item/gear_pack/emp_act(severity) + . = ..() + if(cell && !(. & EMP_PROTECT_CONTENTS)) + deductcharge(1000 / severity) + if(. & EMP_PROTECT_SELF) + return + update_power() + +/obj/item/gear_pack/proc/toggle_gear_handle() + set name = "Toggle gear_handle" + set category = "Object" + on = !on + + var/mob/living/carbon/user = usr + if(on) + //Detach the gear_handle into the user's hands + playsound(src, 'sound/items/handling/multitool_pickup.ogg', 100) + if(!usr.put_in_hands(gear_handle)) + on = FALSE + to_chat(user, "You need a free hand to hold the [gear_handle]!") + update_power() + return + else + //Remove from their hands and back onto the gear pack + remove_gear_handle(user) + + update_power() + for(var/X in actions) + var/datum/action/A = X + A.UpdateButtonIcon() + + +/obj/item/gear_pack/equipped(mob/user, slot) + ..() + if((slot_flags == ITEM_SLOT_BACK && slot != ITEM_SLOT_BACK) || (slot_flags == ITEM_SLOT_BELT && slot != ITEM_SLOT_BELT)) + remove_gear_handle(user) + update_power() + +/obj/item/gear_pack/item_action_slot_check(slot, mob/user) + if(slot == user.getBackSlot()) + return 1 + +/obj/item/gear_pack/proc/remove_gear_handle(mob/user) + if(ismob(gear_handle.loc)) + var/mob/M = gear_handle.loc + M.dropItemToGround(gear_handle, TRUE) + return + +/obj/item/gear_pack/Destroy() + if(on) + var/M = get(gear_handle, /mob) + remove_gear_handle(M) + QDEL_NULL(gear_handle) + QDEL_NULL(cell) + return ..() + +/obj/item/gear_pack/proc/deductcharge(chrgdeductamt) + if(cell) + if(cell.charge < (gear_handle.usecost+chrgdeductamt)) + powered = FALSE + update_power() + if(cell.use(chrgdeductamt)) + update_power() + return TRUE + else + return FALSE + +/obj/item/gear_handle + + name = "gear handle" + desc = "handles the gear." + icon = 'icons/obj/hydroponics/equipment.dmi' + icon_state = "mister" + item_state = "mister" + lefthand_file = 'icons/mob/inhands/equipment/mister_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/mister_righthand.dmi' + + force = 0 + throwforce = 6 + w_class = WEIGHT_CLASS_BULKY + resistance_flags = INDESTRUCTIBLE + base_icon_state = "mister" + + var/req_pack = TRUE + var/usecost = 1000 + var/obj/item/gear_pack/pack + +/obj/item/gear_handle/Initialize() + . = ..() + ADD_TRAIT(src, TRAIT_NO_STORAGE_INSERT, GENERIC_ITEM_TRAIT) + if (!loc || !istype(loc, /obj/item/gear_pack)) + return INITIALIZE_HINT_QDEL + if(!req_pack) + return + pack = loc + update_icon() + +/obj/item/gear_handle/Destroy() + pack = null + return ..() + +/obj/item/gear_handle/equipped(mob/user, slot) + . = ..() + if(!req_pack) + return + RegisterSignal(user, COMSIG_MOVABLE_MOVED, PROC_REF(check_range)) + +/obj/item/gear_handle/Moved() + . = ..() + check_range() + + +/obj/item/gear_handle/fire_act(exposed_temperature, exposed_volume) + . = ..() + if((req_pack && pack) && loc != pack) + pack.fire_act(exposed_temperature, exposed_volume) + +/obj/item/gear_handle/proc/check_range() + SIGNAL_HANDLER + + if(!req_pack ||!pack) + return + if(!in_range(src,pack)) + var/mob/living/L = loc + if(istype(L)) + to_chat(L, "[pack]'s [src] overextends and comes out of your hands!") + else + visible_message("[src] snaps back into [pack].") + snap_back() + +/obj/item/gear_handle/dropped(mob/user) + . = ..() + if(!req_pack) + return ..() + if(user) + UnregisterSignal(user, COMSIG_MOVABLE_MOVED) + if(user != loc) + to_chat(user, "[src] snap back into the main unit.") + snap_back() + return + +/obj/item/gear_handle/proc/snap_back() + if(!pack) + return + playsound() + pack.on = FALSE + forceMove(pack) + pack.update_power() diff --git a/code/game/objects/structures/beds_chairs/bed.dm b/code/game/objects/structures/beds_chairs/bed.dm index ec7132a67cdd..533f58bdf2ac 100644 --- a/code/game/objects/structures/beds_chairs/bed.dm +++ b/code/game/objects/structures/beds_chairs/bed.dm @@ -71,7 +71,7 @@ return attack_hand(user) /obj/structure/bed/attackby(obj/item/W, mob/user, params) - if(W.tool_behaviour == TOOL_WRENCH && !(flags_1&NODECONSTRUCT_1)) + if((W.tool_behaviour == TOOL_WRENCH || W.tool_behaviour == TOOL_DECONSTRUCT) && !(flags_1&NODECONSTRUCT_1)) W.play_tool_sound(src) deconstruct(TRUE) else diff --git a/code/game/objects/structures/beds_chairs/chair.dm b/code/game/objects/structures/beds_chairs/chair.dm index 045bf39ae9b6..40e0d9388515 100644 --- a/code/game/objects/structures/beds_chairs/chair.dm +++ b/code/game/objects/structures/beds_chairs/chair.dm @@ -60,7 +60,7 @@ qdel(src) /obj/structure/chair/attackby(obj/item/W, mob/user, params) - if(W.tool_behaviour == TOOL_WRENCH && !(flags_1&NODECONSTRUCT_1)) + if((W.tool_behaviour == TOOL_WRENCH || W.tool_behaviour == TOOL_DECONSTRUCT) && !(flags_1&NODECONSTRUCT_1)) W.play_tool_sound(src) deconstruct() else if(istype(W, /obj/item/assembly/shock_kit)) diff --git a/code/game/objects/structures/catwalk.dm b/code/game/objects/structures/catwalk.dm index 20986f9e6c27..2202e84d70e4 100644 --- a/code/game/objects/structures/catwalk.dm +++ b/code/game/objects/structures/catwalk.dm @@ -57,7 +57,7 @@ . += "The supporting rods look like they could be welded." /obj/structure/catwalk/attackby(obj/item/C, mob/user, params) - if(C.tool_behaviour == TOOL_WELDER && !(resistance_flags & INDESTRUCTIBLE)) + if((C.tool_behaviour == TOOL_WELDER || C.tool_behaviour == TOOL_DECONSTRUCT) && !(resistance_flags & INDESTRUCTIBLE)) to_chat(user, "You slice off [src]") deconstruct() return diff --git a/code/game/objects/structures/crates_lockers/closets.dm b/code/game/objects/structures/crates_lockers/closets.dm index 7731bf48d2ff..cd1c880eae74 100644 --- a/code/game/objects/structures/crates_lockers/closets.dm +++ b/code/game/objects/structures/crates_lockers/closets.dm @@ -255,10 +255,24 @@ if(user in src) return if(src.tool_interact(W,user)) - return 1 // No afterattack + return TRUE // No afterattack else return ..() +/obj/structure/closet/proc/try_deconstruct(obj/item/W, mob/user) + if(W.tool_behaviour == cutting_tool || W.tool_behaviour == TOOL_DECONSTRUCT) + if(!W.tool_start_check(user, amount = 0)) + return + to_chat(user, span_notice("You begin cutting \the [src] apart...")) + if(W.use_tool(src, user, 40, volume = 50)) + if(!opened) + return + user.visible_message(span_notice("[user] slices apart \the [src]."), + span_notice("You cut \the [src] apart with \the [W]."), + span_hear("You hear welding.")) + deconstruct(TRUE) + return TRUE + /obj/structure/closet/proc/tool_interact(obj/item/W, mob/user)//returns TRUE if attackBy call shouldnt be continued (because tool was used/closet was of wrong type), FALSE if otherwise . = TRUE if(opened) @@ -300,6 +314,13 @@ user.visible_message("[user] [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \ "You [anchored ? "anchored" : "unanchored"] \the [src] [anchored ? "to" : "from"] the ground.", \ "You hear a ratchet.") + + else if(W.tool_behaviour == TOOL_DECONSTRUCT && locked) + user.visible_message("[user] is cutting \the [src] open !", "You begin to cut \the [src] open.") + if (W.use_tool(src, user, 10 SECONDS, volume=0)) + bust_open() + user.visible_message("[user] busted \the [src] open !", "You finish cutting \the [src] open.") + else if(user.a_intent != INTENT_HARM) var/item_is_id = W.GetID() if(!item_is_id) diff --git a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm index 7135b3d199a2..b0674a2d2b60 100644 --- a/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm +++ b/code/game/objects/structures/crates_lockers/closets/cardboardbox.dm @@ -20,6 +20,13 @@ var/move_delay = FALSE var/egged = 0 +/obj/structure/closet/cardboard/try_deconstruct(obj/item/W, mob/user) + if(W.tool_behaviour == cutting_tool) + user.visible_message(span_notice("[user] cut apart \the [src]."), \ + span_notice("You cut \the [src] apart with \the [W].")) + deconstruct(TRUE) + return TRUE + /obj/structure/closet/cardboard/relaymove(mob/living/user, direction) if(opened || move_delay || user.incapacitated() || !isturf(loc) || !has_gravity(loc)) return diff --git a/code/game/objects/structures/door_assembly.dm b/code/game/objects/structures/door_assembly.dm index 4246075e49f6..43052f1f0dbb 100644 --- a/code/game/objects/structures/door_assembly.dm +++ b/code/game/objects/structures/door_assembly.dm @@ -333,6 +333,14 @@ new mineral_path(T, 2) qdel(src) +/obj/structure/door_assembly/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if (I.use_tool(src, user, 3 SECONDS, volume=100)) + to_chat(user, "You slice [src] apart.") + deconstruct(FALSE) + return TRUE /obj/structure/door_assembly/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd) if(the_rcd.mode == RCD_DECONSTRUCT) diff --git a/code/game/objects/structures/false_walls.dm b/code/game/objects/structures/false_walls.dm index d5a8c3e496c1..48bf8817e1e7 100644 --- a/code/game/objects/structures/false_walls.dm +++ b/code/game/objects/structures/false_walls.dm @@ -107,9 +107,6 @@ else if(W.tool_behaviour == TOOL_WELDER) if(W.use_tool(src, user, 0, volume=50)) dismantle(user, TRUE) - else if(istype(W, /obj/item/pickaxe/drill/jackhammer)) - W.play_tool_sound(src) - dismantle(user, TRUE) else return ..() diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm index 362de185e9ba..df0d3cf1f43c 100644 --- a/code/game/objects/structures/girders.dm +++ b/code/game/objects/structures/girders.dm @@ -36,26 +36,7 @@ playsound(src, 'sound/machines/clockcult/integration_cog_install.ogg', 50, TRUE) add_fingerprint(user) - if(istype(W, /obj/item/gun/energy/plasmacutter)) - to_chat(user, "You start slicing apart the girder...") - if(W.use_tool(src, user, 10, volume=100)) - to_chat(user, "You slice apart the girder.") - var/obj/item/stack/sheet/metal/M = new (loc, 2) - M.add_fingerprint(user) - qdel(src) - - return - - else if(istype(W, /obj/item/pickaxe/drill/jackhammer)) - to_chat(user, "You smash through the girder!") - new /obj/item/stack/sheet/metal(get_turf(src)) - W.play_tool_sound(src) - qdel(src) - - return - - - else if(istype(W, /obj/item/stack)) + if(istype(W, /obj/item/stack)) if(iswallturf(loc)) to_chat(user, "There is already a wall present!") return @@ -231,6 +212,15 @@ else return ..() +/obj/structure/girder/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if(I.use_tool(src, user, 3 SECONDS, volume=0)) + to_chat(user, "You cut apart \the [src].", "You cut apart \the [src].") + deconstruct() + return TRUE + // Screwdriver behavior for girders /obj/structure/girder/screwdriver_act(mob/user, obj/item/tool) if(..()) @@ -373,13 +363,6 @@ transfer_fingerprints_to(R) qdel(src) - else if(istype(W, /obj/item/pickaxe/drill/jackhammer)) - to_chat(user, "Your jackhammer smashes through the girder!") - var/obj/item/stack/sheet/mineral/hidden/hellstone/R = new(drop_location(), 2) - transfer_fingerprints_to(R) - W.play_tool_sound(src) - qdel(src) - else if(istype(W, /obj/item/stack/sheet/mineral/hidden/hellstone)) var/obj/item/stack/sheet/mineral/hidden/hellstone/R = W if(R.get_amount() < 1) @@ -447,13 +430,6 @@ transfer_fingerprints_to(B) qdel(src) - else if(istype(W, /obj/item/pickaxe/drill/jackhammer)) - to_chat(user, "Your jackhammer smashes through the girder!") - var/obj/item/stack/tile/bronze/B = new(drop_location(), 2) - transfer_fingerprints_to(B) - W.play_tool_sound(src) - qdel(src) - else if(istype(W, /obj/item/stack/tile/bronze)) var/obj/item/stack/tile/bronze/B = W if(B.get_amount() < 2) diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm index 5bca53e84dd6..b1897ee661d4 100644 --- a/code/game/objects/structures/grille.dm +++ b/code/game/objects/structures/grille.dm @@ -227,6 +227,15 @@ qdel(src) ..() +/obj/structure/grille/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if (I.use_tool(src, user, 1 SECONDS, volume=100)) + to_chat(user, "You slice [src] apart.") + deconstruct(FALSE) + return TRUE + /obj/structure/grille/obj_break() if(!broken && !(flags_1 & NODECONSTRUCT_1)) new broken_type(src.loc) diff --git a/code/game/objects/structures/lattice.dm b/code/game/objects/structures/lattice.dm index 30999b58a620..9aaefb8c014e 100644 --- a/code/game/objects/structures/lattice.dm +++ b/code/game/objects/structures/lattice.dm @@ -40,6 +40,15 @@ var/turf/T = get_turf(src) return T.attackby(C, user) //hand this off to the turf instead (for building plating, catwalks, etc) +/obj/structure/lattice/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if(I.use_tool(src, user, 1 SECONDS, volume=0)) + to_chat(user, "You cut apart \the [src].", "You cut apart \the [src].") + deconstruct() + return TRUE + /obj/structure/lattice/deconstruct(disassembled = TRUE) if(!(flags_1 & NODECONSTRUCT_1)) new build_material(get_turf(src), number_of_mats) diff --git a/code/game/objects/structures/railings.dm b/code/game/objects/structures/railings.dm index 95c24145399f..d8f5c543a168 100644 --- a/code/game/objects/structures/railings.dm +++ b/code/game/objects/structures/railings.dm @@ -65,6 +65,15 @@ deconstruct() return TRUE +/obj/structure/railing/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if (I.use_tool(src, user, 3 SECONDS, volume=0)) + to_chat(user, "You cut apart the railing.") + deconstruct() + return TRUE + /obj/structure/railing/deconstruct(disassembled) . = ..() if(!loc) //quick check if it's qdeleted already. diff --git a/code/game/objects/structures/safe.dm b/code/game/objects/structures/safe.dm index 5f3e2914bc47..44a9f7f94717 100644 --- a/code/game/objects/structures/safe.dm +++ b/code/game/objects/structures/safe.dm @@ -75,6 +75,13 @@ FLOOR SAFES if(istype(I, /obj/item/clothing/neck/stethoscope)) attack_hand(user) return + + else if(I.tool_behaviour == TOOL_DECONSTRUCT) + user.visible_message("[user] begin to cut through the lock of \the [src].","You start cutting trough the lock of [src].") + if(I.use_tool(src, user, 60 SECONDS)) + broken = TRUE + user.visible_message("[user] successfully cuts trough the lock of \the [src].","You successfully cut trough the lock of [src].") + else to_chat(user, "You can't put [I] into the safe while it is closed!") return diff --git a/code/game/objects/structures/salvaging.dm b/code/game/objects/structures/salvaging.dm index dbd75dac488f..f4aad715db19 100644 --- a/code/game/objects/structures/salvaging.dm +++ b/code/game/objects/structures/salvaging.dm @@ -34,6 +34,16 @@ qdel(src) return TRUE +/obj/structure/salvageable/deconstruct_act(mob/living/user, obj/item/tool) + . = ..() + user.visible_message("[user] starts slicing [src].", \ + "You start salvaging anything useful from [src]...") + if(tool.use_tool(src, user, 6 SECONDS)) + user.visible_message("[user] dismantles [src].", \ + "You salvage [src].") + dismantle(user) + qdel(src) + return TRUE //Types themself, use them, but not the parent object diff --git a/code/game/objects/structures/tables_racks.dm b/code/game/objects/structures/tables_racks.dm index a7404ef68a6c..d5b1710b6296 100644 --- a/code/game/objects/structures/tables_racks.dm +++ b/code/game/objects/structures/tables_racks.dm @@ -162,7 +162,7 @@ /obj/structure/table/attackby(obj/item/I, mob/user, params) var/list/modifiers = params2list(params) if(!(flags_1 & NODECONSTRUCT_1) && user.a_intent != INTENT_HELP) - if(I.tool_behaviour == TOOL_SCREWDRIVER && deconstruction_ready) + if((I.tool_behaviour == TOOL_SCREWDRIVER) && deconstruction_ready) to_chat(user, "You start disassembling [src]...") if(I.use_tool(src, user, 20, volume=50)) deconstruct(TRUE) @@ -227,6 +227,15 @@ else return ..() +/obj/structure/table/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if (I.use_tool(src, user, 1 SECONDS, volume=0)) + to_chat(user, span_warning("You cut [src] into sheets.")) + deconstruct(wrench_disassembly = TRUE) + return TRUE + /obj/structure/table/proc/AfterPutItemOnTable(obj/item/I, mob/living/user) return diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm index 5420cc06b490..5064883c5de9 100644 --- a/code/game/objects/structures/window.dm +++ b/code/game/objects/structures/window.dm @@ -27,6 +27,7 @@ var/real_explosion_block //ignore this, just use explosion_block var/breaksound = "shatter" var/hitsound = 'sound/effects/Glasshit.ogg' + var/decon_time = 5 SECONDS flags_ricochet = RICOCHET_HARD ricochet_chance_mod = 0.4 @@ -289,6 +290,15 @@ qdel(src) update_nearby_icons() +/obj/structure/window/deconstruct_act(mob/living/user, obj/item/I) + . = ..() + if(!I.tool_start_check(user, amount=0)) + return FALSE + if (I.use_tool(src, user, decon_time, volume=100)) + to_chat(user, span_warning("You shatter [src] with the [I].")) + deconstruct(FALSE) + return TRUE + /obj/structure/window/proc/spawnDebris(location) . = list() . += new /obj/item/shard(location) @@ -399,6 +409,7 @@ glass_type = /obj/item/stack/sheet/rglass rad_insulation = RAD_HEAVY_INSULATION ricochet_chance_mod = 0.8 + decon_time = 20 SECONDS //this is shitcode but all of construction is shitcode and needs a refactor, it works for now //If you find this like 4 years later and construction still hasn't been refactored, I'm so sorry for this @@ -408,7 +419,7 @@ switch(state) if(RWINDOW_SECURE) - if(I.tool_behaviour == TOOL_WELDER && user.a_intent == INTENT_HARM) + if((I.tool_behaviour == TOOL_WELDER) && user.a_intent == INTENT_HARM) user.visible_message("[user] holds \the [I] to the security screws on \the [src]...", "You begin heating the security screws on \the [src]...") if(I.use_tool(src, user, 150, volume = 100)) @@ -531,6 +542,7 @@ damage_deflection = 11 //WS Edit - Weakens R-Windows explosion_block = 2 glass_type = /obj/item/stack/sheet/plasmarglass + decon_time = 25 SECONDS //entirely copypasted code //take this out when construction is made a component or otherwise modularized in some way @@ -746,6 +758,7 @@ glass_type = /obj/item/stack/sheet/plastitaniumglass glass_amount = 2 rad_insulation = RAD_HEAVY_INSULATION + decon_time = 30 SECONDS /obj/structure/window/plasma/reinforced/plastitanium/unanchored anchored = FALSE diff --git a/code/game/turfs/closed/_closed.dm b/code/game/turfs/closed/_closed.dm index 766d7e0e5a24..ea0c0d4ed4b1 100644 --- a/code/game/turfs/closed/_closed.dm +++ b/code/game/turfs/closed/_closed.dm @@ -269,6 +269,21 @@ return FALSE +/turf/closed/deconstruct_act(mob/living/user, obj/item/I) + var/act_duration = breakdown_duration + if(!I.tool_start_check(user, amount=0)) + return FALSE + to_chat(user, "You begin slicing through the outer plating...") + while(I.use_tool(src, user, act_duration, volume=100)) + if(iswallturf(src)) + to_chat(user, "You slice through some of the outer plating...") + if(!alter_integrity(-(I.wall_decon_damage),user,FALSE,TRUE)) + return TRUE + else + break + + return FALSE + /turf/closed/mech_melee_attack(obj/mecha/M) M.do_attack_animation(src) switch(M.damtype) diff --git a/code/modules/cargo/packs/tools.dm b/code/modules/cargo/packs/tools.dm index e4081a448e0b..36bfefc02796 100644 --- a/code/modules/cargo/packs/tools.dm +++ b/code/modules/cargo/packs/tools.dm @@ -111,6 +111,13 @@ crate_name = "tank transfer valve crate" crate_type = /obj/structure/closet/crate/secure/science +/datum/supply_pack/tools/anglegrinder + name = "Angle Grinder" + desc = "Contains one angle grinder pack, a tool used for quick structure deconstruction and salvaging" + cost = 2000 + contains = list(/obj/item/gear_pack/anglegrinder) + crate_name = "Angle Grinder" + /* Liquid tanks */ diff --git a/code/modules/mining/abandoned_crates.dm b/code/modules/mining/abandoned_crates.dm index caf01866a019..406259246db1 100644 --- a/code/modules/mining/abandoned_crates.dm +++ b/code/modules/mining/abandoned_crates.dm @@ -124,6 +124,10 @@ qdel(src) ..() +// No busting open (used to disallow angle grinder cheesing +/obj/structure/closet/crate/secure/loot/bust_open() + boom() + /obj/structure/closet/crate/secure/loot/proc/spawn_loot() var/loot = rand(1,100) //100 different crates with varying chances of spawning switch(loot) diff --git a/code/modules/mining/equipment/angle_grinder.dm b/code/modules/mining/equipment/angle_grinder.dm new file mode 100644 index 000000000000..290cf0d153d7 --- /dev/null +++ b/code/modules/mining/equipment/angle_grinder.dm @@ -0,0 +1,144 @@ +/obj/item/gear_pack/anglegrinder + name = "grinder pack" + desc = "Supplies the high voltage needed to run the attached grinder." + icon = 'icons/obj/item/gear_packs.dmi' + item_state = "anglegrinderpack" + icon_state = "anglegrinderpack" + lefthand_file = 'icons/mob/inhands/equipment/backpack_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/backpack_righthand.dmi' + gear_handle_type = /obj/item/gear_handle/anglegrinder + +/obj/item/gear_handle/anglegrinder + name = "angle grinder" + desc = "A powerful salvage tool used to cut apart walls and airlocks. A hazard sticker recommends ear and eye protection." + icon = 'icons/obj/item/gear_packs.dmi' + icon_state = "anglegrinder" + item_state = "anglegrinder" + lefthand_file = 'icons/mob/inhands/equipment/gear_handle_lefthand.dmi' + righthand_file = 'icons/mob/inhands/equipment/gear_handle_righthand.dmi' + flags_1 = CONDUCT_1 + force = 13 + armour_penetration = 5 + w_class = WEIGHT_CLASS_BULKY + item_flags = ABSTRACT + attack_verb = list("lacerated", "ripped", "sliced", "sawed", "cut", "chopped", "diced") + hitsound = 'sound/weapons/anglegrinder.ogg' + usesound = 'sound/weapons/anglegrinder.ogg' + tool_behaviour = null // is set to TOOL_DECONSTRUCT once wielded + toolspeed = 1 + wall_decon_damage = 200 + usecost = 5 + pack = /obj/item/gear_pack/anglegrinder + var/startsound = 'sound/weapons/chainsawhit.ogg' + var/adv = FALSE + var/wielded = FALSE // track wielded status on item + var/two_hand_force = 24 + +/obj/item/gear_handle/anglegrinder/tool_start_check(mob/living/user, amount) + if(!pack) + to_chat(user, "how do you not have a pack for this. what.") + return FALSE + if(!pack.cell) + to_chat(user, "You need a cell to start!") + return FALSE + var/obj/item/stock_parts/cell/cell = pack.get_cell() + if(cell.charge < usecost) + to_chat(user, "You need more charge to complete this task!") + return FALSE + return TRUE + +/obj/item/gear_handle/anglegrinder/tool_use_check(mob/living/user, amount) + if(!pack.cell) + return FALSE + if(pack.deductcharge(usecost)) + return TRUE + else + to_chat(user, "You need more charge to complete this task!") + return FALSE + +/obj/item/gear_handle/anglegrinder/use(used) + return TRUE + +/obj/item/gear_handle/anglegrinder/Initialize() + . = ..() + RegisterSignal(src, COMSIG_TWOHANDED_WIELD, PROC_REF(on_wield)) + RegisterSignal(src, COMSIG_TWOHANDED_UNWIELD, PROC_REF(on_unwield)) + +/obj/item/gear_handle/anglegrinder/ComponentInitialize() + . = ..() + AddComponent(/datum/component/butchering, 30, 100, 0, startsound, TRUE) + AddComponent(/datum/component/two_handed, force_unwielded=force, force_wielded=two_hand_force, wieldsound=startsound) + AddElement(/datum/element/tool_bang, 2) + +/// triggered on wield of two handed item +/obj/item/gear_handle/anglegrinder/proc/on_wield(obj/item/source, mob/user) + SIGNAL_HANDLER + + tool_behaviour = TOOL_DECONSTRUCT + wielded = TRUE + sharpness = IS_SHARP + icon_state = "[initial(item_state)]-wield" + item_state = "[initial(item_state)]-wield" + +/// triggered on unwield of two handed item +/obj/item/gear_handle/anglegrinder/proc/on_unwield(obj/item/source, mob/user) + SIGNAL_HANDLER + + tool_behaviour = null + wielded = FALSE + sharpness = initial(sharpness) + icon_state = initial(icon_state) + item_state = initial(item_state) + +/obj/item/gear_handle/anglegrinder/get_dismemberment_chance() + if(wielded) + . = ..() + +/obj/item/gear_handle/anglegrinder/use_tool(atom/target, mob/living/user, delay, amount=1, volume=0, datum/callback/extra_checks) + if(adv) + target.add_overlay(GLOB.advanced_cutting_effect) + . = ..() + target.cut_overlay(GLOB.advanced_cutting_effect) + else + target.add_overlay(GLOB.cutting_effect) + . = ..() + target.cut_overlay(GLOB.cutting_effect) + +/obj/item/gear_pack/anglegrinder/energy + name = "energy supply pack" + desc = "a highly inefficient GEC-E-014 Supply Pack, used to generate and contain an energy field." + item_state = "energyanglegrinderpack" + icon_state = "energyanglegrinderpack" + gear_handle_type = /obj/item/gear_handle/anglegrinder/energy + +/obj/item/gear_handle/anglegrinder/energy + name = "energy saw" + desc = "An early prototype for handheld energy weapons, designed by a joint GEC-Cybersun lab to create an energy field for combat use." + icon_state = "energyanglegrinder" + item_state = "energyanglegrinder" + force = 5 + two_hand_force = 28 + armour_penetration = 16 + w_class = WEIGHT_CLASS_BULKY + item_flags = ABSTRACT + attack_verb = list("lacerated", "ripped", "burned", "sliced", "cauterized", "seared", "diced") + hitsound = 'sound/weapons/blade1.ogg' + usesound = 'sound/weapons/blade1.ogg' + startsound = 'sound/weapons/saberon.ogg' + toolspeed = 0.7 + usecost = 10 + pack = /obj/item/gear_pack/anglegrinder/energy + light_system = MOVABLE_LIGHT + light_range = 3 + light_color = LIGHT_COLOR_ELECTRIC_GREEN + light_on = FALSE + adv = TRUE + +/obj/item/gear_handle/anglegrinder/energy/on_wield(obj/item/source, mob/user) + . = ..() + set_light_on(TRUE) + +/obj/item/gear_handle/anglegrinder/energy/on_unwield(obj/item/source, mob/user) + . = ..() + set_light_on(FALSE) + diff --git a/code/modules/projectiles/ammunition/energy/plasma.dm b/code/modules/projectiles/ammunition/energy/plasma.dm index 00de4a90ffee..d593086157fd 100644 --- a/code/modules/projectiles/ammunition/energy/plasma.dm +++ b/code/modules/projectiles/ammunition/energy/plasma.dm @@ -2,10 +2,9 @@ projectile_type = /obj/projectile/plasma select_name = "plasma burst" fire_sound = 'sound/weapons/plasma_cutter.ogg' - delay = 15 - e_cost = 25 + delay = 30 + e_cost = 100 /obj/item/ammo_casing/energy/plasma/adv projectile_type = /obj/projectile/plasma/adv - delay = 10 - e_cost = 10 + delay = 20 diff --git a/code/modules/projectiles/guns/energy/special.dm b/code/modules/projectiles/guns/energy/special.dm index c63c8358e2de..067a4bbc5d97 100644 --- a/code/modules/projectiles/guns/energy/special.dm +++ b/code/modules/projectiles/guns/energy/special.dm @@ -122,11 +122,12 @@ heat = 3800 usesound = list('sound/items/welder.ogg', 'sound/items/welder2.ogg') - tool_behaviour = TOOL_WELDER + tool_behaviour = TOOL_DECONSTRUCT wall_decon_damage = 200 - toolspeed = 0.7 //plasmacutters can be used as welders, and are faster than standard welders + toolspeed = 0.9 //plasmacutters can be used like angle grinders, and are a bit faster internal_cell = TRUE //so you don't cheese through the need for plasma - WS EDIT - var/charge_weld = 25 //amount of charge used up to start action (multiplied by amount) and per progress_flash_divisor ticks of welding + var/charge_cut = 100 //amount of charge used up to start action (multiplied by amount) and per progress_flash_divisor ticks of cutting + var/adv = FALSE /obj/item/gun/energy/plasmacutter/ComponentInitialize() . = ..() @@ -155,16 +156,16 @@ else ..() -// Can we weld? Plasma cutter does not use charge continuously. +// Can we cut? Plasma cutter does not use charge continuously. // Amount cannot be defaulted to 1: most of the code specifies 0 in the call. /obj/item/gun/energy/plasmacutter/tool_use_check(mob/living/user, amount) if(QDELETED(cell)) to_chat(user, "[src] does not have a cell, and cannot be used!") return FALSE - // Amount cannot be used if drain is made continuous, e.g. amount = 5, charge_weld = 25 + // Amount cannot be used if drain is made continuous, e.g. amount = 5, charge_cut = 25 // Then it'll drain 125 at first and 25 periodically, but fail if charge dips below 125 even though it still can finish action - // Alternately it'll need to drain amount*charge_weld every period, which is either obscene or makes it free for other uses - if(amount ? cell.charge < charge_weld * amount : cell.charge < charge_weld) + // Alternately it'll need to drain amount*charge_cut every period, which is either obscene or makes it free for other uses + if(amount ? cell.charge < charge_cut * amount : cell.charge < charge_cut) to_chat(user, "You need more charge to complete this task!") return FALSE @@ -186,13 +187,19 @@ return TRUE /obj/item/gun/energy/plasmacutter/use(amount) - return (!QDELETED(cell) && cell.use(amount ? amount * charge_weld : charge_weld)) + return (!QDELETED(cell) && cell.use(amount ? amount * charge_cut : charge_cut)) /obj/item/gun/energy/plasmacutter/use_tool(atom/target, mob/living/user, delay, amount=1, volume=0, datum/callback/extra_checks) if(amount) - target.add_overlay(GLOB.welding_sparks) + if(adv) + target.add_overlay(GLOB.advanced_cutting_effect) + else + target.add_overlay(GLOB.cutting_effect) . = ..() - target.cut_overlay(GLOB.welding_sparks) + if(adv) + target.cut_overlay(GLOB.advanced_cutting_effect) + else + target.cut_overlay(GLOB.cutting_effect) else . = ..(amount=1) @@ -201,11 +208,9 @@ icon_state = "adv_plasmacutter" item_state = "adv_plasmacutter" force = 15 + wall_decon_damage = 300 ammo_type = list(/obj/item/ammo_casing/energy/plasma/adv) - wall_decon_damage = 200 - toolspeed = 0.4 - /obj/item/gun/energy/wormhole_projector name = "bluespace wormhole projector" desc = "A projector that emits high density quantum-coupled bluespace beams." //WS Edit - Any anomaly core for phazons diff --git a/code/modules/projectiles/projectile/special/plasma.dm b/code/modules/projectiles/projectile/special/plasma.dm index d957ad924572..68071bd2c557 100644 --- a/code/modules/projectiles/projectile/special/plasma.dm +++ b/code/modules/projectiles/projectile/special/plasma.dm @@ -1,10 +1,10 @@ /obj/projectile/plasma name = "plasma blast" icon_state = "plasmacutter" - damage_type = BRUTE - damage = 5 + damage_type = BURN + damage = 15 range = 4 - dismemberment = 20 + dismemberment = 10 /// chance that the plasmablast ruins the ore var/slag_chance = 33 impact_effect_type = /obj/effect/temp_visual/impact_effect/purple_laser diff --git a/code/modules/surgery/organic_steps.dm b/code/modules/surgery/organic_steps.dm index 8959a7f99715..39fb1d71b258 100644 --- a/code/modules/surgery/organic_steps.dm +++ b/code/modules/surgery/organic_steps.dm @@ -152,13 +152,17 @@ implements = list( TOOL_SAW = 100, /obj/item/melee/axe/fire = 50, + /obj/item/gear_handle/anglegrinder = 50, /obj/item/melee/arm_blade = 40, /obj/item/hatchet = 40, /obj/item/melee/knife/butcher = 33, + /obj/item/gun/energy/plasmacutter = 30, /obj/item = 10) //10% success (sort of) with any sharp item with a force>=10 time = 5.4 SECONDS preop_sound = list( /obj/item/circular_saw = 'sound/surgery/saw.ogg', + /obj/item/gear_handle/anglegrinder = 'sound/surgery/saw.ogg', + /obj/item/gun/energy/plasmacutter = 'sound/weapons/plasma_cutter.ogg', /obj/item/melee/arm_blade = 'sound/surgery/scalpel1.ogg', /obj/item/melee/axe/fire = 'sound/surgery/scalpel1.ogg', /obj/item/hatchet = 'sound/surgery/scalpel1.ogg', diff --git a/icons/effects/cutting_effect.dmi b/icons/effects/cutting_effect.dmi new file mode 100644 index 000000000000..e8b4abeec5d0 Binary files /dev/null and b/icons/effects/cutting_effect.dmi differ diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi index 5e08a834a892..76549c15a3e0 100644 Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ diff --git a/icons/mob/clothing/back.dmi b/icons/mob/clothing/back.dmi index 5508bc67523c..fc00f899ed93 100644 Binary files a/icons/mob/clothing/back.dmi and b/icons/mob/clothing/back.dmi differ diff --git a/icons/mob/inhands/equipment/gear_handle_lefthand.dmi b/icons/mob/inhands/equipment/gear_handle_lefthand.dmi new file mode 100644 index 000000000000..169f91ce6eba Binary files /dev/null and b/icons/mob/inhands/equipment/gear_handle_lefthand.dmi differ diff --git a/icons/mob/inhands/equipment/gear_handle_righthand.dmi b/icons/mob/inhands/equipment/gear_handle_righthand.dmi new file mode 100644 index 000000000000..172f18e6095a Binary files /dev/null and b/icons/mob/inhands/equipment/gear_handle_righthand.dmi differ diff --git a/icons/obj/item/gear_packs.dmi b/icons/obj/item/gear_packs.dmi new file mode 100644 index 000000000000..76fb94bd4ff3 Binary files /dev/null and b/icons/obj/item/gear_packs.dmi differ diff --git a/icons/obj/mining.dmi b/icons/obj/mining.dmi index 337e3bf6d8da..efffc5cebb4a 100644 Binary files a/icons/obj/mining.dmi and b/icons/obj/mining.dmi differ diff --git a/shiptest.dme b/shiptest.dme index 7fdfccc47234..3c585e4a5bda 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -680,6 +680,7 @@ #include "code\datums\elements\selfknockback.dm" #include "code\datums\elements\snail_crawl.dm" #include "code\datums\elements\squish.dm" +#include "code\datums\elements\tool_bang.dm" #include "code\datums\elements\tool_flash.dm" #include "code\datums\elements\turf_transparency.dm" #include "code\datums\elements\undertile.dm" @@ -1187,6 +1188,7 @@ #include "code\game\objects\items\etherealdiscoball.dm" #include "code\game\objects\items\extinguisher.dm" #include "code\game\objects\items\flamethrower.dm" +#include "code\game\objects\items\gear_packs.dm" #include "code\game\objects\items\gift.dm" #include "code\game\objects\items\granters.dm" #include "code\game\objects\items\handcuffs.dm" @@ -2432,6 +2434,7 @@ #include "code\modules\mining\ores_coins.dm" #include "code\modules\mining\satchel_ore_boxdm.dm" #include "code\modules\mining\shelters.dm" +#include "code\modules\mining\equipment\angle_grinder.dm" #include "code\modules\mining\equipment\explorer_gear.dm" #include "code\modules\mining\equipment\kinetic_crusher.dm" #include "code\modules\mining\equipment\lazarus_injector.dm" diff --git a/sound/weapons/anglegrinder.ogg b/sound/weapons/anglegrinder.ogg new file mode 100644 index 000000000000..c0bc5b593a18 Binary files /dev/null and b/sound/weapons/anglegrinder.ogg differ