diff --git a/code/__DEFINES/construction.dm b/code/__DEFINES/construction.dm
index c394d003d8..c93f1b2435 100644
--- a/code/__DEFINES/construction.dm
+++ b/code/__DEFINES/construction.dm
@@ -110,4 +110,7 @@
#define RCD_DECONSTRUCT 3
#define RCD_WINDOWGRILLE 4
#define RCD_MACHINE 8
-#define RCD_COMPUTER 16
\ No newline at end of file
+#define RCD_COMPUTER 16
+
+#define RCD_UPGRADE_FRAMES 1
+#define RCD_UPGRADE_SIMPLE_CIRCUITS 2
\ No newline at end of file
diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm
index 03c1bb3bc8..3e88223037 100644
--- a/code/game/machinery/doors/airlock.dm
+++ b/code/game/machinery/doors/airlock.dm
@@ -1408,6 +1408,9 @@
/obj/machinery/door/airlock/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
switch(the_rcd.mode)
if(RCD_DECONSTRUCT)
+ if(security_level != AIRLOCK_SECURITY_NONE && the_rcd.canRturf != TRUE)
+ to_chat(user, "[src]'s reinforcement needs to be removed first.")
+ return FALSE
return list("mode" = RCD_DECONSTRUCT, "delay" = 50, "cost" = 32)
return FALSE
diff --git a/code/game/machinery/doors/firedoor.dm b/code/game/machinery/doors/firedoor.dm
index dec41b0a59..39b6c8da1d 100644
--- a/code/game/machinery/doors/firedoor.dm
+++ b/code/game/machinery/doors/firedoor.dm
@@ -450,6 +450,21 @@
return
return ..()
+/obj/structure/firelock_frame/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
+ if((constructionStep == CONSTRUCTION_NOCIRCUIT) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS))
+ return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 20, "cost" = 1)
+ return FALSE
+
+/obj/structure/firelock_frame/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_UPGRADE_SIMPLE_CIRCUITS)
+ user.visible_message("[user] fabricates a circuit and places it into [src].", \
+ "You adapt a firelock circuit and slot it into the assembly.")
+ constructionStep = CONSTRUCTION_GUTTED
+ update_icon()
+ return TRUE
+ return FALSE
+
/obj/structure/firelock_frame/heavy
name = "heavy firelock frame"
reinforced = TRUE
diff --git a/code/game/machinery/firealarm.dm b/code/game/machinery/firealarm.dm
index 8f7fce8e3e..1ef3fc0a74 100644
--- a/code/game/machinery/firealarm.dm
+++ b/code/game/machinery/firealarm.dm
@@ -1,325 +1,340 @@
-#define FIREALARM_COOLDOWN 67 // Chosen fairly arbitrarily, it is the length of the audio in FireAlarm.ogg. The actual track length is 7 seconds 8ms but but the audio stops at 6s 700ms
-
-/obj/item/electronics/firealarm
- name = "fire alarm electronics"
- desc = "A fire alarm circuit. Can handle heat levels up to 40 degrees celsius."
-
-/obj/item/wallframe/firealarm
- name = "fire alarm frame"
- desc = "Used for building fire alarms."
- icon = 'icons/obj/monitors.dmi'
- icon_state = "fire_bitem"
- result_path = /obj/machinery/firealarm
-
-/obj/machinery/firealarm
- name = "fire alarm"
- desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever."
- icon = 'icons/obj/monitors.dmi'
- icon_state = "fire0"
- max_integrity = 250
- integrity_failure = 100
- armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
- use_power = IDLE_POWER_USE
- idle_power_usage = 2
- active_power_usage = 6
- power_channel = ENVIRON
- resistance_flags = FIRE_PROOF
-
- light_power = 0
- light_range = 7
- light_color = "#ff3232"
-
- var/detecting = 1
- var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
- var/last_alarm = 0
- var/area/myarea = null
-
-/obj/machinery/firealarm/Initialize(mapload, dir, building)
- . = ..()
- if(dir)
- src.setDir(dir)
- if(building)
- buildstage = 0
- panel_open = TRUE
- pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
- pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
- update_icon()
- myarea = get_area(src)
- LAZYADD(myarea.firealarms, src)
-
-/obj/machinery/firealarm/Destroy()
- LAZYREMOVE(myarea.firealarms, src)
- return ..()
-
-/obj/machinery/firealarm/power_change()
- ..()
- update_icon()
-
-/obj/machinery/firealarm/update_icon()
- cut_overlays()
- SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
-
- if(panel_open)
- icon_state = "fire_b[buildstage]"
- return
-
- if(stat & BROKEN)
- icon_state = "firex"
- return
-
- icon_state = "fire0"
-
- if(stat & NOPOWER)
- return
-
- add_overlay("fire_overlay")
-
- if(is_station_level(z))
- add_overlay("fire_[GLOB.security_level]")
- SSvis_overlays.add_vis_overlay(src, icon, "fire_[GLOB.security_level]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
- else
- add_overlay("fire_[SEC_LEVEL_GREEN]")
- SSvis_overlays.add_vis_overlay(src, icon, "fire_[SEC_LEVEL_GREEN]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
-
- var/area/A = src.loc
- A = A.loc
-
- if(!detecting || !A.fire)
- add_overlay("fire_off")
- SSvis_overlays.add_vis_overlay(src, icon, "fire_off", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
- else if(obj_flags & EMAGGED)
- add_overlay("fire_emagged")
- SSvis_overlays.add_vis_overlay(src, icon, "fire_emagged", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
- else
- add_overlay("fire_on")
- SSvis_overlays.add_vis_overlay(src, icon, "fire_on", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
-
-/obj/machinery/firealarm/emp_act(severity)
- . = ..()
-
- if (. & EMP_PROTECT_SELF)
- return
-
- if(prob(50 / severity))
- alarm()
-
-/obj/machinery/firealarm/emag_act(mob/user)
- . = ..()
- if(obj_flags & EMAGGED)
- return
- obj_flags |= EMAGGED
- update_icon()
- if(user)
- user.visible_message("Sparks fly out of [src]!",
- "You emag [src], disabling its thermal sensors.")
- playsound(src, "sparks", 50, 1)
- return TRUE
-
-/obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume)
- if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && (last_alarm+FIREALARM_COOLDOWN < world.time) && !(obj_flags & EMAGGED) && detecting && !stat)
- alarm()
- ..()
-
-/obj/machinery/firealarm/proc/alarm(mob/user)
- if(!is_operational() || (last_alarm+FIREALARM_COOLDOWN > world.time))
- return
- last_alarm = world.time
- var/area/A = get_area(src)
- A.firealert(src)
- playsound(loc, 'goon/sound/machinery/FireAlarm.ogg', 75)
- if(user)
- log_game("[user] triggered a fire alarm at [COORD(src)]")
-
-/obj/machinery/firealarm/proc/reset(mob/user)
- if(!is_operational())
- return
- var/area/A = get_area(src)
- A.firereset(src)
- if(user)
- log_game("[user] reset a fire alarm at [COORD(src)]")
-
-/obj/machinery/firealarm/attack_hand(mob/user)
- if(buildstage != 2)
- return ..()
- add_fingerprint(user)
- var/area/A = get_area(src)
- if(A.fire)
- reset(user)
- else
- alarm(user)
-
-/obj/machinery/firealarm/attack_ai(mob/user)
- return attack_hand(user)
-
-/obj/machinery/firealarm/attack_robot(mob/user)
- return attack_hand(user)
-
-/obj/machinery/firealarm/attackby(obj/item/W, mob/user, params)
- add_fingerprint(user)
-
- if(istype(W, /obj/item/screwdriver) && buildstage == 2)
- W.play_tool_sound(src)
- panel_open = !panel_open
- to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].")
- update_icon()
- return
-
- if(panel_open)
-
- if(istype(W, /obj/item/weldingtool) && user.a_intent == INTENT_HELP)
- if(obj_integrity < max_integrity)
- if(!W.tool_start_check(user, amount=0))
- return
-
- to_chat(user, "You begin repairing [src]...")
- if(W.use_tool(src, user, 40, volume=50))
- obj_integrity = max_integrity
- to_chat(user, "You repair [src].")
- else
- to_chat(user, "[src] is already in good condition!")
- return
-
- switch(buildstage)
- if(2)
- if(istype(W, /obj/item/multitool))
- detecting = !detecting
- if (src.detecting)
- user.visible_message("[user] has reconnected [src]'s detecting unit!", "You reconnect [src]'s detecting unit.")
- else
- user.visible_message("[user] has disconnected [src]'s detecting unit!", "You disconnect [src]'s detecting unit.")
- return
-
- else if (istype(W, /obj/item/wirecutters))
- buildstage = 1
- W.play_tool_sound(src)
- new /obj/item/stack/cable_coil(user.loc, 5)
- to_chat(user, "You cut the wires from \the [src].")
- update_icon()
- return
- else if(W.force) //hit and turn it on
- ..()
- var/area/A = get_area(src)
- if(!A.fire)
- alarm()
- return
- if(1)
- if(istype(W, /obj/item/stack/cable_coil))
- var/obj/item/stack/cable_coil/coil = W
- if(coil.get_amount() < 5)
- to_chat(user, "You need more cable for this!")
- else
- coil.use(5)
- buildstage = 2
- to_chat(user, "You wire \the [src].")
- update_icon()
- return
-
- else if(istype(W, /obj/item/crowbar))
- user.visible_message("[user.name] removes the electronics from [src.name].", \
- "You start prying out the circuit...")
- if(W.use_tool(src, user, 20, volume=50))
- if(buildstage == 1)
- if(stat & BROKEN)
- to_chat(user, "You remove the destroyed circuit.")
- stat &= ~BROKEN
- else
- to_chat(user, "You pry out the circuit.")
- new /obj/item/electronics/firealarm(user.loc)
- buildstage = 0
- update_icon()
- return
- if(0)
- if(istype(W, /obj/item/electronics/firealarm))
- to_chat(user, "You insert the circuit.")
- qdel(W)
- buildstage = 1
- update_icon()
- return
-
- else if(istype(W, /obj/item/electroadaptive_pseudocircuit))
- var/obj/item/electroadaptive_pseudocircuit/P = W
- if(!P.adapt_circuit(user, 15))
- return
- user.visible_message("[user] fabricates a circuit and places it into [src].", \
- "You adapt a fire alarm circuit and slot it into the assembly.")
- buildstage = 1
- update_icon()
- return
-
- else if(istype(W, /obj/item/wrench))
- user.visible_message("[user] removes the fire alarm assembly from the wall.", \
- "You remove the fire alarm assembly from the wall.")
- var/obj/item/wallframe/firealarm/frame = new /obj/item/wallframe/firealarm()
- frame.forceMove(user.drop_location())
- W.play_tool_sound(src)
- qdel(src)
- return
- return ..()
-
-/obj/machinery/firealarm/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
- . = ..()
- if(.) //damage received
- if(obj_integrity > 0 && !(stat & BROKEN) && buildstage != 0)
- if(prob(33))
- alarm()
-
-/obj/machinery/firealarm/singularity_pull(S, current_size)
- if (current_size >= STAGE_FIVE) // If the singulo is strong enough to pull anchored objects, the fire alarm experiences integrity failure
- deconstruct()
- ..()
-
-/obj/machinery/firealarm/obj_break(damage_flag)
- if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1) && buildstage != 0) //can't break the electronics if there isn't any inside.
- LAZYREMOVE(myarea.firealarms, src)
- stat |= BROKEN
- update_icon()
-
-/obj/machinery/firealarm/deconstruct(disassembled = TRUE)
- if(!(flags_1 & NODECONSTRUCT_1))
- new /obj/item/stack/sheet/metal(loc, 1)
- if(!(stat & BROKEN))
- var/obj/item/I = new /obj/item/electronics/firealarm(loc)
- if(!disassembled)
- I.obj_integrity = I.max_integrity * 0.5
- new /obj/item/stack/cable_coil(loc, 3)
- qdel(src)
-
-/obj/machinery/firealarm/proc/update_fire_light(fire)
- if(fire == !!light_power)
- return // do nothing if we're already active
- if(fire)
- set_light(l_power = 0.8)
- else
- set_light(l_power = 0)
-
-/*
- * Return of Party button
- */
-
-/area
- var/party = FALSE
-
-/obj/machinery/firealarm/partyalarm
- name = "\improper PARTY BUTTON"
- desc = "Cuban Pete is in the house!"
- var/static/party_overlay
-
-/obj/machinery/firealarm/partyalarm/reset()
- if (stat & (NOPOWER|BROKEN))
- return
- var/area/A = get_area(src)
- if (!A || !A.party)
- return
- A.party = FALSE
- A.cut_overlay(party_overlay)
-
-/obj/machinery/firealarm/partyalarm/alarm()
- if (stat & (NOPOWER|BROKEN))
- return
- var/area/A = get_area(src)
- if (!A || A.party || A.name == "Space")
- return
- A.party = TRUE
- if (!party_overlay)
- party_overlay = iconstate2appearance('icons/turf/areas.dmi', "party")
- A.add_overlay(party_overlay)
+#define FIREALARM_COOLDOWN 67 // Chosen fairly arbitrarily, it is the length of the audio in FireAlarm.ogg. The actual track length is 7 seconds 8ms but but the audio stops at 6s 700ms
+
+/obj/item/electronics/firealarm
+ name = "fire alarm electronics"
+ desc = "A fire alarm circuit. Can handle heat levels up to 40 degrees celsius."
+
+/obj/item/wallframe/firealarm
+ name = "fire alarm frame"
+ desc = "Used for building fire alarms."
+ icon = 'icons/obj/monitors.dmi'
+ icon_state = "fire_bitem"
+ result_path = /obj/machinery/firealarm
+
+/obj/machinery/firealarm
+ name = "fire alarm"
+ desc = "\"Pull this in case of emergency\". Thus, keep pulling it forever."
+ icon = 'icons/obj/monitors.dmi'
+ icon_state = "fire0"
+ max_integrity = 250
+ integrity_failure = 100
+ armor = list("melee" = 0, "bullet" = 0, "laser" = 0, "energy" = 0, "bomb" = 0, "bio" = 100, "rad" = 100, "fire" = 90, "acid" = 30)
+ use_power = IDLE_POWER_USE
+ idle_power_usage = 2
+ active_power_usage = 6
+ power_channel = ENVIRON
+ resistance_flags = FIRE_PROOF
+
+ light_power = 0
+ light_range = 7
+ light_color = "#ff3232"
+
+ var/detecting = 1
+ var/buildstage = 2 // 2 = complete, 1 = no wires, 0 = circuit gone
+ var/last_alarm = 0
+ var/area/myarea = null
+
+/obj/machinery/firealarm/Initialize(mapload, dir, building)
+ . = ..()
+ if(dir)
+ src.setDir(dir)
+ if(building)
+ buildstage = 0
+ panel_open = TRUE
+ pixel_x = (dir & 3)? 0 : (dir == 4 ? -24 : 24)
+ pixel_y = (dir & 3)? (dir ==1 ? -24 : 24) : 0
+ update_icon()
+ myarea = get_area(src)
+ LAZYADD(myarea.firealarms, src)
+
+/obj/machinery/firealarm/Destroy()
+ LAZYREMOVE(myarea.firealarms, src)
+ return ..()
+
+/obj/machinery/firealarm/power_change()
+ ..()
+ update_icon()
+
+/obj/machinery/firealarm/update_icon()
+ cut_overlays()
+ SSvis_overlays.remove_vis_overlay(src, managed_vis_overlays)
+
+ if(panel_open)
+ icon_state = "fire_b[buildstage]"
+ return
+
+ if(stat & BROKEN)
+ icon_state = "firex"
+ return
+
+ icon_state = "fire0"
+
+ if(stat & NOPOWER)
+ return
+
+ add_overlay("fire_overlay")
+
+ if(is_station_level(z))
+ add_overlay("fire_[GLOB.security_level]")
+ SSvis_overlays.add_vis_overlay(src, icon, "fire_[GLOB.security_level]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
+ else
+ add_overlay("fire_[SEC_LEVEL_GREEN]")
+ SSvis_overlays.add_vis_overlay(src, icon, "fire_[SEC_LEVEL_GREEN]", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
+
+ var/area/A = src.loc
+ A = A.loc
+
+ if(!detecting || !A.fire)
+ add_overlay("fire_off")
+ SSvis_overlays.add_vis_overlay(src, icon, "fire_off", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
+ else if(obj_flags & EMAGGED)
+ add_overlay("fire_emagged")
+ SSvis_overlays.add_vis_overlay(src, icon, "fire_emagged", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
+ else
+ add_overlay("fire_on")
+ SSvis_overlays.add_vis_overlay(src, icon, "fire_on", ABOVE_LIGHTING_LAYER, ABOVE_LIGHTING_PLANE, dir)
+
+/obj/machinery/firealarm/emp_act(severity)
+ . = ..()
+
+ if (. & EMP_PROTECT_SELF)
+ return
+
+ if(prob(50 / severity))
+ alarm()
+
+/obj/machinery/firealarm/emag_act(mob/user)
+ . = ..()
+ if(obj_flags & EMAGGED)
+ return
+ obj_flags |= EMAGGED
+ update_icon()
+ if(user)
+ user.visible_message("Sparks fly out of [src]!",
+ "You emag [src], disabling its thermal sensors.")
+ playsound(src, "sparks", 50, 1)
+ return TRUE
+
+/obj/machinery/firealarm/temperature_expose(datum/gas_mixture/air, temperature, volume)
+ if((temperature > T0C + 200 || temperature < BODYTEMP_COLD_DAMAGE_LIMIT) && (last_alarm+FIREALARM_COOLDOWN < world.time) && !(obj_flags & EMAGGED) && detecting && !stat)
+ alarm()
+ ..()
+
+/obj/machinery/firealarm/proc/alarm(mob/user)
+ if(!is_operational() || (last_alarm+FIREALARM_COOLDOWN > world.time))
+ return
+ last_alarm = world.time
+ var/area/A = get_area(src)
+ A.firealert(src)
+ playsound(loc, 'goon/sound/machinery/FireAlarm.ogg', 75)
+ if(user)
+ log_game("[user] triggered a fire alarm at [COORD(src)]")
+
+/obj/machinery/firealarm/proc/reset(mob/user)
+ if(!is_operational())
+ return
+ var/area/A = get_area(src)
+ A.firereset(src)
+ if(user)
+ log_game("[user] reset a fire alarm at [COORD(src)]")
+
+/obj/machinery/firealarm/attack_hand(mob/user)
+ if(buildstage != 2)
+ return ..()
+ add_fingerprint(user)
+ var/area/A = get_area(src)
+ if(A.fire)
+ reset(user)
+ else
+ alarm(user)
+
+/obj/machinery/firealarm/attack_ai(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/firealarm/attack_robot(mob/user)
+ return attack_hand(user)
+
+/obj/machinery/firealarm/attackby(obj/item/W, mob/user, params)
+ add_fingerprint(user)
+
+ if(istype(W, /obj/item/screwdriver) && buildstage == 2)
+ W.play_tool_sound(src)
+ panel_open = !panel_open
+ to_chat(user, "The wires have been [panel_open ? "exposed" : "unexposed"].")
+ update_icon()
+ return
+
+ if(panel_open)
+
+ if(istype(W, /obj/item/weldingtool) && user.a_intent == INTENT_HELP)
+ if(obj_integrity < max_integrity)
+ if(!W.tool_start_check(user, amount=0))
+ return
+
+ to_chat(user, "You begin repairing [src]...")
+ if(W.use_tool(src, user, 40, volume=50))
+ obj_integrity = max_integrity
+ to_chat(user, "You repair [src].")
+ else
+ to_chat(user, "[src] is already in good condition!")
+ return
+
+ switch(buildstage)
+ if(2)
+ if(istype(W, /obj/item/multitool))
+ detecting = !detecting
+ if (src.detecting)
+ user.visible_message("[user] has reconnected [src]'s detecting unit!", "You reconnect [src]'s detecting unit.")
+ else
+ user.visible_message("[user] has disconnected [src]'s detecting unit!", "You disconnect [src]'s detecting unit.")
+ return
+
+ else if (istype(W, /obj/item/wirecutters))
+ buildstage = 1
+ W.play_tool_sound(src)
+ new /obj/item/stack/cable_coil(user.loc, 5)
+ to_chat(user, "You cut the wires from \the [src].")
+ update_icon()
+ return
+ else if(W.force) //hit and turn it on
+ ..()
+ var/area/A = get_area(src)
+ if(!A.fire)
+ alarm()
+ return
+ if(1)
+ if(istype(W, /obj/item/stack/cable_coil))
+ var/obj/item/stack/cable_coil/coil = W
+ if(coil.get_amount() < 5)
+ to_chat(user, "You need more cable for this!")
+ else
+ coil.use(5)
+ buildstage = 2
+ to_chat(user, "You wire \the [src].")
+ update_icon()
+ return
+
+ else if(istype(W, /obj/item/crowbar))
+ user.visible_message("[user.name] removes the electronics from [src.name].", \
+ "You start prying out the circuit...")
+ if(W.use_tool(src, user, 20, volume=50))
+ if(buildstage == 1)
+ if(stat & BROKEN)
+ to_chat(user, "You remove the destroyed circuit.")
+ stat &= ~BROKEN
+ else
+ to_chat(user, "You pry out the circuit.")
+ new /obj/item/electronics/firealarm(user.loc)
+ buildstage = 0
+ update_icon()
+ return
+ if(0)
+ if(istype(W, /obj/item/electronics/firealarm))
+ to_chat(user, "You insert the circuit.")
+ qdel(W)
+ buildstage = 1
+ update_icon()
+ return
+
+ else if(istype(W, /obj/item/electroadaptive_pseudocircuit))
+ var/obj/item/electroadaptive_pseudocircuit/P = W
+ if(!P.adapt_circuit(user, 15))
+ return
+ user.visible_message("[user] fabricates a circuit and places it into [src].", \
+ "You adapt a fire alarm circuit and slot it into the assembly.")
+ buildstage = 1
+ update_icon()
+ return
+
+ else if(istype(W, /obj/item/wrench))
+ user.visible_message("[user] removes the fire alarm assembly from the wall.", \
+ "You remove the fire alarm assembly from the wall.")
+ var/obj/item/wallframe/firealarm/frame = new /obj/item/wallframe/firealarm()
+ frame.forceMove(user.drop_location())
+ W.play_tool_sound(src)
+ qdel(src)
+ return
+ return ..()
+
+/obj/machinery/firealarm/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
+ if((buildstage == 0) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS))
+ return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 20, "cost" = 1)
+ return FALSE
+
+/obj/machinery/firealarm/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_UPGRADE_SIMPLE_CIRCUITS)
+ user.visible_message("[user] fabricates a circuit and places it into [src].", \
+ "You adapt a fire alarm circuit and slot it into the assembly.")
+ buildstage = 1
+ update_icon()
+ return TRUE
+ return FALSE
+
+/obj/machinery/firealarm/take_damage(damage_amount, damage_type = BRUTE, damage_flag = 0, sound_effect = 1, attack_dir)
+ . = ..()
+ if(.) //damage received
+ if(obj_integrity > 0 && !(stat & BROKEN) && buildstage != 0)
+ if(prob(33))
+ alarm()
+
+/obj/machinery/firealarm/singularity_pull(S, current_size)
+ if (current_size >= STAGE_FIVE) // If the singulo is strong enough to pull anchored objects, the fire alarm experiences integrity failure
+ deconstruct()
+ ..()
+
+/obj/machinery/firealarm/obj_break(damage_flag)
+ if(!(stat & BROKEN) && !(flags_1 & NODECONSTRUCT_1) && buildstage != 0) //can't break the electronics if there isn't any inside.
+ LAZYREMOVE(myarea.firealarms, src)
+ stat |= BROKEN
+ update_icon()
+
+/obj/machinery/firealarm/deconstruct(disassembled = TRUE)
+ if(!(flags_1 & NODECONSTRUCT_1))
+ new /obj/item/stack/sheet/metal(loc, 1)
+ if(!(stat & BROKEN))
+ var/obj/item/I = new /obj/item/electronics/firealarm(loc)
+ if(!disassembled)
+ I.obj_integrity = I.max_integrity * 0.5
+ new /obj/item/stack/cable_coil(loc, 3)
+ qdel(src)
+
+/obj/machinery/firealarm/proc/update_fire_light(fire)
+ if(fire == !!light_power)
+ return // do nothing if we're already active
+ if(fire)
+ set_light(l_power = 0.8)
+ else
+ set_light(l_power = 0)
+
+/*
+ * Return of Party button
+ */
+
+/area
+ var/party = FALSE
+
+/obj/machinery/firealarm/partyalarm
+ name = "\improper PARTY BUTTON"
+ desc = "Cuban Pete is in the house!"
+ var/static/party_overlay
+
+/obj/machinery/firealarm/partyalarm/reset()
+ if (stat & (NOPOWER|BROKEN))
+ return
+ var/area/A = get_area(src)
+ if (!A || !A.party)
+ return
+ A.party = FALSE
+ A.cut_overlay(party_overlay)
+
+/obj/machinery/firealarm/partyalarm/alarm()
+ if (stat & (NOPOWER|BROKEN))
+ return
+ var/area/A = get_area(src)
+ if (!A || A.party || A.name == "Space")
+ return
+ A.party = TRUE
+ if (!party_overlay)
+ party_overlay = iconstate2appearance('icons/turf/areas.dmi', "party")
+ A.add_overlay(party_overlay)
diff --git a/code/game/objects/effects/temporary_visuals/miscellaneous.dm b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
index 1b85a41f7c..cdf6b77a76 100644
--- a/code/game/objects/effects/temporary_visuals/miscellaneous.dm
+++ b/code/game/objects/effects/temporary_visuals/miscellaneous.dm
@@ -452,4 +452,45 @@
icon_state = "slugboom"
randomdir = FALSE
duration = 30
- pixel_x = -24
\ No newline at end of file
+ pixel_x = -24
+
+/obj/effect/constructing_effect
+ icon = 'icons/effects/effects_rcd.dmi'
+ icon_state = ""
+ layer = ABOVE_ALL_MOB_LAYER
+ anchored = TRUE
+ var/status = 0
+ var/delay = 0
+ mouse_opacity = MOUSE_OPACITY_TRANSPARENT
+
+/obj/effect/constructing_effect/Initialize(mapload, rcd_delay, rcd_status)
+ . = ..()
+ status = rcd_status
+ delay = rcd_delay
+ if (status == RCD_DECONSTRUCT)
+ addtimer(CALLBACK(src, /atom/.proc/update_icon), 11)
+ delay -= 11
+ icon_state = "rcd_end_reverse"
+ else
+ update_icon()
+
+/obj/effect/constructing_effect/update_icon()
+ icon_state = "rcd"
+ if (delay < 10)
+ icon_state += "_shortest"
+ else if (delay < 20)
+ icon_state += "_shorter"
+ else if (delay < 37)
+ icon_state += "_short"
+ if (status == RCD_DECONSTRUCT)
+ icon_state += "_reverse"
+
+/obj/effect/constructing_effect/proc/end_animation()
+ if (status == RCD_DECONSTRUCT)
+ qdel(src)
+ else
+ icon_state = "rcd_end"
+ addtimer(CALLBACK(src, .proc/end), 15)
+
+/obj/effect/constructing_effect/proc/end()
+ qdel(src)
\ No newline at end of file
diff --git a/code/game/objects/items/RCD.dm b/code/game/objects/items/RCD.dm
index 24c241aabc..e151450d8a 100644
--- a/code/game/objects/items/RCD.dm
+++ b/code/game/objects/items/RCD.dm
@@ -47,7 +47,11 @@ RLD
/obj/item/construction/examine(mob/user)
. = ..()
- . += "\A [src]. It currently holds [matter]/[max_matter] matter-units."
+ . += "It currently holds [matter]/[max_matter] matter-units."
+ if(upgrade & RCD_UPGRADE_FRAMES)
+ . += "It contains the design for machine frames, computer frames and deconstruction."
+ if(upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS)
+ . += "It contains the design for firelock, air alarm, fire alarm, apc circuits and crap power cells."
/obj/item/construction/Destroy()
QDEL_NULL(spark_system)
@@ -85,9 +89,11 @@ RLD
to_chat(user, "[src] now holds [matter]/[max_matter] matter-units.")
else if(istype(W, /obj/item/rcd_upgrade))
to_chat(user, "You upgrade the RCD with the [W]!")
- upgrade = TRUE
- playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
- qdel(W)
+ var/obj/item/rcd_upgrade/rcd_up = W
+ if(!(upgrade & rcd_up.upgrade))
+ upgrade |= rcd_up.upgrade
+ playsound(src.loc, 'sound/machines/click.ogg', 50, 1)
+ qdel(W)
else
return ..()
update_icon() //ensures that ammo counters (if present) get updated
@@ -116,10 +122,10 @@ RLD
if(matter < amount)
if(user)
to_chat(user, no_ammo_message)
- return 0
+ return FALSE
matter -= amount
update_icon()
- return 1
+ return TRUE
/obj/item/construction/proc/checkResource(amount, mob/user)
. = matter >= amount
@@ -439,18 +445,22 @@ RLD
var/list/rcd_results = A.rcd_vals(user, src)
if(!rcd_results)
return FALSE
+ var/delay = rcd_results["delay"] * delay_mod
+ var/obj/effect/constructing_effect/rcd_effect = new(get_turf(A), delay, src.mode)
var/turf/the_turf = get_turf(A)
var/turf_coords = "[COORD(the_turf)]"
investigate_log("[user] is attempting to use [src] on [A] (loc [turf_coords] at [the_turf]) with cost [rcd_results["cost"]], delay [rcd_results["delay"]], mode [rcd_results["mode"]].", INVESTIGATE_RCD)
- if(do_after(user, rcd_results["delay"] * delay_mod, target = A))
+ if(do_after(user, delay, target = A))
if(checkResource(rcd_results["cost"], user))
var/atom/cached = A
if(A.rcd_act(user, src, rcd_results["mode"]))
+ rcd_effect.end_animation()
useResource(rcd_results["cost"], user)
activate()
investigate_log("[user] used [src] on [cached] (loc [turf_coords] at [the_turf]) with cost [rcd_results["cost"]], delay [rcd_results["delay"]], mode [rcd_results["mode"]].", INVESTIGATE_RCD)
playsound(src, 'sound/machines/click.ogg', 50, 1)
return TRUE
+ qdel(rcd_effect)
/obj/item/construction/rcd/Initialize()
. = ..()
@@ -467,7 +477,7 @@ RLD
"Grilles & Windows" = image(icon = 'icons/mob/radial.dmi', icon_state = "grillewindow"),
"Floors & Walls" = image(icon = 'icons/mob/radial.dmi', icon_state = "wallfloor")
)
- if(upgrade)
+ if(upgrade & RCD_UPGRADE_FRAMES)
choices += list(
"Deconstruct" = image(icon= 'icons/mob/radial.dmi', icon_state = "delete"),
"Machine Frames" = image(icon = 'icons/mob/radial.dmi', icon_state = "machine"),
@@ -593,6 +603,7 @@ RLD
energyfactor = 66
/obj/item/construction/rcd/loaded
+ materials = list(MAT_METAL=48000, MAT_GLASS=32000)
matter = 160
/obj/item/construction/rcd/loaded/upgraded
@@ -825,9 +836,18 @@ RLD
/obj/item/rcd_upgrade
name = "RCD advanced design disk"
- desc = "It contains the design for machine frames, computer frames, and deconstruction."
+ desc = "It seems to be empty."
icon = 'icons/obj/module.dmi'
icon_state = "datadisk3"
+ var/upgrade
+
+/obj/item/rcd_upgrade/frames
+ desc = "It contains the design for machine frames, computer frames and deconstruction."
+ upgrade = RCD_UPGRADE_FRAMES
+
+/obj/item/rcd_upgrade/simple_circuits
+ desc = "It contains the design for firelock, air alarm, fire alarm, apc circuits and crap power cells."
+ upgrade = RCD_UPGRADE_SIMPLE_CIRCUITS
#undef GLOW_MODE
#undef LIGHT_MODE
diff --git a/code/game/turfs/simulated/floor.dm b/code/game/turfs/simulated/floor.dm
index f9153ff8bf..720490942a 100644
--- a/code/game/turfs/simulated/floor.dm
+++ b/code/game/turfs/simulated/floor.dm
@@ -263,7 +263,7 @@
A.autoclose = TRUE
return TRUE
if(RCD_DECONSTRUCT)
- if(ScrapeAway(flags = CHANGETURF_INHERIT_AIR) == src)
+ if(!ScrapeAway(flags = CHANGETURF_INHERIT_AIR))
return FALSE
to_chat(user, "You deconstruct [src].")
return TRUE
diff --git a/code/modules/atmospherics/machinery/airalarm.dm b/code/modules/atmospherics/machinery/airalarm.dm
index cbbfc05f39..e49368016b 100644
--- a/code/modules/atmospherics/machinery/airalarm.dm
+++ b/code/modules/atmospherics/machinery/airalarm.dm
@@ -822,6 +822,21 @@
return ..()
+/obj/machinery/airalarm/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
+ if((buildstage == 0) && (the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS))
+ return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 20, "cost" = 1)
+ return FALSE
+
+/obj/machinery/airalarm/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_UPGRADE_SIMPLE_CIRCUITS)
+ user.visible_message("[user] fabricates a circuit and places it into [src].", \
+ "You adapt an air alarm circuit and slot it into the assembly.")
+ buildstage = 1
+ update_icon()
+ return TRUE
+ return FALSE
+
/obj/machinery/airalarm/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
diff --git a/code/modules/power/apc.dm b/code/modules/power/apc.dm
index 2652026a11..0ad2983b91 100644
--- a/code/modules/power/apc.dm
+++ b/code/modules/power/apc.dm
@@ -701,6 +701,52 @@
else
return ..()
+/obj/machinery/power/apc/rcd_vals(mob/user, obj/item/construction/rcd/the_rcd)
+ if(the_rcd.upgrade & RCD_UPGRADE_SIMPLE_CIRCUITS)
+ if(!has_electronics)
+ if(stat & BROKEN)
+ to_chat(user, "[src]'s frame is too damaged to support a circuit.")
+ return FALSE
+ return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 20, "cost" = 1)
+ else if(!cell)
+ if(stat & MAINT)
+ to_chat(user, "There's no connector for a power cell.")
+ return FALSE
+ return list("mode" = RCD_UPGRADE_SIMPLE_CIRCUITS, "delay" = 50, "cost" = 10) //16 for a wall
+ else
+ to_chat(user, "[src] has both electronics and a cell.")
+ return FALSE
+ return FALSE
+
+/obj/machinery/power/apc/rcd_act(mob/user, obj/item/construction/rcd/the_rcd, passed_mode)
+ switch(passed_mode)
+ if(RCD_UPGRADE_SIMPLE_CIRCUITS)
+ if(!has_electronics)
+ if(stat & BROKEN)
+ to_chat(user, "[src]'s frame is too damaged to support a circuit.")
+ return
+ user.visible_message("[user] fabricates a circuit and places it into [src].", \
+ "You adapt a power control board and click it into place in [src]'s guts.")
+ has_electronics = TRUE
+ locked = TRUE
+ return TRUE
+ else if(!cell)
+ if(stat & MAINT)
+ to_chat(user, "There's no connector for a power cell.")
+ return FALSE
+ var/obj/item/stock_parts/cell/crap/empty/C = new(src)
+ C.forceMove(src)
+ cell = C
+ chargecount = 0
+ user.visible_message("[user] fabricates a weak power cell and places it into [src].", \
+ "Your [the_rcd.name] whirrs with strain as you create a weak power cell and place it into [src]!")
+ update_icon()
+ return TRUE
+ else
+ to_chat(user, "[src] has both electronics and a cell.")
+ return FALSE
+ return FALSE
+
/obj/machinery/power/apc/AltClick(mob/user)
. = ..()
if(!user.canUseTopic(src, !issilicon(user)) || !isturf(loc))
diff --git a/code/modules/research/designs/misc_designs.dm b/code/modules/research/designs/misc_designs.dm
index 302ac345b7..b18db566af 100644
--- a/code/modules/research/designs/misc_designs.dm
+++ b/code/modules/research/designs/misc_designs.dm
@@ -389,13 +389,23 @@
////////////Tools//////////////
///////////////////////////////
-/datum/design/rcd_upgrade
- name = "Advanced RCD designs upgrade"
+/datum/design/rcd_upgrade/frames
+ name = "RCD frames designs upgrade"
desc = "Adds the computer frame and machine frame to the RCD."
- id = "rcd_upgrade"
+ id = "rcd_upgrade_frames"
build_type = PROTOLATHE
materials = list(MAT_METAL = 5000, MAT_GLASS = 2500, MAT_SILVER = 1500, MAT_TITANIUM = 2000)
- build_path = /obj/item/rcd_upgrade
+ build_path = /obj/item/rcd_upgrade/frames
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/rcd_upgrade/simple_circuits
+ name = "RCD simple circuits designs upgrade"
+ desc = "Adds the simple circuits to the RCD."
+ id = "rcd_upgrade_simple_circuits"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 5000, MAT_GLASS = 2500, MAT_SILVER = 1500, MAT_TITANIUM = 2000)
+ build_path = /obj/item/rcd_upgrade/simple_circuits
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
@@ -429,6 +439,26 @@
category = list("Equipment")
departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+/datum/design/rcd_loaded
+ name = "Rapid Construction Device"
+ desc = "A tool that can construct and deconstruct walls, airlocks and floors on the fly."
+ id = "rcd_loaded"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = MINERAL_MATERIAL_AMOUNT, MAT_GLASS = MINERAL_MATERIAL_AMOUNT) // costs more than what it did in the autolathe, this one comes loaded.
+ build_path = /obj/item/construction/rcd/loaded
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
+/datum/design/rpd
+ name = "Rapid Pipe Dispenser"
+ desc = "A tool that can construct and deconstruct pipes on the fly."
+ id = "rpd"
+ build_type = PROTOLATHE
+ materials = list(MAT_METAL = 75000, MAT_GLASS = 37500)
+ build_path = /obj/item/pipe_dispenser
+ category = list("Equipment")
+ departmental_flags = DEPARTMENTAL_FLAG_ENGINEERING
+
/datum/design/alienwrench
name = "Alien Wrench"
desc = "An advanced wrench obtained through Abductor technology."
diff --git a/code/modules/research/techweb/all_nodes.dm b/code/modules/research/techweb/all_nodes.dm
index f1151d6988..b6a1105cf4 100644
--- a/code/modules/research/techweb/all_nodes.dm
+++ b/code/modules/research/techweb/all_nodes.dm
@@ -200,7 +200,7 @@
display_name = "Advanced Engineering"
description = "Pushing the boundaries of physics, one chainsaw-fist at a time."
prereq_ids = list("engineering", "emp_basic")
- design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription", "rcd_upgrade")
+ design_ids = list("engine_goggles", "magboots", "forcefield_projector", "weldingmask" , "rcd_loaded", "rpd", "tray_goggles_prescription", "engine_goggles_prescription", "mesons_prescription", "rcd_upgrade_frames", "rcd_upgrade_simple_circuits")
research_costs = list(TECHWEB_POINT_TYPE_GENERIC = 4000)
export_price = 5000
diff --git a/icons/effects/effects_rcd.dmi b/icons/effects/effects_rcd.dmi
new file mode 100644
index 0000000000..efb13bfb11
Binary files /dev/null and b/icons/effects/effects_rcd.dmi differ