Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Cherry puck #10

Merged
merged 11 commits into from
Aug 21, 2024
2 changes: 1 addition & 1 deletion code/__DEFINES/ai/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@
///macro for whether it's appropriate to resist right now, used by resist subtree
#define SHOULD_RESIST(source) (source.on_fire || source.buckled || HAS_TRAIT(source, TRAIT_RESTRAINED) || (source.pulledby && source.pulledby.grab_state > GRAB_PASSIVE))
///macro for whether the pawn can act, used generally to prevent some horrifying ai disasters
#define IS_DEAD_OR_INCAP(source) (source.incapacitated() || source.stat)
#define IS_DEAD_OR_INCAP(source) (source.incapacitated || source.stat)

GLOBAL_LIST_INIT(all_radial_directions, list(
"NORTH" = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow", dir = NORTH),
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/signals_mob/signals_mob_ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,5 @@

///Signal sent when a bot is reset
#define COMSIG_BOT_RESET "bot_reset"
///Sent off /mob/living/basic/bot/proc/set_mode_flags() : (new_flags)
#define COMSIG_BOT_MODE_FLAGS_SET "bot_mode_flags_set"
3 changes: 3 additions & 0 deletions code/__DEFINES/dcs/signals/signals_mob/signals_mob_main.dm
Original file line number Diff line number Diff line change
Expand Up @@ -246,3 +246,6 @@

/// from /mob/proc/key_down(): (key, client/client, full_key)
#define COMSIG_MOB_KEYDOWN "mob_key_down"

/// from /mob/update_incapacitated(): (old_incap, new_incap)
#define COMSIG_MOB_INCAPACITATE_CHANGED "mob_incapacitated"
18 changes: 12 additions & 6 deletions code/__DEFINES/status_effects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -24,12 +24,18 @@
#define CURSE_GRASPING (1<<3)

//Incapacitated status effect flags
/// If the incapacitated status effect will ignore a mob in restraints (handcuffs)
#define IGNORE_RESTRAINTS (1<<0)
/// If the incapacitated status effect will ignore a mob in stasis (stasis beds)
#define IGNORE_STASIS (1<<1)
/// If the incapacitated status effect will ignore a mob being agressively grabbed
#define IGNORE_GRAB (1<<2)
/// If the mob is normal incapacitated. Should never need this, just avoids issues if we ever overexpand this
#define TRADITIONAL_INCAPACITATED (1<<0)
/// If the incapacitated status effect is being caused by restraints (handcuffs)
#define INCAPABLE_RESTRAINTS (1<<1)
/// If the incapacitated status effect is being caused by stasis (stasis beds)
#define INCAPABLE_STASIS (1<<2)
/// If the incapacitated status effect is being caused by being agressively grabbed
#define INCAPABLE_GRAB (1<<3)

/// Checks to see if a mob would be incapacitated even while ignoring some types
/// Does this by inverting the passed in flags and seeing if we're still incapacitated
#define INCAPACITATED_IGNORING(mob, flags) (mob.incapacitated & ~(flags))

/// Maxamounts of fire stacks a mob can get
#define MAX_FIRE_STACKS 20
Expand Down
2 changes: 1 addition & 1 deletion code/__HELPERS/paths/path.dm
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,7 @@
src.has_gravity = construct_from.has_gravity()
if(ismob(construct_from))
var/mob/living/mob_construct = construct_from
src.incapacitated = mob_construct.incapacitated()
src.incapacitated = mob_construct.incapacitated
if(mob_construct.buckled)
src.buckled_info = new(mob_construct.buckled, access, no_id, call_depth + 1)
if(isobserver(construct_from))
Expand Down
4 changes: 2 additions & 2 deletions code/_onclick/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
Note that AI have no need for the adjacency proc, and so this proc is a lot cleaner.
*/
/mob/living/silicon/ai/DblClickOn(atom/A, params)
if(control_disabled || incapacitated())
if(control_disabled || incapacitated)
return

if(ismob(A))
Expand Down Expand Up @@ -39,7 +39,7 @@
if(check_click_intercept(params,A))
return

if(control_disabled || incapacitated())
if(control_disabled || incapacitated)
return

var/turf/pixel_turf = get_turf_pixel(A)
Expand Down
4 changes: 2 additions & 2 deletions code/_onclick/click.dm
Original file line number Diff line number Diff line change
Expand Up @@ -102,7 +102,7 @@
CtrlClickOn(A)
return

if(incapacitated(IGNORE_RESTRAINTS|IGNORE_STASIS))
if(INCAPACITATED_IGNORING(src, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS))
return

face_atom(A)
Expand Down Expand Up @@ -366,7 +366,7 @@
return FALSE

/mob/living/CtrlClick(mob/living/user)
if(!isliving(user) || !user.CanReach(src) || user.incapacitated())
if(!isliving(user) || !user.CanReach(src) || user.incapacitated)
return ..()

if(world.time < user.next_move)
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/cyborg.dm
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@
return

if(W)
if(incapacitated())
if(incapacitated)
return

//while buckled, you can still connect to and control things like doors, but you can't use your modules
Expand Down
2 changes: 1 addition & 1 deletion code/_onclick/hud/ai.dm
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
icon = 'icons/hud/screen_ai.dmi'

/atom/movable/screen/ai/Click()
if(isobserver(usr) || usr.incapacitated())
if(isobserver(usr) || usr.incapacitated)
return TRUE

/atom/movable/screen/ai/aicore
Expand Down
10 changes: 5 additions & 5 deletions code/_onclick/hud/screen_objects.dm
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,7 @@
if(world.time <= usr.next_move)
return 1

if(usr.incapacitated())
if(usr.incapacitated)
return 1

if(ismob(usr))
Expand Down Expand Up @@ -122,7 +122,7 @@
screen_loc = ui_building

/atom/movable/screen/area_creator/Click()
if(usr.incapacitated() || (isobserver(usr) && !isAdminGhostAI(usr)))
if(usr.incapacitated || (isobserver(usr) && !isAdminGhostAI(usr)))
return TRUE
var/area/A = get_area(usr)
if(!A.outdoors)
Expand Down Expand Up @@ -183,7 +183,7 @@
if(world.time <= usr.next_move)
return TRUE

if(usr.incapacitated(IGNORE_STASIS))
if(INCAPACITATED_IGNORING(usr, INCAPABLE_STASIS))
return TRUE
if(ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
Expand Down Expand Up @@ -272,7 +272,7 @@
return TRUE
if(world.time <= user.next_move)
return TRUE
if(user.incapacitated())
if(user.incapacitated)
return TRUE
if (ismecha(user.loc)) // stops inventory actions in a mech
return TRUE
Expand Down Expand Up @@ -448,7 +448,7 @@

if(world.time <= usr.next_move)
return TRUE
if(usr.incapacitated())
if(usr.incapacitated)
return TRUE
if(ismecha(usr.loc)) // stops inventory actions in a mech
return TRUE
Expand Down
6 changes: 3 additions & 3 deletions code/_onclick/other_mobs.dm
Original file line number Diff line number Diff line change
Expand Up @@ -109,11 +109,11 @@
if(!(interaction_flags_atom & INTERACT_ATOM_IGNORE_INCAPACITATED))
var/ignore_flags = NONE
if(interaction_flags_atom & INTERACT_ATOM_IGNORE_RESTRAINED)
ignore_flags |= IGNORE_RESTRAINTS
ignore_flags |= INCAPABLE_RESTRAINTS
if(!(interaction_flags_atom & INTERACT_ATOM_CHECK_GRAB))
ignore_flags |= IGNORE_GRAB
ignore_flags |= INCAPABLE_GRAB

if(user.incapacitated(ignore_flags))
if(INCAPACITATED_IGNORING(user, ignore_flags))
return FALSE
return TRUE

Expand Down
36 changes: 29 additions & 7 deletions code/datums/ai/_ai_controller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ multiple modular subtrees with behaviors
///What distance should we be checking for interesting things when considering idling/deidling? Defaults to AI_DEFAULT_INTERESTING_DIST
var/interesting_dist = AI_DEFAULT_INTERESTING_DIST

/// TRUE if we're able to run, FALSE if we aren't
/// Should not be set manually, override get_able_to_run() instead
/// Make sure you hook update_able_to_run() in setup_able_to_run() to whatever parameters changing that you added
/// Otherwise we will not pay attention to them changing
var/able_to_run = FALSE

/datum/ai_controller/New(atom/new_pawn)
change_ai_movement_type(ai_movement)
init_subtrees()
Expand Down Expand Up @@ -106,6 +112,7 @@ multiple modular subtrees with behaviors

///Proc to move from one pawn to another, this will destroy the target's existing controller.
/datum/ai_controller/proc/PossessPawn(atom/new_pawn)
SHOULD_CALL_PARENT(TRUE)
if(pawn) //Reset any old signals
UnpossessPawn(FALSE)

Expand All @@ -130,6 +137,8 @@ multiple modular subtrees with behaviors
RegisterSignal(pawn, COMSIG_MOB_STATCHANGE, PROC_REF(on_stat_changed))
RegisterSignal(pawn, COMSIG_MOB_LOGIN, PROC_REF(on_sentience_gained))
RegisterSignal(pawn, COMSIG_QDELETING, PROC_REF(on_pawn_qdeleted))
update_able_to_run()
setup_able_to_run()

/// Sets the AI on or off based on current conditions, call to reset after you've manually disabled it somewhere
/datum/ai_controller/proc/reset_ai_status()
Expand All @@ -152,7 +161,7 @@ multiple modular subtrees with behaviors
if(ai_traits & CAN_ACT_WHILE_DEAD)
return AI_STATUS_ON
return AI_STATUS_OFF

var/turf/pawn_turf = get_turf(mob_pawn)
#ifdef TESTING
if(!pawn_turf)
Expand Down Expand Up @@ -189,11 +198,13 @@ multiple modular subtrees with behaviors

///Proc for deinitializing the pawn to the old controller
/datum/ai_controller/proc/UnpossessPawn(destroy)
SHOULD_CALL_PARENT(TRUE)
if(isnull(pawn))
return // instantiated without an applicable pawn, fine

set_ai_status(AI_STATUS_OFF)
UnregisterSignal(pawn, list(COMSIG_MOVABLE_Z_CHANGED, COMSIG_MOB_LOGIN, COMSIG_MOB_LOGOUT, COMSIG_MOB_STATCHANGE, COMSIG_QDELETING))
clear_able_to_run()
if(ai_movement.moving_controllers[src])
ai_movement.stop_moving_towards(src)
var/turf/pawn_turf = get_turf(pawn)
Expand All @@ -206,19 +217,28 @@ multiple modular subtrees with behaviors
if(destroy)
qdel(src)

///Returns TRUE if the ai controller can actually run at the moment.
/datum/ai_controller/proc/able_to_run()
/datum/ai_controller/proc/setup_able_to_run()
// paused_until is handled by PauseAi() manually
RegisterSignals(pawn, list(SIGNAL_ADDTRAIT(TRAIT_AI_PAUSED), SIGNAL_REMOVETRAIT(TRAIT_AI_PAUSED)), PROC_REF(update_able_to_run))

/datum/ai_controller/proc/clear_able_to_run()
UnregisterSignal(pawn, list(SIGNAL_ADDTRAIT(TRAIT_AI_PAUSED), SIGNAL_REMOVETRAIT(TRAIT_AI_PAUSED)))

/datum/ai_controller/proc/update_able_to_run()
SIGNAL_HANDLER
able_to_run = get_able_to_run()

///Returns TRUE if the ai controller can actually run at the moment, FALSE otherwise
/datum/ai_controller/proc/get_able_to_run()
if(HAS_TRAIT(pawn, TRAIT_AI_PAUSED))
return FALSE
if(world.time < paused_until)
return FALSE
return TRUE


///Runs any actions that are currently running
/datum/ai_controller/process(seconds_per_tick)

if(!able_to_run())
if(!able_to_run)
SSmove_manager.stop_looping(pawn) //stop moving
return //this should remove them from processing in the future through event-based stuff.

Expand Down Expand Up @@ -311,7 +331,7 @@ multiple modular subtrees with behaviors
/datum/ai_controller/proc/set_ai_status(new_ai_status)
if(ai_status == new_ai_status)
return FALSE //no change

//remove old status, if we've got one
if(ai_status)
SSai_controllers.ai_controllers_by_status[ai_status] -= src
Expand All @@ -329,6 +349,8 @@ multiple modular subtrees with behaviors

/datum/ai_controller/proc/PauseAi(time)
paused_until = world.time + time
update_able_to_run()
addtimer(CALLBACK(src, PROC_REF(update_able_to_run)), time)

///Call this to add a behavior to the stack.
/datum/ai_controller/proc/queue_behavior(behavior_type, ...)
Expand Down
14 changes: 13 additions & 1 deletion code/datums/ai/bane/bane_controller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,19 @@ And the only victory you achieved was a lie. Now you understand Gotham is beyond
return AI_CONTROLLER_INCOMPATIBLE
return ..() //Run parent at end

/datum/ai_controller/bane/able_to_run()
/datum/ai_controller/bane/on_stat_changed(mob/living/source, new_stat)
. = ..()
update_able_to_run()

/datum/ai_controller/bane/setup_able_to_run()
. = ..()
RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run))

/datum/ai_controller/bane/clear_able_to_run()
UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE))
return ..()

