diff --git a/code/game/machinery/bots/cprbot.dm b/code/game/machinery/bots/cprbot.dm
new file mode 100644
index 000000000000..faecf15a5d93
--- /dev/null
+++ b/code/game/machinery/bots/cprbot.dm
@@ -0,0 +1,509 @@
+/obj/item/cprbot_item
+ name = "Placeholder"
+
+/obj/item/cprbot_broken
+ name = "Placeholder"
+
+#define STATE_CPRBOT_IDLE "idle"
+#define STATE_CPRBOT_MOVING "moving"
+#define STATE_CPRBOT_CPR "cpr"
+#define STATE_CPRBOT_FOLLOWING_OWNER "following_owner"
+
+
+/obj/structure/machinery/bot/cprbot
+ name = "\improper CPRbot"
+ desc = "Designed for urgent medical intervention, this CPRbot offers high-tech support in a compact form."
+ icon = 'icons/obj/structures/machinery/aibots.dmi'
+ icon_state = "cprbot0"
+ density = FALSE
+ anchored = FALSE
+ health = 100
+ maxhealth = 100
+ req_access = list(ACCESS_MARINE_MEDBAY)
+
+ /// Radius to search for patients
+ var/static/search_radius = 7
+ /// Radius to check for nearby CPRbots
+ var/static/cprbot_proximity_check_radius = 2
+ /// Current target for CPR (using weak reference)
+ var/datum/weakref/human
+ var/list/botcard_access = list(ACCESS_MARINE_MEDBAY)
+ /// Indicates whether the bot is currently healing
+ var/currently_healing = FALSE
+ var/cpr_ready = TRUE
+ /// IFF signal to check for valid targets
+ var/iff_signal = FACTION_MARINE
+ /// Cooldown for the random idle messages and medical facts
+ var/cooldown_time = 60 SECONDS
+ var/movement_delay = 4
+ var/owner
+ var/fast_processing = FALSE
+ COOLDOWN_DECLARE(message_cooldown)
+
+ var/state = STATE_CPRBOT_IDLE
+
+ var/turf/last_location // used for pathfinding
+
+ var/list/path = list()
+
+ var/move_to_delay = 4
+
+ var/static/list/medical_facts = list(
+ "Did you know? The human heart beats over 100,000 times a day.",
+ "Fun fact: Blood makes up about 7% of your body's weight.",
+ "Medical trivia: Your brain uses 20% of the oxygen you breathe.",
+ "Laughter really can increase your pain tolerance.",
+ "Did you know? The human skeleton is made up of 206 bones.",
+ "Fun fact: The average adult human body contains about 5 liters of blood.",
+ "Medical trivia: The human body has around 37.2 trillion cells.",
+ "The skin is the largest organ in the human body.",
+ "Did you know? The liver can regenerate itself if a portion is removed.",
+ "Fun fact: Your sense of smell is closely linked to your memory.",
+ "The only muscle that never tires is that heart.",
+ "Did you know? Not breathing can lead to a premature cessation of life!"
+ )
+
+ var/static/list/idle_messages = list(
+ "Stay still, I'm assessing the situation.",
+ "Just a routine check-up, don't worry.",
+ "Scanning the area for any casualties.",
+ "I’m ready to save lives, one compression at a time.",
+ "I hope everyone is feeling alright today!",
+ "It's not magic, it's CPR Buddy 9000!",
+ "I should have been a plastic surgeon.",
+ "What kind of medbay is this? Everyone’s dropping like flies.",
+ "Each breath a day keeps me at bay!",
+ "I sense a disturbance in my circuit board, as if a million people stopped breathing and were suddenly silent."
+ )
+
+ /// Message to display when performing CPR
+ var/motivational_message = "Live! Live! Don't die on me now!"
+ /// List of patients who have been warned
+ var/list/has_said_to_patient = list()
+ /// Tracks the last time a message was spoken
+ var/last_message_time = 0
+
+/obj/structure/machinery/bot/cprbot/Initialize(mapload, ...)
+ . = ..()
+ start_processing()
+ playsound(loc, 'sound/CPRbot/CPRbot_poweron.ogg', 25, 1)
+ src.botcard = new /obj/item/card/id(src)
+ if(!LAZYLEN(src.botcard_access))
+ var/datum/job/J = GLOB.RoleAuthority ? GLOB.RoleAuthority.roles_by_path[/datum/job/civilian/doctor] : new /datum/job/civilian/doctor
+ botcard.access = J.get_access()
+ else
+ src.botcard.access = src.botcard_access
+
+/obj/structure/machinery/bot/cprbot/process()
+ if (health > 0)
+ think()
+
+ random_message()
+ else
+ stop_processing()
+
+/obj/structure/machinery/bot/cprbot/proc/think()
+ switch (state)
+ if (STATE_CPRBOT_IDLE)
+ find_and_move_to_patient()
+ if (STATE_CPRBOT_MOVING)
+ move_to_target()
+ if (STATE_CPRBOT_CPR)
+ try_perform_cpr()
+ if (STATE_CPRBOT_FOLLOWING_OWNER)
+ follow_owner()
+
+/obj/structure/machinery/bot/cprbot/proc/follow_owner()
+ if (!owner || owner == null)
+ go_idle()
+ return
+
+ // Check if the owner is in range of the bot's view
+ if (!(owner in view(search_radius, src)))
+ go_idle()
+ return
+
+ // If the bot has a path, proceed with walking along it
+ if (length(src.path))
+ var/turf/next = path[1]
+ if (loc == next)
+ path -= next // Remove the turf from the path once reached
+
+ walk_to(src, next, 0, move_to_delay)
+ return
+
+ // If the owner is not in range, move towards them directly
+ if (!patient_in_range(owner))
+ // If the bot is already moving, just return
+ if (state == STATE_CPRBOT_MOVING)
+ return
+
+ // Set the state to moving and walk directly to the owner's location
+ state = STATE_CPRBOT_MOVING
+ walk_to(src, owner, 0, movement_delay)
+ else
+ go_idle()
+
+/obj/structure/machinery/bot/cprbot/start_processing()
+ START_PROCESSING(SSobj, src)
+
+/obj/structure/machinery/bot/cprbot/stop_processing()
+ if (fast_processing)
+ STOP_PROCESSING(SSfastobj, src)
+ else
+ STOP_PROCESSING(SSobj, src)
+
+/obj/structure/machinery/bot/cprbot/Destroy()
+ human = null
+ path = null
+ botcard_access = null
+
+ stop_processing()
+ return ..()
+
+/obj/structure/machinery/bot/cprbot/proc/random_message()
+ if (!COOLDOWN_FINISHED(src, message_cooldown))
+ return // Exit if the cooldown period has not elapsed yet
+
+ // Send a message based on the current state
+ if (currently_healing)
+ speak(motivational_message)
+ else
+ if (prob(50))
+ speak(pick(medical_facts))
+ else
+ speak(pick(idle_messages))
+
+ // Start the cooldown timer for the next message
+ COOLDOWN_START(src, message_cooldown, cooldown_time)
+
+/obj/structure/machinery/bot/cprbot/proc/speak(message)
+ if (!message)
+ return
+ visible_message("[src] beeps, \"[message]\"")
+ playsound(loc, 'sound/CPRbot/CPRbot_beep.ogg', 25, 1)
+
+/obj/structure/machinery/bot/cprbot/proc/go_idle()
+ human = null
+ state = STATE_CPRBOT_IDLE
+ cpr_ready = TRUE
+ currently_healing = FALSE
+ walk_to(src, 0) // make sure we stop walking
+ update_icon()
+
+/obj/structure/machinery/bot/cprbot/proc/valid_cpr_target(mob/living/carbon/human/patient)
+ return patient.stat == DEAD && patient.check_tod() && patient.is_revivable() && patient.get_target_lock(iff_signal)
+
+/obj/structure/machinery/bot/cprbot/proc/find_and_move_to_patient()
+ var/list/potential_patients = list()
+ has_said_to_patient = list()
+ for (var/mob/living/carbon/human/patient in view(search_radius, src))
+ if (valid_cpr_target(patient))
+ potential_patients += patient
+
+ for (var/obj/structure/machinery/bot/cprbot/another_cpr_bot in view(search_radius, src))
+ if (another_cpr_bot == src)
+ continue
+
+ var/mob/living/carbon/human/another_bot_patient
+
+ // sanity checks
+ if (another_cpr_bot.human != null)
+ another_bot_patient = another_cpr_bot.human.resolve()
+
+ // sanity checks
+ if (another_bot_patient == null)
+ continue
+
+ // Another CPR bot is targetting this patient, skip
+ if (another_bot_patient in potential_patients)
+ potential_patients.Remove(another_bot_patient)
+
+ if (potential_patients.len)
+ var/mob/living/carbon/human/patient = potential_patients[1]
+ human = WEAKREF(patient)
+ if (patient && !(patient in has_said_to_patient))
+ visible_message("[patient] is injured! I'm coming!")
+ has_said_to_patient += patient
+
+ move_to_target()
+ else
+ // If no patients are found, check if owner is nearby and follow them if idle
+ if (state == STATE_CPRBOT_IDLE && (owner && (owner in view(search_radius, src))))
+ state = STATE_CPRBOT_FOLLOWING_OWNER
+ walk_to(src, owner, 0, movement_delay)
+ else if (state == STATE_CPRBOT_FOLLOWING_OWNER)
+ // Continue following the owner if no patient is in sight
+ walk_to(src, owner, 0, movement_delay)
+ else
+ go_idle()
+
+/obj/structure/machinery/bot/cprbot/proc/call_astar_pathfinding()
+ if (human == null)
+ return FALSE
+
+ var/mob/living/carbon/human/patient = human.resolve()
+ if (patient == null)
+ return FALSE
+
+ var/turf/target_turf = get_turf(patient)
+
+ if (!target_turf)
+ return
+
+ // Calculate the path using your A* function
+ path = AStar(src.loc, target_turf, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30, id=botcard)
+
+ if (!length(path))
+ return
+
+ // Delete the straight line sections since walk_to moves better without that.
+ var/list/path_new = list()
+ var/turf/last = path[path.len]
+
+ if (!istype(last, /turf)) // Ensure last is a turf before accessing it
+ return
+
+ path_new.Add(path[1])
+
+ for (var/i = 2; i < path.len; i++) {
+ if (istype(path[i], /turf) && istype(path[i + 1], /turf)) {
+ var/turf/current_turf = path[i]
+ var/turf/next_turf = path[i + 1]
+
+ if ((next_turf.x == current_turf.x) || (next_turf.y == current_turf.y)) { // We have a straight line, scan for more to cut down
+ path_new.Add(current_turf)
+ for (var/j = i + 1; j < path.len; j++) {
+ if (istype(path[j + 1], /turf)) {
+ var/turf/next_next_turf = path[j + 1]
+ var/turf/prev_turf = path[j - 1]
+
+ // This is a corner and the endpoint of our line
+ if ((next_next_turf.x != prev_turf.x) && (next_next_turf.y != prev_turf.y)) {
+ path_new.Add(path[j])
+ i = j + 1
+ break
+ }
+ }
+
+ if (j == path.len - 1) {
+ path = list()
+ path = path_new.Copy()
+ path.Add(last)
+ return
+ }
+ }
+ } else {
+ path_new.Add(current_turf)
+ }
+ }
+ }
+
+ path = list()
+ path = path_new.Copy()
+ path.Add(last)
+
+ if (!path || length(path) == 0) {
+ src.human = null
+ src.currently_healing = FALSE
+ return
+ }
+
+ // Set the path
+ src.path = path
+
+ // Start moving
+ state = STATE_CPRBOT_MOVING
+ move_to_target()
+ return
+
+/obj/structure/machinery/bot/cprbot/proc/can_still_see_patient()
+ if (human == null)
+ return FALSE
+
+ var/mob/living/carbon/human/patient = human.resolve()
+ if (patient == null)
+ return FALSE
+
+ return patient in view(search_radius, src)
+
+/obj/structure/machinery/bot/cprbot/proc/patient_in_range(mob/living/carbon/human/patient = null)
+ if (human == null)
+ return FALSE
+
+ if (patient == null)
+ patient = human.resolve()
+
+ if (patient == null)
+ return FALSE
+
+ return get_dist(src, patient) == 0
+
+/obj/structure/machinery/bot/cprbot/proc/move_to_target()
+ var/mob/living/carbon/human/patient = human ? human.resolve() : null
+ // If we cannot see them anymore then stop moving
+ if (!can_still_see_patient())
+ go_idle()
+ return
+
+ // It might not exist anymore or something
+ if (patient == null)
+ go_idle()
+ return
+
+ if (is_no_longer_valid(patient))
+ go_idle()
+ return
+
+ if (length(src.path))
+ var/turf/next = path[1]
+ if(loc == next)
+ path -= next
+
+ if (length(src.path))
+ walk_to(src, path[1], 0, move_to_delay)
+ else
+ walk_to(src, 0)
+ state = STATE_CPRBOT_CPR
+ switch_to_faster_processing()
+ try_perform_cpr()
+ return
+
+ walk_to(src, next, 0, move_to_delay)
+ return
+
+ if (!patient_in_range())
+ if (last_location == loc)
+ walk_to(src, 0)
+ call_astar_pathfinding()
+ return
+
+ // We are already moving
+ if (state == STATE_CPRBOT_MOVING)
+ last_location = loc
+ return
+
+ state = STATE_CPRBOT_MOVING
+ walk_to(src, patient, 0, movement_delay)
+ else
+ walk_to(src, 0) // make sure we stop walking
+ state = STATE_CPRBOT_CPR
+ switch_to_faster_processing()
+ try_perform_cpr()
+
+/obj/structure/machinery/bot/cprbot/proc/is_no_longer_valid(mob/living/carbon/human/target)
+ return (target.stat != DEAD) || (target.stat == DEAD && !target.check_tod())
+
+/obj/structure/machinery/bot/cprbot/proc/perform_cpr(mob/living/carbon/human/target)
+ if (!cpr_ready)
+ return
+
+ currently_healing = TRUE
+
+ update_icon()
+
+ target.revive_grace_period += 4 SECONDS
+ target.visible_message(SPAN_NOTICE("[src] automatically performs CPR on [target]."))
+ target.balloon_alert_to_viewers("Performing CPR, stay clear!")
+ currently_healing = TRUE
+ playsound(loc, 'sound/CPRbot/CPR.ogg', 25, 1)
+ cpr_ready = FALSE
+ addtimer(VARSET_CALLBACK(src, cpr_ready, TRUE), 7 SECONDS)
+
+/obj/structure/machinery/bot/cprbot/proc/try_perform_cpr()
+ currently_healing = TRUE
+ // Resolve the weak reference to check if the target still exists
+ var/mob/living/carbon/human/target = human.resolve()
+
+ if (!patient_in_range())
+ go_idle()
+ switch_to_slower_processing()
+ return
+
+ // Check if the target is valid and still needs CPR
+ if (is_no_longer_valid(target))
+ go_idle()
+ switch_to_slower_processing()
+ return
+
+ perform_cpr(target)
+
+/obj/structure/machinery/bot/cprbot/proc/self_destruct(mob/living/carbon/human/user = null)
+ var/obj/item/cprbot_item = new /obj/item/cprbot_item(src.loc)
+
+ playsound(loc, 'sound/CPRbot/CPRbot_poweroff.ogg', 25, 1)
+
+ if (user)
+ if (!user.put_in_active_hand(cprbot_item))
+ if (!user.put_in_inactive_hand(cprbot_item))
+ cprbot_item.forceMove(src.loc)
+ else
+ cprbot_item.forceMove(src.loc)
+
+ qdel(src)
+
+/obj/structure/machinery/bot/cprbot/attack_hand(mob/user as mob)
+ if (..())
+ return TRUE
+
+ if(!skillcheck(user, SKILL_MEDICAL, SKILL_MEDICAL_MEDIC))
+ visible_message(SPAN_DANGER("[user] fails to undeploy [src] "))
+ return FALSE
+
+ SEND_SIGNAL(user, COMSIG_LIVING_ATTACKHAND_HUMAN, src)
+
+ if (user != src)
+ visible_message(SPAN_DANGER("[user] begins to undeploy [src]!"))
+ self_destruct(user)
+ return TRUE
+
+/obj/structure/machinery/bot/cprbot/update_icon()
+ . = ..()
+
+ switch(state)
+ if (STATE_CPRBOT_IDLE)
+ icon_state = "cprbot0"
+ if (STATE_CPRBOT_CPR)
+ icon_state = "cprbot_active"
+
+/obj/structure/machinery/bot/cprbot/explode()
+ src.on = FALSE
+ src.visible_message(SPAN_DANGER("[src] blows apart!"), null, null, 1)
+ var/turf/Tsec = get_turf(src)
+
+ playsound(loc, 'sound/CPRbot/CPRbot_poweroff.ogg', 25, 1)
+
+ new /obj/item/cprbot_broken(Tsec)
+
+ var/datum/effect_system/spark_spread/spark = new /datum/effect_system/spark_spread
+ spark.set_up(3, 1, src)
+ spark.start()
+
+ qdel(src)
+ return
+
+/obj/structure/machinery/bot/cprbot/proc/switch_to_faster_processing()
+ STOP_PROCESSING(SSobj, src)
+ START_PROCESSING(SSfastobj, src)
+ fast_processing = TRUE
+
+/obj/structure/machinery/bot/cprbot/proc/switch_to_slower_processing()
+ STOP_PROCESSING(SSfastobj, src)
+ START_PROCESSING(SSobj, src)
+ fast_processing = FALSE
+
+/obj/structure/machinery/bot/medbot/Collide(atom/A) //Leave no door unopened!
+ if ((istype(A, /obj/structure/machinery/door)) && (!isnull(src.botcard)))
+ var/obj/structure/machinery/door/D = A
+ if (!istype(D, /obj/structure/machinery/door/firedoor) && D.check_access(src.botcard) && !istype(D,/obj/structure/machinery/door/poddoor))
+ D.open()
+ src.frustration = 0
+ else if ((istype(A, /mob/living/)) && (!src.anchored))
+ src.forceMove(A.loc)
+ src.frustration = 0
+ return
+
+#undef STATE_CPRBOT_IDLE
+#undef STATE_CPRBOT_MOVING
+#undef STATE_CPRBOT_CPR
+#undef STATE_CPRBOT_FOLLOWING_OWNER
diff --git a/code/game/machinery/vending/vendor_types/crew/synthetic.dm b/code/game/machinery/vending/vendor_types/crew/synthetic.dm
index 240155176efa..841a146898ba 100644
--- a/code/game/machinery/vending/vendor_types/crew/synthetic.dm
+++ b/code/game/machinery/vending/vendor_types/crew/synthetic.dm
@@ -411,6 +411,7 @@ GLOBAL_LIST_INIT(cm_vending_synth_tools, list(
list("Maintenance Jack", 15, /obj/item/maintenance_jack, null, VENDOR_ITEM_REGULAR),
list("Portable Dialysis Machine", 15, /obj/item/tool/portadialysis, null, VENDOR_ITEM_REGULAR),
list("Telescopic Baton", 15, /obj/item/weapon/telebaton, null, VENDOR_ITEM_REGULAR),
+ list("CPR Buddy 9k", 15, /obj/item/cprbot_item, null, VENDOR_ITEM_REGULAR),
))
//------------EXPERIMENTAL TOOL KITS---------------
diff --git a/code/game/objects/items/cprbot.dm b/code/game/objects/items/cprbot.dm
new file mode 100644
index 000000000000..b44f6982d4fe
--- /dev/null
+++ b/code/game/objects/items/cprbot.dm
@@ -0,0 +1,112 @@
+/obj/item/cprbot_item
+ name = "CPRbot"
+ desc = "A compact CPRbot 9000 assembly"
+ icon = 'icons/obj/structures/machinery/aibots.dmi'
+ icon_state = "cprbot"
+ w_class = SIZE_MEDIUM
+ var/deployment_path = /obj/structure/machinery/bot/cprbot
+
+/obj/item/cprbot_item/attack_self(mob/user as mob)
+ if (..())
+ return TRUE
+
+ if(user)
+ deploy_cprbot(user, user.loc)
+
+/obj/item/cprbot_item/proc/deploy_cprbot(mob/user, atom/location)
+ if(!user || !location)
+ return
+
+ if (istype(user) && !skillcheck(user, SKILL_MEDICAL, SKILL_MEDICAL_MEDIC))
+ to_chat(user, SPAN_WARNING("You don't seem to know how to use [src]..."))
+ return
+
+ qdel(src)
+
+ // Proceed with the CPRbot deployment
+ var/obj/structure/machinery/bot/cprbot/cprbot_entity = new deployment_path(location)
+ if(cprbot_entity)
+ cprbot_entity.add_fingerprint(user)
+ cprbot_entity.owner = user
+
+/obj/item/cprbot_item/afterattack(atom/target, mob/user, proximity)
+ if(proximity && isturf(target))
+ var/turf/target_turf = target
+ if(!target_turf.density)
+ deploy_cprbot(user, target_turf)
+
+/obj/item/cprbot_broken
+ name = "CPRbot"
+ desc = "A compact CPRbot 9000 assembly, it appears to be in bad shape"
+ icon = 'icons/obj/structures/machinery/aibots.dmi'
+ icon_state = "cprbot_broken"
+ w_class = SIZE_MEDIUM
+
+/obj/item/cprbot_broken/attackby(obj/item/attacked_by, mob/living/user)
+ if(iswelder(attacked_by))
+ if(!HAS_TRAIT(attacked_by, TRAIT_TOOL_BLOWTORCH))
+ to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
+ return
+
+ var/obj/item/tool/weldingtool/welder_tool = attacked_by
+ if(!welder_tool.isOn())
+ to_chat(user, SPAN_WARNING("The [welder_tool] needs to be on!"))
+ return
+
+ if(!welder_tool.remove_fuel(5, user)) // Ensure the welder has enough fuel to operate
+ to_chat(user, SPAN_NOTICE("You need more welding fuel to complete this task."))
+ return
+
+ playsound(src, 'sound/items/Welder.ogg', 25, 1)
+
+ if(!do_after(user, 10 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL | BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
+ return
+
+ var/obj/item/cprbot_item/new_cprbot_item = new /obj/item/cprbot_item(src.loc)
+
+ if(user)
+ if(!user.put_in_active_hand(new_cprbot_item))
+ if(!user.put_in_inactive_hand(new_cprbot_item))
+ new_cprbot_item.forceMove(src.loc)
+ else
+ new_cprbot_item.forceMove(src.loc)
+
+/obj/item/cprbot_broken/attackby(obj/item/attacked_by, mob/living/user)
+ if(iswelder(attacked_by))
+ if(!HAS_TRAIT(attacked_by, TRAIT_TOOL_BLOWTORCH))
+ to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
+ return
+
+ var/obj/item/tool/weldingtool/welder_tool = attacked_by
+ if(!welder_tool.isOn())
+ to_chat(user, SPAN_WARNING("The [welder_tool] needs to be on!"))
+ return
+
+ if(!welder_tool.remove_fuel(5, user)) // Ensure enough fuel is available
+ to_chat(user, SPAN_NOTICE("You need more welding fuel to complete this task."))
+ return
+
+ playsound(src, 'sound/items/Welder.ogg', 25, 1)
+
+ if(!do_after(user, 10 * user.get_skill_duration_multiplier(SKILL_CONSTRUCTION), INTERRUPT_ALL | BEHAVIOR_IMMOBILE, BUSY_ICON_BUILD))
+ return
+
+ // Create the repaired item
+ var/obj/item/cprbot_item/repaired_cprbot_item = new /obj/item/cprbot_item(src.loc)
+
+ // Check if the broken item is in the user's hand
+ var/hand_was_active = user.get_active_hand() == src
+ var/hand_was_inactive = user.get_inactive_hand() == src
+
+ // Remove the broken item
+ qdel(src)
+
+ // Attempt to place the new item into the user's hands
+ if (hand_was_active)
+ if (!user.put_in_active_hand(repaired_cprbot_item))
+ repaired_cprbot_item.forceMove(user.loc) // Place it at user's location if hands are full
+ else if (hand_was_inactive)
+ if (!user.put_in_inactive_hand(repaired_cprbot_item))
+ repaired_cprbot_item.forceMove(user.loc) // Place it at user's location if hands are full
+ else
+ repaired_cprbot_item.forceMove(user.loc) // Place at the original location if not in hand
diff --git a/colonialmarines.dme b/colonialmarines.dme
index 7af974d6c715..84670390543c 100644
--- a/colonialmarines.dme
+++ b/colonialmarines.dme
@@ -905,6 +905,7 @@
#include "code\game\machinery\atmoalter\scrubber.dm"
#include "code\game\machinery\bots\bots.dm"
#include "code\game\machinery\bots\cleanbot.dm"
+#include "code\game\machinery\bots\cprbot.dm"
#include "code\game\machinery\bots\floorbot.dm"
#include "code\game\machinery\bots\medbot.dm"
#include "code\game\machinery\bots\mulebot.dm"
@@ -1090,6 +1091,7 @@
#include "code\game\objects\items\contraband.dm"
#include "code\game\objects\items\cosmetics.dm"
#include "code\game\objects\items\cpr_dummy.dm"
+#include "code\game\objects\items\cprbot.dm"
#include "code\game\objects\items\disks.dm"
#include "code\game\objects\items\fulton.dm"
#include "code\game\objects\items\gift_wrappaper.dm"
diff --git a/icons/obj/structures/machinery/aibots.dmi b/icons/obj/structures/machinery/aibots.dmi
index 18cf52cb43be..6f5785c4d7b4 100644
Binary files a/icons/obj/structures/machinery/aibots.dmi and b/icons/obj/structures/machinery/aibots.dmi differ
diff --git a/sound/CPRbot/CPR.ogg b/sound/CPRbot/CPR.ogg
new file mode 100644
index 000000000000..87431270242f
Binary files /dev/null and b/sound/CPRbot/CPR.ogg differ
diff --git a/sound/CPRbot/CPRbot_beep.ogg b/sound/CPRbot/CPRbot_beep.ogg
new file mode 100644
index 000000000000..718128602ed6
Binary files /dev/null and b/sound/CPRbot/CPRbot_beep.ogg differ
diff --git a/sound/CPRbot/CPRbot_poweroff.ogg b/sound/CPRbot/CPRbot_poweroff.ogg
new file mode 100644
index 000000000000..9bb77dce2ead
Binary files /dev/null and b/sound/CPRbot/CPRbot_poweroff.ogg differ
diff --git a/sound/CPRbot/CPRbot_poweron.ogg b/sound/CPRbot/CPRbot_poweron.ogg
new file mode 100644
index 000000000000..f6d6f9117777
Binary files /dev/null and b/sound/CPRbot/CPRbot_poweron.ogg differ