Skip to content

Commit

Permalink
CPR Buddy 9000
Browse files Browse the repository at this point in the history
  • Loading branch information
HIDgamer committed Sep 3, 2024
1 parent 13f70c3 commit 3c82deb
Show file tree
Hide file tree
Showing 5 changed files with 311 additions and 0 deletions.
196 changes: 196 additions & 0 deletions code/game/machinery/bots/cprbot.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,196 @@
/obj/structure/machinery/bot/cprbot
name = "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)
var/const/search_radius = 10
var/const/cprbot_proximity_check_radius = 2 // Radius to check for nearby CPRbots
var/processing = TRUE
var/mob/living/carbon/human/target = null
var/cpr_cooldown = 0
var/path = list() // Path for movement logic
var/currently_healing = 0
var/iff_signal = FACTION_MARINE // IFF signal to check for valid targets
var/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/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 of a million people stopped breathing and were suddenly silent."
)
var/motivational_message = "Live! Live! Don't die on me now!"
var/list/has_said_to_patient = list() // Track which patients have been warned
var/last_message_time = 0 // Tracks the last time a message was spoken

/obj/structure/machinery/bot/cprbot/New()
..()
spawn(5) // Wait for 5 seconds after spawning before starting initialization
src.initialize_cprbot()

/obj/structure/machinery/bot/cprbot/proc/initialize_cprbot()
while (processing && health > 0)
src.find_and_move_to_patient()
if (target && world.time >= cpr_cooldown)
src.perform_cpr(target)
src.random_message() // Check if it's time to send a random message
sleep(2) // Slower processing loop, moves once every 2 seconds

/obj/structure/machinery/bot/cprbot/proc/random_message()
if (world.time >= last_message_time + 600) // At least 1 minute (600 deciseconds) cooldown
if (currently_healing)
src.speak(motivational_message)
else
if (prob(50))
src.speak(pick(medical_facts))
else
src.speak(pick(idle_messages))
last_message_time = world.time // Update the last message time

/obj/structure/machinery/bot/cprbot/proc/speak(message)
if (!processing || !message)
return
visible_message("[src] beeps, \"[message]\"")

/obj/structure/machinery/bot/cprbot/proc/find_and_move_to_patient()
var/list/humans = list()
for (var/mob/living/carbon/human/H in range(search_radius))
if (H.stat == DEAD && H.check_tod() && H.is_revivable() && H.get_target_lock(iff_signal) && !src.has_nearby_cprbot(H))
humans += H

if (humans.len > 0)
target = src.get_nearest(humans)
if (target && !has_said_to_patient.Find(target))
visible_message("[target] is injured! I'm coming!")
has_said_to_patient += target
src.move_to_target(target)
else
target = null

/obj/structure/machinery/bot/cprbot/proc/has_nearby_cprbot(mob/living/carbon/human/H)
// Check if there are any other CPRbots within a two-tile radius of the target
for (var/obj/structure/machinery/bot/cprbot/nearby_cprbot in range(H, cprbot_proximity_check_radius))
if (nearby_cprbot != src) // Ignore self
return TRUE
return FALSE

/obj/structure/machinery/bot/cprbot/proc/get_nearest(list/humans)
var/mob/living/carbon/human/nearest = null
var/distance = search_radius + 1

for (var/mob/living/carbon/human/H in humans)
var/d = get_dist(src, H)
if (d < distance)
nearest = H
distance = d

return nearest

/obj/structure/machinery/bot/cprbot/proc/move_to_target(mob/living/carbon/human/H)
if (H)
var/pathfinding_result = AStar(src.loc, get_turf(H), /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 0, 30)
if (length(pathfinding_result) == 0)
// No reachable path to the target, so stop looking for this patient
target = null
return
path = pathfinding_result

// Begin moving towards the target if a path exists
if (get_dist(src, H) > 1)
if (length(path) > 0)
step_to(src, path[1])
path -= path[1]
spawn(10) // Moves every 10 ticks (approximately 1 second)
if (length(path))
step_to(src, path[1])
path -= path[1]
else
currently_healing = 1
else
// No valid target, stop looking
target = null


/obj/structure/machinery/bot/cprbot/proc/perform_cpr(mob/living/carbon/human/H)
if (!H || H.stat != DEAD || !H.is_revivable() || !ishuman_strict(H))
target = null
icon_state = "cprbot0"
currently_healing = 0
return

if (get_dist(src, H) > 1)
src.move_to_target(H)
return