/datum/ai_controller/bane/get_able_to_run()
var/mob/living/living_pawn = pawn
if(IS_DEAD_OR_INCAP(living_pawn))
return FALSE
Expand Down
28 changes: 20 additions & 8 deletions code/datums/ai/basic_mobs/base_basic_controller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,29 @@

return ..() //Run parent at end

/datum/ai_controller/basic_controller/on_stat_changed(mob/living/source, new_stat)
. = ..()
update_able_to_run()

/datum/ai_controller/basic_controller/able_to_run()
/datum/ai_controller/basic_controller/setup_able_to_run()
. = ..()
if(!isliving(pawn))
return
var/mob/living/living_pawn = pawn
var/incap_flags = NONE
if (ai_traits & CAN_ACT_IN_STASIS)
incap_flags |= IGNORE_STASIS
if(!(ai_traits & CAN_ACT_WHILE_DEAD) && (living_pawn.incapacitated(incap_flags) || living_pawn.stat))
RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run))

/datum/ai_controller/basic_controller/clear_able_to_run()
UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE))
return ..()

/datum/ai_controller/basic_controller/get_able_to_run()
. = ..()
if(!.)
return FALSE
var/mob/living/living_pawn = pawn
if(!(ai_traits & CAN_ACT_WHILE_DEAD))
// Unroll for flags here
if (ai_traits & CAN_ACT_IN_STASIS && (living_pawn.stat || INCAPACITATED_IGNORING(living_pawn, INCAPABLE_STASIS)))
return FALSE
else if(IS_DEAD_OR_INCAP(living_pawn))
return FALSE
if(ai_traits & PAUSE_DURING_DO_AFTER && LAZYLEN(living_pawn.do_afters))
return FALSE

