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

Human AI #442

Draft
wants to merge 46 commits into
base: master
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
46 commits
Select commit Hold shift + click to select a range
ccfdaed
wip
Zonespace27 Sep 7, 2024
c6b8a35
good enough for a technical test, probably.
Zonespace27 Sep 8, 2024
c25b26a
Merge branch 'master' of https://github.com/PvE-CMSS13/PvE-CMSS13 int…
Zonespace27 Sep 8, 2024
f8f7ddf
linters? nah
Zonespace27 Sep 8, 2024
ce3dbba
FUCK
Zonespace27 Sep 8, 2024
4d308fe
guh
Zonespace27 Sep 8, 2024
c7d4807
let's just leave this on tbh
Zonespace27 Sep 8, 2024
7dfe97f
Merge pull request #6 from Zonespace27/human-ai
xDanilcusx Sep 8, 2024
78425b0
fixing AI not fully appraising equip sometimes
xDanilcusx Sep 9, 2024
2dc77b5
disables overwatch (might re-enable it in the future but not sure yet…
Zonespace27 Sep 10, 2024
283dccc
faction datums + basic communication + panel fixes
Zonespace27 Sep 12, 2024
b8b6829
huh?
Zonespace27 Sep 12, 2024
0f41636
don't spawn AI human if action is cancelled
xDanilcusx Sep 12, 2024
4ef8055
face target when firing
xDanilcusx Sep 12, 2024
14dc359
Merge pull request #7 from Zonespace27/human-ai
xDanilcusx Sep 12, 2024
de732a4
AI not considering utility pouch fix
xDanilcusx Sep 13, 2024
8d41918
AI flamer fix
xDanilcusx Sep 13, 2024
79b9e95
firearm appraisal add-ons and facing targets
xDanilcusx Sep 13, 2024
c70ae4a
approach target when it's seems incapicated
xDanilcusx Sep 13, 2024
0c6d6da
Update code/modules/mob/living/carbon/human/ai/ai_equipment.dm
xDanilcusx Sep 13, 2024
e03d688
Update ai_brain.dm
xDanilcusx Sep 13, 2024
126d511
Update code/modules/mob/living/carbon/human/ai/firearm_appraisal.dm
xDanilcusx Sep 13, 2024
2843d74
Update code/modules/projectiles/guns/flamer/flamer.dm
xDanilcusx Sep 13, 2024
059588c
Merge pull request #1 from xDanilcusx/human-ai
Zonespace27 Sep 13, 2024
b24ea10
Merge branch 'master' of https://github.com/PvE-CMSS13/PvE-CMSS13 int…
Zonespace27 Sep 14, 2024
1e2a1c1
compile fix + bug fix
Zonespace27 Sep 14, 2024
1e7152b
faction management panel
Zonespace27 Sep 16, 2024
7ca0020
fixes a few bugs
Zonespace27 Sep 16, 2024
328dd91
upp lines by slayer, will be changed later
Zonespace27 Sep 16, 2024
1fe7616
Merge pull request #8 from Zonespace27/human-ai
xDanilcusx Sep 18, 2024
1e5e1cb
More firearm datums + AI equipment & item bugfixes + AI now throw nad…
Zonespace27 Sep 19, 2024
473c512
Retreating and pursuing
xDanilcusx Sep 19, 2024
f48085f
Pick up mags fix
xDanilcusx Sep 19, 2024
54cc736
Merge branch 'human-ai' into human-ai
xDanilcusx Sep 19, 2024
7b30f2d
Merge pull request #9 from Zonespace27/human-ai
xDanilcusx Sep 19, 2024
0e4e5e1
Merge issues
xDanilcusx Sep 19, 2024
59d88ad
Trowback -> Throwback and nade AI action define
xDanilcusx Sep 19, 2024
6927928
Merge pull request #2 from xDanilcusx/human-ai
Zonespace27 Sep 19, 2024
7d6a687
nits
Zonespace27 Sep 19, 2024
c213076
Moves HumanAI verbs to GM tab, adds a simple verb for fortifying rooms
Zonespace27 Sep 20, 2024
6a3fac2
modify recursion limit
Zonespace27 Sep 20, 2024
2c72024
pathfinding improvement
Zonespace27 Sep 24, 2024
ab10637
fixes unrelated bug to human AI, also fixes dropped items not being r…
Zonespace27 Sep 24, 2024
ee48c7e
CLEANUP
Zonespace27 Sep 24, 2024
0ce8fff
Respond to shots from afar & a bunch of tweaks/fixes (#3)
xDanilcusx Sep 24, 2024
9c891c6
changes to the PR since i didn't have perms to push directly
Zonespace27 Sep 24, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions code/__DEFINES/dcs/signals/atom/mob/living/signals_human.dm
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,9 @@
//from /mob/living/carbon/human/equip_to_slot()
#define COMSIG_HUMAN_EQUIPPED_ITEM "human_equipped_item"

//from /mob/living/carbon/human/u_equip()
#define COMSIG_HUMAN_UNEQUIPPED_ITEM "human_unequipped_item"

/// From /mob/proc/equip_to_slot_if_possible()
#define COMSIG_HUMAN_ATTEMPTING_EQUIP "human_attempting_equip"
#define COMPONENT_HUMAN_CANCEL_ATTEMPT_EQUIP (1<<0)
Expand Down
2 changes: 2 additions & 0 deletions code/__DEFINES/dcs/signals/atom/mob/signals_mob.dm
Original file line number Diff line number Diff line change
Expand Up @@ -186,6 +186,8 @@
/// Cancels all running cloaking effects on target
#define COMSIG_MOB_EFFECT_CLOAK_CANCEL "mob_effect_cloak_cancel"

#define COMSIG_MOB_DROP_ITEM "mob_drop_item"

#define COMSIG_MOB_END_TUTORIAL "mob_end_tutorial"

#define COMSIG_MOB_NESTED "mob_nested"
12 changes: 12 additions & 0 deletions code/__DEFINES/equipment.dm
Original file line number Diff line number Diff line change
Expand Up @@ -566,3 +566,15 @@ GLOBAL_LIST_INIT(uniform_categories, list(
#define PHONE_ON_BASE_UNIT_ICON_STATE "[initial(icon_state)]"
#define PHONE_OFF_BASE_UNIT_ICON_STATE "[initial(icon_state)]_ear"
#define PHONE_RINGING_ICON_STATE "[initial(icon_state)]_ring"

// Human AI flags
/// This item is classified as a healing item for the sake of human AI
#define HEALING_ITEM (1<<0)
/// This item is classified as ammunition for the sake of human AI
#define AMMUNITION_ITEM (1<<1)
/// This item is classified as a grenade for the sake of human AI
#define GRENADE_ITEM (1<<2)
/// This item is classified as a tool for the sake of human AI
#define TOOL_ITEM (1<<3)
/// This item is classified as a melee weapon for the sake of human AI
#define MELEE_WEAPON_ITEM (1<<4)
26 changes: 26 additions & 0 deletions code/__DEFINES/human_ai.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#define HUMAN_AI_HEALTHITEMS "health"
#define HUMAN_AI_AMMUNITION "ammo"
#define HUMAN_AI_GRENADES "grenades"
#define HUMAN_AI_TOOLS "tools"

#define AI_ACTION_APPROACH /datum/ongoing_action/approach_target
#define AI_ACTION_APPROACH_CAREFUL /datum/ongoing_action/approach_target/carefully
#define AI_ACTION_RETREAT /datum/ongoing_action/retreat_from_target
#define AI_ACTION_PICKUP /datum/ongoing_action/item_pickup
#define AI_ACTION_PICKUP_GUN /datum/ongoing_action/item_pickup/pickup_primary
#define AI_ACTION_COVER /datum/ongoing_action/take_cover
#define AI_ACTION_COVER_I /datum/ongoing_action/take_inside_cover
#define AI_ACTION_THROWBACK /datum/ongoing_action/throw_back_nade
#define AI_ACTION_NADE /datum/ongoing_action/throw_grenade
#define AI_ACTION_MELEE_ATOM /datum/ongoing_action/melee_atom

/// Action is completed, delete this and move onto the next ongoing action
#define ONGOING_ACTION_COMPLETED "completed"
/// Action isn't finished, move onto the next ongoing action
#define ONGOING_ACTION_UNFINISHED "unfinished"
/// Action isn't finished, block any further actions from the AI this tick
#define ONGOING_ACTION_UNFINISHED_BLOCK "unfinished_block"

#define ADD_ONGOING_ACTION(brain, path, arguments...) brain:_add_ongoing_action(path, ##arguments)

#define HUMAN_AI_MAX_PATHFINDING_RANGE 45
3 changes: 2 additions & 1 deletion code/__DEFINES/subsystems.dm
Original file line number Diff line number Diff line change
Expand Up @@ -163,6 +163,7 @@
#define SS_PRIORITY_SOUND 250
#define SS_PRIORITY_TICKER 200
#define SS_PRIORITY_XENO_AI 185
#define SS_PRIORITY_HUMAN_AI 182
#define SS_PRIORITY_NIGHTMARE 180
#define SS_PRIORITY_QUADTREE 160
#define SS_PRIORITY_CHAT 155
Expand All @@ -172,7 +173,7 @@
#define SS_PRIORITY_MOB 150
#define SS_PRIORITY_XENO 149
#define SS_PRIORITY_HUMAN 148
#define SS_PRIORITY_XENO_PATHFINDING 130
#define SS_PRIORITY_PATHFINDING 130
#define SS_PRIORITY_STAMINA 126
#define SS_PRIORITY_COMPONENT 125
#define SS_PRIORITY_NANOUI 120
Expand Down
4 changes: 2 additions & 2 deletions code/__DEFINES/xeno_ai.dm
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#define XENO_CALCULATING_PATH(X) (X in SSxeno_pathfinding.hash_path)
#define CALCULATING_PATH(X) (X in SSpathfinding.hash_path)

#define DIRECTION_CHANGE_PENALTY 2
#define NO_WEED_PENALTY 2
Expand Down Expand Up @@ -91,7 +91,7 @@ PROBABILITY CALCULATIONS ARE HERE


/// Special blockers for pathfinding or obstacle handling
#define XENO_AI_SPECIAL_BLOCKERS list(/obj/flamer_fire, /obj/vehicle/multitile, /turf/open/space, /turf/open/gm/river)
#define AI_SPECIAL_BLOCKERS list(/obj/flamer_fire, /obj/vehicle/multitile, /turf/open/space, /turf/open/gm/river)

// Friend-or-foe universal check
#define IS_SAME_HIVENUMBER(A,B) (A.hivenumber == B.hivenumber)
31 changes: 29 additions & 2 deletions code/__HELPERS/unsorted.dm
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,8 @@
#define format_frequency(f) "[floor((f) / 10)].[(f) % 10]"

#define reverse_direction(direction) ( \
( dir & (NORTH|SOUTH) ? ~dir & (NORTH|SOUTH) : 0 ) | \
( dir & (EAST|WEST) ? ~dir & (EAST|WEST) : 0 ) \
( direction & (NORTH|SOUTH) ? ~direction & (NORTH|SOUTH) : 0 ) | \
( direction & (EAST|WEST) ? ~direction & (EAST|WEST) : 0 ) \
)

// The sane, counter-clockwise angle to turn to get from /direction/ A to /direction/ B
Expand Down Expand Up @@ -1735,6 +1735,33 @@ GLOBAL_LIST_INIT(duplicate_forbidden_vars,list(
if(NORTHWEST)
return list(NORTHWEST, NORTH, WEST)

/// Makes a given dir cardinal. If the dir is non-cardinal, it will return both cardinal directions that make up the direction. Else, it will be a single-entry list returned.
/proc/make_dir_cardinal(direction)
switch(direction)
if(NORTH)
return list(NORTH)

if(EAST)
return list(EAST)

if(SOUTH)
return list(SOUTH)

if(WEST)
return list(WEST)

if(NORTHEAST)
return list(NORTH, EAST)

if(SOUTHEAST)
return list(EAST, SOUTH)

if(SOUTHWEST)
return list(SOUTH, WEST)

if(NORTHWEST)
return list(NORTH, WEST)

/// Returns TRUE if the target is somewhere that the game should not interact with if possible
/// In this case, admin Zs and tutorial areas
/proc/should_block_game_interaction(atom/target)
Expand Down
2 changes: 1 addition & 1 deletion code/_compile_options.dm
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,6 @@

//#define UNIT_TESTS //If this is uncommented, we do a single run though of the game setup and tear down process with unit tests in between

// #define TESTING
#define TESTING
// #define REFERENCE_TRACKING
// #define GC_FAILURE_HARD_LOOKUP
79 changes: 79 additions & 0 deletions code/controllers/subsystem/human_ai.dm
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@

SUBSYSTEM_DEF(human_ai)
name = "Human AI"
priority = SS_PRIORITY_HUMAN_AI
wait = 0.2 SECONDS
/// A list of mobs scheduled to process
var/list/mob/living/carbon/human/ai/current_run = list()

var/ai_kill = FALSE

/// List of current squads
var/list/datum/human_ai_squad/squads = list()

/// Dict of "id" : squad
var/list/squad_id_dict = list()

/// The current highest ID of any squad
var/highest_squad_id = 0

/// List of all existing orders
var/list/datum/ongoing_action/existing_orders = list()

var/list/human_ai_factions = list()

/datum/controller/subsystem/human_ai/Initialize()
for(var/faction_path in subtypesof(/datum/human_ai_faction))
var/datum/human_ai_faction/faction_obj = new faction_path
human_ai_factions[faction_obj.faction] = faction_obj
return SS_INIT_SUCCESS

/datum/controller/subsystem/human_ai/stat_entry(msg)
msg = "P:[length(GLOB.human_ai_brains)]"
return ..()

/datum/admins/proc/toggle_human_ai()
set name = "Toggle Human AI"
set category = "Game Master.HumanAI"

if(!check_rights(R_DEBUG))
return

SShuman_ai.ai_kill = !SShuman_ai.ai_kill
message_admins("[key_name_admin(usr)] [SShuman_ai.ai_kill? "killed" : "revived"] all human AI.")

/datum/controller/subsystem/human_ai/fire(resumed = FALSE)
if(ai_kill)
return

if(!resumed)
src.current_run = GLOB.human_ai_brains.Copy()
// Cache for sanic speed (lists are references anyways)
var/list/current_run = src.current_run
while(length(current_run))
var/datum/human_ai_brain/brain = current_run[length(current_run)]
current_run.len--
if(!QDELETED(brain) && !brain.tied_human?.client)
brain.process(wait * 0.1)

if(MC_TICK_CHECK)
return

/datum/controller/subsystem/human_ai/proc/create_new_squad()
highest_squad_id++
var/datum/human_ai_squad/new_squad = new
squads += new_squad
squad_id_dict["[highest_squad_id]"] = new_squad

/datum/controller/subsystem/human_ai/proc/get_squad(squad_id)
RETURN_TYPE(/datum/human_ai_squad)

if(!squad_id || !(squad_id in squad_id_dict))
return null
return squad_id_dict[squad_id]

/datum/controller/subsystem/human_ai/proc/create_new_order(datum/ongoing_action/path, ...)
if(!path::order)
stack_trace("Action of [path] was attempted to be created as an order.")
existing_orders += new path(args)

61 changes: 31 additions & 30 deletions code/controllers/subsystem/pathfinding.dm
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
SUBSYSTEM_DEF(xeno_pathfinding)
name = "Xeno Pathfinding"
priority = SS_PRIORITY_XENO_PATHFINDING
SUBSYSTEM_DEF(pathfinding)
name = "Pathfinding"
priority = SS_PRIORITY_PATHFINDING
flags = SS_NO_INIT|SS_TICKER|SS_BACKGROUND
wait = 1
/// A list of mobs scheduled to process
Expand All @@ -11,11 +11,11 @@ SUBSYSTEM_DEF(xeno_pathfinding)
var/list/hash_path = list()
var/current_position = 1

/datum/controller/subsystem/xeno_pathfinding/stat_entry(msg)
/datum/controller/subsystem/pathfinding/stat_entry(msg)
msg = "P:[length(paths_to_calculate)]"
return ..()

/datum/controller/subsystem/xeno_pathfinding/fire(resumed = FALSE)
/datum/controller/subsystem/pathfinding/fire(resumed = FALSE)
if(!resumed)
current_processing = paths_to_calculate.Copy()

Expand All @@ -29,15 +29,13 @@ SUBSYSTEM_DEF(xeno_pathfinding)

var/turf/target = current_run.finish

var/mob/living/carbon/xenomorph/X = current_run.travelling_xeno

var/list/visited_nodes = current_run.visited_nodes
var/list/distances = current_run.distances
var/list/f_distances = current_run.f_distances
var/list/prev = current_run.prev

while(length(visited_nodes))
current_run.current_node = visited_nodes[visited_nodes.len]
current_run.current_node = visited_nodes[length(visited_nodes)]
visited_nodes.len--
if(current_run.current_node == target)
break
Expand All @@ -46,27 +44,30 @@ SUBSYSTEM_DEF(xeno_pathfinding)
var/turf/neighbor = get_step(current_run.current_node, direction)
var/distance_between = distances[current_run.current_node] * DISTANCE_PENALTY
if(isnull(distances[neighbor]))
if(get_dist(neighbor, X) > current_run.path_range)
if(get_dist(neighbor, current_run.agent) > current_run.path_range)
continue
distances[neighbor] = INFINITY
f_distances[neighbor] = INFINITY

if(direction != get_dir(prev[neighbor], neighbor))
distance_between += DIRECTION_CHANGE_PENALTY

if(!neighbor.weeds)
if(isxeno(current_run.agent) && !neighbor.weeds)
distance_between += NO_WEED_PENALTY

for(var/i in neighbor)
var/atom/A = i
distance_between += A.object_weight

var/list/L = LinkBlocked(X, current_run.current_node, neighbor, current_run.ignore, TRUE)
L += check_special_blockers(X, neighbor)
var/list/L = LinkBlocked(current_run.agent, current_run.current_node, neighbor, current_run.ignore, TRUE)
L += check_special_blockers(current_run.agent, neighbor)
if(length(L))
for(var/i in L)
var/atom/A = i
distance_between += A.xeno_ai_obstacle(X, direction, target)
if(isxeno(current_run.agent))
for(var/atom/A as anything in L)
distance_between += A.xeno_ai_obstacle(current_run.agent, direction, target)
else
for(var/atom/A as anything in L)
distance_between += A.human_ai_obstacle(current_run.agent, current_run.agent:ai_brain, direction, target) // zonenote unfuck me later

if(distance_between < distances[neighbor])
distances[neighbor] = distance_between
Expand Down Expand Up @@ -126,34 +127,34 @@ SUBSYSTEM_DEF(xeno_pathfinding)
current_run.to_return.Invoke(path)
QDEL_NULL(current_run)

/datum/controller/subsystem/xeno_pathfinding/proc/check_special_blockers(mob/living/carbon/xenomorph/xeno, turf/checking_turf)
/datum/controller/subsystem/pathfinding/proc/check_special_blockers(mob/agent, turf/checking_turf)
var/list/pass_back = list()

for(var/spec_blocker in XENO_AI_SPECIAL_BLOCKERS)
for(var/spec_blocker in AI_SPECIAL_BLOCKERS)
pass_back += istype(checking_turf, spec_blocker) ? checking_turf : list()

for(var/atom/checked_atom as anything in checking_turf)
pass_back += istype(checked_atom, spec_blocker) ? checked_atom : list()

return pass_back

/datum/controller/subsystem/xeno_pathfinding/proc/stop_calculating_path(mob/living/carbon/xenomorph/X)
var/datum/xeno_pathinfo/data = hash_path[X]
/datum/controller/subsystem/pathfinding/proc/stop_calculating_path(mob/agent)
var/datum/xeno_pathinfo/data = hash_path[agent]
qdel(data)

/datum/controller/subsystem/xeno_pathfinding/proc/calculate_path(atom/start, atom/finish, path_range, mob/living/carbon/xenomorph/travelling_xeno, datum/callback/CB, list/ignore)
/datum/controller/subsystem/pathfinding/proc/calculate_path(atom/start, atom/finish, path_range, mob/agent, datum/callback/CB, list/ignore)
if(!get_turf(start) || !get_turf(finish))
return

var/datum/xeno_pathinfo/data = hash_path[travelling_xeno]
SSxeno_pathfinding.current_processing -= data
var/datum/xeno_pathinfo/data = hash_path[agent]
SSpathfinding.current_processing -= data


if(!data)
data = new()
data.RegisterSignal(travelling_xeno, COMSIG_PARENT_QDELETING, TYPE_PROC_REF(/datum/xeno_pathinfo, qdel_wrapper))
data.RegisterSignal(agent, COMSIG_PARENT_QDELETING, TYPE_PROC_REF(/datum/xeno_pathinfo, qdel_wrapper))

hash_path[travelling_xeno] = data
hash_path[agent] = data
paths_to_calculate += data

data.current_node = get_turf(start)
Expand All @@ -162,7 +163,7 @@ SUBSYSTEM_DEF(xeno_pathfinding)
var/turf/target = get_turf(finish)

data.finish = target
data.travelling_xeno = travelling_xeno
data.agent = agent
data.to_return = CB
data.path_range = path_range
data.ignore = ignore
Expand All @@ -175,7 +176,7 @@ SUBSYSTEM_DEF(xeno_pathfinding)
/datum/xeno_pathinfo
var/turf/start
var/turf/finish
var/mob/living/carbon/xenomorph/travelling_xeno
var/mob/agent
var/datum/callback/to_return
var/path_range

Expand All @@ -198,17 +199,17 @@ SUBSYSTEM_DEF(xeno_pathfinding)
prev = list()

/datum/xeno_pathinfo/Destroy(force)
SSxeno_pathfinding.hash_path -= travelling_xeno
SSxeno_pathfinding.paths_to_calculate -= src
SSxeno_pathfinding.current_processing -= src
SSpathfinding.hash_path -= agent
SSpathfinding.paths_to_calculate -= src
SSpathfinding.current_processing -= src

#ifdef TESTING
addtimer(CALLBACK(src, PROC_REF(clear_colors), distances), 5 SECONDS)
#endif

start = null
finish = null
travelling_xeno = null
agent = null
to_return = null
visited_nodes = null
distances = null
Expand Down
Loading
Loading