diff --git a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm index bedfaf2fa03..bb5b344a89a 100644 --- a/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm +++ b/code/__DEFINES/dcs/signals/signals_atom/signals_atom_x_act.dm @@ -92,3 +92,6 @@ /// from /obj/projectile/energy/fisher/on_hit() or /obj/item/gun/energy/recharge/fisher when striking a target #define COMSIG_ATOM_SABOTEUR_ACT "hit_by_saboteur" #define COMSIG_SABOTEUR_SUCCESS 1 + +/// signal sent when a mouse is hovering over us, sent by atom/proc/on_mouse_entered +#define COMSIG_ATOM_MOUSE_ENTERED "mouse_entered" diff --git a/code/__DEFINES/keybinding.dm b/code/__DEFINES/keybinding.dm index 5f025ad99cf..8ae95933e64 100644 --- a/code/__DEFINES/keybinding.dm +++ b/code/__DEFINES/keybinding.dm @@ -4,6 +4,9 @@ #define COMSIG_KB_ACTIVATED (1<<0) #define COMSIG_KB_EMOTE "keybinding_emote_down" +///Signal sent when a keybind is deactivated +#define DEACTIVATE_KEYBIND(A) "[A]_DEACTIVATED" + //Admin #define COMSIG_KB_ADMIN_ASAY_DOWN "keybinding_admin_asay_down" #define COMSIG_KB_ADMIN_DSAY_DOWN "keybinding_admin_dsay_down" @@ -54,6 +57,7 @@ #define COMSIG_KB_LIVING_DISABLE_COMBAT_DOWN "keybinding_living_disable_combat_down" #define COMSIG_KB_LIVING_TOGGLEMOVEINTENT_DOWN "keybinding_mob_togglemoveintent_down" #define COMSIG_KB_LIVING_TOGGLEMOVEINTENTALT_DOWN "keybinding_mob_togglemoveintentalt_down" +#define COMSIG_KB_LIVING_VIEW_PET_COMMANDS "keybinding_living_view_pet_commands" //Mob #define COMSIG_KB_MOB_FACENORTH_DOWN "keybinding_mob_facenorth_down" diff --git a/code/__DEFINES/radial_defines.dm b/code/__DEFINES/radial_defines.dm new file mode 100644 index 00000000000..35ae6eebb59 --- /dev/null +++ b/code/__DEFINES/radial_defines.dm @@ -0,0 +1,6 @@ +#define NEXT_PAGE_ID "__next__" +#define DEFAULT_CHECK_DELAY 2 SECONDS + +#define BUTTON_SLIDE_IN (1<<0) +#define BUTTON_FADE_IN (1<<1) +#define BUTTON_FADE_OUT (1<<2) diff --git a/code/_onclick/hud/radial.dm b/code/_onclick/hud/radial.dm index ab95d3bb392..041a16b12a1 100644 --- a/code/_onclick/hud/radial.dm +++ b/code/_onclick/hud/radial.dm @@ -1,6 +1,3 @@ -#define NEXT_PAGE_ID "__next__" -#define DEFAULT_CHECK_DELAY 20 - GLOBAL_LIST_EMPTY(radial_menus) /atom/movable/screen/radial @@ -113,7 +110,7 @@ GLOBAL_LIST_EMPTY(radial_menus) var/hudfix_method = TRUE //TRUE to change anchor to user, FALSE to shift by py_shift var/py_shift = 0 - var/entry_animation = TRUE + var/button_animation_flags = BUTTON_SLIDE_IN ///A replacement icon state for the generic radial slice bg icon. Doesn't affect the next page nor the center buttons var/radial_slice_icon @@ -163,6 +160,8 @@ GLOBAL_LIST_EMPTY(radial_menus) var/atom/movable/screen/radial/slice/new_element = new /atom/movable/screen/radial/slice new_element.tooltips = use_tooltips new_element.set_parent(src) + if(button_animation_flags & BUTTON_FADE_IN) + new_element.alpha = 0 elements += new_element var/page = 1 @@ -186,9 +185,9 @@ GLOBAL_LIST_EMPTY(radial_menus) page_data[page] = current pages = page current_page = clamp(set_page, 1, pages) - update_screen_objects(entry_animation, click_on_hover) + update_screen_objects(button_animation_flags, click_on_hover) -/datum/radial_menu/proc/update_screen_objects(anim = FALSE, click_on_hover = FALSE) +/datum/radial_menu/proc/update_screen_objects(anim_flag = NONE, click_on_hover = FALSE) var/list/page_choices = page_data[current_page] var/angle_per_element = round(zone / page_choices.len) for(var/i in 1 to elements.len) @@ -198,11 +197,11 @@ GLOBAL_LIST_EMPTY(radial_menus) HideElement(element) element.click_on_hover = FALSE else - SetElement(element,page_choices[i],angle,anim = anim,anim_order = i) + SetElement(element,page_choices[i],angle,anim_flag = anim_flag,anim_order = i) // Only activate click on hover after the animation plays if (!click_on_hover) continue - if (anim) + if (anim_flag) addtimer(VARSET_CALLBACK(element, click_on_hover, TRUE), i * 0.5) else element.click_on_hover = TRUE @@ -217,11 +216,11 @@ GLOBAL_LIST_EMPTY(radial_menus) E.choice = null E.next_page = FALSE -/datum/radial_menu/proc/SetElement(atom/movable/screen/radial/slice/E,choice_id,angle,anim,anim_order) +/datum/radial_menu/proc/SetElement(atom/movable/screen/radial/slice/E, choice_id, angle, anim_flag, anim_order) //Position var/py = round(cos(angle) * radius) + py_shift var/px = round(sin(angle) * radius) - if(anim) + if(anim_flag & BUTTON_SLIDE_IN) var/timing = anim_order * 0.5 var/matrix/starting = matrix() starting.Scale(0.1,0.1) @@ -232,8 +231,11 @@ GLOBAL_LIST_EMPTY(radial_menus) E.pixel_y = py E.pixel_x = px - //Visuals - E.alpha = 255 + if(anim_flag & BUTTON_FADE_IN) + animate(E, alpha = 255, time = 0.15 SECONDS, easing = EASE_OUT) + else + E.alpha = 255 + E.mouse_opacity = MOUSE_OPACITY_ICON E.cut_overlays() E.vis_contents.Cut() @@ -266,7 +268,9 @@ GLOBAL_LIST_EMPTY(radial_menus) info_button.layer = RADIAL_CONTENT_LAYER E.vis_contents += info_button -/datum/radial_menu/New() +/datum/radial_menu/New(display_close_button) + if(!display_close_button) + return close_button = new close_button.set_parent(src) @@ -327,7 +331,9 @@ GLOBAL_LIST_EMPTY(radial_menus) menu_holder = image(icon='icons/effects/effects.dmi',loc=anchor,icon_state="nothing", layer = RADIAL_BACKGROUND_LAYER, pixel_x = offset_x, pixel_y = offset_y) SET_PLANE_EXPLICIT(menu_holder, ABOVE_HUD_PLANE, M) menu_holder.appearance_flags |= KEEP_APART|RESET_ALPHA|RESET_COLOR|RESET_TRANSFORM - menu_holder.vis_contents += elements + close_button + menu_holder.vis_contents += elements + if(!isnull(close_button)) + menu_holder.vis_contents += close_button current_user.images += menu_holder /datum/radial_menu/proc/hide() @@ -345,6 +351,14 @@ GLOBAL_LIST_EMPTY(radial_menus) next_check = world.time + check_delay stoplag(1) +/datum/radial_menu/proc/remove_menu() + if(!(button_animation_flags & BUTTON_FADE_OUT)) + qdel(src) + return + for(var/atom/movable/element as anything in elements) + animate(element, alpha = 0, time = 0.15 SECONDS) + QDEL_IN(src, 0.5 SECONDS) + /datum/radial_menu/Destroy() Reset() hide() @@ -356,11 +370,11 @@ GLOBAL_LIST_EMPTY(radial_menus) Choices should be a list where list keys are movables or text used for element names and return value and list values are movables/icons/images used for element icons */ -/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice", autopick_single_option = TRUE, entry_animation = TRUE, click_on_hover = FALSE, user_space = FALSE) +/proc/show_radial_menu(mob/user, atom/anchor, list/choices, uniqueid, radius, datum/callback/custom_check, require_near = FALSE, tooltips = FALSE, no_repeat_close = FALSE, radial_slice_icon = "radial_slice", autopick_single_option = TRUE, button_animation_flags = BUTTON_SLIDE_IN, click_on_hover = FALSE, user_space = FALSE, check_delay = DEFAULT_CHECK_DELAY, display_close_button = TRUE, radial_menu_offset = list(0, 0)) if(!user || !anchor || !length(choices)) return - if(length(choices)==1 && autopick_single_option) + if(length(choices) == 1 && autopick_single_option) return choices[1] if(!uniqueid) @@ -372,8 +386,9 @@ GLOBAL_LIST_EMPTY(radial_menus) menu.finished = TRUE return - var/datum/radial_menu/menu = new - menu.entry_animation = entry_animation + var/datum/radial_menu/menu = new(display_close_button) + menu.button_animation_flags = button_animation_flags + menu.check_delay = check_delay GLOB.radial_menus[uniqueid] = menu if(radius) menu.radius = radius @@ -390,10 +405,12 @@ GLOBAL_LIST_EMPTY(radial_menus) var/turf/anchor_turf = get_turf(anchor) offset_x = (anchor_turf.x - user_turf.x) * ICON_SIZE_X + anchor.pixel_x - user.pixel_x offset_y = (anchor_turf.y - user_turf.y) * ICON_SIZE_Y + anchor.pixel_y - user.pixel_y + offset_x += radial_menu_offset[1] + offset_y += radial_menu_offset[2] menu.show_to(user, offset_x, offset_y) menu.wait(user, anchor, require_near) var/answer = menu.selected_choice - qdel(menu) + menu.remove_menu() GLOB.radial_menus -= uniqueid if(require_near && !in_range(anchor, user)) return diff --git a/code/_onclick/hud/radial_persistent.dm b/code/_onclick/hud/radial_persistent.dm index 5fe81d005bd..d48c8d9eb45 100644 --- a/code/_onclick/hud/radial_persistent.dm +++ b/code/_onclick/hud/radial_persistent.dm @@ -43,7 +43,7 @@ /datum/radial_menu/persistent/proc/change_choices(list/newchoices, tooltips = FALSE, animate = FALSE, keep_same_page = FALSE) if(!newchoices.len) return - entry_animation = FALSE + button_animation_flags = NONE var/target_page = keep_same_page ? current_page : 1 //Stores the current_page value before it's set back to 1 on Reset() Reset() set_choices(newchoices,tooltips, set_page = target_page) diff --git a/code/datums/components/callouts.dm b/code/datums/components/callouts.dm index 52a3e007905..854f769f8a1 100644 --- a/code/datums/components/callouts.dm +++ b/code/datums/components/callouts.dm @@ -111,7 +111,7 @@ for(var/datum/callout_option/callout_option as anything in callout_options) callout_items[callout_option] = image(icon = 'icons/hud/radial.dmi', icon_state = callout_option::icon_state) - var/datum/callout_option/selection = show_radial_menu(user, get_turf(clicked_atom), callout_items, entry_animation = FALSE, click_on_hover = TRUE, user_space = TRUE) + var/datum/callout_option/selection = show_radial_menu(user, get_turf(clicked_atom), callout_items, button_animation_flags = NONE, click_on_hover = TRUE, user_space = TRUE) if (!selection) return diff --git a/code/datums/components/pet_commands/fetch.dm b/code/datums/components/pet_commands/fetch.dm index 9a42c485d5c..143ac9ca101 100644 --- a/code/datums/components/pet_commands/fetch.dm +++ b/code/datums/components/pet_commands/fetch.dm @@ -3,11 +3,11 @@ * Watch for someone throwing or pointing at something and then go get it and bring it back. * If it's food we might eat it instead. */ -/datum/pet_command/point_targeting/fetch +/datum/pet_command/fetch command_name = "Fetch" command_desc = "Command your pet to retrieve something you throw or point at." - radial_icon = 'icons/mob/actions/actions_spells.dmi' - radial_icon_state = "summons" + radial_icon_state = "fetch" + requires_pointing = TRUE speech_commands = list("fetch") command_feedback = "bounces" pointed_reaction = "with great interest" @@ -16,22 +16,25 @@ /// If true, this is a poorly trained pet who will eat food you throw instead of bringing it back var/will_eat_targets = TRUE -/datum/pet_command/point_targeting/fetch/New(mob/living/parent) +/datum/pet_command/fetch/New(mob/living/parent) . = ..() if(isnull(parent)) return parent.AddElement(/datum/element/ai_held_item) // We don't remove this on destroy because they might still be holding something -/datum/pet_command/point_targeting/fetch/add_new_friend(mob/living/tamer) +/datum/pet_command/fetch/add_new_friend(mob/living/tamer) . = ..() RegisterSignal(tamer, COMSIG_MOB_THROW, PROC_REF(listened_throw)) -/datum/pet_command/point_targeting/fetch/remove_friend(mob/living/unfriended) +/datum/pet_command/fetch/remove_friend(mob/living/unfriended) . = ..() UnregisterSignal(unfriended, COMSIG_MOB_THROW) +/datum/pet_command/fetch/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to fetch [target]!" + /// A friend has thrown something, if we're listening or at least not busy then go get it -/datum/pet_command/point_targeting/fetch/proc/listened_throw(mob/living/carbon/thrower) +/datum/pet_command/fetch/proc/listened_throw(mob/living/carbon/thrower) SIGNAL_HANDLER var/mob/living/parent = weak_parent.resolve() @@ -57,7 +60,7 @@ RegisterSignal(thrown_thing, COMSIG_MOVABLE_THROW_LANDED, PROC_REF(listen_throw_land)) /// A throw we were listening to has finished, see if it's in range for us to try grabbing it -/datum/pet_command/point_targeting/fetch/proc/listen_throw_land(obj/item/thrown_thing, datum/thrownthing/throwingdatum) +/datum/pet_command/fetch/proc/listen_throw_land(obj/item/thrown_thing, datum/thrownthing/throwingdatum) SIGNAL_HANDLER UnregisterSignal(thrown_thing, COMSIG_MOVABLE_THROW_LANDED) @@ -76,7 +79,7 @@ parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, thrower) // Don't try and fetch turfs or anchored objects if someone points at them -/datum/pet_command/point_targeting/fetch/look_for_target(mob/living/pointing_friend, obj/item/pointed_atom) +/datum/pet_command/fetch/look_for_target(mob/living/pointing_friend, obj/item/pointed_atom) if (!istype(pointed_atom)) return FALSE if (pointed_atom.anchored) @@ -89,7 +92,7 @@ parent.ai_controller.set_blackboard_key(BB_FETCH_DELIVER_TO, pointing_friend) // Finally, plan our actions -/datum/pet_command/point_targeting/fetch/execute_action(datum/ai_controller/controller) +/datum/pet_command/fetch/execute_action(datum/ai_controller/controller) controller.queue_behavior(/datum/ai_behavior/forget_failed_fetches) var/atom/target = controller.blackboard[BB_CURRENT_PET_TARGET] diff --git a/code/datums/components/pet_commands/obeys_commands.dm b/code/datums/components/pet_commands/obeys_commands.dm index 8aaa7e71792..4a68574d6e0 100644 --- a/code/datums/components/pet_commands/obeys_commands.dm +++ b/code/datums/components/pet_commands/obeys_commands.dm @@ -3,12 +3,23 @@ * Manages a list of pet command datums, allowing you to boss it around * Creates a radial menu of pet commands when this creature is alt-clicked, if it has any */ +#define DEFAULT_RADIAL_VIEWING_DISTANCE 9 /datum/component/obeys_commands /// List of commands you can give to the owner of this component var/list/available_commands = list() + ///Users currently viewing our radial options + var/list/radial_viewers = list() + ///radius of our radial menu + var/radial_menu_radius = 48 + ///after how long we shutdown radial menus + var/radial_menu_lifetime = 7 SECONDS + ///offset to display the radial menu + var/list/radial_menu_offset + ///should the commands move with the pet owner's screen? + var/radial_relative_to_user /// The available_commands parameter should be passed as a list of typepaths -/datum/component/obeys_commands/Initialize(list/command_typepaths = list()) +/datum/component/obeys_commands/Initialize(list/command_typepaths = list(), list/radial_menu_offset = list(0, 0), radial_relative_to_user = FALSE) . = ..() if (!isliving(parent)) return COMPONENT_INCOMPATIBLE @@ -17,7 +28,8 @@ return COMPONENT_INCOMPATIBLE if (!length(command_typepaths)) CRASH("Initialised obedience component with no commands.") - + src.radial_menu_offset = radial_menu_offset + src.radial_relative_to_user = radial_relative_to_user for (var/command_path in command_typepaths) var/datum/pet_command/new_command = new command_path(parent) available_commands[new_command.command_name] = new_command @@ -30,7 +42,6 @@ RegisterSignal(parent, COMSIG_LIVING_BEFRIENDED, PROC_REF(add_friend)) RegisterSignal(parent, COMSIG_LIVING_UNFRIENDED, PROC_REF(remove_friend)) RegisterSignal(parent, COMSIG_ATOM_EXAMINE, PROC_REF(on_examine)) - RegisterSignal(parent, COMSIG_CLICK_ALT, PROC_REF(display_menu)) /datum/component/obeys_commands/UnregisterFromParent() UnregisterSignal(parent, list(COMSIG_LIVING_BEFRIENDED, COMSIG_LIVING_UNFRIENDED, COMSIG_ATOM_EXAMINE, COMSIG_CLICK_ALT)) @@ -38,15 +49,26 @@ /// Add someone to our friends list /datum/component/obeys_commands/proc/add_friend(datum/source, mob/living/new_friend) SIGNAL_HANDLER - + RegisterSignal(new_friend, COMSIG_KB_LIVING_VIEW_PET_COMMANDS, PROC_REF(on_key_pressed)) + RegisterSignal(new_friend, DEACTIVATE_KEYBIND(COMSIG_KB_LIVING_VIEW_PET_COMMANDS), PROC_REF(on_key_unpressed)) for (var/command_name as anything in available_commands) var/datum/pet_command/command = available_commands[command_name] INVOKE_ASYNC(command, TYPE_PROC_REF(/datum/pet_command, add_new_friend), new_friend) +/datum/component/obeys_commands/proc/on_key_unpressed(mob/living/source) + SIGNAL_HANDLER + UnregisterSignal(source, COMSIG_ATOM_MOUSE_ENTERED) + +/datum/component/obeys_commands/proc/remove_from_viewers(mob/living/source) + radial_viewers -= REF(source) + /// Remove someone from our friends list /datum/component/obeys_commands/proc/remove_friend(datum/source, mob/living/old_friend) SIGNAL_HANDLER - + UnregisterSignal(old_friend, list( + COMSIG_KB_LIVING_VIEW_PET_COMMANDS, + DEACTIVATE_KEYBIND(COMSIG_KB_LIVING_VIEW_PET_COMMANDS), + )) for (var/command_name as anything in available_commands) var/datum/pet_command/command = available_commands[command_name] INVOKE_ASYNC(command, TYPE_PROC_REF(/datum/pet_command, remove_friend), old_friend) @@ -61,21 +83,34 @@ return examine_list += span_notice("[source.p_They()] seem[source.p_s()] happy to see you!") -/// Displays a radial menu of commands -/datum/component/obeys_commands/proc/display_menu(datum/source, mob/living/clicker) +/datum/component/obeys_commands/proc/on_key_pressed(mob/living/friend) SIGNAL_HANDLER + RegisterSignal(friend, COMSIG_ATOM_MOUSE_ENTERED, PROC_REF(on_mouse_hover)) + +/datum/component/obeys_commands/proc/on_mouse_hover(mob/living/friend, atom/mouse_hovered) + SIGNAL_HANDLER + if(mouse_hovered == parent) + display_menu(friend) + return + if(isliving(mouse_hovered)) + remove_from_viewers(friend) + +/// Displays a radial menu of commands +/datum/component/obeys_commands/proc/display_menu(mob/living/friend) var/mob/living/living_parent = parent - if (IS_DEAD_OR_INCAP(living_parent) || !clicker.can_perform_action(living_parent)) + if (IS_DEAD_OR_INCAP(living_parent) || friend.stat != CONSCIOUS) return - if (!(clicker in living_parent.ai_controller?.blackboard[BB_FRIENDS_LIST])) + if (!(friend in living_parent.ai_controller?.blackboard[BB_FRIENDS_LIST])) return // Not our friend, can't boss us around - - INVOKE_ASYNC(src, PROC_REF(display_radial_menu), clicker) - return CLICK_ACTION_SUCCESS + if(radial_viewers[REF(friend)]) + return + if(!can_see(friend, parent, DEFAULT_RADIAL_VIEWING_DISTANCE)) + return + INVOKE_ASYNC(src, PROC_REF(display_radial_menu), friend) /// Actually display the radial menu and then do something with the result -/datum/component/obeys_commands/proc/display_radial_menu(mob/living/clicker) +/datum/component/obeys_commands/proc/display_radial_menu(mob/living/friend) var/list/radial_options = list() for (var/command_name as anything in available_commands) var/datum/pet_command/command = available_commands[command_name] @@ -83,9 +118,22 @@ if (!choice) continue radial_options += choice - - var/pick = show_radial_menu(clicker, clicker, radial_options, tooltips = TRUE) - if (!pick) + radial_viewers[REF(friend)] = world.time + radial_menu_lifetime + var/pick = show_radial_menu(friend, parent, radial_options, radius = radial_menu_radius, button_animation_flags = BUTTON_FADE_IN | BUTTON_FADE_OUT, custom_check = CALLBACK(src, PROC_REF(check_menu_viewer), friend), check_delay = 0.15 SECONDS, display_close_button = FALSE, radial_menu_offset = radial_menu_offset, user_space = radial_relative_to_user) + remove_from_viewers(friend) + if(!pick) return var/datum/pet_command/picked_command = available_commands[pick] - picked_command.try_activate_command(clicker) + picked_command.try_activate_command(friend, radial_command = TRUE) + +/datum/component/obeys_commands/proc/check_menu_viewer(mob/living/user) + if(QDELETED(user) || !radial_viewers[REF(user)]) + return FALSE + if(world.time > radial_viewers[REF(user)]) + return FALSE + var/viewing_distance = DEFAULT_RADIAL_VIEWING_DISTANCE + if(!can_see(user, parent, viewing_distance)) + return FALSE + return TRUE + +#undef DEFAULT_RADIAL_VIEWING_DISTANCE diff --git a/code/datums/components/pet_commands/pet_command.dm b/code/datums/components/pet_commands/pet_command.dm index 52b4cc88349..fab3de70b79 100644 --- a/code/datums/components/pet_commands/pet_command.dm +++ b/code/datums/components/pet_commands/pet_command.dm @@ -13,7 +13,7 @@ /// If true, command will not appear in radial menu and can only be accessed through speech var/hidden = FALSE /// Icon to display in radial menu - var/icon/radial_icon + var/icon/radial_icon = 'icons/hud/radial_pets.dmi' /// Icon state to display in radial menu var/radial_icon_state /// Speech strings to listen out for @@ -24,6 +24,12 @@ var/command_feedback /// How close a mob needs to be to a target to respond to a command var/sense_radius = 7 + /// does this pet command need a point to activate? + var/requires_pointing = FALSE + /// Blackboard key for targeting strategy, this is likely going to need it + var/targeting_strategy_key = BB_PET_TARGETING_STRATEGY + ///our pointed reaction we play + var/pointed_reaction /datum/pet_command/New(mob/living/parent) . = ..() @@ -34,10 +40,17 @@ RegisterSignal(tamer, COMSIG_MOB_SAY, PROC_REF(respond_to_command)) RegisterSignal(tamer, COMSIG_MOB_AUTOMUTE_CHECK, PROC_REF(waive_automute)) RegisterSignal(tamer, COMSIG_MOB_CREATED_CALLOUT, PROC_REF(respond_to_callout)) + if(requires_pointing) + RegisterSignal(tamer, COMSIG_MOVABLE_POINTED, PROC_REF(point_on_target)) /// Stop listening to a guy /datum/pet_command/proc/remove_friend(mob/living/unfriended) - UnregisterSignal(unfriended, list(COMSIG_MOB_SAY, COMSIG_MOB_AUTOMUTE_CHECK, COMSIG_MOB_CREATED_CALLOUT)) + UnregisterSignal(unfriended, list( + COMSIG_MOB_SAY, + COMSIG_MOB_AUTOMUTE_CHECK, + COMSIG_MOB_CREATED_CALLOUT, + COMSIG_MOVABLE_POINTED, + )) /// Stop the automute from triggering for commands (unless the spoken text is suspiciously longer than the command) /datum/pet_command/proc/waive_automute(mob/living/speaker, client/client, last_message, mute_type) @@ -49,7 +62,6 @@ /// Respond to something that one of our friends has asked us to do /datum/pet_command/proc/respond_to_command(mob/living/speaker, speech_args) SIGNAL_HANDLER - var/mob/living/parent = weak_parent.resolve() if (!parent) return @@ -60,7 +72,7 @@ if (!find_command_in_text(spoken_text)) return - try_activate_command(speaker) + try_activate_command(commander = speaker, radial_command = FALSE) /// Respond to a callout /datum/pet_command/proc/respond_to_callout(mob/living/caller, datum/callout_option/callout, atom/target) @@ -83,7 +95,7 @@ if (!found_new_target) return - if (try_activate_command(caller)) + if (try_activate_command(commander = caller, radial_command = FALSE)) look_for_target(parent, target) /// Does this callout with this target trigger this command? @@ -103,48 +115,77 @@ return TRUE return FALSE -/// Apply a command state if conditions are right, return command if successful -/datum/pet_command/proc/try_activate_command(mob/living/commander) +/datum/pet_command/proc/pet_able_to_respond() var/mob/living/parent = weak_parent.resolve() - if (!parent) + if(isnull(parent) || isnull(parent.ai_controller)) return FALSE - if (!parent.ai_controller) // We stopped having a brain at some point + if(IS_DEAD_OR_INCAP(parent)) // Probably can't hear them if we're dead return FALSE - if (IS_DEAD_OR_INCAP(parent)) // Probably can't hear them if we're dead - return FALSE - if (parent.ai_controller.blackboard[BB_ACTIVE_PET_COMMAND] == src) // We're already doing it - return FALSE - set_command_active(parent, commander) return TRUE -/// Target the pointed atom for actions -/datum/pet_command/proc/look_for_target(mob/living/friend, atom/pointed_atom) +/// Apply a command state if conditions are right, return command if successful +/datum/pet_command/proc/try_activate_command(mob/living/commander, radial_command) + if(!pet_able_to_respond()) + return FALSE var/mob/living/parent = weak_parent.resolve() - if (!parent) + set_command_active(parent, commander, radial_command) + return TRUE + +/datum/pet_command/proc/generate_emote_command(atom/target) + var/mob/living/living_pet = weak_parent?.resolve() + return isnull(living_pet) ? null : retrieve_command_text(living_pet, target) + +/datum/pet_command/proc/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to spring into action!" + +/// Target the pointed atom for actions +/datum/pet_command/proc/look_for_target(mob/living/friend, atom/potential_target) + var/mob/living/parent = weak_parent.resolve() + if(!pet_able_to_respond()) return FALSE - if (!parent.ai_controller) + if (parent.ai_controller.blackboard[BB_CURRENT_PET_TARGET] == potential_target) // That's already our target return FALSE - if (IS_DEAD_OR_INCAP(parent)) - return FALSE - if (parent.ai_controller.blackboard[BB_ACTIVE_PET_COMMAND] != src) // We're not listening right now - return FALSE - if (parent.ai_controller.blackboard[BB_CURRENT_PET_TARGET] == pointed_atom) // That's already our target - return FALSE - if (!can_see(parent, pointed_atom, sense_radius)) + if (!can_see(parent, potential_target, sense_radius)) return FALSE parent.ai_controller.CancelActions() - set_command_target(parent, pointed_atom) + set_command_target(parent, potential_target) return TRUE /// Activate the command, extend to add visible messages and the like -/datum/pet_command/proc/set_command_active(mob/living/parent, mob/living/commander) - set_command_target(parent, null) +/datum/pet_command/proc/set_command_active(mob/living/parent, mob/living/commander, radial_command = FALSE) + parent.ai_controller.clear_blackboard_key(BB_CURRENT_PET_TARGET) parent.ai_controller.CancelActions() // Stop whatever you're doing and do this instead parent.ai_controller.set_blackboard_key(BB_ACTIVE_PET_COMMAND, src) if (command_feedback) parent.balloon_alert_to_viewers("[command_feedback]") // If we get a nicer runechat way to do this, refactor this + if(!radial_command) + return + if(!requires_pointing) + var/manual_emote_text = generate_emote_command() + commander.manual_emote(manual_emote_text) + return + RegisterSignal(commander, COMSIG_MOB_CLICKON, PROC_REF(click_on_target)) + commander.client?.mouse_override_icon = 'icons/effects/mouse_pointers/pet_paw.dmi' + commander.update_mouse_pointer() + +/datum/pet_command/proc/click_on_target(mob/living/source, atom/target, list/modifiers) + SIGNAL_HANDLER + if(!can_see(source, target, 9)) + return COMSIG_MOB_CANCEL_CLICKON + on_target_set(source, target) + UnregisterSignal(source, COMSIG_MOB_CLICKON) + source.client?.mouse_override_icon = source.client::mouse_override_icon + source.update_mouse_pointer() + var/manual_emote_text = generate_emote_command(target) + if(!isnull(manual_emote_text)) + INVOKE_ASYNC(source, TYPE_PROC_REF(/atom, manual_emote), manual_emote_text) + return COMSIG_MOB_CANCEL_CLICKON + +/datum/pet_command/proc/point_on_target(mob/living/friend, atom/potential_target) + SIGNAL_HANDLER + on_target_set(friend, potential_target) /// Store the target for the AI blackboard /datum/pet_command/proc/set_command_target(mob/living/parent, atom/target) @@ -158,11 +199,6 @@ var/datum/radial_menu_choice/choice = new() choice.name = command_name choice.image = icon(icon = radial_icon, icon_state = radial_icon_state) - var/tooltip = command_desc - if (length(speech_commands)) - tooltip += "
Speak this command with the words [speech_commands.Join(", ")]." - choice.info = tooltip - return list("[command_name]" = choice) /** @@ -174,34 +210,15 @@ SHOULD_CALL_PARENT(FALSE) CRASH("Pet command execute action not implemented.") -/** - * # Point Targeting Pet Command - * As above but also listens for you pointing at something and marks it as a target - */ -/datum/pet_command/point_targeting - /// Text describing an action we perform upon receiving a new target - var/pointed_reaction - /// Blackboard key for targeting strategy, this is likely going to need it - var/targeting_strategy_key = BB_PET_TARGETING_STRATEGY - -/datum/pet_command/point_targeting/add_new_friend(mob/living/tamer) - . = ..() - RegisterSignal(tamer, COMSIG_MOVABLE_POINTED, PROC_REF(on_point)) - -/datum/pet_command/point_targeting/remove_friend(mob/living/unfriended) - . = ..() - UnregisterSignal(unfriended, COMSIG_MOVABLE_POINTED) - /// Target the pointed atom for actions -/datum/pet_command/point_targeting/proc/on_point(mob/living/friend, atom/pointed_atom, obj/effect/temp_visual/point/point) - SIGNAL_HANDLER - +/datum/pet_command/proc/on_target_set(mob/living/friend, atom/potential_target) var/mob/living/parent = weak_parent.resolve() if (!parent) - return FALSE + return parent.ai_controller.CancelActions() - if (look_for_target(friend, pointed_atom) && set_command_target(parent, pointed_atom)) - parent.visible_message(span_warning("[parent] follows [friend]'s gesture towards [pointed_atom] [pointed_reaction]!")) - return TRUE - return FALSE + if(!look_for_target(friend, potential_target) || !set_command_target(parent, potential_target)) + return + parent.visible_message(span_warning("[parent] follows [friend]'s gesture towards [potential_target] [pointed_reaction]!")) + + diff --git a/code/datums/components/pet_commands/pet_commands_basic.dm b/code/datums/components/pet_commands/pet_commands_basic.dm index fd4e1f922c8..06d11d353e8 100644 --- a/code/datums/components/pet_commands/pet_commands_basic.dm +++ b/code/datums/components/pet_commands/pet_commands_basic.dm @@ -7,14 +7,16 @@ /datum/pet_command/idle command_name = "Stay" command_desc = "Command your pet to stay idle in this location." - radial_icon = 'icons/obj/bed.dmi' - radial_icon_state = "dogbed" + radial_icon_state = "halt" speech_commands = list("sit", "stay", "stop") command_feedback = "sits" /datum/pet_command/idle/execute_action(datum/ai_controller/controller) return SUBTREE_RETURN_FINISH_PLANNING // This cancels further AI planning +/datum/pet_command/idle/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to stay idle!" + /** * # Pet Command: Stop * Tells a pet to exit command mode and resume its normal behaviour, which includes regular target-seeking and what have you @@ -22,8 +24,7 @@ /datum/pet_command/free command_name = "Loose" command_desc = "Allow your pet to resume its natural behaviours." - radial_icon = 'icons/mob/actions/actions_spells.dmi' - radial_icon_state = "repulse" + radial_icon_state = "free" speech_commands = list("free", "loose") command_feedback = "relaxes" @@ -31,6 +32,9 @@ controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return // Just move on to the next planning subtree. +/datum/pet_command/free/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to go free!" + /** * # Pet Command: Follow * Tells a pet to follow you until you tell it to do something else @@ -38,8 +42,7 @@ /datum/pet_command/follow command_name = "Follow" command_desc = "Command your pet to accompany you." - radial_icon = 'icons/testing/turf_analysis.dmi' - radial_icon_state = "red_arrow" + radial_icon_state = "follow" speech_commands = list("heel", "follow") callout_type = /datum/callout_option/move ///the behavior we use to follow @@ -49,6 +52,9 @@ . = ..() set_command_target(parent, commander) +/datum/pet_command/follow/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to follow!" + /datum/pet_command/follow/execute_action(datum/ai_controller/controller) controller.queue_behavior(follow_behavior, BB_CURRENT_PET_TARGET) return SUBTREE_RETURN_FINISH_PLANNING @@ -60,14 +66,16 @@ /datum/pet_command/play_dead command_name = "Play Dead" command_desc = "Play a macabre trick." - radial_icon = 'icons/mob/simple/pets.dmi' - radial_icon_state = "puppy_dead" + radial_icon_state = "play_dead" speech_commands = list("play dead") // Don't get too creative here, people talk about dying pretty often /datum/pet_command/play_dead/execute_action(datum/ai_controller/controller) controller.queue_behavior(/datum/ai_behavior/play_dead) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/play_dead/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to play dead!" + /** * # Pet Command: Good Boy * React if complimented @@ -115,16 +123,18 @@ controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/untargeted_ability/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to use an ability!" + /** * # Pet Command: Attack * Tells a pet to chase and bite the next thing you point at */ -/datum/pet_command/point_targeting/attack +/datum/pet_command/attack command_name = "Attack" command_desc = "Command your pet to attack things that you point out to it." - radial_icon = 'icons/effects/effects.dmi' - radial_icon_state = "bite" - + radial_icon_state = "attack" + requires_pointing = TRUE callout_type = /datum/callout_option/attack speech_commands = list("attack", "sic", "kill") command_feedback = "growl" @@ -135,7 +145,7 @@ var/attack_behaviour = /datum/ai_behavior/basic_melee_attack // Refuse to target things we can't target, chiefly other friends -/datum/pet_command/point_targeting/attack/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/attack/set_command_target(mob/living/parent, atom/target) if (!target) return var/mob/living/living_parent = parent @@ -149,28 +159,32 @@ return return ..() +/datum/pet_command/attack/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to attack [target]!" + /// Display feedback about not targeting something -/datum/pet_command/point_targeting/attack/proc/refuse_target(mob/living/parent, atom/target) +/datum/pet_command/attack/proc/refuse_target(mob/living/parent, atom/target) var/mob/living/living_parent = parent living_parent.balloon_alert_to_viewers("[refuse_reaction]") living_parent.visible_message(span_notice("[living_parent] refuses to attack [target].")) -/datum/pet_command/point_targeting/attack/execute_action(datum/ai_controller/controller) +/datum/pet_command/attack/execute_action(datum/ai_controller/controller) controller.queue_behavior(attack_behaviour, BB_CURRENT_PET_TARGET, targeting_strategy_key) return SUBTREE_RETURN_FINISH_PLANNING /** * # Breed command. breed with a partner! */ -/datum/pet_command/point_targeting/breed +/datum/pet_command/breed command_name = "Breed" command_desc = "Command your pet to attempt to breed with a partner." - radial_icon = 'icons/mob/simple/animal.dmi' - radial_icon_state = "heart" + requires_pointing = TRUE + radial_icon_state = "breed" speech_commands = list("breed", "consummate") + ///the behavior we use to make babies var/datum/ai_behavior/reproduce_behavior = /datum/ai_behavior/make_babies -/datum/pet_command/point_targeting/breed/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/breed/set_command_target(mob/living/parent, atom/target) if(isnull(target) || !isliving(target)) return if(!HAS_TRAIT(parent, TRAIT_MOB_BREEDER) || !HAS_TRAIT(target, TRAIT_MOB_BREEDER)) @@ -184,21 +198,25 @@ return return ..() -/datum/pet_command/point_targeting/breed/execute_action(datum/ai_controller/controller) +/datum/pet_command/breed/execute_action(datum/ai_controller/controller) if(is_type_in_list(controller.blackboard[BB_CURRENT_PET_TARGET], controller.blackboard[BB_BABIES_PARTNER_TYPES])) controller.queue_behavior(reproduce_behavior, BB_CURRENT_PET_TARGET) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/breed/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to breed with [target]!" + /** * # Pet Command: Targetted Ability * Tells a pet to use some kind of ability on the next thing you point at */ -/datum/pet_command/point_targeting/use_ability +/datum/pet_command/use_ability command_name = "Use ability" command_desc = "Command your pet to use one of its special skills on something that you point out to it." radial_icon = 'icons/mob/actions/actions_spells.dmi' radial_icon_state = "projectile" + requires_pointing = TRUE speech_commands = list("shoot", "blast", "cast") command_feedback = "growl" pointed_reaction = "and growls" @@ -207,7 +225,7 @@ /// The AI behavior to use for the ability var/ability_behavior = /datum/ai_behavior/pet_use_ability -/datum/pet_command/point_targeting/use_ability/execute_action(datum/ai_controller/controller) +/datum/pet_command/use_ability/execute_action(datum/ai_controller/controller) if (!pet_ability_key) return var/datum/action/cooldown/using_action = controller.blackboard[pet_ability_key] @@ -218,6 +236,9 @@ controller.queue_behavior(ability_behavior, pet_ability_key, BB_CURRENT_PET_TARGET) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/use_ability/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to use an ability on [target]!" + /datum/pet_command/protect_owner command_name = "Protect owner" command_desc = "Your pet will run to your aid." @@ -278,25 +299,39 @@ /** * # Fish command: command the mob to fish at the next fishing spot you point at. Requires the profound fisher component */ -/datum/pet_command/point_targeting/fish +/datum/pet_command/fish command_name = "Fish" command_desc = "Command your pet to try fishing at a nearby fishing spot." - radial_icon = 'icons/obj/aquarium/fish.dmi' - radial_icon_state = "goldfish" + requires_pointing = TRUE + radial_icon_state = "fish" speech_commands = list("fish") -// Refuse to target things we can't target, chiefly other friends -/datum/pet_command/point_targeting/fish/set_command_target(mob/living/parent, atom/target) - if (!target) - return - if(!parent.ai_controller || !HAS_TRAIT(parent, TRAIT_PROFOUND_FISHER)) - return - var/datum/targeting_strategy/targeter = GET_TARGETING_STRATEGY(/datum/targeting_strategy/fishing) - if (!targeter?.can_attack(parent, target)) - parent.balloon_alert_to_viewers("shakes head!") - return +/datum/pet_command/fish/execute_action(datum/ai_controller/controller) + if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) + controller.queue_behavior(/datum/ai_behavior/interact_with_target/fishing, BB_CURRENT_PET_TARGET) + return SUBTREE_RETURN_FINISH_PLANNING + +/datum/pet_command/fish/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to go fish!" + +/datum/pet_command/move + command_name = "Move" + command_desc = "Command your pet to move to a location!" + requires_pointing = TRUE + radial_icon_state = "move" + speech_commands = list("move", "walk") + ///the behavior we use to walk towards targets + var/datum/ai_behavior/walk_behavior = /datum/ai_behavior/travel_towards + +/datum/pet_command/move/set_command_target(mob/living/parent, atom/target) + if(isnull(target) || !can_see(parent, target, 9)) + return FALSE return ..() -/datum/pet_command/point_targeting/fish/execute_action(datum/ai_controller/controller) - controller.queue_behavior(/datum/ai_behavior/hunt_target/interact_with_target/reset_target_combat_mode_off, BB_CURRENT_PET_TARGET) +/datum/pet_command/move/execute_action(datum/ai_controller/controller) + if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) + controller.queue_behavior(walk_behavior, BB_CURRENT_PET_TARGET) return SUBTREE_RETURN_FINISH_PLANNING + +/datum/pet_command/move/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to move!" diff --git a/code/datums/elements/pet_cult.dm b/code/datums/elements/pet_cult.dm index 36941e7b742..f26e6e343e6 100644 --- a/code/datums/elements/pet_cult.dm +++ b/code/datums/elements/pet_cult.dm @@ -90,7 +90,8 @@ source.ai_controller.set_blackboard_key(BB_CULT_TEAM, team) var/static/list/new_pet_commands = list( - /datum/pet_command/point_targeting/attack, + /datum/pet_command/move, + /datum/pet_command/attack, /datum/pet_command/follow, /datum/pet_command/free, /datum/pet_command/idle, diff --git a/code/datums/keybinding/_keybindings.dm b/code/datums/keybinding/_keybindings.dm index dfcf492c180..a989d0d22a8 100644 --- a/code/datums/keybinding/_keybindings.dm +++ b/code/datums/keybinding/_keybindings.dm @@ -21,6 +21,8 @@ return SEND_SIGNAL(user.mob, keybind_signal) & COMSIG_KB_ACTIVATED /datum/keybinding/proc/up(client/user) + SHOULD_CALL_PARENT(TRUE) + SEND_SIGNAL(user.mob, DEACTIVATE_KEYBIND(keybind_signal)) return FALSE /datum/keybinding/proc/can_use(client/user) diff --git a/code/datums/keybinding/living.dm b/code/datums/keybinding/living.dm index 7e50e6928f9..61716ee6fe9 100644 --- a/code/datums/keybinding/living.dm +++ b/code/datums/keybinding/living.dm @@ -46,6 +46,7 @@ return TRUE /datum/keybinding/living/look_up/up(client/user) + . = ..() var/mob/living/L = user.mob L.end_look_up() return TRUE @@ -66,6 +67,7 @@ return TRUE /datum/keybinding/living/look_down/up(client/user) + . = ..() var/mob/living/L = user.mob L.end_look_down() return TRUE @@ -144,6 +146,7 @@ return TRUE /datum/keybinding/living/toggle_move_intent/up(client/user) + . = ..() var/mob/living/M = user.mob M.toggle_move_intent() return TRUE diff --git a/code/datums/keybinding/mob.dm b/code/datums/keybinding/mob.dm index 4963e87266c..a1bd06742b5 100644 --- a/code/datums/keybinding/mob.dm +++ b/code/datums/keybinding/mob.dm @@ -191,3 +191,10 @@ if(.) return user.movement_locked = FALSE + +/datum/keybinding/living/view_pet_data + hotkey_keys = list("Shift") + name = "view_pet_commands" + full_name = "View Pet Commands" + description = "Hold down to see all the commands you can give your pets!" + keybind_signal = COMSIG_KB_LIVING_VIEW_PET_COMMANDS diff --git a/code/game/atom/_atom.dm b/code/game/atom/_atom.dm index 9afda5b0dde..c8c3111889e 100644 --- a/code/game/atom/_atom.dm +++ b/code/game/atom/_atom.dm @@ -864,6 +864,8 @@ if (isnull(user)) return + SEND_SIGNAL(user, COMSIG_ATOM_MOUSE_ENTERED, src) + // Screentips var/datum/hud/active_hud = user.hud_used if(!active_hud) diff --git a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm index d545e258a30..d3e1765a0b9 100644 --- a/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm +++ b/code/modules/antagonists/heretic/knowledge/cosmic_lore.dm @@ -226,7 +226,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/star_gazer + /datum/pet_command/attack/star_gazer ) /datum/heretic_knowledge/ultimate/cosmic_final/is_valid_sacrifice(mob/living/carbon/human/sacrifice) @@ -242,7 +242,7 @@ star_gazer_mob.maxHealth = INFINITY star_gazer_mob.health = INFINITY user.AddComponent(/datum/component/death_linked, star_gazer_mob) - star_gazer_mob.AddComponent(/datum/component/obeys_commands, star_gazer_commands) + star_gazer_mob.AddComponent(/datum/component/obeys_commands, star_gazer_commands, radial_menu_lifetime = 15 SECONDS, radial_relative_to_user = TRUE) star_gazer_mob.AddComponent(/datum/component/damage_aura, range = 7, burn_damage = 0.5, simple_damage = 0.5, immune_factions = list(FACTION_HERETIC), current_owner = user) star_gazer_mob.befriend(user) var/datum/action/cooldown/open_mob_commands/commands_action = new /datum/action/cooldown/open_mob_commands() diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm index 68cd6a231e3..14de9f04068 100644 --- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm +++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot.dm @@ -127,7 +127,7 @@ var/static/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, - /datum/pet_command/point_targeting/clean, + /datum/pet_command/clean, ) /mob/living/basic/bot/cleanbot/Initialize(mapload) diff --git a/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm b/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm index 1b6d8400622..0a6a4b03b43 100644 --- a/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm +++ b/code/modules/mob/living/basic/bots/cleanbot/cleanbot_ai.dm @@ -200,14 +200,15 @@ return return ..() -/datum/pet_command/point_targeting/clean +/datum/pet_command/clean command_name = "Clean" command_desc = "Command a cleanbot to clean the mess." + requires_pointing = TRUE radial_icon = 'icons/obj/service/janitor.dmi' radial_icon_state = "mop" speech_commands = list("clean", "mop") -/datum/pet_command/point_targeting/clean/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/clean/set_command_target(mob/living/parent, atom/target) if(isnull(target) || !istype(target, /obj/effect/decal/cleanable)) return if(isnull(parent.ai_controller)) @@ -216,7 +217,7 @@ return return ..() -/datum/pet_command/point_targeting/clean/execute_action(datum/ai_controller/basic_controller/bot/controller) +/datum/pet_command/clean/execute_action(datum/ai_controller/basic_controller/bot/controller) if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) controller.queue_behavior(/datum/ai_behavior/execute_clean, BB_CURRENT_PET_TARGET) return SUBTREE_RETURN_FINISH_PLANNING diff --git a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm index e9dd79fd5ef..09bf3a58195 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/_bee.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/_bee.dm @@ -57,7 +57,7 @@ /datum/pet_command/beehive/enter, /datum/pet_command/beehive/exit, /datum/pet_command/follow/bee, - /datum/pet_command/point_targeting/attack/swirl, + /datum/pet_command/attack/swirl, /datum/pet_command/scatter, ) diff --git a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm index 1081c9b7b63..84720986624 100644 --- a/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm +++ b/code/modules/mob/living/basic/farm_animals/bee/bee_ai_behavior.dm @@ -113,8 +113,9 @@ required_distance = 0 ///swirl around the owner in menacing fashion -/datum/pet_command/point_targeting/attack/swirl +/datum/pet_command/attack/swirl command_name = "Swirl" + requires_pointing = TRUE command_desc = "Your pets will swirl around you and attack whoever you point at!" speech_commands = list("swirl", "spiral", "swarm") pointed_reaction = null @@ -123,7 +124,7 @@ ///the owner we will swarm around var/key_to_swarm = BB_SWARM_TARGET -/datum/pet_command/point_targeting/attack/swirl/try_activate_command(mob/living/commander) +/datum/pet_command/attack/swirl/try_activate_command(mob/living/commander, radial_command) var/mob/living/living_pawn = weak_parent.resolve() if(isnull(living_pawn)) return @@ -134,7 +135,7 @@ controller.set_blackboard_key(key_to_swarm, commander) return ..() -/datum/pet_command/point_targeting/attack/swirl/execute_action(datum/ai_controller/controller) +/datum/pet_command/attack/swirl/execute_action(datum/ai_controller/controller) if(controller.blackboard_key_exists(BB_CURRENT_PET_TARGET)) return ..() controller.queue_behavior(/datum/ai_behavior/swirl_around_target, BB_SWARM_TARGET) @@ -186,7 +187,7 @@ radial_icon = 'icons/obj/service/hydroponics/equipment.dmi' radial_icon_state = "beebox" -/datum/pet_command/beehive/try_activate_command(mob/living/commander) +/datum/pet_command/beehive/try_activate_command(mob/living/commander, radial_command) var/mob/living/living_pawn = weak_parent.resolve() if(isnull(living_pawn)) return diff --git a/code/modules/mob/living/basic/heretic/star_gazer.dm b/code/modules/mob/living/basic/heretic/star_gazer.dm index 57a0ddfe322..7ffd7bc657e 100644 --- a/code/modules/mob/living/basic/heretic/star_gazer.dm +++ b/code/modules/mob/living/basic/heretic/star_gazer.dm @@ -103,7 +103,7 @@ can_attack_turfs = TRUE can_attack_dense_objects = TRUE -/datum/pet_command/point_targeting/attack/star_gazer +/datum/pet_command/attack/star_gazer speech_commands = list("attack", "sic", "kill", "slash them") command_feedback = "stares!" pointed_reaction = "stares intensely!" diff --git a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm index b82092147f6..6056b191909 100644 --- a/code/modules/mob/living/basic/icemoon/wolf/wolf.dm +++ b/code/modules/mob/living/basic/icemoon/wolf/wolf.dm @@ -43,11 +43,12 @@ //commands to give when tamed var/static/list/pet_commands = list( /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, /datum/pet_command/good_boy/wolf, /datum/pet_command/follow/wolf, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/attack, + /datum/pet_command/fetch, /datum/pet_command/play_dead, /datum/pet_command/protect_owner, ) diff --git a/code/modules/mob/living/basic/jungle/leaper/leaper.dm b/code/modules/mob/living/basic/jungle/leaper/leaper.dm index 94babd0218e..d4f310d07ab 100644 --- a/code/modules/mob/living/basic/jungle/leaper/leaper.dm +++ b/code/modules/mob/living/basic/jungle/leaper/leaper.dm @@ -40,13 +40,14 @@ ///list of pet commands we can issue var/list/pet_commands = list( /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, /datum/pet_command/follow, /datum/pet_command/untargeted_ability/blood_rain, /datum/pet_command/untargeted_ability/summon_toad, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/use_ability/flop, - /datum/pet_command/point_targeting/use_ability/bubble, + /datum/pet_command/attack, + /datum/pet_command/use_ability/flop, + /datum/pet_command/use_ability/bubble, ) /mob/living/basic/leaper/Initialize(mapload) diff --git a/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm b/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm index e776117a3a5..b5c917bf2a4 100644 --- a/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm +++ b/code/modules/mob/living/basic/jungle/leaper/leaper_ai.dm @@ -39,7 +39,7 @@ ability_key = BB_LEAPER_SUMMON finish_planning = FALSE -/datum/pet_command/point_targeting/use_ability/flop +/datum/pet_command/use_ability/flop command_name = "Flop" command_desc = "Command your pet to belly flop your target!" radial_icon = 'icons/mob/actions/actions_items.dmi' @@ -47,7 +47,7 @@ speech_commands = list("flop", "crush") pet_ability_key = BB_LEAPER_FLOP -/datum/pet_command/point_targeting/use_ability/bubble +/datum/pet_command/use_ability/bubble command_name = "Poison Bubble" command_desc = "Launch poisonous bubbles at your target!" radial_icon = 'icons/obj/weapons/guns/projectiles.dmi' @@ -55,6 +55,9 @@ speech_commands = list("bubble", "shoot") pet_ability_key = BB_LEAPER_BUBBLE +/datum/pet_command/use_ability/bubble/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to shoot a bubble towards [target]!" + /datum/pet_command/untargeted_ability/blood_rain command_name = "Blood Rain" command_desc = "Let it rain poisonous blood!" @@ -63,6 +66,8 @@ speech_commands = list("blood", "rain", "volley") ability_key = BB_LEAPER_VOLLEY +/datum/pet_command/untargeted_ability/blood_rain/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to unleash a volley of rain!" /datum/pet_command/untargeted_ability/summon_toad command_name = "Summon Toads" @@ -71,3 +76,6 @@ radial_icon_state = "frog_trash" speech_commands = list("frogs", "bombers") ability_key = BB_LEAPER_SUMMON + +/datum/pet_command/untargeted_ability/summon_toad/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to summon some explosive frogs!" diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling.dm b/code/modules/mob/living/basic/jungle/seedling/seedling.dm index 0df19c5c27d..9778aff8753 100644 --- a/code/modules/mob/living/basic/jungle/seedling/seedling.dm +++ b/code/modules/mob/living/basic/jungle/seedling/seedling.dm @@ -214,9 +214,9 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/use_ability/solarbeam, - /datum/pet_command/point_targeting/use_ability/rapidseeds, + /datum/pet_command/attack, + /datum/pet_command/use_ability/solarbeam, + /datum/pet_command/use_ability/rapidseeds, ) //abilities diff --git a/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm b/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm index ee93a9c1236..ae4e7b75c92 100644 --- a/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm +++ b/code/modules/mob/living/basic/jungle/seedling/seedling_ai.dm @@ -166,7 +166,7 @@ finish_planning = FALSE ///pet commands -/datum/pet_command/point_targeting/use_ability/solarbeam +/datum/pet_command/use_ability/solarbeam command_name = "Launch solarbeam" command_desc = "Command your pet to launch a solarbeam at your target!" radial_icon = 'icons/effects/beam.dmi' @@ -174,10 +174,17 @@ speech_commands = list("beam", "solar") pet_ability_key = BB_SOLARBEAM_ABILITY -/datum/pet_command/point_targeting/use_ability/rapidseeds +/datum/pet_command/use_ability/solarbeam/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to use a solar beam on [target]!" + + +/datum/pet_command/use_ability/rapidseeds command_name = "Rapid seeds" command_desc = "Command your pet to launch a volley of seeds at your target!" radial_icon = 'icons/obj/weapons/guns/projectiles.dmi' radial_icon_state = "seedling" speech_commands = list("rapid", "seeds", "volley") pet_ability_key = BB_RAPIDSEEDS_ABILITY + +/datum/pet_command/use_ability/rapidseeds/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to unleash a volley of seeds on [target]!" diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm index 5a1166962be..ce1c4e7cf19 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub.dm @@ -36,7 +36,7 @@ /datum/pet_command/free, /datum/pet_command/grub_spit, /datum/pet_command/follow, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/fetch, ) /mob/living/basic/mining/goldgrub/Initialize(mapload) diff --git a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm index 8ea2467a2a8..3d5d73a7343 100644 --- a/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm +++ b/code/modules/mob/living/basic/lavaland/goldgrub/goldgrub_ai.dm @@ -211,6 +211,8 @@ /datum/pet_command/grub_spit command_name = "Spit" + radial_icon = 'icons/obj/ore.dmi' + radial_icon_state = "uranium" command_desc = "Ask your grub pet to spit out its ores." speech_commands = list("spit", "ores") @@ -222,4 +224,7 @@ controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return SUBTREE_RETURN_FINISH_PLANNING +/datum/pet_command/grub_spit/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to spit its ores!" + #undef BURROW_RANGE diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm index 5bfbbb1051a..347e9a95b61 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers.dm @@ -61,7 +61,7 @@ if(isnull(ore_food)) balloon_alert(src, "no food!") else - melee_attack(ore_food) + UnarmedAttack(ore_food, TRUE, modifiers) return FALSE /mob/living/basic/mining/gutlunch/proc/after_birth(mob/living/basic/mining/gutlunch/grub/baby, mob/living/partner) @@ -111,11 +111,12 @@ //pet commands when we tame the gutluncher var/static/list/pet_commands = list( /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/breed/gutlunch, + /datum/pet_command/attack, + /datum/pet_command/breed/gutlunch, /datum/pet_command/follow, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/fetch, /datum/pet_command/mine_walls, ) diff --git a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm index 261f6d22a02..4b329a0003a 100644 --- a/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm +++ b/code/modules/mob/living/basic/lavaland/gutlunchers/gutlunchers_ai.dm @@ -102,10 +102,11 @@ /datum/pet_command/mine_walls command_name = "Mine" + radial_icon_state = "mine" command_desc = "Command your pet to mine down walls." speech_commands = list("mine", "smash") -/datum/pet_command/mine_walls/try_activate_command(mob/living/commander) +/datum/pet_command/mine_walls/try_activate_command(mob/living/commander, radial_command) var/mob/living/parent = weak_parent.resolve() if(isnull(parent)) return @@ -121,10 +122,13 @@ return SUBTREE_RETURN_FINISH_PLANNING controller.queue_behavior(/datum/ai_behavior/find_mineral_wall, BB_CURRENT_PET_TARGET) -//pet commands -/datum/pet_command/point_targeting/breed/gutlunch +/datum/pet_command/mine_walls/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to start mining!" -/datum/pet_command/point_targeting/breed/gutlunch/set_command_target(mob/living/parent, atom/target) +//pet commands +/datum/pet_command/breed/gutlunch + +/datum/pet_command/breed/gutlunch/set_command_target(mob/living/parent, atom/target) if(GLOB.gutlunch_count >= MAXIMUM_GUTLUNCH_POP) parent.balloon_alert_to_viewers("can't reproduce anymore!") return diff --git a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm index 0b8babf82ec..7e7d3e71819 100644 --- a/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm +++ b/code/modules/mob/living/basic/lavaland/lobstrosity/lobstrosity.dm @@ -32,7 +32,7 @@ /// The type of charging ability we give this mob var/charge_type = /datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster /// The pet command for the charging ability we give this mob - var/charge_command = /datum/pet_command/point_targeting/use_ability/lob_charge + var/charge_command = /datum/pet_command/use_ability/lob_charge /// At which speed do we amputate limbs var/snip_speed = 5 SECONDS ///Lobstrosities are natural anglers. This rapresent their proficiency at fishing when not mindless @@ -72,10 +72,11 @@ var/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, - /datum/pet_command/point_targeting/attack, + /datum/pet_command/move, + /datum/pet_command/attack, charge_command, /datum/pet_command/follow, - /datum/pet_command/point_targeting/fish, + /datum/pet_command/fish, ) AddComponent(/datum/component/happiness) AddComponent(/datum/component/obeys_commands, pet_commands) @@ -153,7 +154,7 @@ ai_controller = /datum/ai_controller/basic_controller/lobstrosity/juvenile snip_speed = 6.5 SECONDS charge_type = /datum/action/cooldown/mob_cooldown/charge/basic_charge/lobster/shrimp - charge_command = /datum/pet_command/point_targeting/use_ability/lob_charge/shrimp + charge_command = /datum/pet_command/use_ability/lob_charge/shrimp base_fishing_level = SKILL_LEVEL_NOVICE /// What do we become when we grow up? var/mob/living/basic/mining/lobstrosity/grow_type = /mob/living/basic/mining/lobstrosity @@ -254,7 +255,7 @@ charger.apply_status_effect(/datum/status_effect/tired_post_charge/lesser) ///Command the lobster to charge at someone. -/datum/pet_command/point_targeting/use_ability/lob_charge +/datum/pet_command/use_ability/lob_charge command_name = "Charge" command_desc = "Command your lobstrosity to charge against someone." radial_icon = 'icons/mob/actions/actions_items.dmi' @@ -265,7 +266,7 @@ pet_ability_key = BB_TARGETED_ACTION ability_behavior = /datum/ai_behavior/pet_use_ability/then_attack/long_ranged -/datum/pet_command/point_targeting/use_ability/lob_charge/set_command_target(mob/living/parent, atom/target) +/datum/pet_command/use_ability/lob_charge/set_command_target(mob/living/parent, atom/target) if (!target) return var/datum/targeting_strategy/targeter = GET_TARGETING_STRATEGY(parent.ai_controller.blackboard[targeting_strategy_key]) @@ -274,5 +275,5 @@ return FALSE return ..() -/datum/pet_command/point_targeting/use_ability/lob_charge/shrimp +/datum/pet_command/use_ability/lob_charge/shrimp ability_behavior = /datum/ai_behavior/pet_use_ability/then_attack/short_ranged diff --git a/code/modules/mob/living/basic/lavaland/mook/mook.dm b/code/modules/mob/living/basic/lavaland/mook/mook.dm index f492c83e74b..539aa47cb28 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook.dm @@ -41,8 +41,8 @@ var/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/attack, + /datum/pet_command/fetch, ) /mob/living/basic/mining/mook/Initialize(mapload) diff --git a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm index 15da812a0b2..2f374e2dda4 100644 --- a/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm +++ b/code/modules/mob/living/basic/lavaland/mook/mook_ai.dm @@ -1,7 +1,7 @@ ///commands the chief can pick from GLOBAL_LIST_INIT(mook_commands, list( - new /datum/pet_command/point_targeting/attack, - new /datum/pet_command/point_targeting/fetch, + new /datum/pet_command/attack, + new /datum/pet_command/fetch, )) /datum/ai_controller/basic_controller/mook @@ -346,7 +346,7 @@ GLOBAL_LIST_INIT(mook_commands, list( if(!locate(/mob/living/basic/mining/mook) in oview(command_distance, controller.pawn)) return if(controller.blackboard_key_exists(BB_BASIC_MOB_CURRENT_TARGET)) - controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_BASIC_MOB_CURRENT_TARGET, /datum/pet_command/point_targeting/attack) + controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_BASIC_MOB_CURRENT_TARGET, /datum/pet_command/attack) return var/atom/ore_target = controller.blackboard[BB_ORE_TARGET] @@ -356,7 +356,7 @@ GLOBAL_LIST_INIT(mook_commands, list( if(get_dist(ore_target, living_pawn) <= 1) return - controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_ORE_TARGET, /datum/pet_command/point_targeting/fetch) + controller.queue_behavior(/datum/ai_behavior/issue_commands, BB_ORE_TARGET, /datum/pet_command/fetch) /datum/ai_behavior/issue_commands action_cooldown = 5 SECONDS diff --git a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm index 8bf54b7165b..3909a392195 100644 --- a/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm +++ b/code/modules/mob/living/basic/lavaland/raptor/_raptor.dm @@ -47,11 +47,13 @@ GLOBAL_LIST_EMPTY(raptor_population) var/ridable_component = /datum/component/riding/creature/raptor //pet commands when we tame the raptor var/static/list/pet_commands = list( + /datum/pet_command/breed, /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, - /datum/pet_command/point_targeting/attack, + /datum/pet_command/attack, /datum/pet_command/follow, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/fetch, ) ///things we inherited from our parent var/datum/raptor_inheritance/inherited_stats @@ -158,7 +160,7 @@ GLOBAL_LIST_EMPTY(raptor_population) if(isnull(ore_food)) balloon_alert(src, "no food!") else - melee_attack(ore_food) + UnarmedAttack(ore_food, TRUE, modifiers) return FALSE /mob/living/basic/raptor/melee_attack(mob/living/target, list/modifiers, ignore_cooldown) diff --git a/code/modules/mob/living/basic/minebots/minebot.dm b/code/modules/mob/living/basic/minebots/minebot.dm index c9edfb0471f..b14d1469ccd 100644 --- a/code/modules/mob/living/basic/minebots/minebot.dm +++ b/code/modules/mob/living/basic/minebots/minebot.dm @@ -42,13 +42,14 @@ ///the commands our owner can give us var/static/list/pet_commands = list( /datum/pet_command/idle/minebot, + /datum/pet_command/move, /datum/pet_command/protect_owner/minebot, /datum/pet_command/minebot_ability/light, /datum/pet_command/minebot_ability/dump, /datum/pet_command/automate_mining, /datum/pet_command/free/minebot, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/minebot, + /datum/pet_command/attack/minebot, ) ///possible colors the bot can have var/static/list/possible_colors= list( diff --git a/code/modules/mob/living/basic/minebots/minebot_ai.dm b/code/modules/mob/living/basic/minebots/minebot_ai.dm index 8043fda65d0..51a4e43f66a 100644 --- a/code/modules/mob/living/basic/minebots/minebot_ai.dm +++ b/code/modules/mob/living/basic/minebots/minebot_ai.dm @@ -281,14 +281,16 @@ /datum/pet_command/automate_mining command_name = "Automate mining" command_desc = "Make your minebot automatically mine!" - radial_icon = 'icons/obj/mining.dmi' - radial_icon_state = "pickaxe" + radial_icon_state = "mine" speech_commands = list("mine") callout_type = /datum/callout_option/mine /datum/pet_command/automate_mining/valid_callout_target(mob/living/caller, datum/callout_option/callout, atom/target) return ismineralturf(target) +/datum/pet_command/automate_mining/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to start mining!" + /datum/pet_command/automate_mining/execute_action(datum/ai_controller/controller) controller.set_blackboard_key(BB_AUTOMATED_MINING, TRUE) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) @@ -315,6 +317,9 @@ radial_icon_state = "mech_lights_off" ability_key = BB_MINEBOT_LIGHT_ABILITY +/datum/pet_command/minebot_ability/light/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to toggle its lights!" + /datum/pet_command/minebot_ability/dump command_name = "Dump ore" command_desc = "Make your minebot dump all its ore!" @@ -322,10 +327,13 @@ radial_icon_state = "mech_eject" ability_key = BB_MINEBOT_DUMP_ABILITY -/datum/pet_command/point_targeting/attack/minebot +/datum/pet_command/minebot_ability/light/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to dump its ore!" + +/datum/pet_command/attack/minebot attack_behaviour = /datum/ai_behavior/basic_ranged_attack/minebot -/datum/pet_command/point_targeting/attack/minebot/execute_action(datum/ai_controller/controller) +/datum/pet_command/attack/minebot/execute_action(datum/ai_controller/controller) controller.set_blackboard_key(BB_AUTOMATED_MINING, FALSE) var/mob/living/living_pawn = controller.pawn if(!living_pawn.combat_mode) diff --git a/code/modules/mob/living/basic/pets/dog/_dog.dm b/code/modules/mob/living/basic/pets/dog/_dog.dm index fd8920d2ca0..8fb053eef09 100644 --- a/code/modules/mob/living/basic/pets/dog/_dog.dm +++ b/code/modules/mob/living/basic/pets/dog/_dog.dm @@ -7,10 +7,10 @@ speech_commands = list("good dog") // Set correct attack behaviour -/datum/pet_command/point_targeting/attack/dog +/datum/pet_command/attack/dog attack_behaviour = /datum/ai_behavior/basic_melee_attack/dog -/datum/pet_command/point_targeting/attack/dog/set_command_active(mob/living/parent, mob/living/commander) +/datum/pet_command/attack/dog/set_command_active(mob/living/parent, mob/living/commander) . = ..() parent.ai_controller.set_blackboard_key(BB_DOG_HARASS_HARM, TRUE) @@ -38,11 +38,12 @@ var/static/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, + /datum/pet_command/move, /datum/pet_command/good_boy/dog, /datum/pet_command/follow/dog, /datum/pet_command/perform_trick_sequence, - /datum/pet_command/point_targeting/attack/dog, - /datum/pet_command/point_targeting/fetch, + /datum/pet_command/attack/dog, + /datum/pet_command/fetch, /datum/pet_command/play_dead, ) ///icon state of the collar we can wear diff --git a/code/modules/mob/living/basic/pets/fox.dm b/code/modules/mob/living/basic/pets/fox.dm index 737f7b21391..fab5e79a313 100644 --- a/code/modules/mob/living/basic/pets/fox.dm +++ b/code/modules/mob/living/basic/pets/fox.dm @@ -31,9 +31,10 @@ ///list of our pet commands we follow var/static/list/pet_commands = list( /datum/pet_command/idle, + /datum/pet_command/move, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack, + /datum/pet_command/attack, /datum/pet_command/perform_trick_sequence, ) diff --git a/code/modules/mob/living/basic/pets/orbie/orbie.dm b/code/modules/mob/living/basic/pets/orbie/orbie.dm index b4099a8c634..202bc84d37e 100644 --- a/code/modules/mob/living/basic/pets/orbie/orbie.dm +++ b/code/modules/mob/living/basic/pets/orbie/orbie.dm @@ -39,8 +39,9 @@ var/static/list/pet_commands = list( /datum/pet_command/idle, /datum/pet_command/free, + /datum/pet_command/move, /datum/pet_command/untargeted_ability/pet_lights, - /datum/pet_command/point_targeting/use_ability/take_photo, + /datum/pet_command/use_ability/take_photo, /datum/pet_command/follow/orbie, /datum/pet_command/perform_trick_sequence, ) diff --git a/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm b/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm index a978b750d50..aef78053379 100644 --- a/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm +++ b/code/modules/mob/living/basic/pets/orbie/orbie_ai.dm @@ -123,17 +123,24 @@ return SUBTREE_RETURN_FINISH_PLANNING return ..() -/datum/pet_command/point_targeting/use_ability/take_photo +/datum/pet_command/use_ability/pet_lights/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to toggle its lights!" + +/datum/pet_command/use_ability/take_photo command_name = "Photo" command_desc = "Make your pet take a photo!" - radial_icon = 'icons/mob/simple/pets.dmi' - radial_icon_state = "orbie_lights_action" + radial_icon = 'icons/obj/art/camera.dmi' + radial_icon_state = "camera" speech_commands = list("photo", "picture", "image") command_feedback = "Readys camera mode" pet_ability_key = BB_PHOTO_ABILITY targeting_strategy_key = BB_TARGETING_STRATEGY -/datum/pet_command/point_targeting/use_ability/take_photo/execute_action(datum/ai_controller/controller) +/datum/pet_command/use_ability/take_photo/retrieve_command_text(atom/living_pet, atom/target) + return isnull(target) ? null : "signals [living_pet] to take a photo of [target]!" + + +/datum/pet_command/use_ability/take_photo/execute_action(datum/ai_controller/controller) if(controller.blackboard[BB_VIRTUAL_PET_LEVEL] < 3) controller.clear_blackboard_key(BB_ACTIVE_PET_COMMAND) return SUBTREE_RETURN_FINISH_PLANNING @@ -152,6 +159,9 @@ return FALSE return findtext(spoken_text, text_command) +/datum/pet_command/perform_trick_sequence/light/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to dance!" + /datum/pet_command/perform_trick_sequence/execute_action(datum/ai_controller/controller) var/mob/living/living_pawn = controller.pawn var/list/trick_sequence = controller.blackboard[BB_TRICK_SEQUENCE] diff --git a/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm index 77263b17489..41b928aa751 100644 --- a/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm +++ b/code/modules/mob/living/basic/pets/pet_cult/pet_cult_ai.dm @@ -236,3 +236,6 @@ radial_icon_state = "1" speech_commands = list("rune", "revival") ability_key = BB_RUNE_ABILITY + +/datum/pet_command/untargeted_ability/draw_rune/retrieve_command_text(atom/living_pet, atom/target) + return "signals [living_pet] to draw a rune!" diff --git a/code/modules/mob/living/basic/slime/ai/pet_command.dm b/code/modules/mob/living/basic/slime/ai/pet_command.dm index 211d7aa552c..4b50b2b32b9 100644 --- a/code/modules/mob/living/basic/slime/ai/pet_command.dm +++ b/code/modules/mob/living/basic/slime/ai/pet_command.dm @@ -1,4 +1,4 @@ -/datum/pet_command/point_targeting/attack/slime +/datum/pet_command/attack/slime speech_commands = list("attack", "sic", "kill", "eat", "feed") command_feedback = "blorbles" pointed_reaction = "and blorbles" @@ -6,7 +6,7 @@ var/hunting_behavior = /datum/ai_behavior/hunt_target/interact_with_target/slime -/datum/pet_command/point_targeting/attack/slime/execute_action(datum/ai_controller/controller) +/datum/pet_command/attack/slime/execute_action(datum/ai_controller/controller) var/mob/living/basic/slime/slime_pawn = controller.pawn if(isslime(slime_pawn) && slime_pawn.can_feed_on(controller.blackboard[BB_CURRENT_PET_TARGET], check_friendship = TRUE)) diff --git a/code/modules/mob/living/basic/slime/slime.dm b/code/modules/mob/living/basic/slime/slime.dm index 010913f4425..8623f69b0e4 100644 --- a/code/modules/mob/living/basic/slime/slime.dm +++ b/code/modules/mob/living/basic/slime/slime.dm @@ -97,7 +97,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/slime, + /datum/pet_command/attack/slime, ) /// Our evolve action diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp.dm b/code/modules/mob/living/basic/space_fauna/carp/carp.dm index 6f843857578..0e0ba3b39a1 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp.dm @@ -59,7 +59,7 @@ /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack + /datum/pet_command/attack ) /// Carp want to eat raw meat var/static/list/desired_food = list(/obj/item/food/meat/slab, /obj/item/food/meat/rawcutlet) diff --git a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm index 810c4560386..26894850b19 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/carp_ai_actions.dm @@ -1,6 +1,6 @@ #define MAGICARP_SPELL_TARGET_SEEK_RANGE 4 -/datum/pet_command/point_targeting/use_ability/magicarp +/datum/pet_command/use_ability/magicarp pet_ability_key = BB_MAGICARP_SPELL /datum/ai_planning_subtree/attack_obstacle_in_path/carp diff --git a/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm b/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm index 65d16cfb490..3b6d1e5e922 100644 --- a/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm +++ b/code/modules/mob/living/basic/space_fauna/carp/magicarp.dm @@ -56,8 +56,8 @@ GLOBAL_LIST_INIT(magicarp_spell_colours, list( /datum/pet_command/idle, /datum/pet_command/free, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack, - /datum/pet_command/point_targeting/use_ability/magicarp, + /datum/pet_command/attack, + /datum/pet_command/use_ability/magicarp, ) /// List of all projectiles we can fire. /// Non-static, because subtypes can have their own lists. diff --git a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm index f7997e58969..74f6c76b459 100644 --- a/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm +++ b/code/modules/mob/living/basic/space_fauna/regal_rat/regal_rat_actions.dm @@ -65,7 +65,7 @@ /datum/pet_command/free, /datum/pet_command/protect_owner, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/mouse + /datum/pet_command/attack/mouse ) /// Commands you can give to glockroaches var/static/list/glockroach_commands = list( @@ -73,7 +73,7 @@ /datum/pet_command/free, /datum/pet_command/protect_owner/glockroach, /datum/pet_command/follow, - /datum/pet_command/point_targeting/attack/glockroach + /datum/pet_command/attack/glockroach ) /datum/action/cooldown/mob_cooldown/riot/IsAvailable(feedback = FALSE) @@ -211,7 +211,7 @@ return TRUE // Command you can give to a mouse to make it kill someone -/datum/pet_command/point_targeting/attack/mouse +/datum/pet_command/attack/mouse speech_commands = list("attack", "sic", "kill", "cheese em") command_feedback = "squeak!" // Frogs and roaches can squeak too it's fine pointed_reaction = "and squeaks aggressively" @@ -219,7 +219,7 @@ attack_behaviour = /datum/ai_behavior/basic_melee_attack // Command you can give to a mouse to make it kill someone -/datum/pet_command/point_targeting/attack/glockroach +/datum/pet_command/attack/glockroach speech_commands = list("attack", "sic", "kill", "cheese em") command_feedback = "squeak!" pointed_reaction = "and cocks its gun" diff --git a/icons/effects/mouse_pointers/pet_paw.dmi b/icons/effects/mouse_pointers/pet_paw.dmi new file mode 100644 index 00000000000..a4443a68967 Binary files /dev/null and b/icons/effects/mouse_pointers/pet_paw.dmi differ diff --git a/icons/hud/radial_pets.dmi b/icons/hud/radial_pets.dmi new file mode 100644 index 00000000000..a9ce7a1d006 Binary files /dev/null and b/icons/hud/radial_pets.dmi differ diff --git a/tgstation.dme b/tgstation.dme index 345b15060c4..bec1ca1f5a4 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -187,6 +187,7 @@ #include "code\__DEFINES\pronouns.dm" #include "code\__DEFINES\qdel.dm" #include "code\__DEFINES\quirks.dm" +#include "code\__DEFINES\radial_defines.dm" #include "code\__DEFINES\radiation.dm" #include "code\__DEFINES\radio.dm" #include "code\__DEFINES\radioactive_nebula.dm"