Expand Down
16 changes: 14 additions & 2 deletions code/datums/ai/monkey/monkey_controller.dm
Original file line number Diff line number Diff line change
Expand Up @@ -103,10 +103,22 @@ have ways of interacting with a specific mob and control it.
. = ..()
set_trip_mode(mode = TRUE)

/datum/ai_controller/monkey/able_to_run()
/datum/ai_controller/monkey/on_stat_changed(mob/living/source, new_stat)
. = ..()
update_able_to_run()

/datum/ai_controller/monkey/setup_able_to_run()
. = ..()
RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run))

/datum/ai_controller/monkey/clear_able_to_run()
UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE))
return ..()

/datum/ai_controller/monkey/get_able_to_run()
var/mob/living/living_pawn = pawn

if(living_pawn.incapacitated(IGNORE_RESTRAINTS | IGNORE_GRAB | IGNORE_STASIS) || living_pawn.stat > CONSCIOUS)
if(INCAPACITATED_IGNORING(living_pawn, INCAPABLE_RESTRAINTS|INCAPABLE_STASIS|INCAPABLE_GRAB) || living_pawn.stat > CONSCIOUS)
return FALSE
return ..()

Expand Down
2 changes: 1 addition & 1 deletion code/datums/ai/movement/_ai_movement.dm
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@
var/datum/ai_controller/controller = source.extra_info

