diff --git a/_maps/configs/independent_kilo.json b/_maps/configs/independent_kilo.json
index 0890ba4a9cef..9ff4ccfbf191 100644
--- a/_maps/configs/independent_kilo.json
+++ b/_maps/configs/independent_kilo.json
@@ -31,7 +31,7 @@
},
"Deckhand": {
"outfit": "/datum/outfit/job/independent/assistant",
- "slots": 2
+ "slots": 1
}
},
"enabled": true
diff --git a/_maps/configs/independent_mudskipper.json b/_maps/configs/independent_mudskipper.json
index 8db7b5668e03..469230d752a3 100644
--- a/_maps/configs/independent_mudskipper.json
+++ b/_maps/configs/independent_mudskipper.json
@@ -15,7 +15,7 @@
"SPACE"
],
"map_path": "_maps/shuttles/independent/independent_mudskipper.dmm",
- "limit": 1,
+ "limit": 2,
"starting_funds": 1500,
"job_slots": {
"Salvage Leader": {
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
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/_maps/shuttles/inteq/inteq_colossus.dmm b/_maps/shuttles/inteq/inteq_colossus.dmm
index 482d6999b28c..74ac142692c6 100644
--- a/_maps/shuttles/inteq/inteq_colossus.dmm
+++ b/_maps/shuttles/inteq/inteq_colossus.dmm
@@ -653,9 +653,9 @@
/turf/open/floor/plasteel/telecomms_floor,
/area/ship/bridge)
"gH" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 6;
- id = "colossus_grid"
+/obj/machinery/porta_turret/ship/inteq{
+ id = "colossus_grid";
+ dir = 4
},
/turf/closed/wall/mineral/plastitanium/nodiagonal,
/area/ship/crew)
@@ -1138,9 +1138,9 @@
/turf/open/floor/plasteel/patterned/grid,
/area/ship/hallway/fore)
"mb" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 5;
- id = "colossus_grid"
+/obj/machinery/porta_turret/ship/inteq/light{
+ id = "colossus_grid";
+ dir = 5
},
/turf/closed/wall/mineral/plastitanium/nodiagonal,
/area/ship/hallway/port)
@@ -1734,9 +1734,9 @@
/turf/open/floor/plasteel/dark,
/area/ship/crew/office)
"sT" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 5;
- id = "colossus_grid"
+/obj/machinery/porta_turret/ship/inteq/light{
+ id = "colossus_grid";
+ dir = 5
},
/turf/closed/wall/mineral/plastitanium,
/area/ship/crew)
@@ -2068,9 +2068,9 @@
/turf/closed/wall/mineral/plastitanium/nodiagonal,
/area/ship/cargo)
"vJ" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 5;
- id = "colossus_grid"
+/obj/machinery/porta_turret/ship/inteq{
+ id = "colossus_grid";
+ dir = 5
},
/turf/closed/wall/mineral/plastitanium,
/area/ship/maintenance/port)
@@ -2442,9 +2442,9 @@
/turf/open/floor/plating,
/area/ship/maintenance/port)
"Bi" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 9;
- id = "colossus_grid"
+/obj/machinery/porta_turret/ship/inteq{
+ id = "colossus_grid";
+ dir = 9
},
/turf/closed/wall/mineral/plastitanium/nodiagonal,
/area/ship/crew/office)
@@ -3320,8 +3320,9 @@
/turf/closed/wall/mineral/plastitanium/nodiagonal,
/area/ship/security/armory)
"Ll" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 5
+/obj/machinery/porta_turret/ship/inteq{
+ id = "colossus_grid";
+ dir = 4
},
/turf/closed/wall/mineral/plastitanium/nodiagonal,
/area/ship/bridge)
@@ -3557,7 +3558,8 @@
/turf/open/floor/plasteel/patterned,
/area/ship/cargo)
"Oa" = (
-/obj/machinery/porta_turret/ship/ballistic{
+/obj/machinery/porta_turret/ship/inteq/light{
+ id = "colossus_grid";
dir = 6
},
/turf/closed/wall/mineral/plastitanium,
@@ -3630,9 +3632,9 @@
/turf/open/floor/engine/hull/reinforced,
/area/ship/maintenance/starboard)
"OI" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 6;
- id = "colossus_grid"
+/obj/machinery/porta_turret/ship/inteq{
+ id = "colossus_grid";
+ dir = 6
},
/turf/closed/wall/mineral/plastitanium,
/area/ship/maintenance/starboard)
@@ -3790,9 +3792,9 @@
/turf/open/floor/plating,
/area/ship/maintenance/starboard)
"Qw" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 10;
- id = "colossus_grid"
+/obj/machinery/porta_turret/ship/inteq{
+ id = "colossus_grid";
+ dir = 10
},
/turf/closed/wall/mineral/plastitanium/nodiagonal,
/area/ship/security/armory)
@@ -3944,9 +3946,9 @@
/turf/open/floor/plasteel/patterned/cargo_one,
/area/ship/cargo)
"RZ" = (
-/obj/machinery/porta_turret/ship/ballistic{
- dir = 6;
- id = "colossus_grid"
+/obj/machinery/porta_turret/ship/inteq/light{
+ id = "talos_grid";
+ dir = 6
},
/turf/closed/wall/mineral/plastitanium,
/area/ship/security)
diff --git a/_maps/shuttles/inteq/inteq_talos.dmm b/_maps/shuttles/inteq/inteq_talos.dmm
index 6b05aa78caaa..2ab9a9405507 100644
--- a/_maps/shuttles/inteq/inteq_talos.dmm
+++ b/_maps/shuttles/inteq/inteq_talos.dmm
@@ -103,7 +103,7 @@
/turf/open/floor/circuit/telecomms/mainframe,
/area/ship/engineering/communications)
"aC" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 5;
id = "talos_grid"
},
@@ -849,7 +849,7 @@
/turf/open/floor/plating/airless,
/area/ship/storage/port)
"fs" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 5;
id = "talos_grid"
},
@@ -2689,14 +2689,14 @@
/turf/open/floor/plasteel/tech/grid,
/area/ship/crew/cryo)
"qt" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 6;
id = "talos_grid"
},
/turf/closed/wall/mineral/plastitanium,
/area/ship/maintenance/starboard)
"qz" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 5;
id = "talos_grid"
},
@@ -4556,9 +4556,9 @@
/turf/open/floor/plasteel/grimy,
/area/ship/crew)
"Cr" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 9;
- id = "talos_grid"
+/obj/machinery/porta_turret/ship/inteq/light{
+ id = "talos_grid";
+ dir = 9
},
/turf/closed/wall/mineral/plastitanium,
/area/ship/engineering/communications)
@@ -4821,7 +4821,7 @@
autolinkers = list("hub","processor4","bus");
network = "irmg_commnet"
},
-/turf/open/floor/circuit/telecomms/mainframe,
+/turf/closed/wall/mineral/plastitanium,
/area/ship/engineering/communications)
"Ep" = (
/obj/item/trash/can,
@@ -4853,9 +4853,9 @@
/turf/open/floor/plasteel/telecomms_floor,
/area/ship/engineering/communications)
"ED" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 10;
- id = "talos_grid"
+/obj/machinery/porta_turret/ship/inteq/light{
+ id = "talos_grid";
+ dir = 10
},
/turf/closed/wall/mineral/plastitanium,
/area/ship/storage)
@@ -6624,7 +6624,7 @@
/turf/open/floor/plasteel/telecomms_floor,
/area/ship/engineering/communications)
"Rf" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 6;
id = "talos_grid"
},
@@ -7491,7 +7491,7 @@
/turf/open/floor/plating,
/area/ship/engineering/engine)
"WN" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 6;
id = "talos_grid"
},
diff --git a/_maps/shuttles/inteq/inteq_vaquero.dmm b/_maps/shuttles/inteq/inteq_vaquero.dmm
index 336bf5792208..92e024ba7bf6 100644
--- a/_maps/shuttles/inteq/inteq_vaquero.dmm
+++ b/_maps/shuttles/inteq/inteq_vaquero.dmm
@@ -1933,7 +1933,7 @@
/turf/open/floor/plasteel/dark,
/area/ship/security)
"DT" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 6;
id = "vaquero_grid"
},
@@ -2027,7 +2027,7 @@
/turf/open/floor/plasteel/dark,
/area/ship/crew/office)
"Fm" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 5;
id = "vaquero_grid"
},
@@ -2523,7 +2523,7 @@
/turf/open/floor/plasteel/patterned/grid,
/area/ship/hallway/central)
"NO" = (
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 6;
id = "vaquero_grid"
},
@@ -2957,7 +2957,7 @@
port_direction = 8;
preferred_direction = 4
},
-/obj/machinery/porta_turret/ship/weak{
+/obj/machinery/porta_turret/ship/inteq{
dir = 5;
id = "vaquero_grid"
},
diff --git a/_maps/shuttles/nanotrasen/nanotrasen_delta.dmm b/_maps/shuttles/nanotrasen/nanotrasen_delta.dmm
index 00967afb927e..351e8e2df037 100644
--- a/_maps/shuttles/nanotrasen/nanotrasen_delta.dmm
+++ b/_maps/shuttles/nanotrasen/nanotrasen_delta.dmm
@@ -1371,9 +1371,9 @@
/turf/open/floor/plasteel/tech/techmaint,
/area/ship/engineering)
"jH" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 9;
- id = "delta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "delta_grid";
+ dir = 9
},
/turf/closed/wall/mineral/titanium,
/area/ship/bridge)
@@ -2891,9 +2891,9 @@
/turf/open/floor/plasteel/white,
/area/ship/science/robotics)
"WG" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 4;
- id = "delta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "delta_grid";
+ dir = 4
},
/turf/closed/wall/mineral/titanium,
/area/ship/bridge)
@@ -3018,9 +3018,9 @@
/turf/open/floor/plasteel/white,
/area/ship/science/robotics)
"YZ" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 10;
- id = "delta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "delta_grid";
+ dir = 10
},
/turf/closed/wall/mineral/titanium,
/area/ship/bridge)
diff --git a/_maps/shuttles/nanotrasen/nanotrasen_meta.dmm b/_maps/shuttles/nanotrasen/nanotrasen_meta.dmm
index eaf4abc2b9b3..95b61c204b54 100644
--- a/_maps/shuttles/nanotrasen/nanotrasen_meta.dmm
+++ b/_maps/shuttles/nanotrasen/nanotrasen_meta.dmm
@@ -1680,9 +1680,10 @@
/turf/open/floor/plating,
/area/ship/cargo)
"jo" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 4;
- id = "meta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "meta_grid";
+ pixel_y = 0;
+ dir = 4
},
/turf/closed/wall/mineral/titanium,
/area/ship/crew)
@@ -2206,9 +2207,10 @@
/turf/open/floor/plasteel/dark,
/area/ship/cargo)
"uT" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 4;
- id = "meta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "meta_grid";
+ pixel_y = 0;
+ dir = 4
},
/turf/closed/wall/mineral/titanium,
/area/ship/crew/canteen/kitchen)
@@ -2399,9 +2401,10 @@
/turf/open/floor/plasteel,
/area/ship/crew/canteen/kitchen)
"yF" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 1;
- id = "meta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "meta_grid";
+ pixel_y = 0;
+ dir = 5
},
/turf/closed/wall/mineral/titanium,
/area/ship/engineering)
@@ -3079,9 +3082,10 @@
/turf/open/floor/plating,
/area/ship/engineering)
"Lo" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 2;
- id = "meta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "meta_grid";
+ pixel_y = 0;
+ dir = 6
},
/turf/closed/wall/mineral/titanium,
/area/ship/engineering)
@@ -3480,16 +3484,18 @@
/turf/open/floor/plasteel/dark,
/area/ship/cargo)
"TR" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 2;
- id = "meta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "meta_grid";
+ pixel_y = 0;
+ dir = 10
},
/turf/closed/wall/mineral/titanium,
/area/ship/crew/canteen)
"TV" = (
-/obj/machinery/porta_turret/ship/weak{
- dir = 1;
- id = "meta_grid"
+/obj/machinery/porta_turret/ship/nt/light{
+ id = "meta_grid";
+ pixel_y = 0;
+ dir = 9
},
/turf/closed/wall/mineral/titanium,
/area/ship/crew)
diff --git a/_maps/shuttles/subshuttles/inteq_anvil.dmm b/_maps/shuttles/subshuttles/inteq_anvil.dmm
index 002ddfe6d0d3..61d7946fb794 100644
--- a/_maps/shuttles/subshuttles/inteq_anvil.dmm
+++ b/_maps/shuttles/subshuttles/inteq_anvil.dmm
@@ -191,14 +191,6 @@
"w" = (
/turf/template_noop,
/area/template_noop)
-"x" = (
-/obj/machinery/porta_turret/ship/weak{
- faction = list("playerInteq","turret");
- dir = 9;
- id = "anvil_grid"
- },
-/turf/closed/wall/mineral/plastitanium/nodiagonal,
-/area/ship/bridge)
"y" = (
/obj/machinery/power/terminal,
/obj/structure/cable{
@@ -387,9 +379,8 @@
/turf/open/floor/plasteel/dark,
/area/ship/bridge)
"T" = (
-/obj/machinery/porta_turret/ship/weak{
- faction = list("playerInteq","turret");
- dir = 10;
+/obj/machinery/porta_turret/ship/inteq/light{
+ dir = 8;
id = "anvil_grid"
},
/turf/closed/wall/mineral/plastitanium/nodiagonal,
@@ -436,7 +427,7 @@
(1,1,1) = {"
w
-x
+T
X
u
Q
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",
'(?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/machinery/pipe/pipe_dispenser.dm b/code/game/machinery/pipe/pipe_dispenser.dm
index 0772e483a536..f21b7a59e035 100644
--- a/code/game/machinery/pipe/pipe_dispenser.dm
+++ b/code/game/machinery/pipe/pipe_dispenser.dm
@@ -1,65 +1,120 @@
+#define ATMOS_CATEGORY 0
+#define DISPOSALS_CATEGORY 1
+#define TRANSIT_CATEGORY 2
+
+
/obj/machinery/pipedispenser
name = "pipe dispenser"
icon = 'icons/obj/stationobjs.dmi'
icon_state = "pipe_d"
desc = "Dispenses countless types of pipes. Very useful if you need pipes."
+ layer = GATEWAY_UNDERLAY_LAYER //so it renders underneath dispensed disposals
density = TRUE
circuit = /obj/item/circuitboard/machine/pipedispenser
interaction_flags_machine = INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_OFFLINE
- var/wait = 0
+ var/delay = 0
+ var/busy = FALSE
+ var/p_dir = NORTH
+ var/p_flipped = FALSE
+ var/category = ATMOS_CATEGORY
var/piping_layer = PIPING_LAYER_DEFAULT
+ var/ducting_layer = DUCT_LAYER_DEFAULT
+ var/datum/pipe_info/recipe
+ var/paint_color = "grey"
+ var/static/datum/pipe_info/first_atmos
+ var/static/datum/pipe_info/first_disposal
+ var/static/datum/pipe_info/first_transit
+
+/obj/machinery/pipedispenser/Initialize()
+ . = ..()
+ if(!first_atmos)
+ first_atmos = GLOB.atmos_pipe_recipes[GLOB.atmos_pipe_recipes[1]][1]
+ if(!first_disposal)
+ first_disposal = GLOB.disposal_pipe_recipes[GLOB.disposal_pipe_recipes[1]][1]
+ if(!first_transit)
+ first_transit = GLOB.transit_tube_recipes[GLOB.transit_tube_recipes[1]][1]
+
+ recipe = first_atmos
+
+/obj/machinery/pipedispenser/ui_assets(mob/user)
+ return list(
+ get_asset_datum(/datum/asset/spritesheet/pipes),
+ )
/obj/machinery/pipedispenser/attack_paw(mob/user)
return attack_hand(user)
-/obj/machinery/pipedispenser/ui_interact(mob/user)
+/obj/machinery/pipedispenser/ui_interact(mob/user, datum/tgui/ui)
+ ui = SStgui.try_update_ui(user, src, ui)
+ if(!ui)
+ ui = new(user, src, "PipeDispenser", name)
+ ui.open()
+
+/obj/machinery/pipedispenser/ui_data(mob/user)
+ var/list/data = list(
+ "category" = category,
+ "piping_layer" = piping_layer,
+ "ducting_layer" = ducting_layer,
+ "preview_rows" = recipe.get_preview(p_dir),
+ "categories" = list(),
+ "selected_color" = paint_color,
+ "paint_colors" = GLOB.pipe_paint_colors
+ )
+
+ var/list/recipes
+ switch(category)
+ if(ATMOS_CATEGORY)
+ recipes = GLOB.atmos_pipe_recipes
+ if(DISPOSALS_CATEGORY)
+ recipes = GLOB.disposal_pipe_recipes
+ if(TRANSIT_CATEGORY)
+ recipes = GLOB.transit_tube_recipes
+ for(var/c in recipes)
+ var/list/cat = recipes[c]
+ var/list/r = list()
+ for(var/i in 1 to cat.len)
+ var/datum/pipe_info/info = cat[i]
+ r += list(list("pipe_name" = info.name, "pipe_index" = i, "selected" = (info == recipe), "all_layers" = info.all_layers))
+ data["categories"] += list(list("cat_name" = c, "recipes" = r))
+
+ return data
+
+/obj/machinery/pipedispenser/ui_act(action, params)
. = ..()
- var/dat = "PIPING LAYER: --[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/code/game/machinery/porta_turret/portable_turret.dm b/code/game/machinery/porta_turret/portable_turret.dm
index 3e50954df0c7..5c592c7409dd 100644
--- a/code/game/machinery/porta_turret/portable_turret.dm
+++ b/code/game/machinery/porta_turret/portable_turret.dm
@@ -77,8 +77,6 @@ DEFINE_BITFIELD(turret_flags, list(
var/has_cover = TRUE
/// The cover that is covering this turret
var/obj/machinery/porta_turret_cover/cover = null
- /// World.time the turret last fired
- var/last_fired = 0
/// Ticks until next shot (1.5 ?)
var/shot_delay = 15
/// Turret flags about who is turret allowed to shoot
@@ -101,6 +99,8 @@ DEFINE_BITFIELD(turret_flags, list(
var/datum/action/turret_toggle/toggle_action
/// Mob that is remotely controlling the turret
var/mob/remote_controller
+ //our cooldowns
+ COOLDOWN_DECLARE(fire_cooldown)
/// For connecting to additional turrets
var/id = ""
@@ -599,9 +599,9 @@ DEFINE_BITFIELD(turret_flags, list(
return
if(!(obj_flags & EMAGGED)) //if it hasn't been emagged, cooldown before shooting again
- if(last_fired + shot_delay > world.time)
+ if(!COOLDOWN_FINISHED(src, fire_cooldown))
return
- last_fired = world.time
+ COOLDOWN_START(src, fire_cooldown, shot_delay)
var/turf/T = get_turf(src)
var/turf/U = get_turf(target)
@@ -842,6 +842,44 @@ DEFINE_BITFIELD(turret_flags, list(
stun_projectile_sound = 'sound/weapons/gun/smg/shot.ogg'
desc = "A ballistic machine gun auto-turret."
+//high rof, range, faster projectile speed
+/* 'Nanotrasen' turrets */
+
+/obj/machinery/porta_turret/ship/nt
+ name = "Sharplite Defense Turret"
+ desc = "A cheap and effective turret designed by Sharplite and purchased and installed on most Nanotrasen Vessels."
+ faction = list(FACTION_PLAYER_NANOTRASEN, "turret")
+ icon_state = "standard_lethal"
+ base_icon_state = "standard"
+ stun_projectile = /obj/projectile/beam/disabler/sharplite
+ lethal_projectile = /obj/projectile/beam/laser/sharplite
+ lethal_projectile_sound = 'sound/weapons/gun/laser/nt-fire.ogg'
+ stun_projectile_sound = 'sound/weapons/taser2.ogg'
+ shot_delay = 10
+ scan_range = 10
+
+/obj/machinery/porta_turret/ship/nt/light
+ name = "Sharplite LDS"
+ desc = "A cheap and effective 'defensive system' designed by Sharplite for installation on Nanotrasen vessels."
+ stun_projectile = /obj/projectile/beam/disabler/weak/sharplite
+ lethal_projectile = /obj/projectile/beam/laser/light/sharplite
+ lethal_projectile_sound = 'sound/weapons/gun/laser/nt-fire.ogg'
+ stun_projectile_sound = 'sound/weapons/taser2.ogg'
+
+
+/obj/machinery/porta_turret/ship/nt/heavy
+ name = "Sharplite Defense Cannon"
+ desc = "A heavy laser mounting designed by Sharplite for usage on Nanotrasen vessels."
+ lethal_projectile = /obj/projectile/beam/laser/heavylaser/sharplite
+ lethal_projectile_sound = 'sound/weapons/lasercannonfire.ogg'
+
+/obj/machinery/porta_turret/ship/nt/pulse
+ name = "Sharplite Pulse Cannon"
+ desc = "A pulse cannon mounting designed by Sharplite. Not sold to any purchasers and exclusively used on Nanotrasen Vessels."
+ lethal_projectile = /obj/projectile/beam/pulse/sharplite_turret
+ lethal_projectile_sound = 'sound/weapons/gun/laser/heavy_laser.ogg'
+
+
/* Syndicate Turrets */
@@ -866,6 +904,40 @@ DEFINE_BITFIELD(turret_flags, list(
lethal_projectile = /obj/projectile/beam/laser/heavylaser
lethal_projectile_sound = 'sound/weapons/lasercannonfire.ogg'
+/* Inteq Turrets */
+
+/obj/machinery/porta_turret/ship/inteq
+ name = "Vanguard Turret"
+ desc = "A turret designed by IRMG engineers for defending ships from hostile flora, fauna, and people (and Elzousa, which count as flora and people)."
+ stun_projectile = /obj/projectile/bullet/a762_40/rubber
+ stun_projectile_sound = 'sound/weapons/gun/rifle/skm.ogg'
+ lethal_projectile = /obj/projectile/bullet/a762_40
+ lethal_projectile_sound = 'sound/weapons/gun/rifle/skm.ogg'
+ scan_range = 8
+ shot_delay = 20
+ faction = list(FACTION_PLAYER_INTEQ, "turret")
+
+/obj/machinery/porta_turret/ship/inteq/light
+ name = "Close-In Vanguard Turret"
+ desc = "A light turret designed by IRMG engineers for the the task of defending from close-in encounters. Low power, high speed."
+ stun_projectile = /obj/projectile/bullet/c10mm/rubber
+ stun_projectile_sound = 'sound/weapons/gun/smg/vector_fire.ogg'
+ lethal_projectile = /obj/projectile/bullet/c10mm
+ lethal_projectile_sound = 'sound/weapons/gun/smg/vector_fire.ogg'
+ subsystem_type = /datum/controller/subsystem/processing/fastprocess //turns out if you have a shot delay below what SSmachines fires at you need to use a different subsystem
+ scan_range = 4
+ shot_delay = 5
+
+/obj/machinery/porta_turret/ship/inteq/heavy
+ name = "Vanguard Overwatch Turret"
+ desc = "A turret designed by IRMG engineers to provide long range defensive fire on their installations. Has a habit of leaving big holes."
+ stun_projectile = /obj/projectile/bullet/a308/rubber
+ stun_projectile_sound = 'sound/weapons/gun/rifle/f4.ogg'
+ lethal_projectile = /obj/projectile/bullet/a308
+ lethal_projectile_sound = 'sound/weapons/gun/rifle/f4.ogg'
+ scan_range = 12
+ shot_delay = 20
+
/* Solcon Turrets */
/obj/machinery/porta_turret/ship/solgov
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/overmap/missions/acquire_mission.dm b/code/modules/overmap/missions/acquire_mission.dm
index 8a3424c8eb11..ea55beb00120 100644
--- a/code/modules/overmap/missions/acquire_mission.dm
+++ b/code/modules/overmap/missions/acquire_mission.dm
@@ -180,14 +180,6 @@ Acquire: Anomaly
weight = 2
objective_type = /mob/living/simple_animal/hostile/asteroid/ice_whelp
-/datum/mission/acquire/creature/ice_demon
- name = "Capture an ice demon"
- desc = "I require a live ice demon for research purposes. Trap one within the given \
- Lifeform Containment Unit and return it to me and you will be paid handsomely."
- value = 1500
- weight = 2
- objective_type = /mob/living/simple_animal/hostile/asteroid/ice_demon
-
/datum/mission/acquire/creature/migo
name = "Capture a live mi-go"
desc = "I require a live mi-go for research purposes. Trap one within the given \
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/guns/manufacturer/clip_lanchester/ballistics.dm b/code/modules/projectiles/guns/manufacturer/clip_lanchester/ballistics.dm
index f32a2f11a508..a244b188863a 100644
--- a/code/modules/projectiles/guns/manufacturer/clip_lanchester/ballistics.dm
+++ b/code/modules/projectiles/guns/manufacturer/clip_lanchester/ballistics.dm
@@ -223,7 +223,6 @@ EMPTY_GUN_HELPER(automatic/smg/cm5)
righthand_file = 'icons/obj/guns/manufacturer/clip_lanchester/righthand.dmi'
mob_overlay_icon = 'icons/obj/guns/manufacturer/clip_lanchester/onmob.dmi'
- fire_sound = 'sound/weapons/gun/rifle/shot.ogg'
icon_state = "f4"
item_state = "f4"
show_magazine_on_sprite = TRUE
diff --git a/code/modules/projectiles/projectile/beams.dm b/code/modules/projectiles/projectile/beams.dm
index c46a4c6cb2f9..b95c3dd37ddb 100644
--- a/code/modules/projectiles/projectile/beams.dm
+++ b/code/modules/projectiles/projectile/beams.dm
@@ -37,6 +37,15 @@
muzzle_type = /obj/effect/projectile/muzzle/laser
impact_type = /obj/effect/projectile/impact/laser
+/obj/projectile/beam/laser/sharplite
+ speed = 0.4
+
+/obj/projectile/beam/laser/light
+ damage = 15
+
+/obj/projectile/beam/laser/light/sharplite
+ speed = 0.4
+
/obj/projectile/beam/laser/eoehoma
damage = 25
armour_penetration = -10
@@ -54,6 +63,9 @@
muzzle_type = /obj/effect/projectile/muzzle/heavy_laser
impact_type = /obj/effect/projectile/impact/heavy_laser
+/obj/projectile/beam/laser/heavylaser/sharplite
+ speed = 0.4
+
/obj/projectile/beam/laser/on_hit(atom/target, blocked = FALSE)
. = ..()
if(iscarbon(target))
@@ -119,9 +131,15 @@
muzzle_type = /obj/effect/projectile/muzzle/disabler
impact_type = /obj/effect/projectile/impact/disabler
+/obj/projectile/beam/disabler/sharplite
+ speed = 0.4
+
/obj/projectile/beam/disabler/weak
damage = 15
+/obj/projectile/beam/disabler/weak/sharplite
+ speed = 0.4
+
/obj/projectile/beam/disabler/weak/negative_ap
armour_penetration = -30
range = 9
@@ -148,6 +166,11 @@
return
targets_turf.IgniteTurf(rand(8,22), "blue")
+/obj/projectile/beam/pulse/sharplite_turret
+ wall_damage_flags = null
+ wall_damage_override = 0
+ speed = 0.4
+
/obj/projectile/beam/pulse/shotgun
damage = 40
diff --git a/code/modules/projectiles/projectile/bullets/rifle.dm b/code/modules/projectiles/projectile/bullets/rifle.dm
index 690f02d6b5c5..1d5d48c9b826 100644
--- a/code/modules/projectiles/projectile/bullets/rifle.dm
+++ b/code/modules/projectiles/projectile/bullets/rifle.dm
@@ -49,6 +49,13 @@
damage = 30
armour_penetration = 20
+/obj/projectile/bullet/a762_40/rubber //"rubber"
+ name = "7.62x40mm CLIP Rubber"
+ damage = 15
+ stamina = 40
+ armour_penetration = 20
+
+
//.308 WIN (M514 & GAL DMRs)
/obj/projectile/bullet/a308
@@ -57,6 +64,13 @@
damage = 30
armour_penetration = 40
+/obj/projectile/bullet/a308/rubber //"rubber"
+ name = ".308 Rubber"
+ speed = 0.3
+ damage = 25
+ stamina = 50
+ armour_penetration = 40
+
// 8x58mm caseless (SG-669)
/obj/projectile/bullet/a858
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/html/changelogs/AutoChangeLog-pr-3146.yml b/html/changelogs/AutoChangeLog-pr-3146.yml
new file mode 100644
index 000000000000..2b6397e66448
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3146.yml
@@ -0,0 +1,5 @@
+author: Thera-Pissed
+changes:
+ - {rscadd: angle grinders for salvage}
+ - {rscadd: reworks plasma cutters for salvage}
+delete-after: true
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-3406.yml b/html/changelogs/AutoChangeLog-pr-3406.yml
new file mode 100644
index 000000000000..16dcd1234872
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3406.yml
@@ -0,0 +1,6 @@
+author: Bjarl
+changes:
+ - {rscadd: IRMG engineers have rolled new turrets out into the frontier. Please
+ report back on their effectiveness. Unless you have been shot. Then you should
+ be dead.}
+delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3421.yml b/html/changelogs/AutoChangeLog-pr-3421.yml
new file mode 100644
index 000000000000..7e32d923d25c
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3421.yml
@@ -0,0 +1,4 @@
+author: SomeguyManperson
+changes:
+ - {rscdel: missions will no longer request capturing ice demons}
+delete-after: true
diff --git a/html/changelogs/AutoChangeLog-pr-3436.yml b/html/changelogs/AutoChangeLog-pr-3436.yml
new file mode 100644
index 000000000000..6020a91bbc22
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3436.yml
@@ -0,0 +1,5 @@
+author: Apogee-dev
+changes:
+ - {balance: increased mudskipper limit to 2}
+ - {balance: cut a deckhand slot from kilo}
+delete-after: true
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
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-3451.yml b/html/changelogs/AutoChangeLog-pr-3451.yml
new file mode 100644
index 000000000000..a09e9e0324b7
--- /dev/null
+++ b/html/changelogs/AutoChangeLog-pr-3451.yml
@@ -0,0 +1,5 @@
+author: Bjarl
+changes:
+ - {rscadd: 'Sharplite has produced a line of turrets for Nanotrasen, which is now
+ mounting them on relevant vessels.'}
+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-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
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
diff --git a/tgui/packages/tgui-dev-server/package.json b/tgui/packages/tgui-dev-server/package.json
index a026558a47a1..1a0f4c972244 100644
--- a/tgui/packages/tgui-dev-server/package.json
+++ b/tgui/packages/tgui-dev-server/package.json
@@ -4,7 +4,7 @@
"version": "4.3.1",
"type": "module",
"dependencies": {
- "axios": "^1.6.0",
+ "axios": "^1.7.4",
"glob": "^7.1.7",
"source-map": "^0.7.3",
"stacktrace-parser": "^0.1.10",
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,
+ })
+ }
+ />
+ ))}
+
+
+
+
+
+ );
+};
diff --git a/tgui/yarn.lock b/tgui/yarn.lock
index bdf58e167804..6bb17b2fc675 100644
--- a/tgui/yarn.lock
+++ b/tgui/yarn.lock
@@ -2951,14 +2951,14 @@ __metadata:
languageName: node
linkType: hard
-"axios@npm:^1.6.0":
- version: 1.6.1
- resolution: "axios@npm:1.6.1"
+"axios@npm:^1.7.4":
+ version: 1.7.5
+ resolution: "axios@npm:1.7.5"
dependencies:
- follow-redirects: ^1.15.0
+ follow-redirects: ^1.15.6
form-data: ^4.0.0
proxy-from-env: ^1.1.0
- checksum: 573f03f59b7487d54551b16f5e155d1d130ad4864ed32d1da93d522b78a57123b34e3bde37f822a65ee297e79f1db840f9ad6514addff50d3cbf5caeed39e8dc
+ checksum: 2859fe01437cf133eee35571abc1d4b5224bb13e530e66cb3581ca226e170541dd5eef9f46abb41592cee0a2f54930c9e4978354e0cf1064748fc20d9a05e9d5
languageName: node
linkType: hard
@@ -4814,13 +4814,13 @@ __metadata:
languageName: node
linkType: hard
-"follow-redirects@npm:^1.15.0":
- version: 1.15.4
- resolution: "follow-redirects@npm:1.15.4"
+"follow-redirects@npm:^1.15.6":
+ version: 1.15.6
+ resolution: "follow-redirects@npm:1.15.6"
peerDependenciesMeta:
debug:
optional: true
- checksum: e178d1deff8b23d5d24ec3f7a94cde6e47d74d0dc649c35fc9857041267c12ec5d44650a0c5597ef83056ada9ea6ca0c30e7c4f97dbf07d035086be9e6a5b7b6
+ checksum: a62c378dfc8c00f60b9c80cab158ba54e99ba0239a5dd7c81245e5a5b39d10f0c35e249c3379eae719ff0285fff88c365dd446fab19dee771f1d76252df1bbf5
languageName: node
linkType: hard
@@ -8940,7 +8940,7 @@ resolve@^2.0.0-next.3:
version: 0.0.0-use.local
resolution: "tgui-dev-server@workspace:packages/tgui-dev-server"
dependencies:
- axios: ^1.6.0
+ axios: ^1.7.4
glob: ^7.1.7
source-map: ^0.7.3
stacktrace-parser: ^0.1.10