From 51dd8099a23a602a2da75a7ac52c04df951b87b6 Mon Sep 17 00:00:00 2001
From: SeepingVisage <160535199+SeepingVisage@users.noreply.github.com>
Date: Sun, 16 Jun 2024 00:02:31 -0400
Subject: [PATCH 1/7] Add the nutribot
This adds a nutribot. This is pretty epic if you ask me. It's supposed to feed you and stuff.. current bug where it thinks you need feeding in assess, but then fails to feed you in medicate. Always thinks you need feeding, too
---
.../code/modules/mob/living/nutribot.dm | 735 ++++++++++++++++++
1 file changed, 735 insertions(+)
create mode 100644 GainStation13/code/modules/mob/living/nutribot.dm
diff --git a/GainStation13/code/modules/mob/living/nutribot.dm b/GainStation13/code/modules/mob/living/nutribot.dm
new file mode 100644
index 00000000..c85fcff0
--- /dev/null
+++ b/GainStation13/code/modules/mob/living/nutribot.dm
@@ -0,0 +1,735 @@
+//nutribot
+//nutribot PATHFINDING
+//nutribot ASSEMBLY
+#define NUTRIBOT_PANIC_NONE 0
+#define NUTRIBOT_PANIC_LOW 15
+#define NUTRIBOT_PANIC_MED 35
+#define NUTRIBOT_PANIC_HIGH 55
+#define NUTRIBOT_PANIC_FUCK 70
+#define NUTRIBOT_PANIC_ENDING 90
+#define NUTRIBOT_PANIC_END 100
+
+/mob/living/simple_animal/bot/nutribot
+ name = "\improper Nutribot"
+ desc = "A little nutritional robot. He looks somewhat underwhelmed."
+ icon = 'icons/mob/aibots.dmi'
+ icon_state = "nutribot0"
+ density = FALSE
+ anchored = FALSE
+ health = 20
+ maxHealth = 20
+ pass_flags = PASSMOB
+
+ status_flags = (CANPUSH | CANSTUN)
+
+ radio_key = /obj/item/encryptionkey/headset_med
+ radio_channel = RADIO_CHANNEL_MEDICAL
+
+ bot_type = MED_BOT
+ model = "Nutribot"
+ bot_core_type = /obj/machinery/bot_core/nutribot
+ window_id = "automed"
+ window_name = "Automatic Nutritional Unit v1.1"
+ data_hud_type = DATA_HUD_MEDICAL_ADVANCED
+ path_image_color = "#DDDDFF"
+
+ var/obj/item/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
+ var/healthanalyzer = /obj/item/healthanalyzer
+ var/firstaid = /obj/item/storage/firstaid
+ var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
+ var/mob/living/carbon/patient = null
+ var/mob/living/carbon/oldpatient = null
+ var/oldloc = null
+ var/last_found = 0
+ var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
+ var/injection_amount = 15 //How much reagent do we inject at a time?
+ var/heal_threshold = 10 //Start healing when they have this much damage in a category
+ var/feed_threshold = 200 // The weight that people should be fed to!
+ var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
+ var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
+ var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
+ var/stationary_mode = 0 //If enabled, the Nutribot will not move automatically.
+ //Setting which reagents to use to treat what by default. By id.
+ var/treatment_thin = /datum/reagent/consumable/nutriment
+ var/treatment_thirsty = /datum/reagent/water
+ var/hunger_check = NUTRITION_LEVEL_FED
+ /*var/treatment_brute_avoid = /datum/reagent/medicine/tricordrazine
+ var/treatment_brute = /datum/reagent/medicine/bicaridine
+ var/treatment_oxy_avoid = null
+ var/treatment_oxy = /datum/reagent/medicine/dexalin
+ var/treatment_fire_avoid = /datum/reagent/medicine/tricordrazine
+ var/treatment_fire = /datum/reagent/medicine/kelotane
+ var/treatment_tox_avoid = /datum/reagent/medicine/tricordrazine
+ var/treatment_tox = /datum/reagent/medicine/charcoal
+ var/treatment_tox_toxlover = /datum/reagent/toxin
+ var/treatment_virus_avoid = null
+ var/treatment_virus = /datum/reagent/medicine/spaceacillin
+ var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
+ */
+ var/shut_up = 0 //self explanatory :)
+
+ //How panicked we are about being tipped over (why would you do this?)
+ var/tipped_status = NUTRIBOT_PANIC_NONE
+ //The name we got when we were tipped
+ var/tipper_name
+ //The last time we were tipped/righted and said a voice line, to avoid spam
+ var/last_tipping_action_voice = 0
+
+/*
+/mob/living/simple_animal/bot/nutribot/mysterious
+ name = "\improper Mysterious Nutribot"
+ desc = "International Nutribot of mystery."
+ skin = "bezerk"
+ treatment_brute = /datum/reagent/medicine/tricordrazine
+ treatment_fire = /datum/reagent/medicine/tricordrazine
+ treatment_tox = /datum/reagent/medicine/tricordrazine
+*/
+
+/*
+/mob/living/simple_animal/bot/nutribot/derelict
+ name = "\improper Old Nutribot"
+ desc = "Looks like it hasn't been modified since the late 2080s."
+ skin = "bezerk"
+ heal_threshold = 0
+ declare_crit = 0
+ treatment_oxy = /datum/reagent/toxin/pancuronium
+ treatment_brute_avoid = null
+ treatment_brute = /datum/reagent/toxin/pancuronium
+ treatment_fire_avoid = null
+ treatment_fire = /datum/reagent/toxin/sodium_thiopental
+ treatment_tox_avoid = null
+ treatment_tox = /datum/reagent/toxin/sodium_thiopental
+*/
+
+/mob/living/simple_animal/bot/nutribot/update_icon()
+ cut_overlays()
+ if(!on)
+ icon_state = "off"
+ return
+ if(IsStun())
+ icon_state = "medibota"
+ return
+ if(mode == BOT_HEALING)
+ icon_state = "medibots[stationary_mode]"
+ return
+ else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
+ icon_state = "medibot2"
+ else
+ icon_state = "medibot1"
+
+/mob/living/simple_animal/bot/nutribot/Initialize(mapload, new_skin)
+ . = ..()
+ var/datum/job/doctor/J = new /datum/job/doctor
+ access_card.access += J.get_access()
+ prev_access = access_card.access
+ qdel(J)
+ skin = new_skin
+ update_icon()
+
+/mob/living/simple_animal/bot/nutribot/update_canmove()
+ . = ..()
+ update_icon()
+
+/mob/living/simple_animal/bot/nutribot/bot_reset()
+ ..()
+ patient = null
+ oldpatient = null
+ oldloc = null
+ last_found = world.time
+ declare_cooldown = 0
+ update_icon()
+
+/mob/living/simple_animal/bot/nutribot/proc/soft_reset() //Allows the Nutribot to still actively perform its medical duties without being completely halted as a hard reset does.
+ path = list()
+ patient = null
+ mode = BOT_IDLE
+ last_found = world.time
+ update_icon()
+
+/mob/living/simple_animal/bot/nutribot/set_custom_texts()
+
+ text_hack = "You corrupt [name]'s reagent processor circuits."
+ text_dehack = "You reset [name]'s reagent processor circuits."
+ text_dehack_fail = "[name] seems damaged and does not respond to reprogramming!"
+
+/mob/living/simple_animal/bot/nutribot/attack_paw(mob/user)
+ return attack_hand(user)
+
+/mob/living/simple_animal/bot/nutribot/get_controls(mob/user)
+ var/dat
+ dat += hack(user)
+ dat += showpai(user)
+ dat += "Medical Unit Controls v1.1
"
+ dat += "Status: [on ? "On" : "Off"]
"
+ dat += "Maintenance panel panel is [open ? "opened" : "closed"]
"
+ dat += "Beaker: "
+ if(reagent_glass)
+ dat += "Loaded \[[reagent_glass.reagents.total_volume]/[reagent_glass.reagents.maximum_volume]\]"
+ else
+ dat += "None Loaded"
+ dat += "
Behaviour controls are [locked ? "locked" : "unlocked"]
"
+ if(!locked || issilicon(user) || IsAdminGhost(user))
+ /*dat += "Healing Threshold: "
+ dat += "-- "
+ dat += "- "
+ dat += "[heal_threshold] "
+ dat += "+ "
+ dat += "++"
+ dat += "
"*/
+
+ dat += "Injection Level: "
+ dat += "- "
+ dat += "[injection_amount] "
+ dat += "+ "
+ dat += "
"
+
+ dat += "Reagent Source: "
+ dat += "[use_beaker ? "Loaded Beaker (When available)" : "Internal Synthesizer"]
"
+
+ dat += "Hunger Check: "
+ dat += "[(hunger_check==NUTRITION_LEVEL_HUNGRY) ? "Yes" : "No"]
"
+
+ dat += "Maximum Weight: "
+ dat += "[feed_threshold ? 140+(feed_threshold*FATNESS_TO_WEIGHT_RATIO) : "???"] "
+ dat += "Disable Maximum Weight: ["Disable"]
"
+ dat += "- "
+ dat += "+ "
+ dat += "
"
+
+ //dat += "Treat Viral Infections: [treat_virus ? "Yes" : "No"]
"
+ dat += "The speaker switch is [shut_up ? "off" : "on"]. Toggle
"
+ //dat += "Critical Patient Alerts: [declare_crit ? "Yes" : "No"]
"
+ dat += "Patrol Station: [auto_patrol ? "Yes" : "No"]
"
+ dat += "Stationary Mode: [stationary_mode ? "Yes" : "No"]
"
+
+ return dat
+
+/mob/living/simple_animal/bot/nutribot/Topic(href, href_list)
+ if(..())
+ return 1
+
+ /*if(href_list["adj_threshold"])
+ var/adjust_num = text2num(href_list["adj_threshold"])
+ heal_threshold += adjust_num
+ if(heal_threshold < 5)
+ heal_threshold = 5
+ if(heal_threshold > 75)
+ heal_threshold = 75
+ */
+
+ else if(href_list["adj_inject"])
+ var/adjust_num = text2num(href_list["adj_inject"])
+ injection_amount += adjust_num
+ if(injection_amount < 5)
+ injection_amount = 5
+ if(injection_amount > 15)
+ injection_amount = 15
+
+ else if(href_list["use_beaker"])
+ use_beaker = !use_beaker
+
+ else if(href_list["eject"] && (!isnull(reagent_glass)))
+ reagent_glass.forceMove(drop_location())
+ reagent_glass = null
+
+ else if(href_list["togglevoice"])
+ shut_up = !shut_up
+
+ /*else if(href_list["critalerts"])
+ declare_crit = !declare_crit*/
+
+ else if(href_list["stationary"])
+ stationary_mode = !stationary_mode
+ path = list()
+ update_icon()
+
+ //else if(href_list["virus"])
+ //treat_virus = !treat_virus
+
+ else if(href_list["hunger_check"])
+ hunger_check = ((hunger_check==NUTRITION_LEVEL_HUNGRY) ? NUTRITION_LEVEL_FULL : NUTRITION_LEVEL_HUNGRY)
+
+ else if(href_list["feed_threshold"])
+ var/adjust_num = text2num(href_list["feed_threshold"])
+ feed_threshold += adjust_num
+ if(adjust_num == 1)
+ feed_threshold = 0
+ if(feed_threshold < 0)
+ feed_threshold = 0
+
+ update_controls()
+ return
+
+/mob/living/simple_animal/bot/nutribot/attackby(obj/item/W as obj, mob/user as mob, params)
+ if(istype(W, /obj/item/reagent_containers/glass))
+ . = 1 //no afterattack
+ if(locked)
+ to_chat(user, "You cannot insert a beaker because the panel is locked!")
+ return
+ if(!isnull(reagent_glass))
+ to_chat(user, "There is already a beaker loaded!")
+ return
+ if(!user.transferItemToLoc(W, src))
+ return
+
+ reagent_glass = W
+ to_chat(user, "You insert [W].")
+ show_controls(user)
+
+ else
+ var/current_health = health
+ ..()
+ if(health < current_health) //if nutribot took some damage
+ step_to(src, (get_step_away(src,user)))
+
+/mob/living/simple_animal/bot/nutribot/emag_act(mob/user)
+ ..()
+ if(emagged == 2)
+ //declare_crit = 0
+ if(user)
+ to_chat(user, "You short out [src]'s reagent synthesis circuits.")
+ audible_message("[src] buzzes oddly!")
+ flick("nutribot_spark", src)
+ playsound(src, "sparks", 75, 1)
+ if(user)
+ oldpatient = user
+
+/mob/living/simple_animal/bot/nutribot/process_scan(mob/living/carbon/human/H)
+ if(H.stat == DEAD)
+ return
+
+ if((H == oldpatient) && (world.time < last_found + 200))
+ return
+
+ if(assess_patient(H))
+ last_found = world.time
+ if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
+ var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/medbot/coming.ogg',"Wait [H.name]! I want to help!" = 'sound/voice/medbot/help.ogg',"[H.name], you appear to be injured!" = 'sound/voice/medbot/injured.ogg')
+ var/message = pick(messagevoice)
+ if(prob(2) && ISINRANGE_EX(H.getFireLoss(), 0, 20))
+ message = "Notices your minor burns*OwO what's this?"
+ messagevoice[message] = 'sound/voice/medbot/owo.ogg'
+ speak(message)
+ playsound(loc, messagevoice[message], 50, 0)
+ last_newpatient_speak = world.time
+ return H
+ else
+ return
+
+/mob/living/simple_animal/bot/nutribot/proc/tip_over(mob/user)
+ canmove = 0
+ //mobility_flags &= ~MOBILITY_MOVE
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 50)
+ user.visible_message("[user] tips over [src]!", "You tip [src] over!")
+ mode = BOT_TIPPED
+ var/matrix/mat = transform
+ transform = mat.Turn(180)
+
+/mob/living/simple_animal/bot/nutribot/proc/set_right(mob/user)
+ canmove = 1
+ //mobility_flags &= MOBILITY_MOVE
+ var/list/messagevoice
+ if(user)
+ user.visible_message("[user] sets [src] right-side up!", "You set [src] right-side up!")
+ if(user.name == tipper_name)
+ messagevoice = list("I forgive you." = 'sound/voice/medbot/forgive.ogg')
+ else
+ messagevoice = list("Thank you!" = 'sound/voice/medbot/thank_you.ogg', "You are a good person." = 'sound/voice/medbot/youre_good.ogg')
+ else
+ visible_message("[src] manages to writhe wiggle enough to right itself.")
+ messagevoice = list("Fuck you." = 'sound/voice/medbot/fuck_you.ogg', "Your behavior has been reported, have a nice day." = 'sound/voice/medbot/reported.ogg')
+
+ tipper_name = null
+ if(world.time > last_tipping_action_voice + 15 SECONDS)
+ last_tipping_action_voice = world.time
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(src, messagevoice[message], 70)
+ tipped_status = NUTRIBOT_PANIC_NONE
+ mode = BOT_IDLE
+ transform = matrix()
+
+// if someone tipped us over, check whether we should ask for help or just right ourselves eventually
+/mob/living/simple_animal/bot/nutribot/proc/handle_panic()
+ tipped_status++
+ var/list/messagevoice
+ switch(tipped_status)
+ if(NUTRIBOT_PANIC_LOW)
+ messagevoice = list("I require assistance." = 'sound/voice/medbot/i_require_asst.ogg')
+ if(NUTRIBOT_PANIC_MED)
+ messagevoice = list("Please put me back." = 'sound/voice/medbot/please_put_me_back.ogg')
+ if(NUTRIBOT_PANIC_HIGH)
+ messagevoice = list("Please, I am scared!" = 'sound/voice/medbot/please_im_scared.ogg')
+ if(NUTRIBOT_PANIC_FUCK)
+ messagevoice = list("I don't like this, I need help!" = 'sound/voice/medbot/dont_like.ogg', "This hurts, my pain is real!" = 'sound/voice/medbot/pain_is_real.ogg')
+ if(NUTRIBOT_PANIC_ENDING)
+ messagevoice = list("Is this the end?" = 'sound/voice/medbot/is_this_the_end.ogg', "Nooo!" = 'sound/voice/medbot/nooo.ogg')
+ if(NUTRIBOT_PANIC_END)
+ speak("PSYCH ALERT: Crewmember [tipper_name] recorded displaying antisocial tendencies torturing bots in [get_area(src)]. Please schedule psych evaluation.", radio_channel)
+ set_right() // strong independent nutribot
+
+ if(prob(tipped_status))
+ do_jitter_animation(tipped_status * 0.1)
+
+ if(messagevoice)
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(src, messagevoice[message], 70)
+ else if(prob(tipped_status * 0.2))
+ playsound(src, 'sound/machines/warning-buzzer.ogg', 30, extrarange=-2)
+
+/mob/living/simple_animal/bot/nutribot/examine(mob/user)
+ . = ..()
+ if(tipped_status == NUTRIBOT_PANIC_NONE)
+ return
+
+ switch(tipped_status)
+ if(NUTRIBOT_PANIC_NONE to NUTRIBOT_PANIC_LOW)
+ . += "It appears to be tipped over, and is quietly waiting for someone to set it right."
+ if(NUTRIBOT_PANIC_LOW to NUTRIBOT_PANIC_MED)
+ . += "It is tipped over and requesting help."
+ if(NUTRIBOT_PANIC_MED to NUTRIBOT_PANIC_HIGH)
+ . += "They are tipped over and appear visibly distressed." // now we humanize the nutribot as a they, not an it
+ if(NUTRIBOT_PANIC_HIGH to NUTRIBOT_PANIC_FUCK)
+ . += "They are tipped over and visibly panicking!"
+ if(NUTRIBOT_PANIC_FUCK to INFINITY)
+ . += "They are freaking out from being tipped over!"
+
+/mob/living/simple_animal/bot/nutribot/handle_automated_action()
+ if(!..())
+ return
+
+ if(mode == BOT_TIPPED)
+ handle_panic()
+ return
+
+ if(mode == BOT_HEALING)
+ return
+
+ if(IsStun())
+ oldpatient = patient
+ patient = null
+ mode = BOT_IDLE
+ return
+
+ if(frustration > 8)
+ oldpatient = patient
+ soft_reset()
+
+ if(QDELETED(patient))
+ if(!shut_up && prob(1))
+ if(emagged && prob(30))
+ var/list/i_need_scissors = list('sound/voice/medbot/fuck_you.ogg', 'sound/voice/medbot/turn_off.ogg', 'sound/voice/medbot/im_different.ogg', 'sound/voice/medbot/close.ogg', 'sound/voice/medbot/shindemashou.ogg')
+ playsound(src, pick(i_need_scissors), 70)
+ else
+ var/list/messagevoice = list("Radar, put a mask on!" = 'sound/voice/medbot/radar.ogg',"There's always a catch, and I'm the best there is." = 'sound/voice/medbot/catch.ogg',"I knew it, I should've been a plastic surgeon." = 'sound/voice/medbot/surgeon.ogg',"What kind of medbay is this? Everyone's dropping like flies." = 'sound/voice/medbot/flies.ogg',"Delicious!" = 'sound/voice/medbot/delicious.ogg', "Why are we still here? Just to suffer?" = 'sound/voice/medbot/why.ogg')
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(src, messagevoice[message], 50)
+ var/scan_range = (stationary_mode ? 1 : DEFAULT_SCAN_RANGE) //If in stationary mode, scan range is limited to adjacent patients.
+ patient = scan(/mob/living/carbon/human, oldpatient, scan_range)
+ oldpatient = patient
+
+ if(patient && (get_dist(src,patient) <= 1)) //Patient is next to us, begin treatment!
+ if(mode != BOT_HEALING)
+ mode = BOT_HEALING
+ update_icon()
+ frustration = 0
+ medicate_patient(patient)
+ return
+
+ //Patient has moved away from us!
+ else if(patient && path.len && (get_dist(patient,path[path.len]) > 2))
+ path = list()
+ mode = BOT_IDLE
+ last_found = world.time
+
+ else if(stationary_mode && patient) //Since we cannot move in this mode, ignore the patient and wait for another.
+ soft_reset()
+ return
+
+ if(patient && path.len == 0 && (get_dist(src,patient) > 1))
+ path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,id=access_card)
+ mode = BOT_MOVING
+ if(!path.len) //try to get closer if you can't reach the patient directly
+ path = get_path_to(src, get_turf(patient), /turf/proc/Distance_cardinal, 0, 30,1,id=access_card)
+ if(!path.len) //Do not chase a patient we cannot reach.
+ soft_reset()
+
+ if(path.len > 0 && patient)
+ if(!bot_move(path[path.len]))
+ oldpatient = patient
+ soft_reset()
+ return
+
+ if(path.len > 8 && patient)
+ frustration++
+
+ if(auto_patrol && !stationary_mode && !patient)
+ if(mode == BOT_IDLE || mode == BOT_START_PATROL)
+ start_patrol()
+
+ if(mode == BOT_PATROL)
+ bot_patrol()
+
+ return
+
+/mob/living/simple_animal/bot/nutribot/proc/assess_patient(mob/living/carbon/C)
+ //Time to see if they need medical help!
+ if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
+ return FALSE //welp too late for them!
+
+ if(!(loc == C.loc) && !(isturf(C.loc) && isturf(loc)))
+ return FALSE
+
+ if(C.suiciding)
+ return FALSE //Kevorkian school of robotic medical assistants.
+
+ if(emagged == 2) //Everyone needs our medicine. (Our medicine is corn oil)
+ return TRUE
+
+ if(ishuman(C))
+ var/mob/living/carbon/human/H = C
+ if (H.wear_suit && H.head && istype(H.wear_suit, /obj/item/clothing) && istype(H.head, /obj/item/clothing))
+ var/obj/item/clothing/CS = H.wear_suit
+ var/obj/item/clothing/CH = H.head
+ if (CS.clothing_flags & CH.clothing_flags & THICKMATERIAL)
+ return FALSE // Skip over them if they have no exposed flesh.
+
+ //if(declare_crit && C.health <= 0) //Critical condition! Call for help!
+ //declare(C)
+
+ //If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
+ if((reagent_glass) && (use_beaker) && (C.fatness <= feed_threshold))
+ for(var/A in reagent_glass.reagents.reagent_list)
+ var/datum/reagent/R = A
+ if(!C.reagents.has_reagent(R.type))
+ return TRUE
+
+ //They're injured enough for it!
+ if((C.nutrition <= hunger_check) && (C.fatness <= feed_threshold) && (!C.reagents.has_reagent(treatment_thin)))
+ return TRUE //If they're already medicated don't bother!
+
+ if((C.thirst <= THIRST_LEVEL_QUENCHED) && (!C.reagents.has_reagent(treatment_thirsty)))
+ return TRUE //If they're already medicated don't bother!
+
+ /*var/treatment_toxavoid = get_avoidchem_toxin(C)
+ if(((isnull(treatment_toxavoid) || !C.reagents.has_reagent(treatment_toxavoid))) && (C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(get_healchem_toxin(C))))
+ return TRUE
+
+ if(treat_virus && !C.reagents.has_reagent(treatment_virus_avoid) && !C.reagents.has_reagent(treatment_virus))
+ for(var/thing in C.diseases)
+ var/datum/disease/D = thing
+ //the Nutribot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
+ if(!(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC) \
+ && D.severity != DISEASE_SEVERITY_POSITIVE \
+ && (D.stage > 1 || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))) // Nutribot can't detect a virus in its initial stage unless it spreads airborne.
+ return TRUE //STOP DISEASE FOREVER
+ */
+
+ return FALSE
+
+/mob/living/simple_animal/bot/nutribot/attack_hand(mob/living/carbon/human/H)
+ if(H.a_intent == INTENT_DISARM && mode != BOT_TIPPED)
+ H.visible_message("[H] begins tipping over [src].", "You begin tipping over [src]...")
+
+ if(world.time > last_tipping_action_voice + 15 SECONDS)
+ last_tipping_action_voice = world.time // message for tipping happens when we start interacting, message for righting comes after finishing
+ var/list/messagevoice = list("Hey, wait..." = 'sound/voice/medbot/hey_wait.ogg',"Please don't..." = 'sound/voice/medbot/please_dont.ogg',"I trusted you..." = 'sound/voice/medbot/i_trusted_you.ogg', "Nooo..." = 'sound/voice/medbot/nooo.ogg', "Oh fuck-" = 'sound/voice/medbot/oh_fuck.ogg')
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(src, messagevoice[message], 70, FALSE)
+
+ if(do_after(H, 3 SECONDS, target=src))
+ tip_over(H)
+
+ else if(H.a_intent == INTENT_HELP && mode == BOT_TIPPED)
+ H.visible_message("[H] begins righting [src].", "You begin righting [src]...")
+ if(do_after(H, 3 SECONDS, target=src))
+ set_right(H)
+ else
+ ..()
+
+/*
+/mob/living/simple_animal/bot/nutribot/proc/get_avoidchem_toxin(mob/M)
+ return HAS_TRAIT(M, TRAIT_TOXINLOVER)? null : treatment_tox_avoid
+*/
+
+/*
+/mob/living/simple_animal/bot/nutribot/proc/get_healchem_toxin(mob/M)
+ return HAS_TRAIT(M, TRAIT_TOXINLOVER)? treatment_tox_toxlover : treatment_tox
+*/
+
+/mob/living/simple_animal/bot/nutribot/UnarmedAttack(atom/A)
+ if(iscarbon(A))
+ var/mob/living/carbon/C = A
+ patient = C
+ mode = BOT_HEALING
+ update_icon()
+ medicate_patient(C)
+ update_icon()
+ else
+ ..()
+
+/mob/living/simple_animal/bot/nutribot/examinate(atom/A as mob|obj|turf in view())
+ ..()
+ if(!is_blind(src))
+ chemscan(src, A)
+
+/mob/living/simple_animal/bot/nutribot/proc/medicate_patient(mob/living/carbon/C)
+ if(!on)
+ return
+
+ if(!istype(C))
+ oldpatient = patient
+ soft_reset()
+ return
+
+ if(C.stat == DEAD || (HAS_TRAIT(C, TRAIT_FAKEDEATH)))
+ var/list/messagevoice = list("No! Stay with me!" = 'sound/voice/medbot/no.ogg',"Live, damnit! LIVE!" = 'sound/voice/medbot/live.ogg',"I...I've never lost a patient before. Not today, I mean." = 'sound/voice/medbot/lost.ogg')
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(loc, messagevoice[message], 50, 0)
+ oldpatient = patient
+ soft_reset()
+ return
+
+ var/reagent_id = null
+
+ if(emagged == 2) //Emagged! Time to poison everybody.
+ reagent_id = "emagged" //evil fucking check for a string as a reagent this shit is evil. its supposed to inject corn oil AND filzulphite but ill handle that later
+
+ else
+ /*if(treat_virus)
+ var/virus = 0
+ for(var/thing in C.diseases)
+ var/datum/disease/D = thing
+ //detectable virus
+ if((!(D.visibility_flags & HIDDEN_SCANNER)) || (!(D.visibility_flags & HIDDEN_PANDEMIC)))
+ if(D.severity != DISEASE_SEVERITY_POSITIVE) //virus is harmful
+ if((D.stage > 1) || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))
+ virus = 1
+
+ if(!reagent_id && (virus))
+ if(!C.reagents.has_reagent(treatment_virus) && !C.reagents.has_reagent(treatment_virus_avoid))
+ reagent_id = treatment_virus*/
+
+ if(!reagent_id && ((feed_threshold == 0) || (C.fatness <= feed_threshold)) && (C.nutrition <= hunger_check))
+ if(!C.reagents.has_reagent(treatment_thin))
+ reagent_id = treatment_thin
+
+ if(!reagent_id && (C.thirst <= THIRST_LEVEL_THIRSTY))
+ if(!C.reagents.has_reagent(treatment_thirsty))
+ reagent_id = treatment_thirsty
+
+ /*if(!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
+ if(!C.reagents.has_reagent(treatment_oxy) && !C.reagents.has_reagent(treatment_oxy_avoid))
+ reagent_id = treatment_oxy
+
+ if(!reagent_id && (C.getFireLoss() >= heal_threshold))
+ if(!C.reagents.has_reagent(treatment_fire) && !C.reagents.has_reagent(treatment_fire_avoid))
+ reagent_id = treatment_fire
+
+ if(!reagent_id && (C.getToxLoss() >= heal_threshold))
+ var/toxin_heal_avoid = get_avoidchem_toxin(C)
+ var/toxin_healchem = get_healchem_toxin(C)
+ if(!C.reagents.has_reagent(toxin_healchem) && (isnull(toxin_heal_avoid) || !C.reagents.has_reagent(toxin_heal_avoid)))
+ reagent_id = toxin_healchem*/
+
+ //If the patient is injured but doesn't have our special reagent in them then we should give it to them first
+ if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
+ for(var/A in reagent_glass.reagents.reagent_list)
+ var/datum/reagent/R = A
+ if(!C.reagents.has_reagent(R.type))
+ reagent_id = "internal_beaker"
+ break
+
+ if(!reagent_id) //If they don't need any of that they're probably cured!
+ if(C.maxHealth - C.health < heal_threshold)
+ to_chat(src, "[C] is healthy! Your programming prevents you from injecting anyone without at least [heal_threshold] damage of any one type ([heal_threshold + 15] for oxygen damage.)")
+ var/list/messagevoice = list("All patched up!" = 'sound/voice/medbot/patchedup.ogg',"An apple a day keeps me away." = 'sound/voice/medbot/apple.ogg',"Feel better soon!" = 'sound/voice/medbot/feelbetter.ogg')
+ var/message = pick(messagevoice)
+ speak(message)
+ playsound(loc, messagevoice[message], 50, 0)
+ bot_reset()
+ return
+ else
+ if(!emagged && check_overdose(patient,reagent_id,injection_amount))
+ soft_reset()
+ return
+ C.visible_message("[src] is trying to inject [patient]!", \
+ "[src] is trying to inject you!")
+
+ var/failed = FALSE
+ if(do_mob(src, patient, 30)) //Is C == patient? This is so confusing
+ if((get_dist(src, patient) <= 1) && (on) && assess_patient(patient))
+ if(reagent_id == "internal_beaker")
+ if(use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
+ var/fraction = min(injection_amount/reagent_glass.reagents.total_volume, 1)
+ reagent_glass.reagents.reaction(patient, INJECT, fraction)
+ reagent_glass.reagents.trans_to(patient,injection_amount) //Inject from beaker instead.
+ else
+ patient.reagents.add_reagent(reagent_id,injection_amount)
+ C.visible_message("[src] injects [patient] with its syringe!", \
+ "[src] injects you with its syringe!")
+ else
+ failed = TRUE
+ else
+ failed = TRUE
+
+ if(failed)
+ visible_message("[src] retracts its syringe.")
+ update_icon()
+ soft_reset()
+ return
+
+ reagent_id = null
+ return
+
+/mob/living/simple_animal/bot/nutribot/proc/check_overdose(mob/living/carbon/patient,reagent_id,injection_amount)
+ var/datum/reagent/R = GLOB.chemical_reagents_list[reagent_id]
+ if(!R.overdose_threshold) //Some chems do not have an OD threshold
+ return FALSE
+ var/current_volume = patient.reagents.get_reagent_amount(reagent_id)
+ if(current_volume + injection_amount > R.overdose_threshold)
+ return TRUE
+ return FALSE
+
+/mob/living/simple_animal/bot/nutribot/explode()
+ on = FALSE
+ visible_message("[src] blows apart!")
+ var/atom/Tsec = drop_location()
+
+ drop_part(firstaid, Tsec)
+ new /obj/item/assembly/prox_sensor(Tsec)
+ drop_part(healthanalyzer, Tsec)
+
+ if(reagent_glass)
+ drop_part(reagent_glass, Tsec)
+
+ if(prob(50))
+ drop_part(robot_arm, Tsec)
+
+ if(emagged && prob(25))
+ playsound(loc, 'sound/voice/medbot/insult.ogg', 50, 0)
+
+ do_sparks(3, TRUE, src)
+ ..()
+
+/mob/living/simple_animal/bot/nutribot/proc/declare(crit_patient)
+ if(declare_cooldown > world.time)
+ return
+ var/area/location = get_area(src)
+ speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_channel)
+ declare_cooldown = world.time + 200
+
+/obj/machinery/bot_core/nutribot
+ req_one_access = list(ACCESS_MEDICAL, ACCESS_ROBOTICS)
+
+#undef NUTRIBOT_PANIC_NONE
+#undef NUTRIBOT_PANIC_LOW
+#undef NUTRIBOT_PANIC_MED
+#undef NUTRIBOT_PANIC_HIGH
+#undef NUTRIBOT_PANIC_FUCK
+#undef NUTRIBOT_PANIC_ENDING
+#undef NUTRIBOT_PANIC_END
From 5a11ad4323069577f973b61b580d0845da592160 Mon Sep 17 00:00:00 2001
From: SeepingVisage <160535199+SeepingVisage@users.noreply.github.com>
Date: Tue, 13 Aug 2024 21:19:24 -0400
Subject: [PATCH 2/7] nutribot improvements
finally gets sprites and some fixes are done. still have to add prefs.
---
.../code/modules/mob/living/nutribot.dm | 48 +++++++++----------
.../crafting/recipes/recipes_robot.dm | 12 ++++-
tgstation.dme | 1 +
3 files changed, 36 insertions(+), 25 deletions(-)
diff --git a/GainStation13/code/modules/mob/living/nutribot.dm b/GainStation13/code/modules/mob/living/nutribot.dm
index c85fcff0..59d710fd 100644
--- a/GainStation13/code/modules/mob/living/nutribot.dm
+++ b/GainStation13/code/modules/mob/living/nutribot.dm
@@ -12,7 +12,7 @@
/mob/living/simple_animal/bot/nutribot
name = "\improper Nutribot"
desc = "A little nutritional robot. He looks somewhat underwhelmed."
- icon = 'icons/mob/aibots.dmi'
+ icon = 'GainStation13/icons/mob/nutribot.dmi'
icon_state = "nutribot0"
density = FALSE
anchored = FALSE
@@ -52,7 +52,7 @@
//Setting which reagents to use to treat what by default. By id.
var/treatment_thin = /datum/reagent/consumable/nutriment
var/treatment_thirsty = /datum/reagent/water
- var/hunger_check = NUTRITION_LEVEL_FED
+ var/hunger_check = NUTRITION_LEVEL_HUNGRY
/*var/treatment_brute_avoid = /datum/reagent/medicine/tricordrazine
var/treatment_brute = /datum/reagent/medicine/bicaridine
var/treatment_oxy_avoid = null
@@ -104,18 +104,18 @@
/mob/living/simple_animal/bot/nutribot/update_icon()
cut_overlays()
if(!on)
- icon_state = "off"
+ icon_state = "nutribot0"
return
if(IsStun())
- icon_state = "medibota"
+ icon_state = "nutribota"
return
if(mode == BOT_HEALING)
- icon_state = "medibots[stationary_mode]"
+ icon_state = "nutribots[stationary_mode]"
return
else if(stationary_mode) //Bot has yellow light to indicate stationary mode.
- icon_state = "medibot2"
+ icon_state = "nutribot2"
else
- icon_state = "medibot1"
+ icon_state = "nutribot1"
/mob/living/simple_animal/bot/nutribot/Initialize(mapload, new_skin)
. = ..()
@@ -177,7 +177,7 @@
dat += "++"
dat += "
"*/
- dat += "Injection Level: "
+ dat += "Feed Amount: "
dat += "- "
dat += "[injection_amount] "
dat += "+ "
@@ -189,9 +189,9 @@
dat += "Hunger Check: "
dat += "[(hunger_check==NUTRITION_LEVEL_HUNGRY) ? "Yes" : "No"]
"
- dat += "Maximum Weight: "
- dat += "[feed_threshold ? 140+(feed_threshold*FATNESS_TO_WEIGHT_RATIO) : "???"] "
- dat += "Disable Maximum Weight: ["Disable"]
"
+ dat += "Maximum BFI: "
+ dat += "[feed_threshold ? feed_threshold : "???"] "
+ dat += "Disable Maximum BFI: ["Disable"]
"
dat += "- "
dat += "+ "
dat += "
"
@@ -304,7 +304,7 @@
if(assess_patient(H))
last_found = world.time
if((last_newpatient_speak + 300) < world.time) //Don't spam these messages!
- var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/medbot/coming.ogg',"Wait [H.name]! I want to help!" = 'sound/voice/medbot/help.ogg',"[H.name], you appear to be injured!" = 'sound/voice/medbot/injured.ogg')
+ var/list/messagevoice = list("Hey, [H.name]! Hold on, I'm coming." = 'sound/voice/medbot/coming.ogg',"Wait [H.name]! I want to help!" = 'sound/voice/medbot/help.ogg')
var/message = pick(messagevoice)
if(prob(2) && ISINRANGE_EX(H.getFireLoss(), 0, 20))
message = "Notices your minor burns*OwO what's this?"
@@ -500,17 +500,17 @@
//declare(C)
//If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
- if((reagent_glass) && (use_beaker) && (C.fatness <= feed_threshold))
+ if((reagent_glass) && (use_beaker) && ((C.fatness <= feed_threshold) || (feed_threshold == 0)))
for(var/A in reagent_glass.reagents.reagent_list)
var/datum/reagent/R = A
if(!C.reagents.has_reagent(R.type))
return TRUE
//They're injured enough for it!
- if((C.nutrition <= hunger_check) && (C.fatness <= feed_threshold) && (!C.reagents.has_reagent(treatment_thin)))
+ if((C.nutrition <= hunger_check) && ((C.fatness <= feed_threshold) || (feed_threshold == 0)) && (!C.reagents.has_reagent(treatment_thin)))
return TRUE //If they're already medicated don't bother!
- if((C.thirst <= THIRST_LEVEL_QUENCHED) && (!C.reagents.has_reagent(treatment_thirsty)))
+ if((C.thirst <= THIRST_LEVEL_THIRSTY) && (!C.reagents.has_reagent(treatment_thirsty)))
return TRUE //If they're already medicated don't bother!
/*var/treatment_toxavoid = get_avoidchem_toxin(C)
@@ -597,7 +597,7 @@
var/reagent_id = null
if(emagged == 2) //Emagged! Time to poison everybody.
- reagent_id = "emagged" //evil fucking check for a string as a reagent this shit is evil. its supposed to inject corn oil AND filzulphite but ill handle that later
+ reagent_id = /datum/reagent/consumable/cornoil //evil fucking check for a string as a reagent this shit is evil. its supposed to inject corn oil AND filzulphite but ill handle that later
else
/*if(treat_virus)
@@ -657,8 +657,8 @@
if(!emagged && check_overdose(patient,reagent_id,injection_amount))
soft_reset()
return
- C.visible_message("[src] is trying to inject [patient]!", \
- "[src] is trying to inject you!")
+ C.visible_message("[src] is trying to feed [patient]!", \
+ "[src] is trying to feed you!")
var/failed = FALSE
if(do_mob(src, patient, 30)) //Is C == patient? This is so confusing
@@ -670,15 +670,15 @@
reagent_glass.reagents.trans_to(patient,injection_amount) //Inject from beaker instead.
else
patient.reagents.add_reagent(reagent_id,injection_amount)
- C.visible_message("[src] injects [patient] with its syringe!", \
- "[src] injects you with its syringe!")
+ C.visible_message("[src] feeds [patient] with its tube!", \
+ "[src] feeds you with its tube!")
else
failed = TRUE
else
failed = TRUE
if(failed)
- visible_message("[src] retracts its syringe.")
+ visible_message("[src] retracts its tube.")
update_icon()
soft_reset()
return
@@ -700,9 +700,9 @@
visible_message("[src] blows apart!")
var/atom/Tsec = drop_location()
- drop_part(firstaid, Tsec)
+ new /obj/item/stack/sheet/cardboard(Tsec)
new /obj/item/assembly/prox_sensor(Tsec)
- drop_part(healthanalyzer, Tsec)
+ new /obj/item/stack/sheet/mineral/calorite(Tsec)
if(reagent_glass)
drop_part(reagent_glass, Tsec)
@@ -724,7 +724,7 @@
declare_cooldown = world.time + 200
/obj/machinery/bot_core/nutribot
- req_one_access = list(ACCESS_MEDICAL, ACCESS_ROBOTICS)
+ req_one_access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_ROBOTICS)
#undef NUTRIBOT_PANIC_NONE
#undef NUTRIBOT_PANIC_LOW
diff --git a/code/datums/components/crafting/recipes/recipes_robot.dm b/code/datums/components/crafting/recipes/recipes_robot.dm
index ae5bca77..d75c6bf6 100644
--- a/code/datums/components/crafting/recipes/recipes_robot.dm
+++ b/code/datums/components/crafting/recipes/recipes_robot.dm
@@ -81,4 +81,14 @@
name = "Potat-OS"
reqs = list(/obj/item/stack/cable_coil = 1, /obj/item/stack/rods = 1, /obj/item/reagent_containers/food/snacks/grown/potato = 1, /obj/item/aicard = 1 )
result = /obj/item/aicard/potato
- category = CAT_ROBOT
\ No newline at end of file
+ category = CAT_ROBOT
+
+/datum/crafting_recipe/nutribot
+ name = "Nutribot"
+ reqs = list(/obj/item/stack/sheet/cardboard = 1,
+ /obj/item/stack/sheet/mineral/calorite = 1,
+ /obj/item/bodypart/r_arm/robot = 1,
+ /obj/item/assembly/prox_sensor = 1)
+ result = /mob/living/simple_animal/bot/nutribot
+ time = 40
+ category = CAT_ROBOT
diff --git a/tgstation.dme b/tgstation.dme
index f1798d7a..79a49aba 100644
--- a/tgstation.dme
+++ b/tgstation.dme
@@ -3119,6 +3119,7 @@
#include "GainStation13\code\modules\mob\living\emote.dm"
#include "GainStation13\code\modules\mob\living\emote_modular.dm"
#include "GainStation13\code\modules\mob\living\emote_ported.dm"
+#include "GainStation13\code\modules\mob\living\nutribot.dm"
#include "GainStation13\code\modules\mob\living\vore\eating\living_vr.dm"
#include "GainStation13\code\modules\mob\living\vore\eating\trasheat_lists.dm"
#include "GainStation13\code\modules\reagents\chemistry\reagents\consumable_reagents.dm"
From ce02d4604b8040e34a01a724245525512291707a Mon Sep 17 00:00:00 2001
From: SeepingVisage <160535199+SeepingVisage@users.noreply.github.com>
Date: Tue, 13 Aug 2024 21:21:28 -0400
Subject: [PATCH 3/7] Add files via upload
---
GainStation13/icons/mob/nutribot.dmi | Bin 0 -> 1329 bytes
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 GainStation13/icons/mob/nutribot.dmi
diff --git a/GainStation13/icons/mob/nutribot.dmi b/GainStation13/icons/mob/nutribot.dmi
new file mode 100644
index 0000000000000000000000000000000000000000..efe9b02c775ddd1920125634b73ad308e670faa4
GIT binary patch
literal 1329
zcmYL}2~d+)5P*M(PLzr%piQ949}wC=u?9m(5GOxJ&>+-82o$vvkz)iwxj`X>6uG4k
z#G(WTic$qyNK`0@CZK4Q5Kyj)BSdaR)IfkF=J*@hY5Qj0+i&0Q?7rPMvju(!_Zu5o
z7y$ra>`kN6^|EGdZ$RkJyCxN&UL^SWGQ2uFJGoqLR#uikAi&{pAPADlWE{@k+}s?C
zwZyC~3lfQBWo5N|HwKHvPMibKXf%;Xij9rs`hT99no1-RT}WgajppLwLMA(d;C4$(
zO9+D8+&tiUVE6%0ebE};y?flj;YT!DpDw3ybXA|-Ac=l30C1aq9;sLA&oY9Os1b=_
z2~lxLQKwG3GD3S%gV9{4(3+?ukbM-5FK56f#U
z^5;7w{qaWRQ?ev32($ix@!Hvu9lJaeojK;PG$67&Z^0t#t(*g
zVPdX#t7CvkFta@?NjiLr>5xlniEHY6U1G2SE@y`_cg9eIpmjFth9vad&BK8aE}GyM
zj^-?|bm1$J>}~YSv>}7CW)IC7Y3zwwu?61dWra(d{REk^2Kh%T?3lu5`JMmCu-i=|
z5#7?5^P@3ME1qr*V9$N3hb_GSApf#Jecz@NS^ffz@3@}
z4QdZWfD!UUIfREuaJHNvhj4oM`-Uv4p1_EBVwldtvoB5lhp*E8Gf5Xn
z$!zKn#TDlDBX=yEtAr(U*(M*U68L>SYM*Kw5$1`JEW9~%Ziy-LvgXpd`(S=XX(b%0
z!V+OmxqGxOZzg+4gOVWYRbVBmOb*$A*Jjx#C^QNDbj|T-7c$i~ETw}i^^yOqDTO)x
z_wJdeQ&k~ls2OCxUVW!{w4jI=R!n=UCiL$Yjb@Y7(U6CtFUHp#}3MC
z{eQyQOSjf4gy4=*U01jcIkQWtZw=GNw19danS(L{w@`2y{7)&g-`TQWcr!9=bKbI+
zGdLwsBO#ecks4Mqt>s*p>XI`BkSxt*3fKB#{~H*@Nl;V
zwR2u~EQz%S$8{BTZUeewxAhhwW%3^g8Paws4WrcA&kU88cOcA~dj_X%4&kAFqWq|_
zsH1>*hxnMicPPc_6zov-`H{zSeC
Date: Tue, 13 Aug 2024 22:09:48 -0400
Subject: [PATCH 4/7] preferences
not working! cant toggle in the menu. seems to be defined in the 3 files that it needs to be. check cant be tested, but since the preference is perma-disabled at the moment it at least seems like the bot is reading the preference and chooses not to feed you
---
GainStation13/code/modules/client/preferences/preferences.dm | 3 +++
GainStation13/code/modules/mob/living/nutribot.dm | 3 +++
code/modules/client/preferences.dm | 4 ++++
code/modules/client/preferences_savefile.dm | 2 ++
4 files changed, 12 insertions(+)
diff --git a/GainStation13/code/modules/client/preferences/preferences.dm b/GainStation13/code/modules/client/preferences/preferences.dm
index 6c20037c..7a968916 100644
--- a/GainStation13/code/modules/client/preferences/preferences.dm
+++ b/GainStation13/code/modules/client/preferences/preferences.dm
@@ -48,6 +48,9 @@
///Does the person wish to be involved with non-con weight gain events?
var/noncon_weight_gain = FALSE
+ //Does the person wish to be fed from bots?
+ var/bot_feeding = FALSE
+
///What is the max weight that the person wishes to be? If set to FALSE, there will be no max weight
var/max_weight = FALSE
diff --git a/GainStation13/code/modules/mob/living/nutribot.dm b/GainStation13/code/modules/mob/living/nutribot.dm
index 59d710fd..3f51c254 100644
--- a/GainStation13/code/modules/mob/living/nutribot.dm
+++ b/GainStation13/code/modules/mob/living/nutribot.dm
@@ -484,6 +484,9 @@
if(C.suiciding)
return FALSE //Kevorkian school of robotic medical assistants.
+
+ if(!C?.client?.prefs.bot_feeding)
+ return FALSE
if(emagged == 2) //Everyone needs our medicine. (Our medicine is corn oil)
return TRUE
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 537ab2ca..626f4219 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1056,6 +1056,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Maximum Weight:[max_weight == FALSE ? "None" : max_weight]
"
dat += "NonCon - Weight Gain:[noncon_weight_gain == TRUE ? "Enabled" : "Disabled"]
"
+ dat += "Bot Feeding:[bot_feeding == TRUE ? "Enabled" : "Disabled"]
"
+
dat += "GS13 Weight Gain
"
dat += "Weight Gain - Food:[weight_gain_food == TRUE ? "Enabled" : "Disabled"]
"
dat += "Weight Gain - Items:[weight_gain_items == TRUE ? "Enabled" : "Disabled"]
"
@@ -2660,6 +2662,8 @@ GLOBAL_LIST_EMPTY(preferences_datums)
weight_gain_extreme = !weight_gain_extreme
if("noncon_weight_gain")
noncon_weight_gain = !noncon_weight_gain
+ if("bot_feeding")
+ bot_feeding = !bot_feeding
if("stuckage")
stuckage = !stuckage
if("blueberry_inflation")
diff --git a/code/modules/client/preferences_savefile.dm b/code/modules/client/preferences_savefile.dm
index 6e12fbb1..ad1f1f0a 100644
--- a/code/modules/client/preferences_savefile.dm
+++ b/code/modules/client/preferences_savefile.dm
@@ -158,6 +158,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
S["wg_rate"] >> wg_rate
S["wl_rate"] >> wl_rate
S["noncon_weight_gain"] >> noncon_weight_gain
+ S["bot_feeding"] >> bot_feeding
S["max_weight"] >> max_weight
S["helplessness_no_movement"] >> helplessness_no_movement
S["helplessness_clumsy"] >> helplessness_clumsy
@@ -311,6 +312,7 @@ SAVEFILE UPDATING/VERSIONING - 'Simplified', or rather, more coder-friendly ~Car
WRITE_FILE(S["wg_rate"], wg_rate)
WRITE_FILE(S["wl_rate"], wl_rate)
WRITE_FILE(S["noncon_weight_gain"], noncon_weight_gain)
+ WRITE_FILE(S["bot_feeding"], bot_feeding)
WRITE_FILE(S["max_weight"], max_weight)
WRITE_FILE(S["helplessness_no_movement"], helplessness_no_movement)
WRITE_FILE(S["helplessness_clumsy"], helplessness_clumsy)
From fba005fc509be1b443f5bbf20c938527c6f6a550 Mon Sep 17 00:00:00 2001
From: SeepingVisage <160535199+SeepingVisage@users.noreply.github.com>
Date: Wed, 14 Aug 2024 02:52:36 -0400
Subject: [PATCH 5/7] fix a typo
makes _src into _src_ and everything is happy
---
code/modules/client/preferences.dm | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/code/modules/client/preferences.dm b/code/modules/client/preferences.dm
index 626f4219..eeeb311e 100644
--- a/code/modules/client/preferences.dm
+++ b/code/modules/client/preferences.dm
@@ -1056,7 +1056,7 @@ GLOBAL_LIST_EMPTY(preferences_datums)
dat += "Maximum Weight:[max_weight == FALSE ? "None" : max_weight]
"
dat += "NonCon - Weight Gain:[noncon_weight_gain == TRUE ? "Enabled" : "Disabled"]
"
- dat += "Bot Feeding:[bot_feeding == TRUE ? "Enabled" : "Disabled"]
"
+ dat += "Bot Feeding:[bot_feeding == TRUE ? "Enabled" : "Disabled"]
"
dat += "GS13 Weight Gain
"
dat += "Weight Gain - Food:[weight_gain_food == TRUE ? "Enabled" : "Disabled"]
"
From 59d6a12a072fc85ffefb88e898633b50a23e6fa3 Mon Sep 17 00:00:00 2001
From: SeepingVisage <160535199+SeepingVisage@users.noreply.github.com>
Date: Wed, 14 Aug 2024 03:22:45 -0400
Subject: [PATCH 6/7] made things more nutri less medi
some stuff was still labeled as medical. this should fix that.
---
GainStation13/code/modules/mob/living/nutribot.dm | 13 +++++++------
1 file changed, 7 insertions(+), 6 deletions(-)
diff --git a/GainStation13/code/modules/mob/living/nutribot.dm b/GainStation13/code/modules/mob/living/nutribot.dm
index 3f51c254..8bfc4cae 100644
--- a/GainStation13/code/modules/mob/living/nutribot.dm
+++ b/GainStation13/code/modules/mob/living/nutribot.dm
@@ -23,19 +23,19 @@
status_flags = (CANPUSH | CANSTUN)
radio_key = /obj/item/encryptionkey/headset_med
- radio_channel = RADIO_CHANNEL_MEDICAL
+ radio_channel = RADIO_CHANNEL_SERVICE
bot_type = MED_BOT
model = "Nutribot"
bot_core_type = /obj/machinery/bot_core/nutribot
- window_id = "automed"
+ window_id = "auto_nutrition"
window_name = "Automatic Nutritional Unit v1.1"
data_hud_type = DATA_HUD_MEDICAL_ADVANCED
path_image_color = "#DDDDFF"
var/obj/item/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
- var/healthanalyzer = /obj/item/healthanalyzer
- var/firstaid = /obj/item/storage/firstaid
+ //var/healthanalyzer = /obj/item/healthanalyzer
+ //var/firstaid = /obj/item/storage/firstaid
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
var/mob/living/carbon/patient = null
var/mob/living/carbon/oldpatient = null
@@ -119,7 +119,7 @@
/mob/living/simple_animal/bot/nutribot/Initialize(mapload, new_skin)
. = ..()
- var/datum/job/doctor/J = new /datum/job/doctor
+ var/datum/job/cook/J = new /datum/job/cook
access_card.access += J.get_access()
prev_access = access_card.access
qdel(J)
@@ -159,7 +159,7 @@
var/dat
dat += hack(user)
dat += showpai(user)
- dat += "Medical Unit Controls v1.1
"
+ dat += "Nutritional Unit Controls v1.1
"
dat += "Status: [on ? "On" : "Off"]
"
dat += "Maintenance panel panel is [open ? "opened" : "closed"]
"
dat += "Beaker: "
@@ -191,6 +191,7 @@
dat += "Maximum BFI: "
dat += "[feed_threshold ? feed_threshold : "???"] "
+ dat += "
"
dat += "Disable Maximum BFI: ["Disable"]
"
dat += "- "
dat += "+ "
From 624ac532492de7f5424f7f862a0b7db186bdc14a Mon Sep 17 00:00:00 2001
From: SeepingVisage <160535199+SeepingVisage@users.noreply.github.com>
Date: Wed, 14 Aug 2024 13:37:54 -0400
Subject: [PATCH 7/7] removing commented code and fixing beakers
---
.../code/modules/mob/living/nutribot.dm | 133 +-----------------
1 file changed, 6 insertions(+), 127 deletions(-)
diff --git a/GainStation13/code/modules/mob/living/nutribot.dm b/GainStation13/code/modules/mob/living/nutribot.dm
index 8bfc4cae..e352dfde 100644
--- a/GainStation13/code/modules/mob/living/nutribot.dm
+++ b/GainStation13/code/modules/mob/living/nutribot.dm
@@ -34,8 +34,6 @@
path_image_color = "#DDDDFF"
var/obj/item/reagent_containers/glass/reagent_glass = null //Can be set to draw from this for reagents.
- //var/healthanalyzer = /obj/item/healthanalyzer
- //var/firstaid = /obj/item/storage/firstaid
var/skin = null //Set to "tox", "ointment" or "o2" for the other two firstaid kits.
var/mob/living/carbon/patient = null
var/mob/living/carbon/oldpatient = null
@@ -43,29 +41,14 @@
var/last_found = 0
var/last_newpatient_speak = 0 //Don't spam the "HEY I'M COMING" messages
var/injection_amount = 15 //How much reagent do we inject at a time?
- var/heal_threshold = 10 //Start healing when they have this much damage in a category
var/feed_threshold = 200 // The weight that people should be fed to!
var/use_beaker = 0 //Use reagents in beaker instead of default treatment agents.
- var/declare_crit = 1 //If active, the bot will transmit a critical patient alert to MedHUD users.
var/declare_cooldown = 0 //Prevents spam of critical patient alerts.
var/stationary_mode = 0 //If enabled, the Nutribot will not move automatically.
//Setting which reagents to use to treat what by default. By id.
var/treatment_thin = /datum/reagent/consumable/nutriment
var/treatment_thirsty = /datum/reagent/water
var/hunger_check = NUTRITION_LEVEL_HUNGRY
- /*var/treatment_brute_avoid = /datum/reagent/medicine/tricordrazine
- var/treatment_brute = /datum/reagent/medicine/bicaridine
- var/treatment_oxy_avoid = null
- var/treatment_oxy = /datum/reagent/medicine/dexalin
- var/treatment_fire_avoid = /datum/reagent/medicine/tricordrazine
- var/treatment_fire = /datum/reagent/medicine/kelotane
- var/treatment_tox_avoid = /datum/reagent/medicine/tricordrazine
- var/treatment_tox = /datum/reagent/medicine/charcoal
- var/treatment_tox_toxlover = /datum/reagent/toxin
- var/treatment_virus_avoid = null
- var/treatment_virus = /datum/reagent/medicine/spaceacillin
- var/treat_virus = 1 //If on, the bot will attempt to treat viral infections, curing them if possible.
- */
var/shut_up = 0 //self explanatory :)
//How panicked we are about being tipped over (why would you do this?)
@@ -75,31 +58,6 @@
//The last time we were tipped/righted and said a voice line, to avoid spam
var/last_tipping_action_voice = 0
-/*
-/mob/living/simple_animal/bot/nutribot/mysterious
- name = "\improper Mysterious Nutribot"
- desc = "International Nutribot of mystery."
- skin = "bezerk"
- treatment_brute = /datum/reagent/medicine/tricordrazine
- treatment_fire = /datum/reagent/medicine/tricordrazine
- treatment_tox = /datum/reagent/medicine/tricordrazine
-*/
-
-/*
-/mob/living/simple_animal/bot/nutribot/derelict
- name = "\improper Old Nutribot"
- desc = "Looks like it hasn't been modified since the late 2080s."
- skin = "bezerk"
- heal_threshold = 0
- declare_crit = 0
- treatment_oxy = /datum/reagent/toxin/pancuronium
- treatment_brute_avoid = null
- treatment_brute = /datum/reagent/toxin/pancuronium
- treatment_fire_avoid = null
- treatment_fire = /datum/reagent/toxin/sodium_thiopental
- treatment_tox_avoid = null
- treatment_tox = /datum/reagent/toxin/sodium_thiopental
-*/
/mob/living/simple_animal/bot/nutribot/update_icon()
cut_overlays()
@@ -169,13 +127,6 @@
dat += "None Loaded"
dat += "
Behaviour controls are [locked ? "locked" : "unlocked"]
"
if(!locked || issilicon(user) || IsAdminGhost(user))
- /*dat += "Healing Threshold: "
- dat += "-- "
- dat += "- "
- dat += "[heal_threshold] "
- dat += "+ "
- dat += "++"
- dat += "
"*/
dat += "Feed Amount: "
dat += "- "
@@ -197,9 +148,7 @@
dat += "+ "
dat += "
"
- //dat += "Treat Viral Infections: [treat_virus ? "Yes" : "No"]
"
dat += "The speaker switch is [shut_up ? "off" : "on"]. Toggle
"
- //dat += "Critical Patient Alerts: [declare_crit ? "Yes" : "No"]
"
dat += "Patrol Station: [auto_patrol ? "Yes" : "No"]
"
dat += "Stationary Mode: [stationary_mode ? "Yes" : "No"]
"
@@ -209,15 +158,6 @@
if(..())
return 1
- /*if(href_list["adj_threshold"])
- var/adjust_num = text2num(href_list["adj_threshold"])
- heal_threshold += adjust_num
- if(heal_threshold < 5)
- heal_threshold = 5
- if(heal_threshold > 75)
- heal_threshold = 75
- */
-
else if(href_list["adj_inject"])
var/adjust_num = text2num(href_list["adj_inject"])
injection_amount += adjust_num
@@ -236,17 +176,11 @@
else if(href_list["togglevoice"])
shut_up = !shut_up
- /*else if(href_list["critalerts"])
- declare_crit = !declare_crit*/
-
else if(href_list["stationary"])
stationary_mode = !stationary_mode
path = list()
update_icon()
- //else if(href_list["virus"])
- //treat_virus = !treat_virus
-
else if(href_list["hunger_check"])
hunger_check = ((hunger_check==NUTRITION_LEVEL_HUNGRY) ? NUTRITION_LEVEL_FULL : NUTRITION_LEVEL_HUNGRY)
@@ -286,7 +220,6 @@
/mob/living/simple_animal/bot/nutribot/emag_act(mob/user)
..()
if(emagged == 2)
- //declare_crit = 0
if(user)
to_chat(user, "You short out [src]'s reagent synthesis circuits.")
audible_message("[src] buzzes oddly!")
@@ -504,32 +437,22 @@
//declare(C)
//If they're injured, we're using a beaker, and don't have one of our WONDERCHEMS.
- if((reagent_glass) && (use_beaker) && ((C.fatness <= feed_threshold) || (feed_threshold == 0)))
+ if((reagent_glass) && (use_beaker) && (C.nutrition <= hunger_check) && ((C.fatness <= feed_threshold) || (feed_threshold == 0)))
for(var/A in reagent_glass.reagents.reagent_list)
var/datum/reagent/R = A
if(!C.reagents.has_reagent(R.type))
return TRUE
//They're injured enough for it!
+
+ //nutrition check
if((C.nutrition <= hunger_check) && ((C.fatness <= feed_threshold) || (feed_threshold == 0)) && (!C.reagents.has_reagent(treatment_thin)))
return TRUE //If they're already medicated don't bother!
+ //hydration check, only gives water till yer not thirsty no more!!
if((C.thirst <= THIRST_LEVEL_THIRSTY) && (!C.reagents.has_reagent(treatment_thirsty)))
return TRUE //If they're already medicated don't bother!
- /*var/treatment_toxavoid = get_avoidchem_toxin(C)
- if(((isnull(treatment_toxavoid) || !C.reagents.has_reagent(treatment_toxavoid))) && (C.getToxLoss() >= heal_threshold) && (!C.reagents.has_reagent(get_healchem_toxin(C))))
- return TRUE
-
- if(treat_virus && !C.reagents.has_reagent(treatment_virus_avoid) && !C.reagents.has_reagent(treatment_virus))
- for(var/thing in C.diseases)
- var/datum/disease/D = thing
- //the Nutribot can't detect viruses that are undetectable to Health Analyzers or Pandemic machines.
- if(!(D.visibility_flags & HIDDEN_SCANNER || D.visibility_flags & HIDDEN_PANDEMIC) \
- && D.severity != DISEASE_SEVERITY_POSITIVE \
- && (D.stage > 1 || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))) // Nutribot can't detect a virus in its initial stage unless it spreads airborne.
- return TRUE //STOP DISEASE FOREVER
- */
return FALSE
@@ -554,16 +477,6 @@
else
..()
-/*
-/mob/living/simple_animal/bot/nutribot/proc/get_avoidchem_toxin(mob/M)
- return HAS_TRAIT(M, TRAIT_TOXINLOVER)? null : treatment_tox_avoid
-*/
-
-/*
-/mob/living/simple_animal/bot/nutribot/proc/get_healchem_toxin(mob/M)
- return HAS_TRAIT(M, TRAIT_TOXINLOVER)? treatment_tox_toxlover : treatment_tox
-*/
-
/mob/living/simple_animal/bot/nutribot/UnarmedAttack(atom/A)
if(iscarbon(A))
var/mob/living/carbon/C = A
@@ -604,19 +517,6 @@
reagent_id = /datum/reagent/consumable/cornoil //evil fucking check for a string as a reagent this shit is evil. its supposed to inject corn oil AND filzulphite but ill handle that later
else
- /*if(treat_virus)
- var/virus = 0
- for(var/thing in C.diseases)
- var/datum/disease/D = thing
- //detectable virus
- if((!(D.visibility_flags & HIDDEN_SCANNER)) || (!(D.visibility_flags & HIDDEN_PANDEMIC)))
- if(D.severity != DISEASE_SEVERITY_POSITIVE) //virus is harmful
- if((D.stage > 1) || (D.spread_flags & DISEASE_SPREAD_AIRBORNE))
- virus = 1
-
- if(!reagent_id && (virus))
- if(!C.reagents.has_reagent(treatment_virus) && !C.reagents.has_reagent(treatment_virus_avoid))
- reagent_id = treatment_virus*/
if(!reagent_id && ((feed_threshold == 0) || (C.fatness <= feed_threshold)) && (C.nutrition <= hunger_check))
if(!C.reagents.has_reagent(treatment_thin))
@@ -626,20 +526,6 @@
if(!C.reagents.has_reagent(treatment_thirsty))
reagent_id = treatment_thirsty
- /*if(!reagent_id && (C.getOxyLoss() >= (15 + heal_threshold)))
- if(!C.reagents.has_reagent(treatment_oxy) && !C.reagents.has_reagent(treatment_oxy_avoid))
- reagent_id = treatment_oxy
-
- if(!reagent_id && (C.getFireLoss() >= heal_threshold))
- if(!C.reagents.has_reagent(treatment_fire) && !C.reagents.has_reagent(treatment_fire_avoid))
- reagent_id = treatment_fire
-
- if(!reagent_id && (C.getToxLoss() >= heal_threshold))
- var/toxin_heal_avoid = get_avoidchem_toxin(C)
- var/toxin_healchem = get_healchem_toxin(C)
- if(!C.reagents.has_reagent(toxin_healchem) && (isnull(toxin_heal_avoid) || !C.reagents.has_reagent(toxin_heal_avoid)))
- reagent_id = toxin_healchem*/
-
//If the patient is injured but doesn't have our special reagent in them then we should give it to them first
if(reagent_id && use_beaker && reagent_glass && reagent_glass.reagents.total_volume)
for(var/A in reagent_glass.reagents.reagent_list)
@@ -649,8 +535,8 @@
break
if(!reagent_id) //If they don't need any of that they're probably cured!
- if(C.maxHealth - C.health < heal_threshold)
- to_chat(src, "[C] is healthy! Your programming prevents you from injecting anyone without at least [heal_threshold] damage of any one type ([heal_threshold + 15] for oxygen damage.)")
+ if((C.nutrition >= hunger_check) || (C.fatness >= feed_threshold))
+ to_chat(src, "[C] is full, or fat! Your programming prevents you from feeding anyone who is over the maximum weight, or doesn't need food!")
var/list/messagevoice = list("All patched up!" = 'sound/voice/medbot/patchedup.ogg',"An apple a day keeps me away." = 'sound/voice/medbot/apple.ogg',"Feel better soon!" = 'sound/voice/medbot/feelbetter.ogg')
var/message = pick(messagevoice)
speak(message)
@@ -720,13 +606,6 @@
do_sparks(3, TRUE, src)
..()
-/mob/living/simple_animal/bot/nutribot/proc/declare(crit_patient)
- if(declare_cooldown > world.time)
- return
- var/area/location = get_area(src)
- speak("Medical emergency! [crit_patient ? "[crit_patient]" : "A patient"] is in critical condition at [location]!",radio_channel)
- declare_cooldown = world.time + 200
-
/obj/machinery/bot_core/nutribot
req_one_access = list(ACCESS_HYDROPONICS, ACCESS_BAR, ACCESS_KITCHEN, ACCESS_ROBOTICS)