mirror of
https://github.com/Bubberstation/Bubberstation.git
synced 2025-12-09 16:05:07 +00:00
Basic Mobs: the cooler simple mobs that run on datum AI. (With reworked cockroach AI as proof of concept) (#7867)
Co-authored-by: AMonkeyThatCodes <20987591+AMonkeyThatCodes@users.noreply.github.com> Co-authored-by: Gandalf <jzo123@hotmail.com>
This commit is contained in:
225
code/datums/ai/oldhostile/hostile_tameable.dm
Normal file
225
code/datums/ai/oldhostile/hostile_tameable.dm
Normal file
@@ -0,0 +1,225 @@
|
||||
///This code needs to be removed at some point as it doesn't actually utilize the AI.
|
||||
|
||||
/datum/ai_controller/hostile_friend
|
||||
blackboard = list(
|
||||
BB_HOSTILE_ORDER_MODE = null,
|
||||
BB_HOSTILE_FRIEND = null,
|
||||
BB_FOLLOW_TARGET = null,
|
||||
BB_ATTACK_TARGET = null,
|
||||
BB_VISION_RANGE = BB_HOSTILE_VISION_RANGE,
|
||||
BB_HOSTILE_ATTACK_WORD = "growls",
|
||||
)
|
||||
ai_movement = /datum/ai_movement/basic_avoidance
|
||||
|
||||
var/ride_penalty_movement = 1 SECONDS
|
||||
|
||||
COOLDOWN_DECLARE(command_cooldown)
|
||||
|
||||
/datum/ai_controller/hostile_friend/process(delta_time)
|
||||
if(isliving(pawn))
|
||||
var/mob/living/living_pawn = pawn
|
||||
movement_delay = living_pawn.cached_multiplicative_slowdown
|
||||
return ..()
|
||||
|
||||
/datum/ai_controller/hostile_friend/TryPossessPawn(atom/new_pawn)
|
||||
if(!ishostile(new_pawn))
|
||||
return AI_CONTROLLER_INCOMPATIBLE
|
||||
|
||||
RegisterSignal(new_pawn, COMSIG_PARENT_EXAMINE, .proc/on_examined)
|
||||
RegisterSignal(new_pawn, COMSIG_CLICK_ALT, .proc/check_altclicked)
|
||||
RegisterSignal(new_pawn, COMSIG_RIDDEN_DRIVER_MOVE, .proc/on_ridden_driver_move)
|
||||
RegisterSignal(new_pawn, COMSIG_MOVABLE_PREBUCKLE, .proc/on_prebuckle)
|
||||
return ..() //Run parent at end
|
||||
|
||||
/datum/ai_controller/hostile_friend/UnpossessPawn(destroy)
|
||||
UnregisterSignal(pawn, list(
|
||||
COMSIG_ATOM_ATTACK_HAND,
|
||||
COMSIG_PARENT_EXAMINE,
|
||||
COMSIG_CLICK_ALT,
|
||||
COMSIG_LIVING_DEATH,
|
||||
COMSIG_PARENT_QDELETING
|
||||
))
|
||||
unfriend()
|
||||
return ..() //Run parent at end
|
||||
|
||||
/datum/ai_controller/hostile_friend/proc/on_prebuckle(mob/source, mob/living/buckler, force, buckle_mob_flags)
|
||||
if(force || ai_status == AI_STATUS_OFF)
|
||||
return
|
||||
if(WEAKREF(buckler) != blackboard[BB_HOSTILE_FRIEND])
|
||||
return COMPONENT_BLOCK_BUCKLE
|
||||
|
||||
/datum/ai_controller/hostile_friend/able_to_run()
|
||||
var/mob/living/living_pawn = pawn
|
||||
|
||||
if(IS_DEAD_OR_INCAP(living_pawn))
|
||||
return FALSE
|
||||
return ..()
|
||||
|
||||
/datum/ai_controller/hostile_friend/get_access()
|
||||
var/mob/living/simple_animal/simple_pawn = pawn
|
||||
if(!istype(simple_pawn))
|
||||
return
|
||||
|
||||
return simple_pawn.access_card
|
||||
|
||||
/datum/ai_controller/hostile_friend/PerformIdleBehavior(delta_time)
|
||||
var/mob/living/living_pawn = pawn
|
||||
if(!isturf(living_pawn.loc) || living_pawn.pulledby || length(living_pawn.buckled_mobs))
|
||||
return
|
||||
|
||||
if(DT_PROB(5, delta_time) && (living_pawn.mobility_flags & MOBILITY_MOVE))
|
||||
var/move_dir = pick(GLOB.alldirs)
|
||||
living_pawn.Move(get_step(living_pawn, move_dir), move_dir)
|
||||
|
||||
/datum/ai_controller/hostile_friend/proc/on_ridden_driver_move(atom/movable/movable_parent, mob/living/user, direction)
|
||||
SIGNAL_HANDLER
|
||||
PauseAi(ride_penalty_movement)
|
||||
|
||||
/// Befriends someone
|
||||
/datum/ai_controller/hostile_friend/proc/befriend(mob/living/new_friend)
|
||||
var/datum/weakref/current_ref = blackboard[BB_HOSTILE_FRIEND]
|
||||
var/datum/weakref/friend_ref = WEAKREF(new_friend)
|
||||
var/mob/living/old_friend = current_ref?.resolve()
|
||||
if(old_friend)
|
||||
unfriend(old_friend)
|
||||
else
|
||||
blackboard[BB_HOSTILE_FRIEND] = null
|
||||
|
||||
if(in_range(pawn, new_friend))
|
||||
new_friend.visible_message("<b>[pawn]</b> looks at [new_friend] in a friendly manner!", span_notice("[pawn] looks at you in a friendly manner!"))
|
||||
blackboard[BB_HOSTILE_FRIEND] = friend_ref
|
||||
RegisterSignal(new_friend, COMSIG_MOB_POINTED, .proc/check_point)
|
||||
RegisterSignal(new_friend, COMSIG_MOB_SAY, .proc/check_verbal_command)
|
||||
|
||||
/// Someone is being mean to us, take them off our friends (add actual enemies behavior later)
|
||||
/datum/ai_controller/hostile_friend/proc/unfriend()
|
||||
var/datum/weakref/friend_ref = blackboard[BB_HOSTILE_FRIEND]
|
||||
var/mob/living/old_friend = friend_ref?.resolve()
|
||||
if(old_friend)
|
||||
UnregisterSignal(old_friend, list(COMSIG_MOB_POINTED, COMSIG_MOB_SAY))
|
||||
blackboard[BB_HOSTILE_FRIEND] = null
|
||||
|
||||
/// Someone is looking at us, if we're currently carrying something then show what it is, and include a message if they're our friend
|
||||
/datum/ai_controller/hostile_friend/proc/on_examined(datum/source, mob/user, list/examine_text)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(blackboard[BB_HOSTILE_FRIEND] == WEAKREF(user))
|
||||
var/mob/living/living_pawn = pawn
|
||||
if(!IS_DEAD_OR_INCAP(living_pawn))
|
||||
examine_text += span_notice("[pawn.p_they(TRUE)] seem[pawn.p_s()] happy to see you!")
|
||||
|
||||
// next section is regarding commands
|
||||
|
||||
/// Someone alt clicked us, see if they're someone we should show the radial command menu to
|
||||
/datum/ai_controller/hostile_friend/proc/check_altclicked(datum/source, mob/living/clicker)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, command_cooldown))
|
||||
return
|
||||
if(!istype(clicker) || blackboard[BB_HOSTILE_FRIEND] == WEAKREF(clicker))
|
||||
return
|
||||
. = COMPONENT_CANCEL_CLICK_ALT
|
||||
INVOKE_ASYNC(src, .proc/command_radial, clicker)
|
||||
|
||||
/// Show the command radial menu
|
||||
/datum/ai_controller/hostile_friend/proc/command_radial(mob/living/clicker)
|
||||
var/list/commands = list(
|
||||
COMMAND_STOP = image(icon = 'icons/testing/turf_analysis.dmi', icon_state = "red_arrow"),
|
||||
COMMAND_FOLLOW = image(icon = 'icons/mob/actions/actions_spells.dmi', icon_state = "summons"),
|
||||
COMMAND_ATTACK = image(icon = 'icons/effects/effects.dmi', icon_state = "bite"),
|
||||
)
|
||||
|
||||
var/choice = show_radial_menu(clicker, pawn, commands, custom_check = CALLBACK(src, .proc/check_menu, clicker), tooltips = TRUE)
|
||||
if(!choice || !check_menu(clicker))
|
||||
return
|
||||
set_command_mode(clicker, choice)
|
||||
|
||||
|
||||
/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))
|
||||
return FALSE
|
||||
return TRUE
|
||||
|
||||
/// One of our friends said something, see if it's a valid command, and if so, take action
|
||||
/datum/ai_controller/hostile_friend/proc/check_verbal_command(mob/speaker, speech_args)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
if(blackboard[BB_HOSTILE_FRIEND] != WEAKREF(speaker))
|
||||
return
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, command_cooldown))
|
||||
return
|
||||
|
||||
var/mob/living/living_pawn = pawn
|
||||
if(IS_DEAD_OR_INCAP(living_pawn))
|
||||
return
|
||||
|
||||
var/spoken_text = speech_args[SPEECH_MESSAGE] // probably should check for full words
|
||||
var/command
|
||||
if(findtext(spoken_text, "stop") || findtext(spoken_text, "stay"))
|
||||
command = COMMAND_STOP
|
||||
else if(findtext(spoken_text, "follow") || findtext(spoken_text, "come"))
|
||||
command = COMMAND_FOLLOW
|
||||
else if(findtext(spoken_text, "attack") || findtext(spoken_text, "sic"))
|
||||
command = COMMAND_ATTACK
|
||||
else
|
||||
return
|
||||
|
||||
if(!can_see(pawn, speaker, length=blackboard[BB_VISION_RANGE]))
|
||||
return
|
||||
set_command_mode(speaker, command)
|
||||
|
||||
/// Whether we got here via radial menu or a verbal command, this is where we actually process what our new command will be
|
||||
/datum/ai_controller/hostile_friend/proc/set_command_mode(mob/commander, command)
|
||||
COOLDOWN_START(src, command_cooldown, AI_HOSTILE_COMMAND_COOLDOWN)
|
||||
|
||||
switch(command)
|
||||
// heel: stop what you're doing, relax and try not to do anything for a little bit
|
||||
if(COMMAND_STOP)
|
||||
pawn.visible_message(span_notice("[pawn] [blackboard[BB_HOSTILE_ATTACK_WORD]] at [commander]'s command, and [pawn.p_they()] stop[pawn.p_s()] obediently, awaiting further orders."))
|
||||
blackboard[BB_HOSTILE_ORDER_MODE] = HOSTILE_COMMAND_NONE
|
||||
CancelActions()
|
||||
// fetch: whatever the commander points to, try and bring it back
|
||||
if(COMMAND_FOLLOW)
|
||||
pawn.visible_message(span_notice("[pawn] [blackboard[BB_HOSTILE_ATTACK_WORD]] at [commander]'s command, and [pawn.p_they()] follow[pawn.p_s()] slightly in anticipation."))
|
||||
CancelActions()
|
||||
blackboard[BB_HOSTILE_ORDER_MODE] = HOSTILE_COMMAND_FOLLOW
|
||||
blackboard[BB_FOLLOW_TARGET] = WEAKREF(commander)
|
||||
current_movement_target = commander
|
||||
var/mob/living/living_pawn = pawn
|
||||
if(living_pawn.buckled)
|
||||
queue_behavior(/datum/ai_behavior/resist)//in case they are in bed or something
|
||||
queue_behavior(/datum/ai_behavior/follow)
|
||||
// attack: harass whoever the commander points to
|
||||
if(COMMAND_ATTACK)
|
||||
pawn.visible_message(span_danger("[pawn] [blackboard[BB_HOSTILE_ATTACK_WORD]] at [commander]'s command, and [pawn.p_they()] growl[pawn.p_s()] intensely.")) // imagine getting intimidated by a corgi
|
||||
CancelActions()
|
||||
blackboard[BB_HOSTILE_ORDER_MODE] = HOSTILE_COMMAND_ATTACK
|
||||
|
||||
/// Someone we like is pointing at something, see if it's something we might want to interact with (like if they might want us to fetch something for them)
|
||||
/datum/ai_controller/hostile_friend/proc/check_point(mob/pointing_friend, atom/movable/pointed_movable)
|
||||
SIGNAL_HANDLER
|
||||
|
||||
var/mob/living/simple_animal/hostile/living_pawn = pawn
|
||||
if(IS_DEAD_OR_INCAP(living_pawn))
|
||||
return
|
||||
|
||||
if(!COOLDOWN_FINISHED(src, command_cooldown))
|
||||
return
|
||||
if(blackboard[BB_HOSTILE_FRIEND] == WEAKREF(pointed_movable) || pointed_movable == pawn || !istype(pointed_movable) || blackboard[BB_HOSTILE_ORDER_MODE] == HOSTILE_COMMAND_NONE) // busy or no command
|
||||
return
|
||||
if(!can_see(pawn, pointing_friend, length=blackboard[BB_VISION_RANGE]) || !can_see(pawn, pointed_movable, length=blackboard[BB_VISION_RANGE]))
|
||||
return
|
||||
|
||||
CancelActions()
|
||||
COOLDOWN_START(src, command_cooldown, AI_HOSTILE_COMMAND_COOLDOWN)
|
||||
|
||||
if(blackboard[BB_HOSTILE_ORDER_MODE] == HOSTILE_COMMAND_ATTACK)
|
||||
pawn.visible_message(span_notice("[pawn] follows [pointing_friend]'s gesture towards [pointed_movable] and [blackboard[BB_HOSTILE_ATTACK_WORD]] intensely!"))
|
||||
current_movement_target = pointed_movable
|
||||
blackboard[BB_ATTACK_TARGET] = WEAKREF(pointed_movable)
|
||||
if(living_pawn.buckled)
|
||||
queue_behavior(/datum/ai_behavior/resist)//in case they are in bed or something
|
||||
queue_behavior(/datum/ai_behavior/attack)
|
||||
Reference in New Issue
Block a user