diff --git a/code/game/objects/items/weapons/RCL.dm b/code/game/objects/items/weapons/RCL.dm
new file mode 100644
index 00000000000..524fd38eb80
--- /dev/null
+++ b/code/game/objects/items/weapons/RCL.dm
@@ -0,0 +1,151 @@
+/obj/item/weapon/twohanded/rcl
+ name = "rapid cable layer (RCL)"
+ desc = "A device used to rapidly deploy cables. It has screws on the side which can be removed to slide off the cables."
+ icon = 'icons/obj/tools.dmi'
+ icon_state = "rcl-0"
+ item_state = "rcl-0"
+ opacity = 0
+ force = 5 //Plastic is soft
+ throwforce = 5
+ throw_speed = 1
+ throw_range = 7
+ w_class = WEIGHT_CLASS_NORMAL
+ origin_tech = "engineering=4;materials=4"
+ var/max_amount = 90
+ var/active = 0
+ var/obj/structure/cable/last = null
+ var/obj/item/stack/cable_coil/loaded = null
+
+/obj/item/weapon/twohanded/rcl/attackby(obj/item/weapon/W, mob/user)
+ if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/C = W
+ if(!loaded)
+ if(user.drop_item())
+ loaded = W
+ loaded.forceMove(src)
+ loaded.max_amount = max_amount //We store a lot.
+ else
+ to_chat(user, "[user.get_active_hand()] is stuck to your hand!")
+ return
+ else
+ if(loaded.amount < max_amount)
+ var/amount = min(loaded.amount + C.amount, max_amount)
+ C.use(amount - loaded.amount)
+ loaded.amount = amount
+ else
+ return
+ update_icon()
+ to_chat(user, "You add the cables to the [src]. It now contains [loaded.amount].")
+ else if(isscrewdriver(W))
+ if(!loaded)
+ return
+ to_chat(user, "You loosen the securing screws on the side, allowing you to lower the guiding edge and retrieve the wires.")
+ while(loaded.amount > 30) //There are only two kinds of situations: "nodiff" (60,90), or "diff" (31-59, 61-89)
+ var/diff = loaded.amount % 30
+ if(diff)
+ loaded.use(diff)
+ new /obj/item/stack/cable_coil(user.loc, diff)
+ else
+ loaded.use(30)
+ new /obj/item/stack/cable_coil(user.loc, 30)
+ loaded.max_amount = initial(loaded.max_amount)
+ loaded.forceMove(user.loc)
+ user.put_in_hands(loaded)
+ loaded = null
+ update_icon()
+ else
+ ..()
+
+/obj/item/weapon/twohanded/rcl/examine(mob/user)
+ ..()
+ if(loaded)
+ to_chat(user, "It contains [loaded.amount]/[max_amount] cables.")
+
+/obj/item/weapon/twohanded/rcl/Destroy()
+ if(loaded)
+ qdel(loaded)
+ loaded = null
+ last = null
+ active = 0
+ return ..()
+
+/obj/item/weapon/twohanded/rcl/update_icon()
+ if(!loaded)
+ icon_state = "rcl-0"
+ item_state = "rcl-0"
+ return
+ switch(loaded.amount)
+ if(61 to INFINITY)
+ icon_state = "rcl-30"
+ item_state = "rcl"
+ if(31 to 60)
+ icon_state = "rcl-20"
+ item_state = "rcl"
+ if(1 to 30)
+ icon_state = "rcl-10"
+ item_state = "rcl"
+ else
+ icon_state = "rcl-0"
+ item_state = "rcl-0"
+
+/obj/item/weapon/twohanded/rcl/proc/is_empty(mob/user, loud = 1)
+ update_icon()
+ if(!loaded || !loaded.amount)
+ if(loud)
+ to_chat(user, "The last of the cables unreel from [src].")
+ if(loaded)
+ qdel(loaded)
+ loaded = null
+ unwield(user)
+ active = wielded
+ return 1
+ return 0
+
+/obj/item/weapon/twohanded/rcl/dropped(mob/wearer)
+ ..()
+ active = 0
+ last = null
+
+/obj/item/weapon/twohanded/rcl/attack_self(mob/user)
+ ..()
+ active = wielded
+ if(!active)
+ last = null
+ else if(!last)
+ for(var/obj/structure/cable/C in get_turf(user))
+ if(C.d1 == 0 || C.d2 == 0)
+ last = C
+ break
+
+/obj/item/weapon/twohanded/rcl/moved(mob/user, turf/old_loc, direct)
+ if(active)
+ trigger(user)
+
+/obj/item/weapon/twohanded/rcl/proc/trigger(mob/user)
+ if(is_empty(user, 0))
+ to_chat(user, "\The [src] is empty!")
+ return
+ if(last)
+ if(get_dist(last, user) == 1) //hacky, but it works
+ var/turf/T = get_turf(user)
+ if(!isturf(T) || T.intact || !T.can_have_cabling())
+ last = null
+ return
+ if(get_dir(last, user) == last.d2)
+ //Did we just walk backwards? Well, that's the one direction we CAN'T complete a stub.
+ last = null
+ return
+ loaded.cable_join(last, user)
+ if(is_empty(user))
+ return //If we've run out, display message and exit
+ else
+ last = null
+ last = loaded.place_turf(get_turf(loc), user, turn(user.dir, 180))
+ is_empty(user) //If we've run out, display message
+
+/obj/item/weapon/twohanded/rcl/pre_loaded/New() //Comes preloaded with cable, for testing stuff
+ ..()
+ loaded = new()
+ loaded.max_amount = max_amount
+ loaded.amount = max_amount
+ update_icon()
\ No newline at end of file
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 69b0df22ae3..a5e4190d6ea 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -386,15 +386,25 @@
if(ticker)
cameranet.updateVisibility(src)
-/turf/attackby(obj/item/C, mob/user, params)
- if(can_lay_cable() && istype(C, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/coil = C
- for(var/obj/structure/cable/LC in src)
- if((LC.d1==0)||(LC.d2==0))
- LC.attackby(C,user)
- return
- coil.place_turf(src, user)
- return 1
+/turf/attackby(obj/item/I, mob/user, params)
+ if(can_lay_cable())
+ if(istype(I, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/C = I
+ for(var/obj/structure/cable/LC in src)
+ if(LC.d1 == 0 || LC.d2==0)
+ LC.attackby(C,user)
+ return
+ C.place_turf(src, user)
+ return 1
+ else if(istype(I, /obj/item/weapon/twohanded/rcl))
+ var/obj/item/weapon/twohanded/rcl/R = I
+ if(R.loaded)
+ for(var/obj/structure/cable/LC in src)
+ if(LC.d1 == 0 || LC.d2==0)
+ LC.attackby(R, user)
+ return
+ R.loaded.place_turf(src, user)
+ R.is_empty(user)
return 0
diff --git a/code/modules/mob/mob_movement.dm b/code/modules/mob/mob_movement.dm
index 8b8fafd32b7..52fdbdf0328 100644
--- a/code/modules/mob/mob_movement.dm
+++ b/code/modules/mob/mob_movement.dm
@@ -199,6 +199,10 @@
var/atom/O = mob.loc
return O.relaymove(mob, direct)
+ if(istype(mob.get_active_hand(), /obj/item))
+ var/obj/item/I = mob.get_active_hand()
+ I.moved(mob, n, direct)
+
if(!mob.Process_Spacemove(direct))
return 0
diff --git a/code/modules/power/cable.dm b/code/modules/power/cable.dm
index 849511a48e7..176ce72f005 100644
--- a/code/modules/power/cable.dm
+++ b/code/modules/power/cable.dm
@@ -114,7 +114,7 @@ By design, d1 is the smallest direction and d2 is the highest
//
/obj/structure/cable/attackby(obj/item/W, mob/user)
- var/turf/T = src.loc
+ var/turf/T = get_turf(src)
if(T.intact)
return
@@ -149,7 +149,7 @@ By design, d1 is the smallest direction and d2 is the highest
if(c.d1 == 12 || c.d2 == 12)
c.qdel()*/
///// Z-Level Stuff
- investigate_log("was cut by [key_name(usr, usr.client)] in [user.loc.loc]([T.x], [T.y], [T.z] - JMP)","wires")
+ investigate_log("was cut by [key_name(usr, usr.client)] in [get_area(user)]([T.x], [T.y], [T.z] - [ADMIN_JMP(T)])","wires")
qdel(src) // qdel
return
@@ -162,6 +162,12 @@ By design, d1 is the smallest direction and d2 is the highest
return
coil.cable_join(src, user)
+ else if(istype(W, /obj/item/weapon/twohanded/rcl))
+ var/obj/item/weapon/twohanded/rcl/R = W
+ if(R.loaded)
+ R.loaded.cable_join(src, user)
+ R.is_empty(user)
+
else if(istype(W, /obj/item/device/multitool))
if(powernet && (powernet.avail > 0)) // is it powered?
@@ -197,12 +203,12 @@ By design, d1 is the smallest direction and d2 is the highest
qdel(src) // qdel
if(2.0)
if(prob(50))
- new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, color)
+ new/obj/item/stack/cable_coil(get_turf(src), src.d1 ? 2 : 1, color)
qdel(src) // qdel
if(3.0)
if(prob(25))
- new/obj/item/stack/cable_coil(src.loc, src.d1 ? 2 : 1, color)
+ new/obj/item/stack/cable_coil(get_turf(src), src.d1 ? 2 : 1, color)
qdel(src) // qdel
return
@@ -505,7 +511,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list(
// General procedures
///////////////////////////////////
//you can use wires to heal robotics
-/obj/item/stack/cable_coil/attack(mob/M as mob, mob/user as mob)
+/obj/item/stack/cable_coil/attack(mob/M, mob/user)
if(ishuman(M))
var/mob/living/carbon/human/H = M
var/obj/item/organ/external/S = H.organs_by_name[user.zone_sel.selecting]
@@ -613,11 +619,11 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list(
return C
// called when cable_coil is clicked on a turf/simulated/floor
-/obj/item/stack/cable_coil/proc/place_turf(turf/T, mob/user)
+/obj/item/stack/cable_coil/proc/place_turf(turf/T, mob/user, dirnew)
if(!isturf(user.loc))
return
- if(!T.can_have_cabling())
+ if(!isturf(T) || T.intact || !T.can_have_cabling())
to_chat(user, "You can only lay cables on catwalks and plating!")
return
@@ -629,44 +635,46 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list(
to_chat(user, "You can't lay cable at a place that far away!")
return
- else
- var/dirn
-
+ var/dirn = null
+ if(!dirnew) //If we weren't given a direction, come up with one! (Called as null from catwalk.dm and floor.dm)
if(user.loc == T)
- dirn = user.dir // if laying on the tile we're on, lay in the direction we're facing
+ dirn = user.dir //If laying on the tile we're on, lay in the direction we're facing
else
dirn = get_dir(T, user)
+ else
+ dirn = dirnew
- for(var/obj/structure/cable/LC in T)
- if(LC.d2 == dirn && LC.d1 == 0)
- to_chat(user, "There's already a cable at that position!")
- return
+ for(var/obj/structure/cable/LC in T)
+ if(LC.d2 == dirn && LC.d1 == 0)
+ to_chat(user, "There's already a cable at that position!")
+ return
- var/obj/structure/cable/C = get_new_cable(T)
+ var/obj/structure/cable/C = get_new_cable(T)
- //set up the new cable
- C.d1 = 0 //it's a O-X node cable
- C.d2 = dirn
- C.add_fingerprint(user)
- C.updateicon()
+ //set up the new cable
+ C.d1 = 0 //it's a O-X node cable
+ C.d2 = dirn
+ C.add_fingerprint(user)
+ C.updateicon()
- //create a new powernet with the cable, if needed it will be merged later
- var/datum/powernet/PN = new()
- PN.add_cable(C)
+ //create a new powernet with the cable, if needed it will be merged later
+ var/datum/powernet/PN = new()
+ PN.add_cable(C)
- C.mergeConnectedNetworks(C.d2) //merge the powernet with adjacents powernets
- C.mergeConnectedNetworksOnTurf() //merge the powernet with on turf powernets
+ C.mergeConnectedNetworks(C.d2) //merge the powernet with adjacents powernets
+ C.mergeConnectedNetworksOnTurf() //merge the powernet with on turf powernets
- if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
- C.mergeDiagonalsNetworks(C.d2)
+ if(C.d2 & (C.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
+ C.mergeDiagonalsNetworks(C.d2)
+ use(1)
- use(1)
+ if(C.shock(user, 50))
+ if(prob(50)) //fail
+ new /obj/item/stack/cable_coil(get_turf(C), 1, C.color)
+ qdel(C) // qdel
- if(C.shock(user, 50))
- if(prob(50)) //fail
- new/obj/item/stack/cable_coil(C.loc, 1, C.color)
- qdel(C) // qdel
+ return C
// called when cable_coil is click on an installed obj/cable
// or click on a turf that already contains a "node" cable
@@ -675,7 +683,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list(
if(!isturf(U))
return
- var/turf/T = C.loc
+ var/turf/T = get_turf(C)
if(!isturf(T) || T.intact) // sanity checks, also stop use interacting with T-scanner revealed cable
return
@@ -700,38 +708,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list(
// cable is pointing at us, we're standing on an open tile
// so create a stub pointing at the clicked cable on our tile
- var/fdirn = turn(dirn, 180) // the opposite direction
-
- for(var/obj/structure/cable/LC in U) // check to make sure there's not a cable there already
- if(LC.d1 == fdirn || LC.d2 == fdirn)
- to_chat(user, "There's already a cable at that position.")
- return
-
- var/obj/structure/cable/NC = new(U)
- NC.cableColor(color)
-
- NC.d1 = 0
- NC.d2 = fdirn
- NC.add_fingerprint()
- NC.updateicon()
-
- //create a new powernet with the cable, if needed it will be merged later
- var/datum/powernet/newPN = new()
- newPN.add_cable(NC)
-
- NC.mergeConnectedNetworks(NC.d2) //merge the powernet with adjacents powernets
- NC.mergeConnectedNetworksOnTurf() //merge the powernet with on turf powernets
-
- if(NC.d2 & (NC.d2 - 1))// if the cable is layed diagonally, check the others 2 possible directions
- NC.mergeDiagonalsNetworks(NC.d2)
-
- use(1)
-
- if(NC.shock(user, 50))
- if(prob(50)) //fail
- new/obj/item/stack/cable_coil(NC.loc, 1, NC.color)
- qdel(NC) // qdel
-
+ place_turf(T, user, turn(dirn, 180))
return
// exisiting cable doesn't point at our position, so see if it's a stub
@@ -777,7 +754,7 @@ var/global/list/datum/stack_recipe/cable_coil_recipes = list(
if(C.shock(user, 50))
if(prob(50)) //fail
- new/obj/item/stack/cable_coil(C.loc, 2, C.color)
+ new/obj/item/stack/cable_coil(get_turf(C), 2, C.color)
qdel(C) // qdel
return
diff --git a/icons/mob/inhands/items_lefthand.dmi b/icons/mob/inhands/items_lefthand.dmi
index 0c9090c5b81..9682a110971 100644
Binary files a/icons/mob/inhands/items_lefthand.dmi and b/icons/mob/inhands/items_lefthand.dmi differ
diff --git a/icons/mob/inhands/items_righthand.dmi b/icons/mob/inhands/items_righthand.dmi
index 0f889055ad0..023222ad451 100644
Binary files a/icons/mob/inhands/items_righthand.dmi and b/icons/mob/inhands/items_righthand.dmi differ
diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi
index d1aca5822c3..00f5ac98691 100644
Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ
diff --git a/paradise.dme b/paradise.dme
index c0fe429cc82..258cabc1507 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -807,6 +807,7 @@
#include "code\game\objects\items\weapons\power_cells.dm"
#include "code\game\objects\items\weapons\powerfist.dm"
#include "code\game\objects\items\weapons\RCD.dm"
+#include "code\game\objects\items\weapons\RCL.dm"
#include "code\game\objects\items\weapons\RSF.dm"
#include "code\game\objects\items\weapons\scissors.dm"
#include "code\game\objects\items\weapons\scrolls.dm"