// Check if this controller can actually run, so we don't chase people with corpses
if(!controller.able_to_run())
if(!controller.able_to_run)
controller.CancelActions()
qdel(source) //stop moving
return MOVELOOP_SKIP_STEP
Expand Down
16 changes: 14 additions & 2 deletions code/datums/ai/oldhostile/hostile_tameable.dm
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,19 @@
if(buckler != blackboard[BB_HOSTILE_FRIEND])
return COMPONENT_BLOCK_BUCKLE

/datum/ai_controller/hostile_friend/able_to_run()
/datum/ai_controller/hostile_friend/on_stat_changed(mob/living/source, new_stat)
. = ..()
update_able_to_run()

/datum/ai_controller/hostile_friend/setup_able_to_run()
. = ..()
RegisterSignal(pawn, COMSIG_MOB_INCAPACITATE_CHANGED, PROC_REF(update_able_to_run))

/datum/ai_controller/hostile_friend/clear_able_to_run()
UnregisterSignal(pawn, list(COMSIG_MOB_INCAPACITATE_CHANGED, COMSIG_MOB_STATCHANGE))
return ..()

/datum/ai_controller/hostile_friend/get_able_to_run()
var/mob/living/living_pawn = pawn

if(IS_DEAD_OR_INCAP(living_pawn))
Expand Down Expand Up @@ -128,7 +140,7 @@
/datum/ai_controller/hostile_friend/proc/check_menu(mob/user)
if(!istype(user))
CRASH("A non-mob is trying to issue an order to [pawn].")
if(user.incapacitated() || !can_see(user, pawn))
if(user.incapacitated || !can_see(user, pawn))
return FALSE
return TRUE

Expand Down
Loading
Loading