icon_state = "cprbot_active"
H.revive_grace_period += 4 SECONDS
cpr_cooldown = world.time + 7 SECONDS
H.visible_message(SPAN_NOTICE("<b>[src]</b> automatically performs <b>CPR</b> on <b>[H]</b>."))
H.visible_message(SPAN_DANGER("Currently performing CPR on <b>[H]</b> do not intervene!"))
currently_healing = 1

spawn(0.5)
while (H.is_revivable() && H.stat == DEAD && get_dist(src, H) <= 1)
sleep(0.5)
icon_state = "cprbot0"
currently_healing = 0

/obj/structure/machinery/bot/cprbot/proc/self_destruct(mob/living/carbon/human/user = null)
var/obj/item/cprbot_item/I = new /obj/item/cprbot_item(src.loc)

if (user)
if (!user.put_in_active_hand(I))
if (!user.put_in_inactive_hand(I))
I.forceMove(src.loc)
else
I.forceMove(src.loc)

qdel(src)

/obj/structure/machinery/bot/cprbot/attack_hand(mob/user as mob)
if (..())
return TRUE

SEND_SIGNAL(user, COMSIG_LIVING_ATTACKHAND_HUMAN, src)

if (user != src)
visible_message(SPAN_DANGER("<B>[user] begins to undeploy [src]!</B>"))
src.self_destruct(user)
return TRUE

/obj/structure/machinery/bot/cprbot/explode()
src.on = 0
src.visible_message(SPAN_DANGER("<B>[src] blows apart!</B>"), null, null, 1)
var/turf/Tsec = get_turf(src)

new /obj/item/cprbot_broken(Tsec)

var/datum/effect_system/spark_spread/s = new /datum/effect_system/spark_spread
s.set_up(3, 1, src)
s.start()
qdel(src)
return

1 change: 1 addition & 0 deletions code/game/machinery/vending/vendor_types/crew/synthetic.dm
Original file line number Diff line number Diff line change
Expand Up @@ -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---------------
Expand Down
112 changes: 112 additions & 0 deletions code/game/objects/items/cprbot.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
/obj/item/cprbot_item
name = "CPRbot"
desc = "A compact CPRbot 9000 asemply"
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/proc/deploy_cprbot(mob/user, atom/location)
if(!user || !location)
return
// Attempt to delete the item first
qdel(src)
world << "Deleting item [src]. Deploying CPRbot at [location]."

// Proceed with the CPRbot deployment
var/obj/structure/machinery/bot/cprbot/R = new deployment_path(location)
if(R)
R.add_fingerprint(user)
world << "CPRbot deployed successfully at [location]."
else
world << "Failed to deploy CPRbot at [location]."

/obj/item/cprbot_item/attack_self(mob/user)
if (..())
return TRUE
if(user)
deploy_cprbot(user, user.loc)

/obj/item/cprbot_item/afterattack(atom/target, mob/user, proximity)
if(proximity && isturf(target))
var/turf/T = target
if(!T.density)
deploy_cprbot(user, T)

/obj/item/cprbot_broken
name = "CPRbot"
desc = "A compact CPRbot 9000 asemply 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/W, mob/living/user)
if(iswelder(W))
if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH))
to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
return

var/obj/item/tool/weldingtool/WT = W
if(!WT.isOn())
to_chat(user, SPAN_WARNING("\The [WT] needs to be on!"))
return

if(!WT.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/I = new /obj/item/cprbot_item(src.loc)

if(user)
if(!user.put_in_active_hand(I))
if(!user.put_in_inactive_hand(I))
I.forceMove(src.loc)
else
I.forceMove(src.loc)

/obj/item/cprbot_broken/attackby(obj/item/W, mob/living/user)
if(iswelder(W))
if(!HAS_TRAIT(W, TRAIT_TOOL_BLOWTORCH))
to_chat(user, SPAN_WARNING("You need a stronger blowtorch!"))
return

var/obj/item/tool/weldingtool/WT = W
if(!WT.isOn())
to_chat(user, SPAN_WARNING("\The [WT] needs to be on!"))
return

if(!WT.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/I = 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(I))
I.forceMove(user.loc) // Place it at user's location if hands are full
else if (hand_was_inactive)
if (!user.put_in_inactive_hand(I))
I.forceMove(user.loc) // Place it at user's location if hands are full
else
I.forceMove(user.loc) // Place at the original location if not in hand


2 changes: 2 additions & 0 deletions colonialmarines.dme
Original file line number Diff line number Diff line change
Expand Up @@ -904,6 +904,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"
Expand Down Expand Up @@ -1088,6 +1089,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"
Expand Down
Binary file modified icons/obj/structures/machinery/aibots.dmi
Binary file not shown.

0 comments on commit 3c82deb

Please sign in to comment.