diff --git a/code/__DEFINES/vv.dm b/code/__DEFINES/vv.dm index 04addf1786d..6c9d4e2b850 100644 --- a/code/__DEFINES/vv.dm +++ b/code/__DEFINES/vv.dm @@ -135,6 +135,7 @@ #define VV_HK_OFFER_GHOSTS "offer_ghosts" #define VV_HK_VIEW_PLANES "view_planes" #define VV_HK_GIVE_AI "give_ai" +#define VV_HK_GIVE_AI_SPEECH "give_ai_speech" // /mob/living #define VV_HK_GIVE_SPEECH_IMPEDIMENT "impede_speech" diff --git a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm index 7d877731e2b..7dbce139b57 100644 --- a/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm +++ b/code/datums/ai/basic_mobs/basic_subtrees/speech_subtree.dm @@ -34,6 +34,9 @@ var/total_choices_length = audible_emotes_length + non_audible_emotes_length + speak_lines_length + if (total_choices_length == 0) + return + var/random_number_in_range = rand(1, total_choices_length) var/sound_to_play = length(sound) > 0 ? pick(sound) : null diff --git a/code/datums/ai/basic_mobs/generic_controllers.dm b/code/datums/ai/basic_mobs/generic_controllers.dm index d38cfc70763..8bf0026e1aa 100644 --- a/code/datums/ai/basic_mobs/generic_controllers.dm +++ b/code/datums/ai/basic_mobs/generic_controllers.dm @@ -122,3 +122,10 @@ planning_subtrees = list( /datum/ai_planning_subtree/pet_planning, ) + +/// Literally does nothing except random speedh +/datum/ai_controller/basic_controller/talk + idle_behavior = null + planning_subtrees = list( + /datum/ai_planning_subtree/random_speech/blackboard, + ) diff --git a/code/modules/admin/admin_verbs.dm b/code/modules/admin/admin_verbs.dm index 7ac5fa72372..ec4107e5d64 100644 --- a/code/modules/admin/admin_verbs.dm +++ b/code/modules/admin/admin_verbs.dm @@ -679,3 +679,103 @@ ADMIN_VERB(give_ai_controller, R_FUN, "Give AI Controller", ADMIN_VERB_NO_DESCRI var/chosen_type = controllers_by_name[chosen] var/datum/admin_ai_template/using_template = new chosen_type using_template.apply(my_guy, user) + +ADMIN_VERB(give_ai_speech, R_FUN, "Give Random AI Speech", ADMIN_VERB_NO_DESCRIPTION, ADMIN_CATEGORY_HIDDEN, mob/living/my_guy) + if (isnull(my_guy.ai_controller)) + var/create_controller = tgui_alert(user, "Target has no AI controller, add one?", "Give AI?", list("Yes", "No")) == "Yes" + if (!create_controller) + return + var/run_with_mind = tgui_alert(user, "Run AI controller while the target has a client?", "Override Client?", list("Yes", "No")) + if (isnull(run_with_mind)) + return + if (QDELETED(my_guy)) + to_chat(user, span_warning("Target ceased to exist.")) + return + my_guy.ai_controller = new /datum/ai_controller/basic_controller/talk(my_guy) + if (run_with_mind == "Yes") + var/datum/ai_controller/guy_controller = my_guy.ai_controller + guy_controller.continue_processing_when_client = TRUE + guy_controller.reset_ai_status() + + var/speech_chance + var/list/spoken_lines + var/list/audible_emotes + var/list/visible_emotes + var/list/sounds + + speech_chance = tgui_input_number(user, "Enter chance per second to say something", "Speech Chance", default = 2, min_value = 0, max_value = 100, round_value = FALSE) + if (isnull(speech_chance)) + return + + var/add_another + var/next_line + + add_another = tgui_alert(user, "Add [length(spoken_lines) ? "another" : "a"] spoken line?", "Spoken Lines", list("Yes", "No")) + while (add_another == "Yes") + next_line = tgui_input_text(user, "Enter [length(spoken_lines) ? "another" : "a"] thing spoken out loud.", "Spoken Lines") + if (isnull(next_line)) + return + LAZYADD(spoken_lines, next_line) + add_another = tgui_alert(user, "Add [length(spoken_lines) ? "another" : "a"] spoken line?", "Spoken Lines", list("Yes", "No")) + if (isnull(add_another)) + return + + add_another = tgui_alert(user, "Add [length(spoken_lines) ? "another" : "a"] emote which people can hear?", "Audible Emotes", list("Yes", "No")) + while (add_another == "Yes") + next_line = tgui_input_text(user, "Enter [length(spoken_lines) ? "another" : "an"] emote which people can hear.", "Audible Emotes") + if (isnull(next_line)) + return + LAZYADD(audible_emotes, next_line) + add_another = tgui_alert(user, "Add [length(spoken_lines) ? "another" : "a"] emote which people can hear?", "Audible Emotes", list("Yes", "No")) + if (isnull(add_another)) + return + + add_another = tgui_alert(user, "Add [length(spoken_lines) ? "another" : "a"] emote which people can see?", "Visible Emotes", list("Yes", "No")) + while (add_another == "Yes") + next_line = tgui_input_text(user, "Enter [length(spoken_lines) ? "another" : "an"] emote which people can see.", "Visible Emotes") + if (isnull(next_line)) + return + LAZYADD(visible_emotes, next_line) + add_another = tgui_alert(user, "Add [length(spoken_lines) ? "another" : "a"] emote which people can see?", "Visible Emotes", list("Yes", "No")) + if (isnull(add_another)) + return + + if (!length(spoken_lines) && !length(audible_emotes) && !length(visible_emotes)) + return // Well you didn't tell it to say anything... + + if (length(spoken_lines) || length(audible_emotes)) + add_another = tgui_alert(user, "Add [length(spoken_lines) ? "another" : "a"] sound to play when doing something audible?", "Sounds", list("Yes", "No")) + while (add_another == "Yes") + next_line = input("", "Select sound",) as null|sound + if (isnull(next_line)) + return + LAZYADD(sounds, next_line) + add_another = tgui_alert(user, "Add [length(spoken_lines) ? "another" : "a"] sound to play when doing something audible?", "Sounds", list("Yes", "No")) + if (isnull(add_another)) + return + + if (QDELETED(my_guy)) + to_chat(user, span_warning("Target stopped existing.")) + return + + var/datum/ai_controller/our_controller = my_guy.ai_controller + if (length(spoken_lines)) + spoken_lines = string_list(spoken_lines) + if (length(audible_emotes)) + audible_emotes = string_list(audible_emotes) + if (length(visible_emotes)) + visible_emotes = string_list(visible_emotes) + + var/list/emotes = list( + BB_EMOTE_SAY = spoken_lines, + BB_EMOTE_HEAR = audible_emotes, + BB_EMOTE_SEE = visible_emotes, + BB_EMOTE_SOUND = sounds, + BB_SPEAK_CHANCE = speech_chance, + ) + our_controller.set_blackboard_key(BB_BASIC_MOB_SPEAK_LINES, emotes) + + var/behaviour_exists = !!(locate(/datum/ai_planning_subtree/random_speech/blackboard) in our_controller.planning_subtrees) + if (behaviour_exists) + return + our_controller.planning_subtrees = list(GLOB.ai_subtrees[/datum/ai_planning_subtree/random_speech/blackboard]) + our_controller.planning_subtrees diff --git a/code/modules/mob/mob.dm b/code/modules/mob/mob.dm index e6d552295c2..91ffef4c3fa 100644 --- a/code/modules/mob/mob.dm +++ b/code/modules/mob/mob.dm @@ -1372,7 +1372,7 @@ VV_DROPDOWN_OPTION("", "---------") VV_DROPDOWN_OPTION(VV_HK_GIB, "Gib") VV_DROPDOWN_OPTION(VV_HK_GIVE_AI, "Give AI Controller") - VV_DROPDOWN_OPTION(VV_HK_REMOVE_SPELL, "Remove Spell") + VV_DROPDOWN_OPTION(VV_HK_GIVE_AI_SPEECH, "Give Random AI Speech") VV_DROPDOWN_OPTION(VV_HK_GIVE_SPELL, "Give Spell") VV_DROPDOWN_OPTION(VV_HK_REMOVE_SPELL, "Remove Spell") VV_DROPDOWN_OPTION(VV_HK_GIVE_MOB_ACTION, "Give Mob Ability") @@ -1417,6 +1417,9 @@ if(href_list[VV_HK_GIVE_AI]) return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_ai_controller, src) + if(href_list[VV_HK_GIVE_AI_SPEECH]) + return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_ai_speech, src) + if(href_list[VV_HK_GIVE_MOB_ACTION]) return SSadmin_verbs.dynamic_invoke_verb(usr, /datum/admin_verb/give_mob_action, src)