diff --git a/code/__HELPERS/game.dm b/code/__HELPERS/game.dm index 1cc419e39020..ebe47d3a3f42 100644 --- a/code/__HELPERS/game.dm +++ b/code/__HELPERS/game.dm @@ -484,6 +484,31 @@ return pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates) +/** + * Poll all mentor ghosts for looking for a candidate + * + * Poll all mentor ghosts a question + * returns people who voted yes in a list + * Arguments: + * * Question: String, what do you want to ask them + * * jobbanType: List, Which roles/jobs to exclude from being asked + * * gametypeCheck: Datum, Check if they have the time required for that role + * * be_special_flag: Bool, Only notify ghosts with special antag on + * * poll_time: Integer, How long to poll for in deciseconds(0.1s) + * * ignore_category: Define, ignore_category: People with this category(defined in poll_ignore.dm) turned off dont get the message + * * flashwindow: Bool, Flash their window to grab their attention + */ +/proc/pollMentorGhostCandidates(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, ignore_category = null, flashwindow = TRUE) + var/list/candidates = list() + if(!(GLOB.ghost_role_flags & GHOSTROLE_STATION_SENTIENCE)) + return candidates + + for(var/mob/dead/observer/G in GLOB.player_list) + if(is_mentor(G)) + candidates += G + + return pollCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category, flashwindow, candidates) + /** * Poll all in the group for a candidate * @@ -550,6 +575,26 @@ return list() return L +/** + * Poll mentor ghosts to take control of a mob + * + * Poll mentor ghosts for mob control + * returns people who voted yes in a list + * Arguments: + * * Question: String, what do you want to ask them + * * jobbanType: List, Which roles/jobs to exclude from being asked + * * gametypeCheck: Datum, Check if they have the time required for that role + * * be_special_flag: Bool, Only notify ghosts with special antag on + * * poll_time: Integer, How long to poll for in deciseconds(0.1s) + * * M: Mob, /mob to offer + * * ignore_category: Unknown + */ +/proc/pollMentorCandidatesForMob(Question, jobbanType, datum/game_mode/gametypeCheck, be_special_flag = 0, poll_time = 300, mob/M, ignore_category = null) + var/list/L = pollMentorGhostCandidates(Question, jobbanType, gametypeCheck, be_special_flag, poll_time, ignore_category) + if(!M || QDELETED(M) || !M.loc) + return list() + return L + /** * Poll ghosts to take control of a mob * diff --git a/code/datums/brain_damage/mrat.dm b/code/datums/brain_damage/mrat.dm new file mode 100644 index 000000000000..557339d478a4 --- /dev/null +++ b/code/datums/brain_damage/mrat.dm @@ -0,0 +1,146 @@ +/datum/brain_trauma/special/imaginary_friend/mrat + name = "Epistemania" + desc = "Patient suffers from a manic pursuit of knowlewdge." + scan_desc = "epistemania" + gain_text = "Requesting mentor..." + lose_text = "" + resilience = TRAUMA_RESILIENCE_ABSOLUTE + +/datum/brain_trauma/special/imaginary_friend/mrat/make_friend() + friend = new /mob/camera/imaginary_friend/mrat(get_turf(owner), src) + +/datum/brain_trauma/special/imaginary_friend/mrat/get_ghost() + set waitfor = FALSE + var/list/mob/dead/observer/candidates = pollMentorCandidatesForMob("Do you want to play as [owner]'s mentor rat?", ROLE_PAI, null, null, 75, friend, POLL_IGNORE_IMAGINARYFRIEND) + if(LAZYLEN(candidates)) + var/mob/dead/observer/C = pick(candidates) + friend.key = C.key + friend.real_name = friend.key + friend.name = friend.real_name + + var/mob/camera/imaginary_friend/mrat/I = friend + I.Costume() + + friend_initialized = TRUE + to_chat(owner, "You have acquired the mentor rat [friend.key], ask them any question you like. They will leave your presence when they are done.") + else + to_chat(owner, "No mentor responded to your request. Try again later.") + qdel(src) + +/mob/camera/imaginary_friend/mrat + name = "Mentor Rat" + real_name = "Mentor Rat" + desc = "Your personal mentor assistant." + + var/datum/action/innate/mrat_costume/costume + var/datum/action/innate/mrat_leave/leave + var/list/icons_available = list() + var/current_costume = FALSE + +/mob/camera/imaginary_friend/mrat/proc/update_available_icons() + icons_available = list() + + icons_available += list("Mouse" = image(icon = 'icons/mob/animal.dmi', icon_state = "mouse_white")) + icons_available += list("Moonrat" = image(icon = 'yogstation/icons/mob/pets.dmi', icon_state = "moonrat")) + icons_available += list("Hologram" = image(icon = 'icons/mob/ai.dmi', icon_state = "default")) + icons_available += list("Spaceman" = image(icon = 'icons/mob/animal.dmi', icon_state = "old")) + icons_available += list("Cheese" = image(icon = 'icons/mob/animal.dmi', icon_state = "parmesan")) + +/mob/camera/imaginary_friend/mrat/proc/Costume() + update_available_icons() + if(icons_available) + var/selection = show_radial_menu(src, src, icons_available, radius = 38) + if(!selection) + return + + current_costume = selection + + switch(selection) + if("Mouse") + human_image = icon('icons/mob/animal.dmi', icon_state = "mouse_white") + color = "#1ABC9C" + Show() + if("Moonrat") + human_image = icon('yogstation/icons/mob/pets.dmi', icon_state = "moonrat") + color = "#1ABC9C" + Show() + if("Hologram") + human_image = icon('icons/mob/ai.dmi', icon_state = "default") + color = "#1ABC9C" + Show() + if("Spaceman") + human_image = icon('icons/mob/animal.dmi', icon_state = "old") + color = null + Show() + if("Cheese") + human_image = icon('icons/mob/animal.dmi', icon_state = "parmesan") + color = null + Show() + +/mob/camera/imaginary_friend/mrat/friend_talk() + . = ..() + if(!current_costume) + return + switch(current_costume) + if("Mouse") + SEND_SOUND(owner, sound('sound/effects/mousesqueek.ogg')) + SEND_SOUND(src, sound('sound/effects/mousesqueek.ogg')) + if("Moonrat") + SEND_SOUND(owner, sound('sound/machines/uplinkpurchase.ogg')) + SEND_SOUND(src, sound('sound/machines/uplinkpurchase.ogg')) + if("Hologram") + SEND_SOUND(owner, sound('sound/machines/ping.ogg')) + SEND_SOUND(src, sound('sound/machines/ping.ogg')) + if("Spaceman") + SEND_SOUND(owner, sound('sound/machines/buzz-sigh.ogg')) + SEND_SOUND(src, sound('sound/machines/buzz-sigh.ogg')) + if("Cheese") + SEND_SOUND(owner, sound('sound/misc/soggy.ogg')) + SEND_SOUND(src, sound('sound/misc/soggy.ogg')) + +/mob/camera/imaginary_friend/mrat/greet() + to_chat(src, "You are the mentor rat of [owner]!") + to_chat(src, "Do not give [owner] any OOC information from your time as a ghost.") + to_chat(src, "Your job is to answer [owner]'s question(s) and you are given this form to assist in that.") + to_chat(src, "Don't be stupid with this or you will face the consequences.") + +/mob/camera/imaginary_friend/mrat/Initialize(mapload, _trauma) + . = ..() + costume = new + costume.Grant(src) + leave = new + leave.Grant(src) + +/mob/camera/imaginary_friend/mrat/setup_friend() + human_image = null + +/datum/action/innate/mrat_costume + name = "Change Appearance" + desc = "Shape your appearance to whatever you desire." + icon_icon = 'icons/mob/actions/actions_minor_antag.dmi' + background_icon_state = "bg_revenant" + button_icon_state = "ninja_phase" + +/datum/action/innate/mrat_costume/Activate() + var/mob/camera/imaginary_friend/mrat/I = owner + I.Costume() + +/datum/action/innate/mrat_leave + name = "Leave" + desc = "Leave and return to your ghost form." + icon_icon = 'icons/mob/actions/actions_minor_antag.dmi' + background_icon_state = "bg_revenant" + button_icon_state = "beam_up" + +/datum/action/innate/mrat_leave/Activate() + var/mob/camera/imaginary_friend/I = owner + to_chat(I, "You have ejected yourself from [I.owner].") + to_chat(I.owner, "Your mentor has left.") + qdel(I.trauma) + +/mob/camera/imaginary_friend/mrat/pointed(atom/A as mob|obj|turf in view()) + if(!..()) + return FALSE + to_chat(owner, "[src] points at [A].") + to_chat(src, "You point at [A].") + return TRUE diff --git a/yogstation.dme b/yogstation.dme index 51435b3a2f91..df5920d57f70 100644 --- a/yogstation.dme +++ b/yogstation.dme @@ -386,6 +386,7 @@ #include "code\datums\brain_damage\imaginary_friend.dm" #include "code\datums\brain_damage\magic.dm" #include "code\datums\brain_damage\mild.dm" +#include "code\datums\brain_damage\mrat.dm" #include "code\datums\brain_damage\phobia.dm" #include "code\datums\brain_damage\severe.dm" #include "code\datums\brain_damage\special.dm" diff --git a/yogstation/code/modules/mentor/mentor_verbs.dm b/yogstation/code/modules/mentor/mentor_verbs.dm index 7a8e85dca6c1..946ae9e6a2eb 100644 --- a/yogstation/code/modules/mentor/mentor_verbs.dm +++ b/yogstation/code/modules/mentor/mentor_verbs.dm @@ -70,6 +70,30 @@ GLOBAL_PROTECT(mentor_verbs) msg += "Mentorhelps are also seen by admins. If no mentors are available in game adminhelp instead and an admin will see it and respond." to_chat(src, msg, confidential=TRUE) +/client/verb/mrat() + set name = "Request Mentor Assistance" + set category = "Mentor" + + if(!istype(src.mob, /mob/living/carbon/human)) + to_chat(src, "You must be humanoid to use this!") + return + + var/mob/living/carbon/human/M = src.mob + + if(M.stat == DEAD) + to_chat(src, "You must be alive to use this!") + return + + if(M.has_trauma_type(/datum/brain_trauma/special/imaginary_friend/mrat)) + to_chat(src, "You already have or are requesting a mentor!") + return + + var/alertresult = alert(M, "This will create a rat-shaped avatar that a mentor can possess and guide you in person. Do you wish to continue?",,"Yes", "No") + if(alertresult == "No" || QDELETED(M) || !istype(M) || !M.key) + return + + M.gain_trauma(/datum/brain_trauma/special/imaginary_friend/mrat) + /client/proc/dementor() set name = "Dementor" set category = "Mentor"