mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-16 12:43:09 +00:00
<!-- Write **BELOW** The Headers and **ABOVE** The comments else it may not be viewable. --> <!-- You can view Contributing.MD for a detailed description of the pull request process. --> ## About The Pull Request Fixes #89060 and a few other inconsistencies that I think aren't reported yet. In particular, these are: - Ordering the Stargazer to attack a window, machinery, and essentially anything that isn't a wall or person will result in refusal. This behavior was different. - The spell to remotely command the Stargazer doesn't work. - The shift-hover radial menu is weirdly offset. I'm still trying to figure out what makes the mob not attack windows unlike before, so I'll set it as a draft until I fix it. ## Why It's Good For The Game Summoning an elder god bound to your will would be even better if it was actually bound to your will. ## Changelog <!-- If your PR modifies aspects of the game that can be concretely observed by players or admins you should add a changelog. If your change does NOT meet this description, remove this section. Be sure to properly mark your PRs to prevent unnecessary GBP loss. You can read up on GBP and its effects on PRs in the tgstation guides for contributors. Please note that maintainers freely reserve the right to remove and add tags should they deem it appropriate. You can attempt to finagle the system all you want, but it's best to shoot for clear communication right off the bat. --> 🆑 fix: The Stargazer, a cosmic heretic's ascension, can be properly commanded once more. code: Basic mob pets can now target objects, or objects and walls by using two new targeting strategies. /🆑 <!-- Both 🆑's are required for the changelog to work! You can put your name to the right of the first 🆑 if you want to overwrite your GitHub username as author ingame. --> <!-- You can use multiple of the same prefix (they're only used for the icon ingame) and delete the unneeded ones. Despite some of the tags, changelogs should generally represent how a player might be affected by the changes rather than a summary of the PR's contents. -->
141 lines
6.0 KiB
Plaintext
141 lines
6.0 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_NULL(available_commands)
|
|
|
|
/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)
|
|
|
|
/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
|
|
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) || 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
|