From efe62c5a728a5135d5d92a058fbcb57ffffa90f3 Mon Sep 17 00:00:00 2001
From: Ben10Omintrix <138636438+Ben10Omintrix@users.noreply.github.com>
Date: Sun, 22 Dec 2024 04:05:30 +0200
Subject: [PATCH] Pet Commands QOL . makes pet commands easier to use (#88495)
## About The Pull Request
this PR improves the UX of pet commands a bit. i decided to expand on
their radial menu. You can now hold shift and hover over your pet to
display a menu of commands which you can choose from. alternatively, you
can still type out commands in chat
https://github.com/user-attachments/assets/9da7f7ea-58a3-4fd6-b040-45cc05cda51d
## Why It's Good For The Game
makes pet commands easier to give out when you're managing more than 1
pet. also fixes the fishing command not working.
## Changelog
:cl:
qol: holding shift and hovering over your pet will display a list of
commands you can click from
fix: fixes the fishing pet command not working
/:cl:
---
.../signals_atom/signals_atom_x_act.dm | 3 +
code/__DEFINES/keybinding.dm | 4 +
code/__DEFINES/radial_defines.dm | 6 +
code/_onclick/hud/radial.dm | 55 ++++---
code/_onclick/hud/radial_persistent.dm | 2 +-
code/datums/components/callouts.dm | 2 +-
code/datums/components/pet_commands/fetch.dm | 23 +--
.../components/pet_commands/obeys_commands.dm | 82 ++++++++---
.../components/pet_commands/pet_command.dm | 135 ++++++++++--------
.../pet_commands/pet_commands_basic.dm | 109 +++++++++-----
code/datums/elements/pet_cult.dm | 3 +-
code/datums/keybinding/_keybindings.dm | 2 +
code/datums/keybinding/living.dm | 3 +
code/datums/keybinding/mob.dm | 7 +
code/game/atom/_atom.dm | 2 +
.../heretic/knowledge/cosmic_lore.dm | 4 +-
.../living/basic/bots/cleanbot/cleanbot.dm | 2 +-
.../living/basic/bots/cleanbot/cleanbot_ai.dm | 7 +-
.../mob/living/basic/farm_animals/bee/_bee.dm | 2 +-
.../basic/farm_animals/bee/bee_ai_behavior.dm | 9 +-
.../mob/living/basic/heretic/star_gazer.dm | 2 +-
.../mob/living/basic/icemoon/wolf/wolf.dm | 5 +-
.../mob/living/basic/jungle/leaper/leaper.dm | 7 +-
.../living/basic/jungle/leaper/leaper_ai.dm | 12 +-
.../living/basic/jungle/seedling/seedling.dm | 6 +-
.../basic/jungle/seedling/seedling_ai.dm | 11 +-
.../basic/lavaland/goldgrub/goldgrub.dm | 2 +-
.../basic/lavaland/goldgrub/goldgrub_ai.dm | 5 +
.../basic/lavaland/gutlunchers/gutlunchers.dm | 9 +-
.../lavaland/gutlunchers/gutlunchers_ai.dm | 12 +-
.../basic/lavaland/lobstrosity/lobstrosity.dm | 15 +-
.../mob/living/basic/lavaland/mook/mook.dm | 4 +-
.../mob/living/basic/lavaland/mook/mook_ai.dm | 8 +-
.../living/basic/lavaland/raptor/_raptor.dm | 8 +-
.../mob/living/basic/minebots/minebot.dm | 3 +-
.../mob/living/basic/minebots/minebot_ai.dm | 16 ++-
.../modules/mob/living/basic/pets/dog/_dog.dm | 9 +-
code/modules/mob/living/basic/pets/fox.dm | 3 +-
.../mob/living/basic/pets/orbie/orbie.dm | 3 +-
.../mob/living/basic/pets/orbie/orbie_ai.dm | 18 ++-
.../living/basic/pets/pet_cult/pet_cult_ai.dm | 3 +
.../mob/living/basic/slime/ai/pet_command.dm | 4 +-
code/modules/mob/living/basic/slime/slime.dm | 2 +-
.../mob/living/basic/space_fauna/carp/carp.dm | 2 +-
.../basic/space_fauna/carp/carp_ai_actions.dm | 2 +-
.../living/basic/space_fauna/carp/magicarp.dm | 4 +-
.../regal_rat/regal_rat_actions.dm | 8 +-
icons/effects/mouse_pointers/pet_paw.dmi | Bin 0 -> 372 bytes
icons/hud/radial_pets.dmi | Bin 0 -> 3317 bytes
tgstation.dme | 1 +
50 files changed, 426 insertions(+), 220 deletions(-)
create mode 100644 code/__DEFINES/radial_defines.dm
create mode 100644 icons/effects/mouse_pointers/pet_paw.dmi
create mode 100644 icons/hud/radial_pets.dmi
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 0000000000000000000000000000000000000000..a4443a6896721c22686c526c79991c7388b32792
GIT binary patch
literal 372
zcmV-)0gL{LP)fFDZ*Bkp
zc$`yKaB_9`^iy#0_2eo`Eh^5;&r`5fFwryM;w;ZhDainG%uKjAGg33tGfE(w;*!LY
zR3K9+F(*ffi!&v&s2IpIU~_|-tp{lE0wOzr#0&V)`(I@--J?<19ty)B1A<@M-#WLla${g?>jwaM
zcsvGT1^_8~8B@#vcnnd;5CV7vTEiICU0tZh$52;!|>H<6fMZ(DjkED57z`>rX-^~{^a0)nWAUEA~z6UESe~~wQkQ)MU
S(jk-p0000&biL#oa;_Tncd`q3PS+^;4-|WZ_czh
z=5qc6!raFqBMq6RBob{CqK^%}8{`=f;_2@P0O9#*gM-j6Wgb>q@D`tO)ajGzmRl)H
z!=3S!gX65!8&3&6&3h<@^r|mJ*Ujr)gZ1=vs%-~K@$8^8t$o_N5z;FL%TLEdK)HwP
zWK&I?i}c(?@L5)hODqsLCQV3YYAdJXT&I8faB|RjvG(#SHv~TE@E!#UKK^~#?VJ!n
zkSbRvtFSfB_qDJ*vB|$^rScfqe;ipZ{dH^{0AMgf{cGs({B;Kh57AzJ-E?q=0Kw1R
z?=Jewjr|@jmHlg8qm%j-`X+J3}ln(dM4G*_4x6Rbh^#bnhkN@Bc=7T#A
zTB5901x}y-TapwWR3$Ir;_;2VTD^sTsU0|DIhP@aF#~1i?Arhe@K$
zq$H!>-(^!M1A1JdM07C-QEs`!m7}|Kohzm{1omvM4afqjI5`t4;ANC4E%{!@YB&gr
ztm0oe@>o%)gnY{T^gSbMkKyuGG(Fo)4G}Z!u4DC@&WFPgeKySM{9qYur?!JhV$8S8
z8~ZQj)am85H~$W)qy*z~oWuf}j-DMtDBp1blak;TK1tcB}W@(a?{pzdY1n%aZP9Vid5iegk^DL>SgxYes}
zNjX(f52&P-mVHNFVu()jcgEE_PwIXaU4N%d5i(788y2x9cip~ZliHn*}6APV8Z
z_9$nGUsS_qfrh&V5)Q-7G2?6uIY?1(vLd(-|Kvl;DoE(5aQvOmaO4$klnxQhOEfaC
ztAv(UB>3eSMi2#&*j+=IMB=9@kXLqLwzYXrs4!77=OIX+@V9{&MkDKmQlRu)*josS
za3?m!J6^qe8ksY#B!sq8Z9OV(FjKJ4mQKV5wN5Kr#}v15HQFXMs7}0S=Ps(h?E6z@
z!b+2!=Pc1;zWc%nEv-3Mu<0*6RPopRxAQ22*LA_T%FNKI;o-Q6H(4?uy3g@XrID5N
z0HxTC0|kKhwFm%E3ej`HK|3b=j3JWHG638(GgY+}?*A@V_=KhJD}Sq0VCbWSkZSFW
z33`<*pwR5^@_bYH8&3OjXEJr;{(*vzoZkb{1xHz4bvSPs^Dl
zYq3lrF*Nf9=o@VnkH9|MmoGH=Y7>!B?{vb{kjubHZx{dm-qo5*Go+Si8Myy!lMq>z
zxBQn?wjTn1JNFMIC8e>U57w1BkLFx+H@^3zFiYrh&%MYQ&b!xGUBa0P?4Np&`ZJ6x
zgd9BNA6GT4K`C8)4>>UHNgK9y5}(9X_*;5Pe{n7WCR=u32q?U_VB;~H$LoMv1LszG
zgOUa%ISO}d!&xg9gy>}a|AX5hMKTeJ%P~;fgd1J>{a^R!6#dU`f4!u7Z=Y1hrE3;c
zg8{GX*x&R#1-d2``9S3%+dVciKEMM#8vH9}Bqus;UQ`t_L7{r;6yB&zP{}5Px
zDM+_gDzkgHj%fHt*trVVaIYaGFZ5m*(miYt`bIV6URd|$$!9lEo(y5XW@9eLymK8v
zYq+;GdcG|*20YW+2};k;bFEP4Wm89R*vr!vAf3zBq%Jfc(4x`K?y=36F4nzcni`b9
z8Mu4XM%n+P!>Hby|gO_x*O7T}JcAb1U+m1K>}r^q8eF7Qh%
zGoYEl;cR_c?JP?o%;WS#@dW!=N#w36?)+pq6_e#{eoQ&m1tY5*xuB@+d5gmi8N$l`
zkb7LE*{jVCn;N&@Tb?biQd-j6BCVQt8ak~T4aaXha~I|VVt%?&f__URJ{##?e!8Xd
zP;OJNm@83UN>Tp$1ovNMGd~#TpY@cz!rirzx@+E4S%6sQ{Zcwq=>kNW8lS0tF05{v
zDid*fRnO9@F|sC(t32^_Wm=Go{NWkpUOK%ExV2#lxIjVqppO1~3
zp{FOznfj+?#84tuS{0U+T#d?}>3>QDiD600##03vHbNa_qtP8UQG|
zPuQ!}(?Ckz;l6sxq1HTG6DgfK91{Sf#l38DumjbC9WRJ3wLuWH@ASjr%PRfNe$z1E
z5<$}%A2{`6^n0=HBp|PdnLcb2-uUdw`q^cp8GMOgp>j=48T){kvk8`qGi*~+0a|Y^
z(40=zQY=-QklXsiSkE`R8#p#GtkZQU_{@+}^g~@KFJ=OsA!mfh$;B
z*EQU5!E_-AAt4`rJTbOOvyYJ8HgYPnhi1i!3GLg+`i>bAX3!iys@IB#rBxlz)!sIF
zA;IiiGbagMyo}IYZTD@GjbhL4P$$kVM>h-ptID{L1vlG>e0r|MnZ>6$UG00tFG1xv
z6|ls|EcZ!HLc&ZIeV~6&0jkR3?g$l
zR8@d30u$YH3E=2Ou79tPF3Fti0r%bFRyJ5rpa4eICd(FF2>h-#npH0AqtX3kloGpgee?rs!1Pur`3p(>
zo;7|&m^`|5$`OR&lcx6f2B*McIh702fA29Beu4@AkF@)ago~P+!>Wk2r3~2rsQka1
zz*!yk06NicQHfD|w7m_L1*3_3K+HTN<2_SrErK~8UWx3!rW#;6tNRDflt7U&bI^xP
zlM`H&FAIhmVtChZ@y!MCK`_=dmS9wou+~`>v<;C01EW{&{OkYiOwH5ImyE^D
zHCy`4NjQK}-mk1mwmJ?PSpxj*8NWI=_}o(HMxGDMsUVS0~P3^+nG=%O&$^mQ7T3#DNfP
z+C@h)Bmkfl%!>Y7L8R}O_2s}t*cI|aqPoMN@zxSx4Y1GKk+l94ViHOl#XlxqzM4^^
z@j_zoRUl)Pny|}#>Bz-ax^l
zugolrUwnpw@F+OBCQYT2H(5qZAw8VBW9&kVeDWCk88K@cJMg<-_E1dyN8R~Ca4w}^(K)XWyKje67`Vv?
v_5EQqZ`TyFbbJUzoT&7X1n~cvF2~#?v}Mw;rq93M8NkrMOut&sIsX3u{pv@W
literal 0
HcmV?d00001
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"