diff --git a/code/__DEFINES/lighting_defines.dm b/code/__DEFINES/lighting_defines.dm
index 87bde728432..03e1789a51d 100644
--- a/code/__DEFINES/lighting_defines.dm
+++ b/code/__DEFINES/lighting_defines.dm
@@ -27,6 +27,11 @@
0, 0, 0, 1 \
) \
+// Defines that handle the current status of a light
+#define LIGHT_OK 0
+#define LIGHT_EMPTY 1
+#define LIGHT_BROKEN 2
+#define LIGHT_BURNED 3
//Some defines to generalise colours used in lighting.
//Important note on colors. Colors can end up significantly different from the basic html picture, especially when saturated
diff --git a/code/game/mecha/equipment/tools/janitor_tools.dm b/code/game/mecha/equipment/tools/janitor_tools.dm
new file mode 100644
index 00000000000..8dce3ccb1a1
--- /dev/null
+++ b/code/game/mecha/equipment/tools/janitor_tools.dm
@@ -0,0 +1,295 @@
+// Mecha mop, light replacer, mecha spray, garbage bag
+
+/obj/item/mecha_parts/mecha_equipment/janitor
+
+/obj/item/mecha_parts/mecha_equipment/janitor/can_attach(obj/mecha/nkarrdem/M)
+ if(..() && istype(M))
+ return TRUE
+
+// Mop
+//! How many seconds before the mopping sound triggers again
+#define MOP_SOUND_CD 2 SECONDS
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop
+ name = "\improper WLLY mega mop"
+ desc = "An upsized advanced mop, designed for use in exosuits."
+ icon_state = "mecha_mop"
+ equip_cooldown = 1.5 SECONDS
+ energy_drain = 1
+ range = MECHA_MELEE | MECHA_RANGED
+ /// When the mopping sound was last played.
+ COOLDOWN_DECLARE(mop_sound_cooldown)
+ /// How fast does this mop?
+ var/mop_speed = 2 SECONDS
+ /// Toggle for refilling itself
+ var/refill_enabled = TRUE
+ /// Rate per process() tick mop refills itself
+ var/refill_rate = 5
+ /// Power use per process to refill reagents
+ var/refill_cost = 10
+ /// What reagent to refill with
+ var/refill_reagent = "water"
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop/Initialize(mapload)
+ . = ..()
+ create_reagents(1000)
+ reagents.add_reagent("water", 1000)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop/emag_act(mob/user)
+ . = ..()
+ emagged = TRUE
+ to_chat(user, "You short out the automatic watering system on [src].")
+ reagents.clear_reagents()
+ refill_reagent = "lube"
+ refill_cost = 50
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop/action(atom/target)
+ if(get_dist(chassis, target) > 2)
+ return
+ if(istype(target, /obj/structure/reagent_dispensers/watertank) && get_dist(chassis,target) <= 1)
+ var/obj/structure/reagent_dispensers/watertank/WT = target
+ WT.reagents.trans_to(src, 1000)
+ occupant_message("Mop refilled.")
+ playsound(chassis, 'sound/effects/refill.ogg', 50, TRUE, -6)
+ return
+ if(reagents.total_volume > 0)
+ if(COOLDOWN_FINISHED(src, mop_sound_cooldown))
+ playsound(loc, pick('sound/weapons/mopping1.ogg', 'sound/weapons/mopping2.ogg'), 30, TRUE, -1)
+ COOLDOWN_START(src, mop_sound_cooldown, MOP_SOUND_CD)
+ // 3x3 mopping area
+ var/turf/target_turf = get_turf(target)
+ if(!istype(target_turf) || iswallturf(target_turf))
+ return
+ chassis.occupant.visible_message("[chassis] begins to mop \the [target_turf] with \the [src].", "You begin to mop \the [target_turf] with \the [src].")
+ if(do_after(chassis.occupant, mop_speed, target = target))
+ for(var/turf/current_target_turf in view(1, target))
+ current_target_turf.cleaning_act(chassis.occupant, src, mop_speed, "mop", ".", skip_do_after = TRUE)
+ chassis.occupant_message("You mop \the [target].")
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop/post_clean(atom/target, mob/user)
+ var/turf/T = get_turf(target)
+ if(issimulatedturf(T))
+ reagents.reaction(T, REAGENT_TOUCH, 10) // 10 is the multiplier for the reaction effect. 10 is needed to properly wet a floor.
+ reagents.remove_any(1) // reaction() doesn't use up the reagents
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop/can_clean()
+ return reagents.has_reagent("water", 1) || reagents.has_reagent("cleaner", 1) || reagents.has_reagent("holywater", 1)
+
+// Auto-regeneration of water. Takes energy.
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop/process()
+ if(reagents.total_volume < 1000)
+ reagents.add_reagent(refill_reagent, refill_rate)
+ chassis.use_power(refill_cost)
+ update_equip_info()
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop/get_equip_info()
+ var/output = ..()
+ if(output)
+ return "[output] \[Refill [refill_enabled? "Enabled" : "Disabled"]\] \[[reagents.total_volume]\]"
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_mop/Topic(href, href_list)
+ ..()
+ var/datum/topic_input/afilter = new (href, href_list)
+ if(afilter.get("toggle_mode"))
+ refill_enabled = !refill_enabled
+ if(refill_enabled)
+ START_PROCESSING(SSobj, src)
+ else
+ STOP_PROCESSING(SSobj, src)
+ update_equip_info()
+
+#undef MOP_SOUND_CD
+
+// Light Replacer
+/obj/item/mecha_parts/mecha_equipment/janitor/light_replacer
+ name = "\improper NT-12 illuminator"
+ desc = "A modified light replacer fit for an exosuit that zaps lights into place."
+ icon_state = "mecha_light_replacer"
+ equip_cooldown = 1.5 SECONDS
+ energy_drain = 100
+ range = MECHA_MELEE | MECHA_RANGED
+
+/obj/item/mecha_parts/mecha_equipment/janitor/light_replacer/emag_act(mob/user)
+ . = ..()
+ emagged = TRUE
+ to_chat(user, "You short out the safeties on [src].")
+
+/obj/item/mecha_parts/mecha_equipment/janitor/light_replacer/action(atom/target)
+ if(istype(target, /obj/machinery/light))
+ chassis.Beam(target, icon_state = "rped_upgrade", icon = 'icons/effects/effects.dmi', time = 5)
+ playsound(src, 'sound/items/pshoom.ogg', 40, 1)
+ var/obj/machinery/light/light_to_fix = target
+ light_to_fix.fix(chassis.occupant, src, emagged)
+
+// Mecha spray
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_spray
+ name = "\improper JS-33 super spray"
+ desc = "A spray bottle, upscaled for an exosuit. Capable of mass sanitation."
+ icon_state = "mecha_spray"
+ equip_cooldown = 1.5 SECONDS
+ energy_drain = 200
+ range = MECHA_MELEE | MECHA_RANGED
+ /// Toggle for refilling itself
+ var/refill_enabled = TRUE
+ /// Rate per process() tick spray refills itself
+ var/refill_rate = 1
+ /// Power use per process to refill reagents
+ var/refill_cost = 25
+ /// What reagent to refill with
+ var/refill_reagent = "cleaner"
+ /// The range of tiles the sprayer will reach.
+ var/spray_range = 4
+ /// Internal sprayer object
+ var/obj/item/reagent_containers/spray/spray_controller = new /obj/item/reagent_containers/spray
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_spray/Initialize(mapload)
+ . = ..()
+ // Setup spray controller
+ spray_controller.loc = src
+ spray_controller.spray_maxrange = spray_range
+ spray_controller.spray_currentrange = spray_range
+ spray_controller.volume = 100
+ spray_controller.reagents.add_reagent("cleaner", 100)
+ START_PROCESSING(SSobj, src)
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_spray/emag_act(mob/user)
+ . = ..()
+ emagged = TRUE
+ to_chat(user, "You short out the automatic watering system on [src].")
+ spray_controller.reagents.clear_reagents()
+ refill_reagent = "lube"
+ refill_cost = 50
+ refill_rate = 5
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_spray/action(atom/target)
+ if(spray_controller.reagents.total_volume < 15) // Needs at least enough reagents to apply the full spray
+ to_chat(chassis.occupant, "*click*")
+ playsound(src, 'sound/weapons/empty.ogg', 100, 1)
+ return
+ var/direction = get_dir(chassis, target)
+ var/turf/T = get_turf(target)
+ var/turf/T1 = get_step(T, turn(direction, 90))
+ var/turf/T2 = get_step(T, turn(direction, -90))
+ var/list/the_targets = list(T, T1, T2)
+ playsound(chassis, 'sound/effects/spray2.ogg', 75, TRUE, -3)
+ for(var/turf/target_turf in the_targets)
+ INVOKE_ASYNC(src, PROC_REF(spray), target_turf)
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_spray/proc/spray(turf/target)
+ spray_controller.spray(target)
+
+// Auto-regeneration of space cleaner. Takes energy.
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_spray/process()
+ if(spray_controller.reagents.total_volume < 100)
+ spray_controller.reagents.add_reagent(refill_reagent, refill_rate)
+ chassis.use_power(refill_cost)
+ update_equip_info()
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_spray/get_equip_info()
+ var/output = ..()
+ if(output)
+ return "[output] \[Refill [refill_enabled? "Enabled" : "Disabled"]\] \[[spray_controller.reagents.total_volume]\]"
+
+/obj/item/mecha_parts/mecha_equipment/janitor/mega_spray/Topic(href,href_list)
+ ..()
+ var/datum/topic_input/afilter = new (href,href_list)
+ if(afilter.get("toggle_mode"))
+ refill_enabled = !refill_enabled
+ if(refill_enabled)
+ START_PROCESSING(SSobj, src)
+ else
+ STOP_PROCESSING(SSobj, src)
+ update_equip_info()
+
+// Garbage Magnet
+/obj/item/mecha_parts/mecha_equipment/janitor/garbage_magnet
+ name = "\improper WA1E Garbage Magnet"
+ desc = "Bluespace technology integrated with an oversized garbage bag and heavy duty magnets allows this device to pick up all manner of litter. \
+ The complex technology prevents users from directly looking inside the bag."
+ icon_state = "mecha_trash_magnet"
+ equip_cooldown = 1.5 SECONDS
+ energy_drain = 5
+ range = MECHA_MELEE | MECHA_RANGED
+ /// Toggle for filling the bag (true) or emptying (false)
+ var/bagging = TRUE
+ /// Toggle for wide area or single tile pickups
+ var/extended = FALSE
+ /// Garbage magnet range
+ var/max_range = 3
+ /// List of items the bag cannot hold
+ var/list/cant_hold = list(/obj/item/disk/nuclear, /obj/item/grown/bananapeel/traitorpeel, /obj/item/storage/bag)
+ /// Handles controlling the storage of items
+ var/obj/item/storage/bag/trash/storage_controller = new /obj/item/storage/bag/trash
+
+/obj/item/mecha_parts/mecha_equipment/janitor/garbage_magnet/Initialize(mapload)
+ . = ..()
+ storage_controller.loc = src
+ storage_controller.storage_slots = 100
+ storage_controller.max_combined_w_class = 100
+ storage_controller.max_w_class = WEIGHT_CLASS_NORMAL
+ storage_controller.w_class = WEIGHT_CLASS_NORMAL
+ storage_controller.allow_same_size = TRUE // This needs to be true or it won't be able to pick up smaller storages like boxes
+ storage_controller.cant_hold = typecacheof(cant_hold)
+
+/obj/item/mecha_parts/mecha_equipment/janitor/garbage_magnet/deconstruct()
+ var/turf/T = get_turf(src)
+ for(var/obj/item/I in storage_controller.contents)
+ storage_controller.remove_from_storage(I, T)
+ qdel(src)
+
+/obj/item/mecha_parts/mecha_equipment/janitor/garbage_magnet/get_equip_info()
+ var/output = ..()
+ if(output)
+ return "[output] \[[bagging? "Filling" : "Dumping"]\] \[Area [extended? "Extended" : "Focused"]\] \[Cargo: [length(storage_controller.contents)]/[storage_controller.max_combined_w_class]\]\]"
+
+/obj/item/mecha_parts/mecha_equipment/janitor/garbage_magnet/Topic(href,href_list)
+ ..()
+ var/datum/topic_input/afilter = new (href,href_list)
+ if(afilter.get("toggle_bagging"))
+ bagging = !bagging
+ update_equip_info()
+ return
+ if(afilter.get("toggle_extended"))
+ extended = !extended
+ update_equip_info()
+ return
+
+/obj/item/mecha_parts/mecha_equipment/janitor/garbage_magnet/action(atom/target)
+ if(get_dist(chassis, target) > max_range)
+ return
+ if(istype(target, /obj/machinery/disposal)) // Emptying stuff into disposals
+ chassis.occupant.visible_message(
+ "[chassis.occupant] empties [src] into the disposal unit.",
+ "You empty [src] into disposal unit.",
+ "You hear someone emptying something into a disposal unit."
+ )
+ chassis.Beam(target, icon_state = "rped_upgrade", icon = 'icons/effects/effects.dmi', time = 5)
+ playsound(src, 'sound/items/pshoom.ogg', 40, 1)
+ for(var/obj/item/I in storage_controller.contents)
+ storage_controller.remove_from_storage(I, target)
+ return
+ var/turf/target_turf
+ if(iswallturf(target))
+ return
+ if(isturf(target))
+ target_turf = target
+ else
+ target_turf = get_turf(target)
+ if(bagging) // If picking up
+ if(extended) // If extended reach
+ for(var/turf/current_target_turf in view(1, target_turf))
+ for(var/obj/item/I in current_target_turf.contents)
+ if(storage_controller.can_be_inserted(I))
+ storage_controller.handle_item_insertion(I, null, TRUE)
+ else // Single turf
+ for(var/obj/item/I in target_turf.contents)
+ if(storage_controller.can_be_inserted(I))
+ storage_controller.handle_item_insertion(I, null, TRUE)
+ chassis.occupant_message("You pick up all the items with [src]. Remaining cargo compartment capacity: [storage_controller.max_combined_w_class - length(storage_controller.contents)]")
+
+ else // Dumping
+ for(var/obj/item/I in storage_controller.contents)
+ storage_controller.remove_from_storage(I, target_turf)
+ chassis.occupant_message("You dump everything out of [src].")
+ update_equip_info()
diff --git a/code/game/mecha/equipment/weapons/weapons.dm b/code/game/mecha/equipment/weapons/weapons.dm
index 59762a09548..ba98e8b6ad8 100644
--- a/code/game/mecha/equipment/weapons/weapons.dm
+++ b/code/game/mecha/equipment/weapons/weapons.dm
@@ -391,6 +391,37 @@
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/flashbang/clusterbang/limited/rearm()
return//Extra bit of security
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/cleaner
+ name = "\improper N23 Rotary Janitation Launcher"
+ desc = "A tool of mass cleaning. Launches primed cleaning foam grenades. Major slipping hazard."
+ icon_state = "mecha_grenadelnchr"
+ origin_tech = "combat=4;engineering=4"
+ projectile = /obj/item/grenade/chem_grenade/cleaner
+ fire_sound = 'sound/effects/bang.ogg'
+ equip_cooldown = 6 SECONDS
+ projectiles = 6
+ missile_speed = 1.5
+ projectile_energy_cost = 1000
+ size = 1
+ /// Time until grenade detonates
+ var/det_time = 2 SECONDS
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/cleaner/action(target, params)
+ if(!action_checks(target))
+ return
+ set_ready_state(0)
+ var/obj/item/grenade/chem_grenade/cleaner/grenade = new projectile(chassis.loc)
+ playsound(chassis, fire_sound, 50, TRUE)
+ grenade.throw_at(target, missile_range, missile_speed)
+ projectiles--
+ log_message("Fired from [name], targeting [target].")
+ log_attack(chassis.occupant, target, "Cleaning grenade fired from [name], targeting [target].")
+ addtimer(CALLBACK(grenade, TYPE_PROC_REF(/obj/item/grenade/chem_grenade/cleaner, prime)), det_time)
+ do_after_cooldown()
+
+/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/cleaner/can_attach(obj/mecha/nkarrdem/M as obj)
+ return ..() && istype(M)
+
/obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/banana_mortar
equip_cooldown = 2 SECONDS
name = "banana mortar"
diff --git a/code/game/mecha/janitor/nkarrdem.dm b/code/game/mecha/janitor/nkarrdem.dm
new file mode 100644
index 00000000000..7018c597940
--- /dev/null
+++ b/code/game/mecha/janitor/nkarrdem.dm
@@ -0,0 +1,92 @@
+/obj/mecha/nkarrdem
+ desc = "A heavy duty sanitation exosuit; optimized for the removal of mass amounts of dirt, grime, and grease."
+ name = "Nkarrdem"
+ icon_state = "nkarrdem"
+ initial_icon = "nkarrdem"
+ step_in = 3
+ turnsound = 'sound/mecha/mechmove01.ogg'
+ stepsound = 'sound/mecha/mechstep.ogg'
+ max_temperature = 10000
+ max_integrity = 110
+ max_equip = 4
+ wreckage = /obj/structure/mecha_wreckage/nkarrdem
+ internal_damage_threshold = 35
+ deflect_chance = 15
+ step_energy_drain = 6
+ normal_step_energy_drain = 6
+ /// Is the janihud on?
+ var/builtin_hud_user = FALSE
+ /// Action that controls the floor buffer
+ var/datum/action/innate/mecha/mech_toggle_floorbuffer/floorbuffer_action = new
+
+/obj/mecha/nkarrdem/examine_more(mob/user)
+ ..()
+ . = list()
+ . += "The Nkarrdem is an older-generation CBRN mech developed jointly by Interdyne and Shellguard for rapid decontamination during a period where biological weapons are frequently used, though it suffered from several \
+ cost-cutting measures that exposes the operator to the hazardous environments. Surplus units are then sold for cleaning purposes."
+ . += ""
+ . += "The name 'Nkarrdem' comes from Skrellian legend, meaning 'Turquoise Fields'. The Turquoise Fields are an algae plataeu, where the kings of old would go to their final rest."
+
+
+/obj/mecha/nkarrdem/moved_inside(mob/living/carbon/human/H)
+ . = ..()
+ if(. && ishuman(H))
+ if(istype(H.glasses, /obj/item/clothing/glasses/hud))
+ occupant_message("[H.glasses] prevent you from using [src]'s built-in janitorial HUD.")
+ else
+ var/datum/atom_hud/data/janitor/jani_hud = GLOB.huds[DATA_HUD_JANITOR]
+ jani_hud.add_hud_to(H)
+ builtin_hud_user = TRUE
+
+/obj/mecha/nkarrdem/mmi_moved_inside(obj/item/mmi/mmi_as_oc, mob/user)
+ . = ..()
+ if(.)
+ if(occupant.client)
+ var/datum/atom_hud/data/janitor/jani_hud = GLOB.huds[DATA_HUD_JANITOR]
+ jani_hud.add_hud_to(occupant)
+ builtin_hud_user = TRUE
+
+/obj/mecha/nkarrdem/go_out()
+ if(ishuman(occupant) && builtin_hud_user)
+ var/mob/living/carbon/human/H = occupant
+ var/datum/atom_hud/data/janitor/jani_hud = GLOB.huds[DATA_HUD_JANITOR]
+ jani_hud.remove_hud_from(H)
+ builtin_hud_user = FALSE
+ else if((isbrain(occupant) || pilot_is_mmi()) && builtin_hud_user)
+ var/mob/living/brain/H = occupant
+ var/datum/atom_hud/data/janitor/jani_hud = GLOB.huds[DATA_HUD_JANITOR]
+ jani_hud.remove_hud_from(H)
+ builtin_hud_user = FALSE
+ return ..()
+
+/obj/mecha/nkarrdem/GrantActions(mob/living/user, human_occupant = 0)
+ . = ..()
+ floorbuffer_action.Grant(user, src)
+
+/obj/mecha/nkarrdem/RemoveActions(mob/living/user, human_occupant = 0)
+ . = ..()
+ floorbuffer_action.Remove(user)
+
+// Moving has to clean floors if the buffer is active
+/obj/mecha/nkarrdem/Move()
+ . = ..()
+ if(!floor_buffer)
+ return
+ var/turf/tile = get_turf(src)
+ if(!isturf(tile))
+ return
+ tile.clean_blood()
+ for(var/obj/effect/E in tile)
+ if(E.is_cleanable())
+ qdel(E)
+
+/obj/mecha/nkarrdem/loaded/Initialize(mapload)
+ . = ..()
+ var/obj/item/mecha_parts/mecha_equipment/ME = new /obj/item/mecha_parts/mecha_equipment/janitor/mega_spray
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/janitor/mega_mop
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/janitor/light_replacer
+ ME.attach(src)
+ ME = new /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/cleaner
+ ME.attach(src)
diff --git a/code/game/mecha/mech_fabricator.dm b/code/game/mecha/mech_fabricator.dm
index c64cfd40f11..a7f2be30560 100644
--- a/code/game/mecha/mech_fabricator.dm
+++ b/code/game/mecha/mech_fabricator.dm
@@ -71,6 +71,7 @@
"MODsuit Modules",
"Ripley",
"Firefighter",
+ "Nkarrdem",
"Odysseus",
"Gygax",
"Durand",
diff --git a/code/game/mecha/mecha.dm b/code/game/mecha/mecha.dm
index 813b9983e04..d04a540066a 100644
--- a/code/game/mecha/mecha.dm
+++ b/code/game/mecha/mecha.dm
@@ -109,6 +109,10 @@
var/phasing = FALSE
var/phasing_energy_drain = 200
var/phase_state = "" //icon_state when phasing
+ /// How much speed the mech loses while the buffer is active
+ var/buffer_delay = 1
+ /// Does it clean the tile under it?
+ var/floor_buffer = FALSE
//Action datums
var/datum/action/innate/mecha/mech_eject/eject_action = new
diff --git a/code/game/mecha/mecha_actions.dm b/code/game/mecha/mecha_actions.dm
index 316e4eb737e..437cf6aba10 100644
--- a/code/game/mecha/mecha_actions.dm
+++ b/code/game/mecha/mecha_actions.dm
@@ -221,6 +221,22 @@
playsound(src, 'sound/mecha/mechmove01.ogg', 50, TRUE)
UpdateButtons()
+// Floor Buffer Action
+/datum/action/innate/mecha/mech_toggle_floorbuffer
+ name = "Toggle Floor Buffer"
+ desc = "Movement speed is decreased while active."
+ button_overlay_icon = 'icons/obj/vehicles.dmi'
+ button_overlay_icon_state = "upgrade"
+
+/datum/action/innate/mecha/mech_toggle_floorbuffer/Activate()
+ if(!chassis.floor_buffer)
+ chassis.floor_buffer = TRUE
+ chassis.step_in += chassis.buffer_delay
+ else
+ chassis.floor_buffer = FALSE
+ chassis.step_in -= chassis.buffer_delay
+ to_chat(usr, "The floor buffer is now [chassis.floor_buffer ? "active" : "deactivated"].")
+
/datum/action/innate/mecha/select_module
name = "Hey, you shouldn't see this please make a bug report"
var/obj/item/mecha_parts/mecha_equipment/equipment
diff --git a/code/game/mecha/mecha_construction_paths.dm b/code/game/mecha/mecha_construction_paths.dm
index 02e7450f548..253f5acb0c4 100644
--- a/code/game/mecha/mecha_construction_paths.dm
+++ b/code/game/mecha/mecha_construction_paths.dm
@@ -1810,4 +1810,249 @@
holder.icon_state = "odysseus12"
return 1
+// NKARRDEM
+
+/datum/construction/mecha/nkarrdem_chassis
+ steps = list(list("key"=/obj/item/mecha_parts/part/nkarrdem_torso), // 1
+ list("key"=/obj/item/mecha_parts/part/nkarrdem_head), // 2
+ list("key"=/obj/item/mecha_parts/part/nkarrdem_left_arm), // 3
+ list("key"=/obj/item/mecha_parts/part/nkarrdem_right_arm), // 4
+ list("key"=/obj/item/mecha_parts/part/nkarrdem_left_leg), // 5
+ list("key"=/obj/item/mecha_parts/part/nkarrdem_right_leg) // 6
+ )
+
+/datum/construction/mecha/nkarrdem_chassis/custom_action(step, atom/used_atom, mob/user)
+ user.visible_message("[user] has connected [used_atom] to the [holder].", "You connect [used_atom] to the [holder]")
+ holder.overlays += used_atom.icon_state + "+o"
+ qdel(used_atom)
+ return TRUE
+
+/datum/construction/mecha/nkarrdem_chassis/action(atom/used_atom,mob/user as mob)
+ return check_all_steps(used_atom,user)
+
+/datum/construction/mecha/nkarrdem_chassis/spawn_result(mob/user, result_name)
+ ..(user, "Nkarrdem")
+ var/obj/item/mecha_parts/chassis/const_holder = holder
+ const_holder.construct = new /datum/construction/reversible/mecha/nkarrdem(const_holder)
+ const_holder.icon = 'icons/mecha/mech_construction.dmi'
+ const_holder.icon_state = "nkarrdem0"
+ const_holder.density = TRUE
+ qdel(src)
+
+/datum/construction/reversible/mecha/nkarrdem
+ result = "/obj/mecha/janitor/nkarrdem"
+ steps = list(
+ //1
+ list(
+ "key" = TOOL_WELDER,
+ "backkey" = TOOL_WRENCH,
+ "desc" = "External armor is wrenched."),
+ //2
+ list(
+ "key" = TOOL_WRENCH,
+ "backkey" = TOOL_CROWBAR,
+ "desc" = "External armor is installed."),
+ //3
+ list(
+ "key" = /obj/item/stack/sheet/plasteel,
+ "backkey" = TOOL_WELDER,
+ "desc" = "Internal armor is welded."),
+ //4
+ list(
+ "key" = TOOL_WELDER,
+ "backkey" = TOOL_WRENCH,
+ "desc" = "Internal armor is wrenched."),
+ //5
+ list(
+ "key" = TOOL_WRENCH,
+ "backkey" = TOOL_CROWBAR,
+ "desc" = "Internal armor is installed."),
+ //6
+ list(
+ "key" = /obj/item/stack/sheet/metal,
+ "backkey" = TOOL_SCREWDRIVER,
+ "desc" = "Floor buffer is secured."),
+ //7
+ list(
+ "key" = TOOL_SCREWDRIVER,
+ "backkey" = TOOL_CROWBAR,
+ "desc" = "Floor buffer is installed."),
+ //8
+ list(
+ "key" = /obj/item/borg/upgrade/floorbuffer,
+ "backkey" = TOOL_SCREWDRIVER,
+ "desc" = "Peripherals control module is secured."),
+ //9
+ list(
+ "key" = TOOL_SCREWDRIVER,
+ "backkey" = TOOL_CROWBAR,
+ "desc" = "Peripherals control module is installed."),
+ //10
+ list(
+ "key" = /obj/item/circuitboard/mecha/nkarrdem/peripherals,
+ "backkey" = TOOL_SCREWDRIVER,
+ "desc" = "Central control module is secured."),
+
+ //11
+ list(
+ "key" = TOOL_SCREWDRIVER,
+ "backkey" = TOOL_CROWBAR,
+ "desc" = "Central control module is installed."),
+ //12
+ list(
+ "key" = /obj/item/circuitboard/mecha/nkarrdem/main,
+ "backkey" = TOOL_SCREWDRIVER,
+ "desc" = "The wiring is adjusted."),
+ //13
+ list(
+ "key" = /obj/item/wirecutters,
+ "backkey" = TOOL_SCREWDRIVER,
+ "desc" = "The wiring is added."),
+ //14
+ list(
+ "key" = /obj/item/stack/cable_coil,
+ "backkey" = TOOL_SCREWDRIVER,
+ "desc" = "The hydraulic systems are active."),
+ //15
+ list(
+ "key" = TOOL_SCREWDRIVER,
+ "backkey" = TOOL_WRENCH,
+ "desc" = "The hydraulic systems are connected."),
+ //16
+ list(
+ "key" = TOOL_WRENCH,
+ "desc" = "The hydraulic systems are disconnected.")
+ )
+
+/datum/construction/reversible/mecha/nkarrdem/action(atom/used_atom, mob/user)
+ return check_step(used_atom,user)
+
+/datum/construction/reversible/mecha/nkarrdem/custom_action(index, diff, atom/used_atom, mob/user)
+ if(!..())
+ return FALSE
+
+ switch(index)
+ if(16)
+ user.visible_message("[user] connects the [holder] hydraulic systems", "You connect the [holder] hydraulic systems.")
+ holder.icon_state = "nkarrdem1"
+ if(15)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] activates the [holder] hydraulic systems.", "You activate the [holder] hydraulic systems.")
+ holder.icon_state = "nkarrdem2"
+ else
+ user.visible_message("[user] disconnects the [holder] hydraulic systems", "You disconnect the [holder] hydraulic systems.")
+ holder.icon_state = "nkarrdem0"
+ if(14)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] adds the wiring to the [holder].", "You add the wiring to the [holder].")
+ holder.icon_state = "nkarrdem3"
+ else
+ user.visible_message("[user] deactivates the [holder] hydraulic systems.", "You deactivate the [holder] hydraulic systems.")
+ holder.icon_state = "nkarrdem1"
+ if(13)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] adjusts the wiring of the [holder].", "You adjust the wiring of the [holder].")
+ holder.icon_state = "nkarrdem4"
+ else
+ user.visible_message("[user] removes the wiring from the [holder].", "You remove the wiring from the [holder].")
+ var/obj/item/stack/cable_coil/coil = new /obj/item/stack/cable_coil(get_turf(holder))
+ coil.amount = 4
+ holder.icon_state = "nkarrdem2"
+ if(12)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] installs the central control module into the [holder].", "You install the central computer mainboard into the [holder].")
+ qdel(used_atom)
+ holder.icon_state = "nkarrdem5"
+ else
+ user.visible_message("[user] disconnects the wiring of the [holder].", "You disconnect the wiring of the [holder].")
+ holder.icon_state = "nkarrdem3"
+ if(11)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] secures the mainboard.", "You secure the mainboard.")
+ holder.icon_state = "nkarrdem6"
+ else
+ user.visible_message("[user] removes the central control module from the [holder].", "You remove the central computer mainboard from the [holder].")
+ new /obj/item/circuitboard/mecha/nkarrdem/main(get_turf(holder))
+ holder.icon_state = "nkarrdem4"
+ if(10)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] installs the peripherals control module into the [holder].", "You install the peripherals control module into the [holder].")
+ qdel(used_atom)
+ holder.icon_state = "nkarrdem7"
+ else
+ user.visible_message("[user] unfastens the mainboard.", "You unfasten the mainboard.")
+ holder.icon_state = "nkarrdem5"
+ if(9)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] secures the peripherals control module.", "You secure the peripherals control module.")
+ holder.icon_state = "nkarrdem8"
+ else
+ user.visible_message("[user] removes the peripherals control module from the [holder].", "You remove the peripherals control module from the [holder].")
+ new /obj/item/circuitboard/mecha/nkarrdem/peripherals(get_turf(holder))
+ holder.icon_state = "nkarrdem6"
+ if(8)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] installs a floor buffer into [holder].", "You install a floor buffer into [holder].")
+ qdel(used_atom)
+ holder.icon_state = "nkarrdem9"
+ else
+ user.visible_message("[user] unfastens the peripherals control module.", "You unfasten the peripherals control module.")
+ holder.icon_state = "nkarrdem7"
+ if(7)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] secures a floor buffer into [holder].", "You secure the floor buffer into [holder].")
+ holder.icon_state = "nkarrdem10"
+ else
+ user.visible_message("[user] removes the floor buffer from the [holder].", "You unfasten the floor buffer from the [holder].")
+ new /obj/item/borg/upgrade/floorbuffer(get_turf(holder))
+ holder.icon_state = "nkarrdem8"
+ if(6)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] installs the internal armor layer to the [holder].", "You install the internal armor layer to the [holder].")
+ holder.icon_state = "nkarrdem11"
+ else
+ user.visible_message("[user] unfastens the floor buffer.", "You unfasten the floor buffer.")
+ holder.icon_state = "nkarrdem9"
+ if(5)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] secures the internal armor layer.", "You secure the internal armor layer.")
+ holder.icon_state = "nkarrdem12"
+ else
+ user.visible_message("[user] pries internal armor layer from the [holder].", "You pry internal armor layer from the [holder].")
+ var/obj/item/stack/sheet/metal/MS = new /obj/item/stack/sheet/metal(get_turf(holder))
+ MS.amount = 5
+ holder.icon_state = "nkarrdem10"
+ if(4)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] welds the internal armor layer to the [holder].", "You weld the internal armor layer to the [holder].")
+ holder.icon_state = "nkarrdem13"
+ else
+ user.visible_message("[user] unfastens the internal armor layer.", "You unfasten the internal armor layer.")
+ holder.icon_state = "nkarrdem11"
+ if(3)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] installs [used_atom] layer to the [holder].", "You install the external reinforced armor layer to the [holder].")
+
+ holder.icon_state = "nkarrdem14"
+ else
+ user.visible_message("[user] cuts the internal armor layer from the [holder].", "You cut the internal armor layer from the [holder].")
+ holder.icon_state = "nkarrdem12"
+ if(2)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] secures the external armor layer.", "You secure the external reinforced armor layer.")
+ holder.icon_state = "nkarrdem15"
+ else
+ var/obj/item/stack/sheet/plasteel/MS = new /obj/item/stack/sheet/plasteel(get_turf(holder))
+ MS.amount = 5
+ user.visible_message("[user] pries [MS] from the [holder].", "You pry [MS] from the [holder].")
+ holder.icon_state = "nkarrdem13"
+ if(1)
+ if(diff == CONSTRUCTION_PATH_FORWARDS)
+ user.visible_message("[user] welds the external armor layer to the [holder].", "You weld the external armor layer to the [holder].")
+ holder.icon_state = "nkarrdem16"
+ else
+ user.visible_message("[user] unfastens the external armor layer.", "You unfasten the external armor layer.")
+ holder.icon_state = "nkarrdem14"
+ return TRUE
+
#undef STANDARD_STACK_AMOUNT
diff --git a/code/game/mecha/mecha_parts.dm b/code/game/mecha/mecha_parts.dm
index 6773202fd41..f21c8c91573 100644
--- a/code/game/mecha/mecha_parts.dm
+++ b/code/game/mecha/mecha_parts.dm
@@ -349,6 +349,44 @@
icon_state = "odysseus_armour"
origin_tech = "materials=3;engineering=3")*/
+///////// Nkarrdem
+/obj/item/mecha_parts/chassis/nkarrdem
+ name = "\improper Nkarrdem Chassis"
+
+/obj/item/mecha_parts/chassis/nkarrdem/New()
+ ..()
+ construct = new /datum/construction/mecha/nkarrdem_chassis(src)
+
+/obj/item/mecha_parts/part/nkarrdem_head
+ name = "\improper Nkarrdem head"
+ icon_state = "nkarrdem_head"
+
+/obj/item/mecha_parts/part/nkarrdem_torso
+ name = "\improper Nkarrdem torso"
+ desc = "A torso part of Nkarrdem. Contains power unit, processing core and life support systems."
+ icon_state = "nkarrdem_harness"
+ origin_tech = "programming=2;materials=2;biotech=2;engineering=2"
+
+/obj/item/mecha_parts/part/nkarrdem_left_arm
+ name = "\improper Nkarrdem left arm"
+ desc = "A Nkarrdem left arm. Data and power sockets are compatible with most exosuit tools."
+ icon_state = "nkarrdem_l_arm"
+
+/obj/item/mecha_parts/part/nkarrdem_right_arm
+ name = "\improper Nkarrdem right arm"
+ desc = "A Nkarrdem right arm. Data and power sockets are compatible with most exosuit tools."
+ icon_state = "nkarrdem_r_arm"
+
+/obj/item/mecha_parts/part/nkarrdem_left_leg
+ name = "\improper Nkarrdem left leg"
+ desc = "A Nkarrdem left leg. Contains somewhat complex servodrives and balance maintaining systems."
+ icon_state = "nkarrdem_l_leg"
+
+/obj/item/mecha_parts/part/nkarrdem_right_leg
+ name = "\improper Nkarrdem right leg"
+ desc = "A Nkarrdem right leg. Contains somewhat complex servodrives and balance maintaining systems."
+ icon_state = "nkarrdem_r_leg"
+
///////// Circuitboards
@@ -373,6 +411,16 @@
board_name = "Ripley Peripherals Control Module"
icon_state = "mcontroller"
+/obj/item/circuitboard/mecha/nkarrdem
+ origin_tech = "programming=2"
+
+/obj/item/circuitboard/mecha/nkarrdem/main
+ board_name = "Nkarrdem Central Control Module"
+ icon_state = "mainboard"
+
+/obj/item/circuitboard/mecha/nkarrdem/peripherals
+ board_name = "Nkarrdem Peripherals Control Module"
+ icon_state = "mcontroller"
/obj/item/circuitboard/mecha/gygax
origin_tech = "programming=4;combat=3;engineering=3"
diff --git a/code/game/mecha/mecha_wreckage.dm b/code/game/mecha/mecha_wreckage.dm
index c5e87d3789d..18938ca2054 100644
--- a/code/game/mecha/mecha_wreckage.dm
+++ b/code/game/mecha/mecha_wreckage.dm
@@ -218,3 +218,15 @@
/obj/item/mecha_parts/part/odysseus_right_arm,
/obj/item/mecha_parts/part/odysseus_left_leg,
/obj/item/mecha_parts/part/odysseus_right_leg)
+
+/obj/structure/mecha_wreckage/nkarrdem
+ name = "\improper Nkarrdem wreckage"
+ icon_state = "nkarrdem-broken"
+ parts = list(
+ /obj/item/mecha_parts/part/nkarrdem_torso,
+ /obj/item/mecha_parts/part/nkarrdem_head,
+ /obj/item/mecha_parts/part/nkarrdem_left_arm,
+ /obj/item/mecha_parts/part/nkarrdem_right_arm,
+ /obj/item/mecha_parts/part/nkarrdem_left_leg,
+ /obj/item/mecha_parts/part/nkarrdem_right_leg
+ )
diff --git a/code/game/objects/cleaning.dm b/code/game/objects/cleaning.dm
index 5c81fd4b27b..82c1df31961 100644
--- a/code/game/objects/cleaning.dm
+++ b/code/game/objects/cleaning.dm
@@ -13,7 +13,9 @@
//Can normally be left alone, but needs to be defined if the thing being cleaned isn't necessarily the thing being clicked on,
//such as /obj/effect/rune/cleaning_act() bouncing to turf/simulated/cleaning_act().
-/atom/proc/cleaning_act(mob/user, atom/cleaner, cleanspeed = 5 SECONDS, text_verb = "clean", text_description = " with [cleaner].", text_targetname = name)
+// skip_do_after - When TRUE, do after and visible messages are disabled
+
+/atom/proc/cleaning_act(mob/user, atom/cleaner, cleanspeed = 5 SECONDS, text_verb = "clean", text_description = " with [cleaner].", text_targetname = name, skip_do_after = FALSE)
var/is_cmagged = FALSE
if(user.client && (src in user.client.screen)) //You can't clean items you're wearing for technical reasons
@@ -25,9 +27,10 @@
text_verb = "clean the ooze off"
cleanspeed = CMAG_CLEANTIME
- user.visible_message("[user] begins to [text_verb] \the [text_targetname][text_description]", "You begin to [text_verb] \the [text_targetname][text_description]")
- if(!do_after(user, cleanspeed, target = src))
- return FALSE
+ if(!skip_do_after)
+ user.visible_message("[user] begins to [text_verb] \the [text_targetname][text_description]", "You begin to [text_verb] \the [text_targetname][text_description]")
+ if(!do_after(user, cleanspeed, target = src))
+ return FALSE
if(!cleaner.can_clean())
cleaner.post_clean(src, user)
@@ -35,7 +38,8 @@
cleaner.post_clean(src, user)
- to_chat(user, "You [text_verb] \the [text_targetname][text_description]")
+ if(!skip_do_after)
+ to_chat(user, "You [text_verb] \the [text_targetname][text_description]")
if(is_cmagged) //If we've cleaned a cmagged object
REMOVE_TRAIT(src, TRAIT_CMAGGED, CLOWN_EMAG)
diff --git a/code/game/objects/items/devices/lightreplacer.dm b/code/game/objects/items/devices/lightreplacer.dm
index 30a73ab0ad1..7dac6e3640e 100644
--- a/code/game/objects/items/devices/lightreplacer.dm
+++ b/code/game/objects/items/devices/lightreplacer.dm
@@ -31,13 +31,6 @@
// access to them, and only one of them can emag their device.
//
// The explosion cannot insta-kill anyone with 30% or more health.
-
-#define LIGHT_OK 0
-#define LIGHT_EMPTY 1
-#define LIGHT_BROKEN 2
-#define LIGHT_BURNED 3
-
-
/obj/item/lightreplacer
name = "light replacer"
desc = "A device to automatically replace lights. Refill with broken or working light bulbs, or sheets of glass."
@@ -198,21 +191,10 @@
if(CanUse(U))
if(!Use(U))
return
- to_chat(U, "You replace the light [target.fitting] with [src].")
-
if(target.status != LIGHT_EMPTY)
AddShards(1, U)
target.status = LIGHT_EMPTY
-
- var/obj/item/light/replacement = target.light_type
- target.status = LIGHT_OK
- target.switchcount = 0
- target.rigged = emagged
- target.brightness_range = initial(replacement.brightness_range)
- target.brightness_power = initial(replacement.brightness_power)
- target.brightness_color = initial(replacement.brightness_color)
- target.on = target.has_power()
- target.update(TRUE, TRUE, FALSE)
+ target.fix(U, src, emagged)
else
to_chat(U, "[src]'s refill light blinks red.")
@@ -270,8 +252,3 @@
/obj/item/lightreplacer/bluespace/emag_act()
return // long range explosions are stupid
-
-#undef LIGHT_OK
-#undef LIGHT_EMPTY
-#undef LIGHT_BROKEN
-#undef LIGHT_BURNED
diff --git a/code/game/objects/items/weapons/storage/storage_base.dm b/code/game/objects/items/weapons/storage/storage_base.dm
index 9ae621d4693..0789f3ff9df 100644
--- a/code/game/objects/items/weapons/storage/storage_base.dm
+++ b/code/game/objects/items/weapons/storage/storage_base.dm
@@ -464,7 +464,8 @@
if(observer.client && observer.s_active != src)
observer.client.screen -= I
I.dropped(user, TRUE)
- add_fingerprint(user)
+ if(user)
+ add_fingerprint(user)
if(!prevent_warning)
// all mobs with clients attached, sans the item's user
@@ -481,10 +482,10 @@
// restrict player list to include only those in view
for(var/mob/M in oviewers(7, user))
M.show_message("[user] puts [I] into [src].")
-
orient2hud(user)
- if(user.s_active)
- user.s_active.show_to(user)
+ if(user)
+ if(user.s_active)
+ user.s_active.show_to(user)
I.mouse_opacity = MOUSE_OPACITY_OPAQUE //So you can click on the area around the item to equip it, instead of having to pixel hunt
I.in_inventory = TRUE
diff --git a/code/game/turfs/simulated.dm b/code/game/turfs/simulated.dm
index a175af95f5a..53cf6694f5e 100644
--- a/code/game/turfs/simulated.dm
+++ b/code/game/turfs/simulated.dm
@@ -37,7 +37,7 @@
/turf/simulated/proc/burn_tile()
return
-/turf/simulated/cleaning_act(mob/user, atom/cleaner, cleanspeed = 50, text_verb = "clean", text_description = " with [cleaner].", text_targetname = name)
+/turf/simulated/cleaning_act(mob/user, atom/cleaner, cleanspeed = 50, text_verb = "clean", text_description = " with [cleaner].", text_targetname = name, skip_do_after = FALSE)
if(!..())
return
diff --git a/code/modules/power/lights.dm b/code/modules/power/lights.dm
index f0590e08844..0728db514bc 100644
--- a/code/modules/power/lights.dm
+++ b/code/modules/power/lights.dm
@@ -2,12 +2,6 @@
//
// Consists of light fixtures (/obj/machinery/light) and light tube/bulb items (/obj/item/light)
-// status values shared between lighting fixtures and items
-#define LIGHT_OK 0
-#define LIGHT_EMPTY 1
-#define LIGHT_BROKEN 2
-#define LIGHT_BURNED 3
-
#define LIGHT_ON_DELAY_LOWER 1 SECONDS
#define LIGHT_ON_DELAY_UPPER 3 SECONDS
@@ -376,6 +370,17 @@
else
underlays += emissive_appearance(icon, "[base_state]_lightmask")
+/obj/machinery/light/fix(mob/user, obj/used_tool, emagged = FALSE)
+ if(status != LIGHT_OK)
+ to_chat(user, "You replace the [fitting] with [used_tool].")
+ status = LIGHT_OK
+ switchcount = 0
+ rigged = emagged
+ on = has_power()
+ update(TRUE, TRUE, FALSE)
+ else
+ to_chat(user, "There is a working [fitting] already inserted!")
+ return
/**
* Updates the light's 'on' state and power consumption based on [/obj/machinery/light/var/on].
*
@@ -1024,9 +1029,5 @@
#undef MAXIMUM_SAFE_BACKUP_CHARGE
#undef EMERGENCY_LIGHT_POWER_USE
-#undef LIGHT_OK
-#undef LIGHT_EMPTY
-#undef LIGHT_BROKEN
-#undef LIGHT_BURNED
#undef LIGHT_ON_DELAY_LOWER
#undef LIGHT_ON_DELAY_UPPER
diff --git a/code/modules/research/designs/mecha_designs.dm b/code/modules/research/designs/mecha_designs.dm
index 837f80365c0..d1ee3690dd8 100644
--- a/code/modules/research/designs/mecha_designs.dm
+++ b/code/modules/research/designs/mecha_designs.dm
@@ -27,7 +27,7 @@
name = "Exosuit Board (\"Odysseus\" Central Control module)"
desc = "Allows for the construction of a \"Odysseus\" Central Control module."
id = "odysseus_main"
- req_tech = list("programming" = 3,"biotech" = 3, "engineering" = 3)
+ req_tech = list("programming" = 3, "biotech" = 3, "engineering" = 3)
build_type = IMPRINTER
materials = list(MAT_GLASS = 1000)
build_path = /obj/item/circuitboard/mecha/odysseus/main
@@ -37,7 +37,28 @@
name = "Exosuit Board (\"Odysseus\" Peripherals Control module)"
desc = "Allows for the construction of a \"Odysseus\" Peripheral Control module."
id = "odysseus_peri"
- req_tech = list("programming" = 3,"biotech" = 3, "engineering" = 3)
+ req_tech = list("programming" = 3, "biotech" = 3, "engineering" = 3)
+ build_type = IMPRINTER
+ materials = list(MAT_GLASS = 1000)
+ build_path = /obj/item/circuitboard/mecha/odysseus/peripherals
+ category = list("Exosuit Modules")
+
+// Nkarrdem
+/datum/design/nkarrdem_main
+ name = "Exosuit Board (\"Nkarrdem\" Central Control module)"
+ desc = "Allows for the construction of a \"Nkarrdem\" Central Control module."
+ id = "nkarrdem_main"
+ req_tech = list("programming" = 3, "biotech" = 3, "engineering" = 3)
+ build_type = IMPRINTER
+ materials = list(MAT_GLASS = 1000)
+ build_path = /obj/item/circuitboard/mecha/odysseus/main
+ category = list("Exosuit Modules")
+
+/datum/design/nkarrdem_peri
+ name = "Exosuit Board (\"Nkarrdem\" Peripherals Control module)"
+ desc = "Allows for the construction of a \"Nkarrdem\" Peripheral Control module."
+ id = "nkarrdem_peri"
+ req_tech = list("programming" = 3, "biotech" = 3, "engineering" = 3)
build_type = IMPRINTER
materials = list(MAT_GLASS = 1000)
build_path = /obj/item/circuitboard/mecha/odysseus/peripherals
diff --git a/code/modules/research/designs/mechfabricator_designs.dm b/code/modules/research/designs/mechfabricator_designs.dm
index 92b1f19de11..39448394c68 100644
--- a/code/modules/research/designs/mechfabricator_designs.dm
+++ b/code/modules/research/designs/mechfabricator_designs.dm
@@ -249,6 +249,70 @@
construction_time = 13 SECONDS
category = list("Odysseus")
+//Nkarrdem
+/datum/design/nkarrdem_chassis
+ name = "Exosuit Chassis (\"Nkarrdem\")"
+ id = "nkarrdem_chassis"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/chassis/nkarrdem
+ materials = list(MAT_METAL=20000)
+ construction_time = 10 SECONDS
+ category = list("Nkarrdem")
+
+/datum/design/nkarrdem_torso
+ name = "Exosuit Torso (\"Nkarrdem\")"
+ id = "nkarrdem_torso"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/part/nkarrdem_torso
+ materials = list(MAT_METAL=12000)
+ construction_time = 18 SECONDS
+ category = list("Nkarrdem")
+
+/datum/design/nkarrdem_head
+ name = "Exosuit Head (\"Nkarrdem\")"
+ id = "nkarrdem_head"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/part/nkarrdem_head
+ materials = list(MAT_METAL=6000,MAT_GLASS=10000)
+ construction_time = 10 SECONDS
+ category = list("Nkarrdem")
+
+/datum/design/nkarrdem_left_arm
+ name = "Exosuit Left Arm (\"Nkarrdem\")"
+ id = "nkarrdem_left_arm"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/part/nkarrdem_left_arm
+ materials = list(MAT_METAL=6000)
+ construction_time = 12 SECONDS
+ category = list("Nkarrdem")
+
+/datum/design/nkarrdem_right_arm
+ name = "Exosuit Right Arm (\"Nkarrdem\")"
+ id = "nkarrdem_right_arm"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/part/nkarrdem_right_arm
+ materials = list(MAT_METAL=6000)
+ construction_time = 12 SECONDS
+ category = list("Nkarrdem")
+
+/datum/design/nkarrdem_left_leg
+ name = "Exosuit Left Leg (\"Nkarrdem\")"
+ id = "nkarrdem_left_leg"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/part/nkarrdem_left_leg
+ materials = list(MAT_METAL=12000)
+ construction_time = 13 SECONDS
+ category = list("Nkarrdem")
+
+/datum/design/nkarrdem_right_leg
+ name = "Exosuit Right Leg (\"Nkarrdem\")"
+ id = "nkarrdem_right_leg"
+ build_type = MECHFAB
+ build_path = /obj/item/mecha_parts/part/nkarrdem_right_leg
+ materials = list(MAT_METAL=12000)
+ construction_time = 13 SECONDS
+ category = list("Nkarrdem")
+
//Gygax
/datum/design/gygax_chassis
name = "Exosuit Chassis (\"Gygax\")"
@@ -672,6 +736,56 @@
construction_time = 20 SECONDS
category = list("Exosuit Equipment")
+/datum/design/mech_mop
+ name = "Exosuit Janitorial Equipment (Mega Mop)"
+ id = "mech_mop"
+ build_type = MECHFAB
+ req_tech = list("materials" = 4, "engineering" = 3)
+ build_path = /obj/item/mecha_parts/mecha_equipment/janitor/mega_mop
+ materials = list(MAT_METAL=5000,MAT_GLASS=3000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_garbage_bag
+ name = "Exosuit Janitorial Equipment (Garbage Magnet)"
+ id = "mech_garbage_bag"
+ build_type = MECHFAB
+ req_tech = list("materials" = 5, "bluespace" = 4, "engineering" = 4, "plasmatech" = 3)
+ build_path = /obj/item/mecha_parts/mecha_equipment/janitor/garbage_magnet
+ materials = list(MAT_METAL=1500,MAT_GOLD=1500,MAT_URANIUM=700,MAT_PLASMA=2000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_mega_spray
+ name = "Exosuit Janitorial Equipment (Mega Spray)"
+ id = "mech_mega_spray"
+ build_type = MECHFAB
+ req_tech = list("biotech" = 5, "engineering" = 6, "plasmatech" = 6)
+ build_path = /obj/item/mecha_parts/mecha_equipment/janitor/mega_spray
+ materials = list(MAT_METAL=1000,MAT_GLASS=4000,MAT_GOLD=1000,MAT_PLASMA=3000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_light_replacer
+ name = "Exosuit Janitorial Equipment (Light Replacer)"
+ id = "mech_light_replacer"
+ build_type = MECHFAB
+ req_tech = list("bluespace" = 7, "materials" = 5, "engineering" = 6, "plasmatech" = 6)
+ build_path = /obj/item/mecha_parts/mecha_equipment/janitor/light_replacer
+ materials = list(MAT_METAL=1500,MAT_SILVER=150,MAT_GLASS=6000,MAT_BLUESPACE=300)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Equipment")
+
+/datum/design/mech_cleaning_grenade_launcher
+ name = "Exosuit Janitorial Equipment (Cleaning Grenade Launcher)"
+ id = "mech_cleaning_grenade_launcher"
+ build_type = MECHFAB
+ req_tech = list("toxins" = 7, "engineering" = 7, "plasmatech" = 6, "combat" = 6)
+ build_path = /obj/item/mecha_parts/mecha_equipment/weapon/ballistic/missile_rack/cleaner
+ materials = list(MAT_METAL=5000,MAT_GLASS=3000,MAT_SILVER=4000,MAT_GOLD=6000)
+ construction_time = 10 SECONDS
+ category = list("Exosuit Equipment")
+
/datum/design/mech_generator
name = "Exosuit Equipment (Plasma Generator)"
id = "mech_generator"
diff --git a/icons/mecha/mech_construct.dmi b/icons/mecha/mech_construct.dmi
index fe81a8e2b96..3ac2bc928f8 100644
Binary files a/icons/mecha/mech_construct.dmi and b/icons/mecha/mech_construct.dmi differ
diff --git a/icons/mecha/mech_construction.dmi b/icons/mecha/mech_construction.dmi
index e89db4ff9ad..f00b27e101c 100644
Binary files a/icons/mecha/mech_construction.dmi and b/icons/mecha/mech_construction.dmi differ
diff --git a/icons/mecha/mecha.dmi b/icons/mecha/mecha.dmi
index 28b04958109..ea0d7391cc6 100644
Binary files a/icons/mecha/mecha.dmi and b/icons/mecha/mecha.dmi differ
diff --git a/icons/mecha/mecha_equipment.dmi b/icons/mecha/mecha_equipment.dmi
index 50c0338d831..f26012f3259 100644
Binary files a/icons/mecha/mecha_equipment.dmi and b/icons/mecha/mecha_equipment.dmi differ
diff --git a/paradise.dme b/paradise.dme
index 2216a29cc84..dcfa51943b3 100644
--- a/paradise.dme
+++ b/paradise.dme
@@ -956,11 +956,13 @@
#include "code\game\mecha\combat\phazon.dm"
#include "code\game\mecha\combat\reticence.dm"
#include "code\game\mecha\equipment\mecha_equipment.dm"
+#include "code\game\mecha\equipment\tools\janitor_tools.dm"
#include "code\game\mecha\equipment\tools\mecha_mining_tools.dm"
#include "code\game\mecha\equipment\tools\medical_tools.dm"
#include "code\game\mecha\equipment\tools\other_tools.dm"
#include "code\game\mecha\equipment\tools\work_tools.dm"
#include "code\game\mecha\equipment\weapons\weapons.dm"
+#include "code\game\mecha\janitor\nkarrdem.dm"
#include "code\game\mecha\medical\medical_base.dm"
#include "code\game\mecha\medical\odysseus.dm"
#include "code\game\mecha\working\ripley.dm"