From f3fd10a0a4cc6a7a46e9d24236226747da4912ce Mon Sep 17 00:00:00 2001
From: HelmCrab <90987989+Thera-Pissed@users.noreply.github.com>
Date: Fri, 4 Oct 2024 15:49:09 -0500
Subject: [PATCH 01/16] TGUI pipe dispenser (#3464)
## About The Pull Request
Implements a tweaked UI from rapid pipe dispensers for normal
(obj/machinery/pipedispenser) dispensers
Pipe dispensers now have a 5ms delay on prints and can make disposals
and transport tubes.
Removes dispenser/disposals and dispenser/transport because they're
redundant now.
![image](https://github.com/user-attachments/assets/73a9bd7a-7d5d-49d2-a8f2-3313350ee4c8)
updates text2path regex to 115 from 117
updates non-bitwise << uses to 262 from 266
## Why It's Good For The Game
The old UI sucks and is laggy and bad.
## Changelog
:cl:
add: pipe dispenser UI is now similar to rapid pipe dispenser UI.
/:cl:
---------
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
---
.../independent/independent_junker.dmm | 2 +-
check_regex.yaml | 4 +-
code/game/machinery/pipe/pipe_dispenser.dm | 338 +++++++++---------
.../packages/tgui/interfaces/PipeDispenser.js | 193 ++++++++++
4 files changed, 362 insertions(+), 175 deletions(-)
create mode 100644 tgui/packages/tgui/interfaces/PipeDispenser.js
diff --git a/_maps/shuttles/independent/independent_junker.dmm b/_maps/shuttles/independent/independent_junker.dmm
index 7819d04ec1c2..0ae98ef37fe2 100644
--- a/_maps/shuttles/independent/independent_junker.dmm
+++ b/_maps/shuttles/independent/independent_junker.dmm
@@ -2284,7 +2284,6 @@
/turf/closed/wall/r_wall,
/area/ship/maintenance/port)
"Ro" = (
-/obj/machinery/pipedispenser/disposal,
/obj/item/reagent_containers/food/drinks/mug/tea{
pixel_y = 8;
pixel_x = -7
@@ -2305,6 +2304,7 @@
/obj/machinery/atmospherics/components/unary/vent_pump/on/layer2{
dir = 1
},
+/obj/machinery/pipedispenser,
/turf/open/floor/plating,
/area/ship/maintenance/central)
"RQ" = (
diff --git a/check_regex.yaml b/check_regex.yaml
index eadd642f0676..41174bd9aa22 100644
--- a/check_regex.yaml
+++ b/check_regex.yaml
@@ -31,14 +31,14 @@ standards:
- exactly: [4, "/mob text paths", '"/mob']
- exactly: [42, "/obj text paths", '"/obj']
- exactly: [0, "/turf text paths", '"/turf']
- - exactly: [117, "text2path uses", "text2path"]
+ - exactly: [115, "text2path uses", "text2path"]
- exactly: [18, "world<< uses", 'world[ \t]*<<']
- exactly: [0, "world.log<< uses", 'world.log[ \t]*<<']
- exactly:
[
- 266,
+ 262,
"non-bitwise << uses",
'(?--[piping_layer]++
"
-
- var/recipes = GLOB.atmos_pipe_recipes
-
- for(var/category in recipes)
- var/list/cat_recipes = recipes[category]
- dat += "[category]:
"
-
- for(var/i in cat_recipes)
- var/datum/pipe_info/I = i
- dat += I.Render(src)
-
- dat += "
"
-
- user << browse("[src][dat]", "window=pipedispenser")
- onclose(user, "pipedispenser")
- return
-
-/obj/machinery/pipedispenser/Topic(href, href_list)
- if(..())
- return 1
- var/mob/living/L = usr
- if(!anchored || (istype(L) && !(L.mobility_flags & MOBILITY_UI)) || usr.stat != CONSCIOUS || HAS_TRAIT(usr, TRAIT_HANDS_BLOCKED) || !in_range(loc, usr))
- usr << browse(null, "window=pipedispenser")
- return 1
- usr.set_machine(src)
- add_fingerprint(usr)
- if(href_list["makepipe"])
- if(wait < world.time)
- var/p_type = text2path(href_list["makepipe"])
- if (!verify_recipe(GLOB.atmos_pipe_recipes, p_type))
- return
- var/p_dir = text2num(href_list["dir"])
- var/obj/item/pipe/P = new (loc, p_type, p_dir)
- P.setPipingLayer(piping_layer)
- P.add_fingerprint(usr)
- wait = world.time + 10
- if(href_list["makemeter"])
- if(wait < world.time)
- new /obj/item/pipe_meter(loc)
- wait = world.time + 15
- if(href_list["layer_up"])
- piping_layer = clamp(++piping_layer, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
- if(href_list["layer_down"])
- piping_layer = clamp(--piping_layer, PIPING_LAYER_MIN, PIPING_LAYER_MAX)
- return
+ if(.)
+ return
+
+ if(!usr.canUseTopic(src, BE_CLOSE))
+ return
+ switch(action)
+ if("color")
+ paint_color = params["paint_color"]
+ if("category")
+ category = text2num(params["category"])
+ switch(category)
+ if(DISPOSALS_CATEGORY)
+ recipe = first_disposal
+ if(ATMOS_CATEGORY)
+ recipe = first_atmos
+ if(TRANSIT_CATEGORY)
+ recipe = first_transit
+ p_dir = NORTH
+ if("print")
+ make_pipe()
+ if("piping_layer")
+ piping_layer = text2num(params["piping_layer"])
+ if("ducting_layer")
+ ducting_layer = text2num(params["ducting_layer"])
+ if("pipe_type")
+ var/static/list/recipes
+ if(!recipes)
+ recipes = GLOB.disposal_pipe_recipes + GLOB.atmos_pipe_recipes + GLOB.transit_tube_recipes
+ recipe = recipes[params["category"]][text2num(params["pipe_type"])]
+ p_dir = NORTH
+ if("setdir")
+ p_dir = text2dir(params["dir"])
+ p_flipped = text2num(params["flipped"])
+ return TRUE
/obj/machinery/pipedispenser/attackby(obj/item/W, mob/user, params)
add_fingerprint(user)
@@ -70,15 +125,6 @@
else
return ..()
-/obj/machinery/pipedispenser/proc/verify_recipe(recipes, path)
- for(var/category in recipes)
- var/list/cat_recipes = recipes[category]
- for(var/i in cat_recipes)
- var/datum/pipe_info/info = i
- if (path == info.id)
- return TRUE
- return FALSE
-
/obj/machinery/pipedispenser/wrench_act(mob/living/user, obj/item/I)
..()
if(default_unfasten_wrench(user, I, 40))
@@ -96,129 +142,77 @@
default_deconstruction_crowbar(I)
return TRUE
-/obj/machinery/pipedispenser/disposal
- name = "disposal pipe dispenser"
- icon = 'icons/obj/stationobjs.dmi'
- icon_state = "pipe_d"
- desc = "Dispenses pipes that will ultimately be used to move trash around."
- density = TRUE
-
-
//Allow you to drag-drop disposal pipes and transit tubes into it
-/obj/machinery/pipedispenser/disposal/MouseDrop_T(obj/structure/pipe, mob/usr)
- if(!usr.incapacitated())
+/obj/machinery/pipedispenser/MouseDrop_T(obj/structure/pipe, mob/usr)
+ if(usr.incapacitated())
return
- if (!istype(pipe, /obj/structure/disposalconstruct) && !istype(pipe, /obj/structure/c_transit_tube) && !istype(pipe, /obj/structure/c_transit_tube_pod))
+ if(!istype(pipe, /obj/structure/disposalconstruct) && !istype(pipe, /obj/structure/c_transit_tube) && !istype(pipe, /obj/structure/c_transit_tube_pod))
return
- if (get_dist(usr, src) > 1 || get_dist(src,pipe) > 1)
+ if(get_dist(usr, src) > 1 || get_dist(src,pipe) > 1)
return
- if (pipe.anchored)
+ if(pipe.anchored)
return
qdel(pipe)
-/obj/machinery/pipedispenser/disposal/interact(mob/user)
-
- var/dat = ""
- var/recipes = GLOB.disposal_pipe_recipes
-
- for(var/category in recipes)
- var/list/cat_recipes = recipes[category]
- dat += "[category]:"
-
- for(var/i in cat_recipes)
- var/datum/pipe_info/I = i
- dat += I.Render(src)
-
- dat += "
"
-
- user << browse("[src][dat]", "window=pipedispenser")
- return
-
-
-/obj/machinery/pipedispenser/disposal/Topic(href, href_list)
- if(..())
- return 1
- usr.set_machine(src)
- add_fingerprint(usr)
- if(href_list["dmake"])
- if(wait < world.time)
- var/p_type = text2path(href_list["dmake"])
- if (!verify_recipe(GLOB.disposal_pipe_recipes, p_type))
- return
- var/obj/structure/disposalconstruct/C = new (loc, p_type)
-
- if(!C.can_place())
- to_chat(usr, "There's not enough room to build that here!")
- qdel(C)
- return
- if(href_list["dir"])
- C.setDir(text2num(href_list["dir"]))
- C.add_fingerprint(usr)
- C.update_appearance()
- wait = world.time + 15
- return
-
-//transit tube dispenser
-//inherit disposal for the dragging proc
-/obj/machinery/pipedispenser/disposal/transit_tube
- name = "transit tube dispenser"
- icon = 'icons/obj/stationobjs.dmi'
- icon_state = "pipe_d"
- density = TRUE
- desc = "Dispenses pipes that will move beings around."
-
-/obj/machinery/pipedispenser/disposal/transit_tube/interact(mob/user)
-
- var/dat = {"Transit Tubes:
-Straight Tube
-Straight Tube with Crossing
-Curved Tube
-Diagonal Tube
-Diagonal Tube with Crossing
-Junction
-Station Equipment:
-Through Tube Station
-Terminus Tube Station
-Transit Tube Pod
-"}
-
- user << browse("[src][dat]", "window=pipedispenser")
- return
-
-
-/obj/machinery/pipedispenser/disposal/transit_tube/Topic(href, href_list)
- if(..())
- return 1
- usr.set_machine(src)
- add_fingerprint(usr)
- if(wait < world.time)
- if(href_list["tube"])
- var/tube_type = text2num(href_list["tube"])
- var/obj/structure/C
- switch(tube_type)
- if(TRANSIT_TUBE_STRAIGHT)
- C = new /obj/structure/c_transit_tube(loc)
- if(TRANSIT_TUBE_STRAIGHT_CROSSING)
- C = new /obj/structure/c_transit_tube/crossing(loc)
- if(TRANSIT_TUBE_CURVED)
- C = new /obj/structure/c_transit_tube/curved(loc)
- if(TRANSIT_TUBE_DIAGONAL)
- C = new /obj/structure/c_transit_tube/diagonal(loc)
- if(TRANSIT_TUBE_DIAGONAL_CROSSING)
- C = new /obj/structure/c_transit_tube/diagonal/crossing(loc)
- if(TRANSIT_TUBE_JUNCTION)
- C = new /obj/structure/c_transit_tube/junction(loc)
- if(TRANSIT_TUBE_STATION)
- C = new /obj/structure/c_transit_tube/station(loc)
- if(TRANSIT_TUBE_TERMINUS)
- C = new /obj/structure/c_transit_tube/station/reverse(loc)
- if(TRANSIT_TUBE_POD)
- C = new /obj/structure/c_transit_tube_pod(loc)
- if(C)
- C.add_fingerprint(usr)
- wait = world.time + 15
- return
+/obj/machinery/pipedispenser/proc/make_pipe(mob/user)
+ if(busy)
+ src.visible_message(span_warning("[src] is busy."))
+ return
+ var/queued_p_type = recipe.id
+ var/queued_p_dir = p_dir
+ var/queued_p_flipped = p_flipped
+ switch(category)
+ if(ATMOS_CATEGORY)
+ if(recipe.type == /datum/pipe_info/meter)
+ new /obj/item/pipe_meter(loc)
+ on_make_pipe()
+ else
+ if(recipe.all_layers == FALSE && (piping_layer == 1 || piping_layer == 5))
+ src.visible_message(span_warning("[src] can't print this object on the layer..."))
+ return
+ var/obj/machinery/atmospherics/path = queued_p_type
+ var/pipe_item_type = initial(path.construction_type) || /obj/item/pipe
+ var/obj/item/pipe/P = new pipe_item_type(loc, queued_p_type, queued_p_dir)
+ on_make_pipe()
+
+ if(queued_p_flipped && istype(P, /obj/item/pipe/trinary/flippable))
+ var/obj/item/pipe/trinary/flippable/F = P
+ F.flipped = queued_p_flipped
+
+ P.update()
+ P.setPipingLayer(piping_layer)
+ if(ispath(path, /obj/machinery/atmospherics/pipe) && !findtext("[queued_p_type]", "layer_manifold"))
+ P.add_atom_colour(GLOB.pipe_paint_colors[paint_color], FIXED_COLOUR_PRIORITY)
+
+ if(DISPOSALS_CATEGORY) //Making disposals pipes
+ new /obj/structure/disposalconstruct(loc, queued_p_type, queued_p_dir, queued_p_flipped)
+ on_make_pipe()
+ return
+
+ if(TRANSIT_CATEGORY) //Making transit tubes
+ if(istype(queued_p_type, /obj/structure/c_transit_tube_pod))
+ new /obj/structure/c_transit_tube_pod(loc)
+ on_make_pipe()
+ else
+ var/obj/structure/c_transit_tube/tube = new queued_p_type(loc)
+ on_make_pipe()
+ tube.setDir(queued_p_dir)
+
+ if(queued_p_flipped)
+ tube.setDir(turn(queued_p_dir, 45))
+ tube.simple_rotate_flip()
+
+/obj/machinery/pipedispenser/proc/on_make_pipe()
+ busy = TRUE
+ delay = addtimer(CALLBACK(src, PROC_REF(reset_busy)), 5)
+
+/obj/machinery/pipedispenser/proc/reset_busy()
+ busy = FALSE
+
+#undef ATMOS_CATEGORY
+#undef DISPOSALS_CATEGORY
+#undef TRANSIT_CATEGORY
diff --git a/tgui/packages/tgui/interfaces/PipeDispenser.js b/tgui/packages/tgui/interfaces/PipeDispenser.js
new file mode 100644
index 000000000000..61798b67306a
--- /dev/null
+++ b/tgui/packages/tgui/interfaces/PipeDispenser.js
@@ -0,0 +1,193 @@
+import { classes } from 'common/react';
+import { useBackend, useLocalState } from '../backend';
+import {
+ Box,
+ Button,
+ ColorBox,
+ Flex,
+ LabeledList,
+ Section,
+ Tabs,
+} from '../components';
+import { Window } from '../layouts';
+
+const ROOT_CATEGORIES = ['Atmospherics', 'Disposals', 'Transit Tubes'];
+
+const ICON_BY_CATEGORY_NAME = {
+ 'Atmospherics': 'wrench',
+ 'Disposals': 'trash-alt',
+ 'Transit Tubes': 'bus',
+ 'Pipes': 'grip-lines',
+ 'Disposal Pipes': 'grip-lines',
+ 'Devices': 'microchip',
+ 'Heat Exchange': 'thermometer-half',
+ 'Station Equipment': 'microchip',
+};
+
+const PAINT_COLORS = {
+ grey: '#bbbbbb',
+ amethyst: '#a365ff',
+ blue: '#4466ff',
+ brown: '#b26438',
+ cyan: '#48eae8',
+ dark: '#808080',
+ green: '#1edd00',
+ orange: '#ffa030',
+ purple: '#b535ea',
+ red: '#ff3333',
+ violet: '#6e00f6',
+ yellow: '#ffce26',
+};
+
+export const PipeDispenser = (props, context) => {
+ const { act, data } = useBackend(context);
+ const {
+ category: rootCategoryIndex,
+ categories = [],
+ selected_color,
+ piping_layer,
+ mode,
+ } = data;
+ const previews = data.preview_rows.flatMap((row) => row.previews);
+ const [categoryName, setCategoryName] = useLocalState(
+ context,
+ 'categoryName'
+ );
+ const shownCategory =
+ categories.find((category) => category.cat_name === categoryName) ||
+ categories[0];
+ return (
+
+
+
+
+
+ {ROOT_CATEGORIES.map((categoryName, i) => (
+
+
+
+
+
+ {selected_color}
+
+ {Object.keys(PAINT_COLORS).map((colorName) => (
+
+ act('color', {
+ paint_color: colorName,
+ })
+ }
+ />
+ ))}
+
+
+
+
+
+
+ {rootCategoryIndex === 0 && (
+
+ {[1, 2, 3, 4, 5].map((layer) => (
+
+ act('piping_layer', {
+ piping_layer: layer,
+ })
+ }
+ />
+ ))}
+
+ )}
+
+ {previews.map((preview) => (
+
+ ))}
+
+
+
+
+
+
+ {categories.map((category, i) => (
+ setCategoryName(category.cat_name)}
+ >
+ {category.cat_name}
+
+ ))}
+
+ {shownCategory?.recipes.map((recipe) => (
+
+ act('pipe_type', {
+ pipe_type: recipe.pipe_index,
+ category: shownCategory.cat_name,
+ })
+ }
+ />
+ ))}
+
+
+
+
+
+ );
+};
From 99d997dd367af9432197796edd1f8951c6f7f4a8 Mon Sep 17 00:00:00 2001
From: Changelogs
Date: Fri, 4 Oct 2024 16:00:11 -0500
Subject: [PATCH 02/16] Automatic changelog generation for PR #3464 [ci skip]
---
html/changelogs/AutoChangeLog-pr-3464.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-3464.yml
diff --git a/html/changelogs/AutoChangeLog-pr-3464.yml b/html/changelogs/AutoChangeLog-pr-3464.yml
new file mode 100644
index 000000000000..766a414f4cd5
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3464.yml
@@ -0,0 +1,4 @@
+author: Thera-Pissed
+changes:
+ - {rscadd: pipe dispenser UI is now similar to rapid pipe dispenser UI.}
+delete-after: true
From 34170c1ab1a4e6f27f4e98549997611610cd2c0b Mon Sep 17 00:00:00 2001
From: Changelogs
Date: Sat, 5 Oct 2024 01:01:27 +0000
Subject: [PATCH 03/16] Automatic changelog compile [ci skip]
---
html/changelogs/AutoChangeLog-pr-3382.yml | 7 -------
html/changelogs/AutoChangeLog-pr-3442.yml | 4 ----
html/changelogs/AutoChangeLog-pr-3452.yml | 6 ------
html/changelogs/AutoChangeLog-pr-3464.yml | 4 ----
html/changelogs/AutoChangeLog-pr-3466.yml | 4 ----
html/changelogs/AutoChangeLog-pr-3468.yml | 7 -------
html/changelogs/AutoChangeLog-pr-3473.yml | 4 ----
html/changelogs/AutoChangeLog-pr-3476.yml | 4 ----
html/changelogs/archive/2024-10.yml | 25 +++++++++++++++++++++++
9 files changed, 25 insertions(+), 40 deletions(-)
delete mode 100644 html/changelogs/AutoChangeLog-pr-3382.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-3442.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-3452.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-3464.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-3466.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-3468.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-3473.yml
delete mode 100644 html/changelogs/AutoChangeLog-pr-3476.yml
diff --git a/html/changelogs/AutoChangeLog-pr-3382.yml b/html/changelogs/AutoChangeLog-pr-3382.yml
deleted file mode 100644
index eedebb40d990..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3382.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: Gristlebee, Rye-Rice, INFRARED_BARON
-changes:
- - {rscadd: Inteq Gygax and mech charges}
- - {rscadd: Paladin shield backlash}
- - {bugfix: Durand shield blocking all projectiles}
- - {imageadd: Inteq Gygax sprites}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3442.yml b/html/changelogs/AutoChangeLog-pr-3442.yml
deleted file mode 100644
index 93368cdd5e5a..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3442.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: zimon9
-changes:
- - {bugfix: fixed the waste and scrubber gas reclamation filters on the colossus}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3452.yml b/html/changelogs/AutoChangeLog-pr-3452.yml
deleted file mode 100644
index 227901e38429..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3452.yml
+++ /dev/null
@@ -1,6 +0,0 @@
-author: Jedi-Toothpaste
-changes:
- - {rscadd: Added extra intercoms in high traffic areas on the Valor Class}
- - {rscadd: Added Firelocks underneath the Cargo-Bay Doors on the Valor Class}
- - {rscadd: 'Air Alarms, Scrubbers and Vents to every applicable room'}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3464.yml b/html/changelogs/AutoChangeLog-pr-3464.yml
deleted file mode 100644
index 766a414f4cd5..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3464.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: Thera-Pissed
-changes:
- - {rscadd: pipe dispenser UI is now similar to rapid pipe dispenser UI.}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3466.yml b/html/changelogs/AutoChangeLog-pr-3466.yml
deleted file mode 100644
index d35081929039..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3466.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: generalthrax
-changes:
- - {balance: Replace red insuls with yellow insuls in syndicate toolboxes}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3468.yml b/html/changelogs/AutoChangeLog-pr-3468.yml
deleted file mode 100644
index a0130e2f3b75..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3468.yml
+++ /dev/null
@@ -1,7 +0,0 @@
-author: Bjarl
-changes:
- - {rscadd: A cargo ship happened to lose an entire crate of Hammer Rocket Launchers
- while travelling through the system. We have reason to believe they're probably
- on sale now.}
- - {rscdel: you can no longer purchase PML-9s on the black market.}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3473.yml b/html/changelogs/AutoChangeLog-pr-3473.yml
deleted file mode 100644
index 6ef0f09fd71e..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3473.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: PositiveEntropy
-changes:
- - {imageadd: Waste Planet Turfs Now Look Much More Refined!}
-delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3476.yml b/html/changelogs/AutoChangeLog-pr-3476.yml
deleted file mode 100644
index 51594996de27..000000000000
--- a/html/changelogs/AutoChangeLog-pr-3476.yml
+++ /dev/null
@@ -1,4 +0,0 @@
-author: MemeSnorfer
-changes:
- - {rscadd: 'Three new Elzuose horn types. Cervid, Prong, and Brow'}
-delete-after: true
diff --git a/html/changelogs/archive/2024-10.yml b/html/changelogs/archive/2024-10.yml
index 7dff4c0f36d5..2055dcb1e4c0 100644
--- a/html/changelogs/archive/2024-10.yml
+++ b/html/changelogs/archive/2024-10.yml
@@ -24,3 +24,28 @@
2024-10-03:
Bjarl:
- bugfix: defibs now work again.
+2024-10-05:
+ Bjarl:
+ - rscadd: A cargo ship happened to lose an entire crate of Hammer Rocket Launchers
+ while travelling through the system. We have reason to believe they're probably
+ on sale now.
+ - rscdel: you can no longer purchase PML-9s on the black market.
+ Gristlebee, Rye-Rice, INFRARED_BARON:
+ - rscadd: Inteq Gygax and mech charges
+ - rscadd: Paladin shield backlash
+ - bugfix: Durand shield blocking all projectiles
+ - imageadd: Inteq Gygax sprites
+ Jedi-Toothpaste:
+ - rscadd: Added extra intercoms in high traffic areas on the Valor Class
+ - rscadd: Added Firelocks underneath the Cargo-Bay Doors on the Valor Class
+ - rscadd: Air Alarms, Scrubbers and Vents to every applicable room
+ MemeSnorfer:
+ - rscadd: Three new Elzuose horn types. Cervid, Prong, and Brow
+ PositiveEntropy:
+ - imageadd: Waste Planet Turfs Now Look Much More Refined!
+ Thera-Pissed:
+ - rscadd: pipe dispenser UI is now similar to rapid pipe dispenser UI.
+ generalthrax:
+ - balance: Replace red insuls with yellow insuls in syndicate toolboxes
+ zimon9:
+ - bugfix: fixed the waste and scrubber gas reclamation filters on the colossus
From 8ad1a719bfb5df4f3994870399246c994c0a0649 Mon Sep 17 00:00:00 2001
From: Apogee-dev <60533805+Apogee-dev@users.noreply.github.com>
Date: Fri, 4 Oct 2024 20:39:43 -0700
Subject: [PATCH 04/16] Shaves the Vaquero (#3438)
## About The Pull Request
Snips one recruit slot off of the Vaquero
## Why It's Good For The Game
thgvr request, also the vaq's genuinely overpopped. two
recruits/deckhands is a handful even on a bigger ship, the vaq doesnt
need a third of its crew to not know what they're doing
## Changelog
:cl:
balance: removed one recruit slot from the vaquero
/:cl:
---
_maps/configs/inteq_vaquero.json | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/_maps/configs/inteq_vaquero.json b/_maps/configs/inteq_vaquero.json
index 232562369a3d..2b0bed8bfe98 100644
--- a/_maps/configs/inteq_vaquero.json
+++ b/_maps/configs/inteq_vaquero.json
@@ -39,7 +39,7 @@
},
"Recruit": {
"outfit": "/datum/outfit/job/inteq/assistant",
- "slots": 2
+ "slots": 1
}
},
"enabled": true
From b5370df08612779732c9ccb8722a3daf63cfc048 Mon Sep 17 00:00:00 2001
From: Changelogs
Date: Fri, 4 Oct 2024 22:50:54 -0500
Subject: [PATCH 05/16] Automatic changelog generation for PR #3438 [ci skip]
---
html/changelogs/AutoChangeLog-pr-3438.yml | 4 ++++
1 file changed, 4 insertions(+)
create mode 100644 html/changelogs/AutoChangeLog-pr-3438.yml
diff --git a/html/changelogs/AutoChangeLog-pr-3438.yml b/html/changelogs/AutoChangeLog-pr-3438.yml
new file mode 100644
index 000000000000..f446f6f0d204
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3438.yml
@@ -0,0 +1,4 @@
+author: Apogee-dev
+changes:
+ - {balance: removed one recruit slot from the vaquero}
+delete-after: true
From dd08ffa6609590363497fca01e67aa0bd3a1b10b Mon Sep 17 00:00:00 2001
From: HelmCrab <90987989+Thera-Pissed@users.noreply.github.com>
Date: Fri, 4 Oct 2024 22:42:01 -0500
Subject: [PATCH 06/16] Angle grinder AGAIN! Also, makes plasma cutters used
for salvage instead of mining (and base gearpacks) (#3146)
## About The Pull Request
re-implements #1716 as a base and adds cutter functionality to plasma
cutters
also implements and uses gear packs from #2103 that never got in.
makes plasma cutters unable to mine, shorter range, and do burn instead
of brute.
angle grinders are integrated into grinder packs, like water backtanks.
Also draws power from a cell.
jackhammers can no longer break down walls and girders.
### Cutters can currently deconstruct:
- girders
- walls
- reinforced walls
- airlocks
- airlock frames
- grilles
- machine frames
- computer frames
- catwalks
- chairs
- beds
- tables
- lockers & crates
- salvage machines (the wasteplanet ones)
- railings
- lattice
- wooden barricades
cutters can also cut open safes and locked lockers & crates
attempted to revert map changes but using git checkout doesn't
completely revert the gecko. Will try again later.
adds a mech salvage saw and a prototype energy saw. Doesn't make either
available yet.
sprites by me
![image](https://github.com/shiptest-ss13/Shiptest/assets/90987989/65bd6b99-d63d-4c75-9227-a9987fddf9d2)
https://github.com/shiptest-ss13/Shiptest/assets/90987989/12262338-055f-4c7c-86d1-d31279ab953c
## Why It's Good For The Game
Jackhammers as a main salvage tool is dumb, and angle grinders and
cutters make more sense and have better functionality. Cutting apart old
ruins and ships should be a reasonable source of material and shouldn't
take years.
## Changelog
:cl:
add: angle grinders for salvage
add: reworks plasma cutters for salvage
/:cl:
---------
Signed-off-by: HelmCrab <90987989+Thera-Pissed@users.noreply.github.com>
Co-authored-by: ritorizo
Co-authored-by: FalloutFalcon
Co-authored-by: FalloutFalcon <86381784+FalloutFalcon@users.noreply.github.com>
---
code/__DEFINES/dcs/signals/signals.dm | 2 +
code/__DEFINES/tools.dm | 1 +
code/datums/action.dm | 3 +
code/datums/components/twohanded.dm | 4 +-
code/datums/elements/tool_bang.dm | 40 +++
code/game/atoms.dm | 6 +
code/game/machinery/constructable_frame.dm | 12 +-
code/game/machinery/deployable.dm | 8 +
code/game/machinery/doors/airlock.dm | 15 +
code/game/mecha/equipment/tools/work_tools.dm | 80 +++++
code/game/mecha/mecha.dm | 3 +
code/game/objects/items.dm | 4 +
code/game/objects/items/gear_packs.dm | 285 ++++++++++++++++++
.../objects/structures/beds_chairs/bed.dm | 2 +-
.../objects/structures/beds_chairs/chair.dm | 2 +-
code/game/objects/structures/catwalk.dm | 2 +-
.../structures/crates_lockers/closets.dm | 23 +-
.../crates_lockers/closets/cardboardbox.dm | 7 +
code/game/objects/structures/door_assembly.dm | 8 +
code/game/objects/structures/false_walls.dm | 3 -
code/game/objects/structures/girders.dm | 44 +--
code/game/objects/structures/grille.dm | 9 +
code/game/objects/structures/lattice.dm | 9 +
code/game/objects/structures/railings.dm | 9 +
code/game/objects/structures/safe.dm | 7 +
code/game/objects/structures/salvaging.dm | 10 +
code/game/objects/structures/tables_racks.dm | 11 +-
code/game/objects/structures/window.dm | 15 +-
code/game/turfs/closed/_closed.dm | 15 +
code/modules/cargo/packs/tools.dm | 7 +
code/modules/mining/abandoned_crates.dm | 4 +
.../modules/mining/equipment/angle_grinder.dm | 144 +++++++++
.../projectiles/ammunition/energy/plasma.dm | 7 +-
.../projectiles/guns/energy/special.dm | 31 +-
.../projectiles/projectile/special/plasma.dm | 6 +-
code/modules/surgery/organic_steps.dm | 4 +
icons/effects/cutting_effect.dmi | Bin 0 -> 1628 bytes
icons/mecha/mecha_equipment.dmi | Bin 22898 -> 23410 bytes
icons/mob/clothing/back.dmi | Bin 132854 -> 134924 bytes
.../equipment/gear_handle_lefthand.dmi | Bin 0 -> 2222 bytes
.../equipment/gear_handle_righthand.dmi | Bin 0 -> 2130 bytes
icons/obj/item/gear_packs.dmi | Bin 0 -> 3311 bytes
icons/obj/mining.dmi | Bin 65510 -> 66610 bytes
shiptest.dme | 3 +
sound/weapons/anglegrinder.ogg | Bin 0 -> 63533 bytes
45 files changed, 778 insertions(+), 67 deletions(-)
create mode 100644 code/datums/elements/tool_bang.dm
create mode 100644 code/game/objects/items/gear_packs.dm
create mode 100644 code/modules/mining/equipment/angle_grinder.dm
create mode 100644 icons/effects/cutting_effect.dmi
create mode 100644 icons/mob/inhands/equipment/gear_handle_lefthand.dmi
create mode 100644 icons/mob/inhands/equipment/gear_handle_righthand.dmi
create mode 100644 icons/obj/item/gear_packs.dmi
create mode 100644 sound/weapons/anglegrinder.ogg
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 0000000000000000000000000000000000000000..e8b4abeec5d087d5859cfd4243b70eb771f8a4fe
GIT binary patch
literal 1628
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
Ji9tcDNlKLX7
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