diff --git a/code/__defines/misc.dm b/code/__defines/misc.dm
index d8c4c69e0a..aa334224ad 100644
--- a/code/__defines/misc.dm
+++ b/code/__defines/misc.dm
@@ -288,4 +288,18 @@ var/global/list/##LIST_NAME = list();\
#define IS_SCREWDRIVER "screwdriver"
#define IS_CROWBAR "crowbar"
#define IS_WIRECUTTER "wirecutter"
-#define IS_WRENCH "wrench"
\ No newline at end of file
+#define IS_WRENCH "wrench"
+
+// RCD modes. Used on the RCD, and gets passed to an object's rcd_act() when an RCD is used on it, to determine what happens.
+#define RCD_FLOORWALL "Floor / Wall" // Builds plating on space/ground/open tiles. Builds a wall when on floors. Finishes walls when used on girders.
+#define RCD_AIRLOCK "Airlock" // Builds an airlock on the tile if one isn't already there.
+#define RCD_WINDOWGRILLE "Window / Grille" // Builds a full tile window and grille pair on floors.
+#define RCD_DECONSTRUCT "Deconstruction" // Removes various things. Still consumes compressed matter.
+
+#define RCD_VALUE_MODE "mode"
+#define RCD_VALUE_DELAY "delay"
+#define RCD_VALUE_COST "cost"
+
+
+#define RCD_SHEETS_PER_MATTER_UNIT 4 // Each physical material sheet is worth four matter units.
+#define RCD_MAX_CAPACITY 30 * RCD_SHEETS_PER_MATTER_UNIT
\ No newline at end of file
diff --git a/code/datums/progressbar.dm b/code/datums/progressbar.dm
index 8d2edbeeb9..bf38ab7a1c 100644
--- a/code/datums/progressbar.dm
+++ b/code/datums/progressbar.dm
@@ -15,6 +15,7 @@
bar = image('icons/effects/progessbar.dmi', target, "prog_bar_0")
bar.appearance_flags = APPEARANCE_UI_IGNORE_ALPHA
bar.pixel_y = 32
+ bar.plane = PLANE_PLAYER_HUD
src.user = user
if(user)
client = user.client
diff --git a/code/game/atoms.dm b/code/game/atoms.dm
index 983c92cdf5..d1289a23de 100644
--- a/code/game/atoms.dm
+++ b/code/game/atoms.dm
@@ -209,6 +209,16 @@
/atom/proc/fire_act()
return
+
+// Returns an assoc list of RCD information.
+// Example would be: list(RCD_VALUE_MODE = RCD_DECONSTRUCT, RCD_VALUE_DELAY = 50, RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 4)
+// This occurs before rcd_act() is called, and it won't be called if it returns FALSE.
+/atom/proc/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ return FALSE
+
+/atom/proc/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ return
+
/atom/proc/melt()
return
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 327b1e11cd..541e461f27 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1260,3 +1260,24 @@ About the new airlock wires panel:
src.open()
src.lock()
return
+
+
+/obj/machinery/door/airlock/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_DECONSTRUCT)
+ // Old RCD code made it cost 10 units to decon an airlock.
+ // Now the new one costs ten "sheets".
+ return list(
+ RCD_VALUE_MODE = RCD_DECONSTRUCT,
+ RCD_VALUE_DELAY = 5 SECONDS,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 10
+ )
+ return FALSE
+
+/obj/machinery/door/airlock/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_DECONSTRUCT)
+ to_chat(user, span("notice", "You deconstruct \the [src]."))
+ qdel(src)
+ return TRUE
+ return FALSE
diff --git a/code/game/mecha/equipment/tools/tools.dm b/code/game/mecha/equipment/tools/tools.dm
index dd4472282c..73bddbb433 100644
--- a/code/game/mecha/equipment/tools/tools.dm
+++ b/code/game/mecha/equipment/tools/tools.dm
@@ -244,100 +244,43 @@
equip_cooldown = 10
energy_drain = 250
range = MELEE|RANGED
- var/mode = 0 //0 - deconstruct, 1 - wall or floor, 2 - airlock.
- var/disabled = 0 //malf
-
equip_type = EQUIP_SPECIAL
+ var/obj/item/weapon/rcd/electric/mounted/mecha/my_rcd = null
+
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/initialize()
+ my_rcd = new(src)
+ return ..()
+
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/Destroy()
+ QDEL_NULL(my_rcd)
+ return ..()
/obj/item/mecha_parts/mecha_equipment/tool/rcd/action(atom/target)
- if(istype(target,/area/shuttle)||istype(target, /turf/space/transit))//>implying these are ever made -Sieve
- disabled = 1
- else
- disabled = 0
- if(!istype(target, /turf) && !istype(target, /obj/machinery/door/airlock))
- target = get_turf(target)
- if(!action_checks(target) || disabled || get_dist(chassis, target)>3) return
- playsound(chassis, 'sound/machines/click.ogg', 50, 1)
- //meh
- switch(mode)
- if(0)
- if (istype(target, /turf/simulated/wall))
- occupant_message("Deconstructing [target]...")
- set_ready_state(0)
- if(do_after_cooldown(target))
- if(disabled) return
- chassis.spark_system.start()
- target:ChangeTurf(/turf/simulated/floor/plating)
- playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
- chassis.use_power(energy_drain)
- else if (istype(target, /turf/simulated/floor))
- occupant_message("Deconstructing [target]...")
- set_ready_state(0)
- if(do_after_cooldown(target))
- if(disabled) return
- chassis.spark_system.start()
- target:ChangeTurf(get_base_turf_by_area(target))
- playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
- chassis.use_power(energy_drain)
- else if (istype(target, /obj/machinery/door/airlock))
- occupant_message("Deconstructing [target]...")
- set_ready_state(0)
- if(do_after_cooldown(target))
- if(disabled) return
- chassis.spark_system.start()
- qdel(target)
- playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
- chassis.use_power(energy_drain)
- if(1)
- if(istype(target, /turf/space) || istype(target,get_base_turf_by_area(target)))
- occupant_message("Building Floor...")
- set_ready_state(0)
- if(do_after_cooldown(target))
- if(disabled) return
- target:ChangeTurf(/turf/simulated/floor/plating)
- playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
- chassis.spark_system.start()
- chassis.use_power(energy_drain*2)
- else if(istype(target, /turf/simulated/floor))
- occupant_message("Building Wall...")
- set_ready_state(0)
- if(do_after_cooldown(target))
- if(disabled) return
- target:ChangeTurf(/turf/simulated/wall)
- playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
- chassis.spark_system.start()
- chassis.use_power(energy_drain*2)
- if(2)
- if(istype(target, /turf/simulated/floor))
- occupant_message("Building Airlock...")
- set_ready_state(0)
- if(do_after_cooldown(target))
- if(disabled) return
- chassis.spark_system.start()
- var/obj/machinery/door/airlock/T = new /obj/machinery/door/airlock(target)
- T.autoclose = 1
- playsound(target, 'sound/items/Deconstruct.ogg', 50, 1)
- playsound(target, 'sound/effects/sparks2.ogg', 50, 1)
- chassis.use_power(energy_drain*2)
- return
+ if(!action_checks(target) || get_dist(chassis, target) > 3)
+ return FALSE
+
+ my_rcd.use_rcd(target, chassis.occupant)
/obj/item/mecha_parts/mecha_equipment/tool/rcd/Topic(href,href_list)
..()
if(href_list["mode"])
- mode = text2num(href_list["mode"])
- switch(mode)
- if(0)
- occupant_message("Switched RCD to Deconstruct.")
- if(1)
- occupant_message("Switched RCD to Construct.")
- if(2)
- occupant_message("Switched RCD to Construct Airlock.")
- return
-
+ my_rcd.mode_index = text2num(href_list["mode"])
+ occupant_message("RCD reconfigured to '[my_rcd.modes[my_rcd.mode_index]]'.")
+/*
/obj/item/mecha_parts/mecha_equipment/tool/rcd/get_equip_info()
return "[..()] \[D|C|A\]"
+*/
+/obj/item/mecha_parts/mecha_equipment/tool/rcd/get_equip_info()
+ var/list/content = list(..()) // This is all for one line, in the interest of string tree conservation.
+ var/i = 1
+ content += "
"
+ for(var/mode in my_rcd.modes)
+ content += " [mode]"
+ if(i < my_rcd.modes.len)
+ content += "
"
+ i++
-
+ return content.Join()
/obj/item/mecha_parts/mecha_equipment/teleporter
diff --git a/code/game/objects/items/weapons/RCD.dm b/code/game/objects/items/weapons/RCD.dm
index d9543fed20..a0587d5dbb 100644
--- a/code/game/objects/items/weapons/RCD.dm
+++ b/code/game/objects/items/weapons/RCD.dm
@@ -1,167 +1,291 @@
-//Contains the rapid construction device.
+// Contains the rapid construction device.
/obj/item/weapon/rcd
name = "rapid construction device"
- desc = "A device used to rapidly build walls and floors."
- icon = 'icons/obj/items.dmi'
+ desc = "A device used to rapidly build and deconstruct. Reload with compressed matter cartridges."
+ icon = 'icons/obj/tools.dmi'
icon_state = "rcd"
- opacity = 0
- density = 0
- anchored = 0.0
- flags = CONDUCT
- force = 10.0
- throwforce = 10.0
+ item_state = "rcd"
+ flags = CONDUCT | NOBLUDGEON
+ force = 10
+ throwforce = 10
throw_speed = 1
throw_range = 5
w_class = ITEMSIZE_NORMAL
origin_tech = list(TECH_ENGINEERING = 4, TECH_MATERIAL = 2)
matter = list(DEFAULT_WALL_MATERIAL = 50000)
- preserve_item = 1
+ preserve_item = TRUE // RCDs are pretty important.
var/datum/effect/effect/system/spark_spread/spark_system
var/stored_matter = 0
- var/max_stored_matter = 30
- var/working = 0
- var/mode = 1
- var/list/modes = list("Floor & Walls","Airlock","Deconstruct")
- var/canRwall = 0
- var/disabled = 0
+ var/max_stored_matter = RCD_MAX_CAPACITY
+ var/ranged = FALSE
+ var/busy = FALSE
+ var/allow_concurrent_building = FALSE // If true, allows for multiple RCD builds at the same time.
+ var/mode_index = 1
+ var/list/modes = list(RCD_FLOORWALL, RCD_AIRLOCK, RCD_WINDOWGRILLE, RCD_DECONSTRUCT)
+ var/can_remove_rwalls = FALSE
+ var/airlock_type = /obj/machinery/door/airlock
+ var/window_type = /obj/structure/window/reinforced/full
+ var/material_to_use = DEFAULT_WALL_MATERIAL // So badmins can make RCDs that print diamond walls.
+ var/make_rwalls = FALSE // If true, when building walls, they will be reinforced.
-/obj/item/weapon/rcd/attack()
- return 0
-
-/obj/item/weapon/rcd/proc/can_use(var/mob/user,var/turf/T)
- var/usable = 0
- if(user.Adjacent(T) && user.get_active_hand() == src && !user.stat && !user.restrained())
- usable = 1
- if(!user.IsAdvancedToolUser() && istype(user, /mob/living/simple_animal))
- var/mob/living/simple_animal/S = user
- if(!S.IsHumanoidToolUser(src))
- usable = 0
- return usable
-
-/obj/item/weapon/rcd/examine()
- ..()
- if(src.type == /obj/item/weapon/rcd && loc == usr)
- usr << "It currently holds [stored_matter]/[max_stored_matter] matter-units."
-
-/obj/item/weapon/rcd/New()
- ..()
+/obj/item/weapon/rcd/initialize()
src.spark_system = new /datum/effect/effect/system/spark_spread
spark_system.set_up(5, 0, src)
spark_system.attach(src)
+ return ..()
/obj/item/weapon/rcd/Destroy()
- qdel(spark_system)
+ QDEL_NULL(spark_system)
spark_system = null
return ..()
-/obj/item/weapon/rcd/attackby(obj/item/weapon/W, mob/user)
+/obj/item/weapon/rcd/examine(mob/user)
+ ..()
+ to_chat(user, display_resources())
+// Used to show how much stuff (matter units, cell charge, etc) is left inside.
+/obj/item/weapon/rcd/proc/display_resources()
+ return "It currently holds [stored_matter]/[max_stored_matter] matter-units."
+
+// Used to add new cartridges.
+/obj/item/weapon/rcd/attackby(obj/item/weapon/W, mob/user)
if(istype(W, /obj/item/weapon/rcd_ammo))
var/obj/item/weapon/rcd_ammo/cartridge = W
if((stored_matter + cartridge.remaining) > max_stored_matter)
- to_chat(user, "The RCD can't hold that many additional matter-units.")
- return
+ to_chat(user, span("warning", "The RCD can't hold that many additional matter-units."))
+ return FALSE
stored_matter += cartridge.remaining
user.drop_from_inventory(W)
qdel(W)
playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
- to_chat(user, "The RCD now holds [stored_matter]/[max_stored_matter] matter-units.")
- return
- ..()
+ to_chat(user, span("notice", "The RCD now holds [stored_matter]/[max_stored_matter] matter-units."))
+ return TRUE
+ return ..()
-/obj/item/weapon/rcd/attack_self(mob/user)
- //Change the mode
- if(++mode > 3) mode = 1
- user << "Changed mode to '[modes[mode]]'"
- playsound(src.loc, 'sound/effects/pop.ogg', 50, 0)
- if(prob(20)) src.spark_system.start()
-
-/obj/item/weapon/rcd/afterattack(atom/A, mob/user, proximity)
- if(!proximity) return
- if(disabled && !isrobot(user))
- return 0
- if(istype(get_area(A),/area/shuttle)||istype(get_area(A),/turf/space/transit))
- return 0
- return alter_turf(A,user,(mode == 3))
-
-/obj/item/weapon/rcd/proc/useResource(var/amount, var/mob/user)
- if(stored_matter < amount)
- return 0
- stored_matter -= amount
- return 1
-
-/obj/item/weapon/rcd/proc/alter_turf(var/turf/T,var/mob/user,var/deconstruct)
-
- var/build_cost = 0
- var/build_type
- var/build_turf
- var/build_delay
- var/build_other
-
- if(working == 1)
- return 0
-
- if(mode == 3 && istype(T,/obj/machinery/door/airlock))
- build_cost = 10
- build_delay = 50
- build_type = "airlock"
- else if(mode == 2 && !deconstruct && istype(T,/turf/simulated/floor))
- build_cost = 10
- build_delay = 50
- build_type = "airlock"
- build_other = /obj/machinery/door/airlock
- else if(!deconstruct && isturf(T) && (istype(T,/turf/space) || istype(T,get_base_turf_by_area(T))))
- build_cost = 1
- build_type = "floor"
- build_turf = /turf/simulated/floor/airless
- else if(!deconstruct && istype(T,/turf/simulated/mineral/floor))
- build_cost = 1
- build_type = "floor"
- build_turf = /turf/simulated/floor/plating
- else if(deconstruct && istype(T,/turf/simulated/wall))
- var/turf/simulated/wall/W = T
- build_delay = deconstruct ? 50 : 40
- build_cost = 5
- build_type = (!canRwall && W.reinf_material) ? null : "wall"
- build_turf = /turf/simulated/floor
- else if(istype(T,/turf/simulated/floor) || (istype(T,/turf/simulated/mineral) && !T.density))
- var/turf/simulated/F = T
- build_delay = deconstruct ? 50 : 20
- build_cost = deconstruct ? 10 : 3
- build_type = deconstruct ? "floor" : "wall"
- build_turf = deconstruct ? get_base_turf_by_area(F) : /turf/simulated/wall
-
- if(!build_type)
- working = 0
- return 0
-
- if(!useResource(build_cost, user))
- user << "Insufficient resources."
- return 0
-
- playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
-
- working = 1
- user << "[(deconstruct ? "Deconstructing" : "Building")] [build_type]..."
-
- if(build_delay && !do_after(user, build_delay))
- working = 0
- return 0
-
- working = 0
- if(build_delay && !can_use(user,T))
- return 0
-
- if(build_turf)
- T.ChangeTurf(build_turf, preserve_outdoors = TRUE)
- else if(build_other)
- new build_other(T)
+// Changes which mode it is on.
+/obj/item/weapon/rcd/attack_self(mob/living/user)
+ if(mode_index >= modes.len) // Shouldn't overflow unless someone messes with it in VV poorly but better safe than sorry.
+ mode_index = 1
else
- qdel(T)
+ mode_index++
- playsound(src.loc, 'sound/items/Deconstruct.ogg', 50, 1)
- return 1
+ to_chat(user, span("notice", "Changed mode to '[modes[mode_index]]'."))
+ playsound(src.loc, 'sound/effects/pop.ogg', 50, 0)
+ if(prob(20))
+ src.spark_system.start()
+
+// Removes resources if the RCD can afford it.
+/obj/item/weapon/rcd/proc/consume_resources(amount)
+ if(!can_afford(amount))
+ return FALSE
+ stored_matter -= amount
+ return TRUE
+
+// Useful for testing before actually paying (e.g. before a do_after() ).
+/obj/item/weapon/rcd/proc/can_afford(amount)
+ return stored_matter >= amount
+
+/obj/item/weapon/rcd/afterattack(atom/A, mob/living/user, proximity)
+ if(!ranged && !proximity)
+ return FALSE
+ use_rcd(A, user)
+
+// Used to call rcd_act() on the atom hit.
+/obj/item/weapon/rcd/proc/use_rcd(atom/A, mob/living/user)
+ if(busy && !allow_concurrent_building)
+ to_chat(user, span("warning", "\The [src] is busy finishing its current operation, be patient."))
+ return FALSE
+
+ var/list/rcd_results = A.rcd_values(user, src, modes[mode_index])
+ if(!rcd_results)
+ to_chat(user, span("warning", "\The [src] blinks a red light as you point it towards \the [A], indicating \
+ that it won't work. Try changing the mode, or use it on something else."))
+ return FALSE
+ if(!can_afford(rcd_results[RCD_VALUE_COST]))
+ to_chat(user, span("warning", "\The [src] lacks the required material to start."))
+ return FALSE
+
+ playsound(get_turf(src), 'sound/machines/click.ogg', 50, 1)
+
+ var/true_delay = rcd_results[RCD_VALUE_DELAY] * toolspeed
+
+ var/datum/beam/rcd_beam = null
+ if(ranged)
+ var/atom/movable/beam_origin = user // This is needed because mecha pilots are inside an object and the beam won't be made if it tries to attach to them..
+ if(!isturf(beam_origin.loc))
+ beam_origin = user.loc
+ rcd_beam = beam_origin.Beam(A, icon_state = "rped_upgrade", time = max(true_delay, 5))
+ busy = TRUE
+
+ if(do_after(user, true_delay, target = A))
+ busy = FALSE
+ // Doing another check in case we lost matter during the delay for whatever reason.
+ if(!can_afford(rcd_results[RCD_VALUE_COST]))
+ to_chat(user, span("warning", "\The [src] lacks the required material to finish the operation."))
+ return FALSE
+ if(A.rcd_act(user, src, rcd_results[RCD_VALUE_MODE]))
+ consume_resources(rcd_results[RCD_VALUE_COST])
+ playsound(get_turf(A), 'sound/items/deconstruct.ogg', 50, 1)
+ return TRUE
+
+ // If they moved, kill the beam immediately.
+ qdel(rcd_beam)
+ busy = FALSE
+ return FALSE
+
+// RCD variants.
+
+// This one starts full.
+/obj/item/weapon/rcd/loaded/initialize()
+ stored_matter = max_stored_matter
+ return ..()
+
+// This one makes cooler walls by using an alternative material.
+/obj/item/weapon/rcd/shipwright
+ name = "shipwright's rapid construction device"
+ desc = "A device used to rapidly build and deconstruct. This version creates a stronger variant of wall, often \
+ used in the construction of hulls for starships. Reload with compressed matter cartridges."
+ material_to_use = MAT_STEELHULL
+
+/obj/item/weapon/rcd/shipwright/loaded/initialize()
+ stored_matter = max_stored_matter
+ return ..()
+
+
+/obj/item/weapon/rcd/advanced
+ name = "advanced rapid construction device"
+ desc = "A device used to rapidly build and deconstruct. This version works at a range, builds faster, and has a much larger capacity. \
+ Reload with compressed matter cartridges."
+ icon_state = "adv_rcd"
+ ranged = TRUE
+ toolspeed = 0.5 // Twice as fast.
+ max_stored_matter = RCD_MAX_CAPACITY * 3 // Three times capacity.
+
+/obj/item/weapon/rcd/advanced/loaded/initialize()
+ stored_matter = max_stored_matter
+ return ..()
+
+
+// Electric RCDs.
+// Currently just a base for the mounted RCDs.
+// Currently there isn't a way to swap out the cells.
+// One could be added if there is demand to do so.
+/obj/item/weapon/rcd/electric
+ name = "electric rapid construction device"
+ desc = "A device used to rapidly build and deconstruct. It runs directly off of electricity, no matter cartridges needed."
+ icon_state = "electric_rcd"
+ var/obj/item/weapon/cell/cell = null
+ var/make_cell = TRUE // If false, initialize() won't spawn a cell for this.
+ var/electric_cost_coefficent = 83.33 // Higher numbers make it less efficent. 86.3... means it should matche the standard RCD capacity on a 10k cell.
+
+/obj/item/weapon/rcd/electric/initialize()
+ if(make_cell)
+ cell = new /obj/item/weapon/cell/high(src)
+ return ..()
+
+/obj/item/weapon/rcd/electric/Destroy()
+ if(cell)
+ QDEL_NULL(cell)
+ return ..()
+
+/obj/item/weapon/rcd/electric/get_cell()
+ return cell
+
+/obj/item/weapon/rcd/electric/can_afford(amount) // This makes it so borgs won't drain their last sliver of charge by mistake, as a bonus.
+ var/obj/item/weapon/cell/cell = get_cell()
+ if(cell)
+ return cell.check_charge(amount * electric_cost_coefficent)
+ return FALSE
+
+/obj/item/weapon/rcd/electric/consume_resources(amount)
+ if(!can_afford(amount))
+ return FALSE
+ var/obj/item/weapon/cell/cell = get_cell()
+ return cell.checked_use(amount * electric_cost_coefficent)
+
+/obj/item/weapon/rcd/electric/display_resources()
+ var/obj/item/weapon/cell/cell = get_cell()
+ if(cell)
+ return "The power source connected to \the [src] has a charge of [cell.percent()]%."
+ return "It lacks a source of power, and cannot function."
+
+
+
+// 'Mounted' RCDs, used for borgs/RIGs/Mechas, all of which use their cells to drive the RCD.
+/obj/item/weapon/rcd/electric/mounted
+ name = "mounted electric rapid construction device"
+ desc = "A device used to rapidly build and deconstruct. It runs directly off of electricity from an external power source."
+ make_cell = FALSE
+
+/obj/item/weapon/rcd/electric/mounted/get_cell()
+ return get_external_power_supply()
+
+/obj/item/weapon/rcd/electric/mounted/proc/get_external_power_supply()
+ if(isrobot(loc)) // In a borg.
+ var/mob/living/silicon/robot/R = loc
+ return R.cell
+ if(istype(loc, /obj/item/rig_module)) // In a RIG.
+ var/obj/item/rig_module/module = loc
+ if(module.holder) // Is it attached to a RIG?
+ return module.holder.cell
+ if(istype(loc, /obj/item/mecha_parts/mecha_equipment)) // In a mech.
+ var/obj/item/mecha_parts/mecha_equipment/ME = loc
+ if(ME.chassis) // Is the part attached to a mech?
+ return ME.chassis.cell
+ return null
+
+
+// RCDs for borgs.
+/obj/item/weapon/rcd/electric/mounted/borg
+ can_remove_rwalls = TRUE
+ desc = "A device used to rapidly build and deconstruct. It runs directly off of electricity, drawing directly from your cell."
+ electric_cost_coefficent = 41.66 // Twice as efficent, out of pity.
+ toolspeed = 0.5 // Twice as fast, since borg versions typically have this.
+
+/obj/item/weapon/rcd/electric/mounted/borg/lesser
+ can_remove_rwalls = FALSE
+
+
+// RCDs for RIGs.
+/obj/item/weapon/rcd/electric/mounted/rig
+
+
+// RCDs for Mechs.
+/obj/item/weapon/rcd/electric/mounted/mecha
+ ranged = TRUE
+ toolspeed = 0.5
+
+
+// Infinite use RCD for debugging/adminbuse.
+/obj/item/weapon/rcd/debug
+ name = "self-repleshing rapid construction device"
+ desc = "An RCD that appears to be plated with gold. For some reason it also seems to just \
+ be vastly superior to all other RCDs ever created, possibly due to it being colored gold."
+ icon_state = "debug_rcd"
+ ranged = TRUE
+ can_remove_rwalls = TRUE
+ allow_concurrent_building = TRUE
+ toolspeed = 0.25 // Four times as fast.
+
+/obj/item/weapon/rcd/debug/can_afford(amount)
+ return TRUE
+
+/obj/item/weapon/rcd/debug/consume_resources(amount)
+ return TRUE
+
+/obj/item/weapon/rcd/debug/attackby(obj/item/weapon/W, mob/user)
+ if(istype(W, /obj/item/weapon/rcd_ammo))
+ to_chat(user, span("notice", "\The [src] makes its own material, no need to add more."))
+ return FALSE
+ return ..()
+
+/obj/item/weapon/rcd/debug/display_resources()
+ return "It has UNLIMITED POWER!"
+
+
+
+// Ammo for the (non-electric) RCDs.
/obj/item/weapon/rcd_ammo
name = "compressed matter cartridge"
desc = "Highly compressed matter for the RCD."
@@ -171,50 +295,11 @@
w_class = ITEMSIZE_SMALL
origin_tech = list(TECH_MATERIAL = 2)
matter = list(DEFAULT_WALL_MATERIAL = 30000,"glass" = 15000)
- var/remaining = 10
+ var/remaining = RCD_MAX_CAPACITY / 3
/obj/item/weapon/rcd_ammo/large
name = "high-capacity matter cartridge"
desc = "Do not ingest."
matter = list(DEFAULT_WALL_MATERIAL = 45000,"glass" = 22500)
- remaining = 30
origin_tech = list(TECH_MATERIAL = 4)
-
-/obj/item/weapon/rcd/borg
- canRwall = 1
-
-/obj/item/weapon/rcd/borg/lesser
- canRwall = FALSE
-
-/obj/item/weapon/rcd/borg/useResource(var/amount, var/mob/user)
- if(isrobot(user))
- var/mob/living/silicon/robot/R = user
- if(R.cell)
- var/cost = amount*30
- if(R.cell.charge >= cost)
- R.cell.use(cost)
- return 1
- return 0
-
-/obj/item/weapon/rcd/borg/attackby()
- return
-
-/obj/item/weapon/rcd/borg/can_use(var/mob/user,var/turf/T)
- return (user.Adjacent(T) && !user.stat)
-
-
-/obj/item/weapon/rcd/mounted/useResource(var/amount, var/mob/user)
- var/cost = amount*130 //so that a rig with default powercell can build ~2.5x the stuff a fully-loaded RCD can.
- if(istype(loc,/obj/item/rig_module))
- var/obj/item/rig_module/module = loc
- if(module.holder && module.holder.cell)
- if(module.holder.cell.charge >= cost)
- module.holder.cell.use(cost)
- return 1
- return 0
-
-/obj/item/weapon/rcd/mounted/attackby()
- return
-
-/obj/item/weapon/rcd/mounted/can_use(var/mob/user,var/turf/T)
- return (user.Adjacent(T) && !user.stat && !user.restrained())
+ remaining = RCD_MAX_CAPACITY
diff --git a/code/game/objects/structures/girders.dm b/code/game/objects/structures/girders.dm
index b61d01d2a4..058398d850 100644
--- a/code/game/objects/structures/girders.dm
+++ b/code/game/objects/structures/girders.dm
@@ -353,3 +353,54 @@
to_chat(user, "You drill through the girder!")
new /obj/effect/decal/remains/human(get_turf(src))
dismantle()
+
+
+/obj/structure/girder/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ var/turf/simulated/T = get_turf(src)
+ if(!istype(T) || T.density)
+ return FALSE
+
+ switch(passed_mode)
+ if(RCD_FLOORWALL)
+ // Finishing a wall costs two sheets.
+ var/cost = RCD_SHEETS_PER_MATTER_UNIT * 2
+ // Rwalls cost three to finish.
+ if(the_rcd.make_rwalls)
+ cost += RCD_SHEETS_PER_MATTER_UNIT * 1
+ return list(
+ RCD_VALUE_MODE = RCD_FLOORWALL,
+ RCD_VALUE_DELAY = 2 SECONDS,
+ RCD_VALUE_COST = cost
+ )
+ if(RCD_DECONSTRUCT)
+ return list(
+ RCD_VALUE_MODE = RCD_DECONSTRUCT,
+ RCD_VALUE_DELAY = 2 SECONDS,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5
+ )
+ return FALSE
+
+/obj/structure/girder/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ var/turf/simulated/T = get_turf(src)
+ if(!istype(T) || T.density) // Should stop future bugs of people bringing girders to centcom and RCDing them, or somehow putting a girder on a durasteel wall and deconning it.
+ return FALSE
+
+ switch(passed_mode)
+ if(RCD_FLOORWALL)
+ to_chat(user, span("notice", "You finish a wall."))
+ // This is mostly the same as using on a floor. The girder's material is preserved, however.
+ T.ChangeTurf(/turf/simulated/wall)
+ var/turf/simulated/wall/new_T = get_turf(src) // Ref to the wall we just built.
+ // Apparently set_material(...) for walls requires refs to the material singletons and not strings.
+ // This is different from how other material objects with their own set_material(...) do it, but whatever.
+ var/material/M = name_to_material[the_rcd.material_to_use]
+ new_T.set_material(M, the_rcd.make_rwalls ? M : null, girder_material)
+ new_T.add_hiddenprint(user)
+ qdel(src)
+ return TRUE
+
+ if(RCD_DECONSTRUCT)
+ to_chat(user, span("notice", "You deconstruct \the [src]."))
+ qdel(src)
+ return TRUE
+
diff --git a/code/game/objects/structures/grille.dm b/code/game/objects/structures/grille.dm
index f8d532688c..50fa3e8c6e 100644
--- a/code/game/objects/structures/grille.dm
+++ b/code/game/objects/structures/grille.dm
@@ -96,7 +96,9 @@
/obj/structure/grille/attackby(obj/item/W as obj, mob/user as mob)
if(!istype(W))
return
- if(W.is_wirecutter())
+ if(istype(W, /obj/item/weapon/rcd)) // To stop us from hitting the grille when building windows, because grilles don't let parent handle it properly.
+ return FALSE
+ else if(W.is_wirecutter())
if(!shock(user, 100))
playsound(src, W.usesound, 100, 1)
new /obj/item/stack/rods(get_turf(src), destroyed ? 1 : 2)
@@ -252,3 +254,38 @@
/obj/structure/grille/broken/rustic
icon_state = "grillerustic-b"
+
+
+/obj/structure/grille/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_WINDOWGRILLE)
+ // A full tile window costs 4 glass sheets.
+ return list(
+ RCD_VALUE_MODE = RCD_WINDOWGRILLE,
+ RCD_VALUE_DELAY = 2 SECONDS,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 4
+ )
+
+ if(RCD_DECONSTRUCT)
+ return list(
+ RCD_VALUE_MODE = RCD_DECONSTRUCT,
+ RCD_VALUE_DELAY = 2 SECONDS,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 2
+ )
+ return FALSE
+
+/obj/structure/grille/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_DECONSTRUCT)
+ to_chat(user, span("notice", "You deconstruct \the [src]."))
+ qdel(src)
+ return TRUE
+ if(RCD_WINDOWGRILLE)
+ if(locate(/obj/structure/window) in loc)
+ return FALSE
+ to_chat(user, span("notice", "You construct a window."))
+ var/obj/structure/window/WD = new the_rcd.window_type(loc)
+ WD.anchored = TRUE
+ return TRUE
+ return FALSE
+
diff --git a/code/game/objects/structures/window.dm b/code/game/objects/structures/window.dm
index 5ada656156..5c7adf8f0e 100644
--- a/code/game/objects/structures/window.dm
+++ b/code/game/objects/structures/window.dm
@@ -647,3 +647,20 @@
MT.update_icon()
return TRUE
. = ..()
+
+/obj/structure/window/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_DECONSTRUCT)
+ return list(
+ RCD_VALUE_MODE = RCD_DECONSTRUCT,
+ RCD_VALUE_DELAY = 5 SECONDS,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5
+ )
+
+/obj/structure/window/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_DECONSTRUCT)
+ to_chat(user, span("notice", "You deconstruct \the [src]."))
+ qdel(src)
+ return TRUE
+ return FALSE
diff --git a/code/game/turfs/flooring/flooring_premade.dm b/code/game/turfs/flooring/flooring_premade.dm
index d80e5f249e..e3e955ff17 100644
--- a/code/game/turfs/flooring/flooring_premade.dm
+++ b/code/game/turfs/flooring/flooring_premade.dm
@@ -298,7 +298,7 @@
initial_flooring = /decl/flooring/tiling/asteroidfloor
/turf/simulated/floor/tiled/asteroid_steel/airless
- name = "airless plating"
+ name = "plating"
oxygen = 0
nitrogen = 0
@@ -332,25 +332,25 @@
temperature = TCMB
/turf/simulated/floor/airless
- name = "airless plating"
+ name = "plating"
oxygen = 0
nitrogen = 0
temperature = TCMB
/turf/simulated/floor/tiled/airless
- name = "airless floor"
+ name = "floor"
oxygen = 0
nitrogen = 0
temperature = TCMB
/turf/simulated/floor/bluegrid/airless
- name = "airless floor"
+ name = "floor"
oxygen = 0
nitrogen = 0
temperature = TCMB
/turf/simulated/floor/greengrid/airless
- name = "airless floor"
+ name = "floor"
oxygen = 0
nitrogen = 0
temperature = TCMB
@@ -359,7 +359,7 @@
oxygen = 0
/turf/simulated/floor/tiled/white/airless
- name = "airless floor"
+ name = "floor"
oxygen = 0
nitrogen = 0
temperature = TCMB
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index 9f3a8e67b0..b615c0cc42 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -91,3 +91,71 @@
/turf/simulated/floor/levelupdate()
for(var/obj/O in src)
O.hide(O.hides_under_flooring() && src.flooring)
+
+/turf/simulated/floor/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_FLOORWALL)
+ // A wall costs four sheets to build (two for the grider and two for finishing it).
+ var/cost = RCD_SHEETS_PER_MATTER_UNIT * 4
+ // R-walls cost five sheets, however.
+ if(the_rcd.make_rwalls)
+ cost += RCD_SHEETS_PER_MATTER_UNIT * 1
+ return list(
+ RCD_VALUE_MODE = RCD_FLOORWALL,
+ RCD_VALUE_DELAY = 2 SECONDS,
+ RCD_VALUE_COST = cost
+ )
+ if(RCD_AIRLOCK)
+ // Airlock assemblies cost four sheets. Let's just add another for the electronics/wires/etc.
+ return list(
+ RCD_VALUE_MODE = RCD_AIRLOCK,
+ RCD_VALUE_DELAY = 5 SECONDS,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5
+ )
+ if(RCD_WINDOWGRILLE)
+ // One steel sheet for the girder (two rods, which is one sheet).
+ return list(
+ RCD_VALUE_MODE = RCD_WINDOWGRILLE,
+ RCD_VALUE_DELAY = 1 SECOND,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 1
+ )
+ if(RCD_DECONSTRUCT)
+ // Old RCDs made deconning the floor cost 10 units (IE, three times on full RCD).
+ // Now it's ten sheets worth of units (which is the same capacity-wise, three times on full RCD).
+ return list(
+ RCD_VALUE_MODE = RCD_DECONSTRUCT,
+ RCD_VALUE_DELAY = 5 SECONDS,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 10
+ )
+ return FALSE
+
+
+/turf/simulated/floor/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_FLOORWALL)
+ to_chat(user, span("notice", "You build a wall."))
+ ChangeTurf(/turf/simulated/wall)
+ var/turf/simulated/wall/T = get_turf(src) // Ref to the wall we just built.
+ // Apparently set_material(...) for walls requires refs to the material singletons and not strings.
+ // This is different from how other material objects with their own set_material(...) do it, but whatever.
+ var/material/M = name_to_material[the_rcd.material_to_use]
+ T.set_material(M, the_rcd.make_rwalls ? M : null, M)
+ T.add_hiddenprint(user)
+ return TRUE
+ if(RCD_AIRLOCK)
+ if(locate(/obj/machinery/door/airlock) in src)
+ return FALSE // No more airlock stacking.
+ to_chat(user, span("notice", "You build an airlock."))
+ new the_rcd.airlock_type(src)
+ return TRUE
+ if(RCD_WINDOWGRILLE)
+ if(locate(/obj/structure/grille) in src)
+ return FALSE
+ to_chat(user, span("notice", "You construct the grille."))
+ var/obj/structure/grille/G = new(src)
+ G.anchored = TRUE
+ return TRUE
+ if(RCD_DECONSTRUCT)
+ to_chat(user, span("notice", "You deconstruct \the [src]."))
+ ChangeTurf(get_base_turf_by_area(src), preserve_outdoors = TRUE)
+ return TRUE
diff --git a/code/game/turfs/simulated/outdoors/outdoors.dm b/code/game/turfs/simulated/outdoors/outdoors.dm
index fc373c0577..968816dc6a 100644
--- a/code/game/turfs/simulated/outdoors/outdoors.dm
+++ b/code/game/turfs/simulated/outdoors/outdoors.dm
@@ -15,6 +15,7 @@ var/list/turf_edge_cache = list()
edge_blending_priority = 1
outdoors = TRUE // This variable is used for weather effects.
can_dirty = FALSE // Looks hideous with dirt on it.
+ can_build_into_floor = TRUE
// When a turf gets demoted or promoted, this list gets adjusted. The top-most layer is the layer on the bottom of the list, due to how pop() works.
var/list/turf_layers = list(/turf/simulated/floor/outdoors/rocks)
diff --git a/code/game/turfs/simulated/walls.dm b/code/game/turfs/simulated/walls.dm
index b64ba73ee3..136b8eeba6 100644
--- a/code/game/turfs/simulated/walls.dm
+++ b/code/game/turfs/simulated/walls.dm
@@ -287,3 +287,27 @@
W.burn((temperature/4))
for(var/obj/machinery/door/airlock/phoron/D in range(3,src))
D.ignite(temperature/4)
+
+/turf/simulated/wall/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ if(material.integrity > 1000) // Don't decon things like elevatorium.
+ return FALSE
+ if(reinf_material && !the_rcd.can_remove_rwalls) // Gotta do it the old fashioned way if your RCD can't.
+ return FALSE
+
+ if(passed_mode == RCD_DECONSTRUCT)
+ var/delay_to_use = material.integrity / 3 // Steel has 150 integrity, so it'll take five seconds to down a regular wall.
+ if(reinf_material)
+ delay_to_use += reinf_material.integrity / 3
+ return list(
+ RCD_VALUE_MODE = RCD_DECONSTRUCT,
+ RCD_VALUE_DELAY = delay_to_use,
+ RCD_VALUE_COST = RCD_SHEETS_PER_MATTER_UNIT * 5
+ )
+ return FALSE
+
+/turf/simulated/wall/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ if(passed_mode == RCD_DECONSTRUCT)
+ to_chat(user, span("notice", "You deconstruct \the [src]."))
+ ChangeTurf(/turf/simulated/floor/airless, preserve_outdoors = TRUE)
+ return TRUE
+ return FALSE
diff --git a/code/game/turfs/space/space.dm b/code/game/turfs/space/space.dm
index ed48013050..d9a41718a8 100644
--- a/code/game/turfs/space/space.dm
+++ b/code/game/turfs/space/space.dm
@@ -6,6 +6,7 @@
temperature = T20C
thermal_conductivity = OPEN_HEAT_TRANSFER_COEFFICIENT
+ can_build_into_floor = TRUE
var/keep_sprite = FALSE
// heat_capacity = 700000 No.
diff --git a/code/game/turfs/space/transit.dm b/code/game/turfs/space/transit.dm
index 79550c3f30..0bfcb4e0f6 100644
--- a/code/game/turfs/space/transit.dm
+++ b/code/game/turfs/space/transit.dm
@@ -1,5 +1,6 @@
/turf/space/transit
keep_sprite = TRUE
+ can_build_into_floor = FALSE
var/pushdirection // push things that get caught in the transit tile this direction
//Overwrite because we dont want people building rods in space.
diff --git a/code/game/turfs/turf.dm b/code/game/turfs/turf.dm
index 8d26d11543..0c18524346 100644
--- a/code/game/turfs/turf.dm
+++ b/code/game/turfs/turf.dm
@@ -31,6 +31,7 @@
var/list/footstep_sounds = null
var/block_tele = FALSE // If true, most forms of teleporting to or from this turf tile will fail.
+ var/can_build_into_floor = FALSE // Used for things like RCDs (and maybe lattices/floor tiles in the future), to see if a floor should replace it.
/turf/New()
..()
@@ -321,3 +322,28 @@ var/const/enterloopsanity = 100
/turf/AllowDrop()
return TRUE
+
+// This is all the way up here since its the common ancestor for things that need to get replaced with a floor when an RCD is used on them.
+// More specialized turfs like walls should instead override this.
+// The code for applying lattices/floor tiles onto lattices could also utilize something similar in the future.
+/turf/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ if(density || !can_build_into_floor)
+ return FALSE
+ if(passed_mode == RCD_FLOORWALL)
+ var/obj/structure/lattice/L = locate() in src
+ // A lattice costs one rod to make. A sheet can make two rods, meaning a lattice costs half of a sheet.
+ // A sheet also makes four floor tiles, meaning it costs 1/4th of a sheet to place a floor tile on a lattice.
+ // Therefore it should cost 3/4ths of a sheet if a lattice is not present, or 1/4th of a sheet if it does.
+ return list(
+ RCD_VALUE_MODE = RCD_FLOORWALL,
+ RCD_VALUE_DELAY = 0,
+ RCD_VALUE_COST = L ? RCD_SHEETS_PER_MATTER_UNIT * 0.25 : RCD_SHEETS_PER_MATTER_UNIT * 0.75
+ )
+ return FALSE
+
+/turf/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ if(passed_mode == RCD_FLOORWALL)
+ to_chat(user, span("notice", "You build a floor."))
+ ChangeTurf(/turf/simulated/floor/airless, preserve_outdoors = TRUE)
+ return TRUE
+ return FALSE
diff --git a/code/game/turfs/unsimulated.dm b/code/game/turfs/unsimulated.dm
index b4c1999b48..fe6a77cb08 100644
--- a/code/game/turfs/unsimulated.dm
+++ b/code/game/turfs/unsimulated.dm
@@ -4,6 +4,7 @@
nitrogen = MOLES_N2STANDARD
initialized = TRUE // Don't call init on unsimulated turfs (at least not yet)
+<<<<<<< HEAD
//VOREStation Add
/turf/unsimulated/fake_space
name = "\proper space"
@@ -14,4 +15,12 @@
/turf/unsimulated/fake_space/New()
..()
icon_state = "[((x + y) ^ ~(x * y) + z) % 25]"
-//VOREStation Add End
\ No newline at end of file
+//VOREStation Add End
+=======
+// Better nip this just in case.
+/turf/unsimulated/rcd_values(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ return FALSE
+
+/turf/unsimulated/rcd_act(mob/living/user, obj/item/weapon/rcd/the_rcd, passed_mode)
+ return FALSE
+>>>>>>> 3b72438... Makes RCDs Clean Again (#5679)
diff --git a/code/modules/clothing/spacesuits/rig/modules/utility.dm b/code/modules/clothing/spacesuits/rig/modules/utility.dm
index 583f491d5e..058c1118ca 100644
--- a/code/modules/clothing/spacesuits/rig/modules/utility.dm
+++ b/code/modules/clothing/spacesuits/rig/modules/utility.dm
@@ -94,7 +94,7 @@
usable = 1
engage_string = "Configure RCD"
- device_type = /obj/item/weapon/rcd/mounted
+ device_type = /obj/item/weapon/rcd/electric/mounted/rig
/obj/item/rig_module/device/New()
..()
diff --git a/code/modules/mining/mine_turfs.dm b/code/modules/mining/mine_turfs.dm
index 11ac4dcae9..4ff5fd7e17 100644
--- a/code/modules/mining/mine_turfs.dm
+++ b/code/modules/mining/mine_turfs.dm
@@ -62,6 +62,7 @@ var/list/mining_overlay_cache = list()
density = 0
opacity = 0
blocks_air = 0
+ can_build_into_floor = TRUE
/turf/simulated/mineral/floor/ignore_mapgen
ignore_mapgen = 1
@@ -72,6 +73,7 @@ var/list/mining_overlay_cache = list()
density = 0
opacity = 0
blocks_air = 0
+ can_build_into_floor = TRUE
update_general()
/turf/simulated/mineral/proc/make_wall()
@@ -80,6 +82,7 @@ var/list/mining_overlay_cache = list()
density = 1
opacity = 1
blocks_air = 1
+ can_build_into_floor = FALSE
update_general()
/turf/simulated/mineral/proc/update_general()
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/station.dm b/code/modules/mob/living/silicon/robot/robot_modules/station.dm
index 90b51ac415..2416b339ff 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/station.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/station.dm
@@ -423,7 +423,7 @@ var/global/list/robot_modules = list(
src.modules += new /obj/item/weapon/inflatable_dispenser/robot(src)
src.emag = new /obj/item/weapon/melee/baton/robot/arm(src)
src.modules += new /obj/item/device/geiger(src)
- src.modules += new /obj/item/weapon/rcd/borg(src)
+ src.modules += new /obj/item/weapon/rcd/electric/mounted/borg(src)
src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
src.modules += new /obj/item/weapon/gripper/no_use/loader(src)
@@ -890,7 +890,7 @@ var/global/list/robot_modules = list(
/obj/item/weapon/robot_module/drone/construction/New()
..()
- src.modules += new /obj/item/weapon/rcd/borg(src)
+ src.modules += new /obj/item/weapon/rcd/electric/mounted/borg/lesser(src)
/obj/item/weapon/robot_module/drone/respawn_consumable(var/mob/living/silicon/robot/R, var/amount)
var/obj/item/device/lightreplacer/LR = locate() in src.modules
diff --git a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
index 3c8e981c3b..72caaa2d73 100644
--- a/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
+++ b/code/modules/mob/living/silicon/robot/robot_modules/syndicate.dm
@@ -83,7 +83,7 @@
src.modules += new /obj/item/weapon/tool/wirecutters/cyborg(src)
src.modules += new /obj/item/device/multitool/ai_detector(src)
src.modules += new /obj/item/weapon/pickaxe/plasmacutter(src)
- src.modules += new /obj/item/weapon/rcd/borg/lesser(src) // Can't eat rwalls to prevent AI core cheese.
+ src.modules += new /obj/item/weapon/rcd/electric/mounted/borg/lesser(src) // Can't eat rwalls to prevent AI core cheese.
src.modules += new /obj/item/weapon/melee/energy/sword/ionic_rapier(src)
// FBP repair.
diff --git a/code/modules/multiz/turf.dm b/code/modules/multiz/turf.dm
index ae44c58412..cbf7623267 100644
--- a/code/modules/multiz/turf.dm
+++ b/code/modules/multiz/turf.dm
@@ -26,6 +26,7 @@
plane = OPENSPACE_PLANE_START
pathweight = 100000 //Seriously, don't try and path over this one numbnuts
dynamic_lighting = 0 // Someday lets do proper lighting z-transfer. Until then we are leaving this off so it looks nicer.
+ can_build_into_floor = TRUE
var/turf/below
diff --git a/html/changelogs/Neerti-RCDs.yml b/html/changelogs/Neerti-RCDs.yml
new file mode 100644
index 0000000000..04c5778974
--- /dev/null
+++ b/html/changelogs/Neerti-RCDs.yml
@@ -0,0 +1,37 @@
+################################
+# Example Changelog File
+#
+# Note: This file, and files beginning with ".", and files that don't end in ".yml" will not be read. If you change this file, you will look really dumb.
+#
+# Your changelog will be merged with a master changelog. (New stuff added only, and only on the date entry for the day it was merged.)
+# When it is, any changes listed below will disappear.
+#
+# Valid Prefixes:
+# bugfix
+# wip (For works in progress)
+# tweak
+# soundadd
+# sounddel
+# rscadd (general adding of nice things)
+# rscdel (general deleting of nice things)
+# imageadd
+# imagedel
+# maptweak
+# spellcheck (typo fixes)
+# experiment
+#################################
+
+# Your name.
+author: Neerti
+
+# Optional: Remove this file after generating master changelog. Useful for PR changelogs that won't get used again.
+delete-after: True
+
+# Any changes you've made. See valid prefix list above.
+# INDENT WITH TWO SPACES. NOT TABS. SPACES.
+# SCREW THIS UP AND IT WON'T WORK.
+# Also, all entries are changed into a single [] after a master changelog generation. Just remove the brackets when you add new entries.
+# Please surround your changes in double quotes ("), as certain characters otherwise screws up compiling. The quotes will not show up in the changelog.
+changes:
+ - rscadd: "RCDs can now build grilles and windows, with a new mode. They can also finish walls when used on girders on floor/wall mode."
+ - rscadd: "Adds various new RCDs that are not obtainable at the moment."
diff --git a/icons/obj/items.dmi b/icons/obj/items.dmi
index a8e41841c3..d33437164e 100644
Binary files a/icons/obj/items.dmi and b/icons/obj/items.dmi differ
diff --git a/icons/obj/tools.dmi b/icons/obj/tools.dmi
index 9cbb46748a..b25a6cbc56 100644
Binary files a/icons/obj/tools.dmi and b/icons/obj/tools.dmi differ