mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2026-01-05 14:32:52 +00:00
## About The Pull Request Hovering over mobs on the same tile as the commanded mob will no longer close the command menu, and it will automatically get closed once the user lets go of the hotkey without having to forcefully time out. ## Why It's Good For The Game The same tile requirement prevents the menu from fading out if you're trying to command the mob you're riding, and not closing the menu when unregistering the hover signal actually prevented you from getting rid of the menu without waiting for the automatic timeout, which is super weird and unintuitive. ## Changelog 🆑 qol: Letting go of the pet command hotkey (Shift by default) will instantly close the menu fix: Hovering over things on the same tile no longer closes the pet command menu /🆑
144 lines
6.1 KiB
Plaintext
144 lines
6.1 KiB
Plaintext
/**
|
|
* # Obeys Commands Component
|
|
* 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(), list/radial_menu_offset = list(0, 0), radial_menu_lifetime = 7 SECONDS, radial_relative_to_user = FALSE)
|
|
. = ..()
|
|
if (!isliving(parent))
|
|
return COMPONENT_INCOMPATIBLE
|
|
var/mob/living/living_parent = parent
|
|
if (!living_parent.ai_controller)
|
|
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
|
|
src.radial_menu_lifetime = radial_menu_lifetime
|
|
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
|
|
|
|
/datum/component/obeys_commands/Destroy(force)
|
|
QDEL_LIST_ASSOC_VAL(available_commands)
|
|
return ..()
|
|
|
|
/datum/component/obeys_commands/RegisterWithParent()
|
|
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))
|
|
|
|
/datum/component/obeys_commands/UnregisterFromParent()
|
|
UnregisterSignal(parent, list(COMSIG_LIVING_BEFRIENDED, COMSIG_LIVING_UNFRIENDED, COMSIG_ATOM_EXAMINE, COMSIG_CLICK_ALT))
|
|
|
|
/// 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)
|
|
remove_from_viewers(source)
|
|
|
|
/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)
|
|
|
|
/// Add a note about whether they will follow the instructions of the inspecting mob
|
|
/datum/component/obeys_commands/proc/on_examine(mob/living/source, mob/user, list/examine_list)
|
|
SIGNAL_HANDLER
|
|
|
|
if (IS_DEAD_OR_INCAP(source))
|
|
return
|
|
if (!(user in source.ai_controller?.blackboard[BB_FRIENDS_LIST]))
|
|
return
|
|
examine_list += span_notice("[source.p_They()] seem[source.p_s()] happy to see you!")
|
|
|
|
/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
|
|
|
|
var/mob/living/owner = parent
|
|
if(isliving(mouse_hovered) && mouse_hovered.loc != owner.loc)
|
|
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) || friend.stat != CONSCIOUS)
|
|
return
|
|
if (!(friend in living_parent.ai_controller?.blackboard[BB_FRIENDS_LIST]))
|
|
return // Not our friend, can't boss us around
|
|
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/friend)
|
|
var/list/radial_options = list()
|
|
for (var/command_name as anything in available_commands)
|
|
var/datum/pet_command/command = available_commands[command_name]
|
|
var/datum/radial_menu_choice/choice = command.provide_radial_data()
|
|
if (!choice)
|
|
continue
|
|
radial_options += choice
|
|
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(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
|