mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-08-28 15:47:15 +01:00
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 🆑 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 /🆑
This commit is contained in:
@@ -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"
|
||||
|
||||
@@ -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"
|
||||
|
||||
@@ -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)
|
||||
+36
-19
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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 += "<br>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]!"))
|
||||
|
||||
|
||||
|
||||
@@ -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!"
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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()
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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!"
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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!"
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]!"
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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(
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
|
||||
@@ -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,
|
||||
)
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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!"
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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"
|
||||
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 372 B |
Binary file not shown.
|
After Width: | Height: | Size: 3.2 KiB |
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user