From 6a7deab9dc23517c252d37be3dc4a74b3593f7a9 Mon Sep 17 00:00:00 2001 From: dwasint <82520990+dwasint@users.noreply.github.com> Date: Mon, 25 Sep 2023 18:14:03 -0400 Subject: [PATCH] basic fish mob --- code/__DEFINES/ai/ai_blackboard.dm | 2 + .../basic_ai_behaviors/step_towards_turf.dm | 26 +++---- .../code/modules/ocean_content/icons/fish.dmi | Bin 0 -> 3997 bytes .../mobs/ai/behaviours/attempt_group_find.dm | 24 +++++++ .../mobs/ai/behaviours/group_move_towards.dm | 28 ++++++++ .../ocean_content/mobs/ai/controller.dm | 10 +++ .../ai/subtrees/simple_try_attach_group.dm | 24 +++++++ .../modules/ocean_content/mobs/fish_base.dm | 18 +++++ .../ocean_content/mobs/group_planning.dm | 68 ++++++++++++++++++ tgstation.dme | 6 ++ 10 files changed, 194 insertions(+), 12 deletions(-) create mode 100644 monkestation/code/modules/ocean_content/icons/fish.dmi create mode 100644 monkestation/code/modules/ocean_content/mobs/ai/behaviours/attempt_group_find.dm create mode 100644 monkestation/code/modules/ocean_content/mobs/ai/behaviours/group_move_towards.dm create mode 100644 monkestation/code/modules/ocean_content/mobs/ai/controller.dm create mode 100644 monkestation/code/modules/ocean_content/mobs/ai/subtrees/simple_try_attach_group.dm create mode 100644 monkestation/code/modules/ocean_content/mobs/fish_base.dm create mode 100644 monkestation/code/modules/ocean_content/mobs/group_planning.dm diff --git a/code/__DEFINES/ai/ai_blackboard.dm b/code/__DEFINES/ai/ai_blackboard.dm index 289f75862229..fe8e9541bf33 100644 --- a/code/__DEFINES/ai/ai_blackboard.dm +++ b/code/__DEFINES/ai/ai_blackboard.dm @@ -83,3 +83,5 @@ #define BB_MOD_IMPLANT "BB_mod_implant" ///Range for a MOD AI controller. #define MOD_AI_RANGE 200 + +#define BB_GROUP_DATUM "BB_group_datum" diff --git a/code/datums/ai/basic_mobs/basic_ai_behaviors/step_towards_turf.dm b/code/datums/ai/basic_mobs/basic_ai_behaviors/step_towards_turf.dm index f941b2eb95d5..70a557ccc436 100644 --- a/code/datums/ai/basic_mobs/basic_ai_behaviors/step_towards_turf.dm +++ b/code/datums/ai/basic_mobs/basic_ai_behaviors/step_towards_turf.dm @@ -9,22 +9,24 @@ /// How far ahead do we plot movement per action? Further means longer until we return to the decision tree, fewer means jerkier movement /// This can still result in long moves because this is "a tile x tiles away" not "only move x tiles", you might path around some walls var/step_distance = 3 + var/overwrites_main = FALSE /datum/ai_behavior/step_towards_turf/setup(datum/ai_controller/controller, turf_key) - var/turf/target_turf = controller.blackboard[turf_key] - if (QDELETED(target_turf) || target_turf.is_blocked_turf(exclude_mobs = TRUE)) - target_turf = find_destination_turf(args) - if (!target_turf) - return FALSE - controller.set_blackboard_key(turf_key, target_turf) + if(!overwrites_main) + var/turf/target_turf = controller.blackboard[turf_key] + if (QDELETED(target_turf) || target_turf.is_blocked_turf(exclude_mobs = TRUE)) + target_turf = find_destination_turf(args) + if (!target_turf) + return FALSE + controller.set_blackboard_key(turf_key, target_turf) - if (target_turf.z != controller.pawn.z) - return FALSE + if (target_turf.z != controller.pawn.z) + return FALSE - var/turf/destination = plot_movement(controller, target_turf) - if (!destination) - return FALSE - set_movement_target(controller, destination) + var/turf/destination = plot_movement(controller, target_turf) + if (!destination) + return FALSE + set_movement_target(controller, destination) return ..() /** diff --git a/monkestation/code/modules/ocean_content/icons/fish.dmi b/monkestation/code/modules/ocean_content/icons/fish.dmi new file mode 100644 index 0000000000000000000000000000000000000000..028d52fdc2d5661e8f5430a5bce6b6aa678a82d7 GIT binary patch literal 3997 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 A!vFvP literal 0 HcmV?d00001 diff --git a/monkestation/code/modules/ocean_content/mobs/ai/behaviours/attempt_group_find.dm b/monkestation/code/modules/ocean_content/mobs/ai/behaviours/attempt_group_find.dm new file mode 100644 index 000000000000..9d0f176f7fd7 --- /dev/null +++ b/monkestation/code/modules/ocean_content/mobs/ai/behaviours/attempt_group_find.dm @@ -0,0 +1,24 @@ +/datum/ai_behavior/attempt_group_find + var/group_to_find = /datum/group_planning + +/datum/ai_behavior/attempt_group_find/perform(seconds_per_tick, datum/ai_controller/controller, ...) + . = ..() + for(var/mob/living/basic/found_basic in view(7, controller.pawn)) + if(BB_GROUP_DATUM in found_basic.ai_controller.blackboard) + var/datum/group_planning/found_group = found_basic.ai_controller.blackboard[BB_GROUP_DATUM] + if(!found_group) + continue + if(found_group.type != group_to_find) + continue + controller.blackboard[BB_GROUP_DATUM] = found_group + found_group.group_mobs |= controller.pawn + finish_action(controller, TRUE) + break + + var/datum/group_planning/new_group = new group_to_find + controller.blackboard[BB_GROUP_DATUM] = new_group + new_group.group_mobs |= controller.pawn + finish_action(controller, TRUE) + +/datum/ai_behavior/attempt_group_find/fish + group_to_find = /datum/group_planning/fish diff --git a/monkestation/code/modules/ocean_content/mobs/ai/behaviours/group_move_towards.dm b/monkestation/code/modules/ocean_content/mobs/ai/behaviours/group_move_towards.dm new file mode 100644 index 000000000000..8cd5218651f0 --- /dev/null +++ b/monkestation/code/modules/ocean_content/mobs/ai/behaviours/group_move_towards.dm @@ -0,0 +1,28 @@ +/datum/ai_behavior/step_towards_turf/group_movement + overwrites_main = TRUE + +/datum/ai_behavior/step_towards_turf/group_movement/setup(datum/ai_controller/controller, turf_key) + var/datum/group_planning/listed_group = controller.blackboard[BB_GROUP_DATUM] + var/turf/target_turf = listed_group.target + + if(!target_turf) + listed_group.decide_next_action() + target_turf = listed_group.target + if(!target_turf) + return FALSE + + if (target_turf.z != controller.pawn.z) + return FALSE + + var/turf/destination = plot_movement(controller, target_turf) + if (!destination) + return FALSE + set_movement_target(controller, destination) + return ..() + + +/datum/ai_behavior/step_towards_turf/group_movement/finish_action(datum/ai_controller/controller, succeeded, ...) + . = ..() + var/datum/group_planning/listed_group = controller.blackboard[BB_GROUP_DATUM] + if(listed_group) + listed_group.finish_action(controller) diff --git a/monkestation/code/modules/ocean_content/mobs/ai/controller.dm b/monkestation/code/modules/ocean_content/mobs/ai/controller.dm new file mode 100644 index 000000000000..b4b0bc58f519 --- /dev/null +++ b/monkestation/code/modules/ocean_content/mobs/ai/controller.dm @@ -0,0 +1,10 @@ +/datum/ai_controller/basic_controller/fish + blackboard = list( + BB_GROUP_DATUM = null + ) + + ai_movement = /datum/ai_movement/basic_avoidance + idle_behavior = /datum/idle_behavior/idle_random_walk + planning_subtrees = list( + /datum/ai_planning_subtree/simple_create_or_follow_commands/fish, + ) diff --git a/monkestation/code/modules/ocean_content/mobs/ai/subtrees/simple_try_attach_group.dm b/monkestation/code/modules/ocean_content/mobs/ai/subtrees/simple_try_attach_group.dm new file mode 100644 index 000000000000..cf52ae6d8ebd --- /dev/null +++ b/monkestation/code/modules/ocean_content/mobs/ai/subtrees/simple_try_attach_group.dm @@ -0,0 +1,24 @@ +/datum/ai_planning_subtree/simple_create_or_follow_commands + var/group_finding_behaviour = /datum/ai_behavior/attempt_group_find + +/datum/ai_planning_subtree/simple_create_or_follow_commands/fish + group_finding_behaviour = /datum/ai_behavior/attempt_group_find/fish + + +/datum/ai_planning_subtree/simple_create_or_follow_commands/SelectBehaviors(datum/ai_controller/controller, seconds_per_tick) + var/datum/group_planning/attached = controller.blackboard[BB_GROUP_DATUM] + if(!attached) + controller.queue_behavior(group_finding_behaviour) + return + + if(length(attached.in_progress_mobs) && !(controller.pawn in attached.in_progress_mobs) && !(controller.pawn in attached.finished_mobs)) + attached.add_to_current_action(controller) + return + + if(!attached.next_action > world.time && !length(attached.in_progress_mobs)) + return + + if(!attached.fetched_behaviour) + attached.decide_next_action() + attached.bulk_queue() + diff --git a/monkestation/code/modules/ocean_content/mobs/fish_base.dm b/monkestation/code/modules/ocean_content/mobs/fish_base.dm new file mode 100644 index 000000000000..d592a19bd47b --- /dev/null +++ b/monkestation/code/modules/ocean_content/mobs/fish_base.dm @@ -0,0 +1,18 @@ +/mob/living/basic/aquatic/fish + icon = 'monkestation/code/modules/ocean_content/icons/fish.dmi' + icon_state = "fish" + icon_living = "fish" + icon_dead = "fish_dead" + icon_gib = "fish_dead" + + mob_size = MOB_SIZE_SMALL + faction = list(FACTION_CARP) + speak_emote = list("glubs") + + habitable_atmos = list("min_oxy" = 2, "max_oxy" = 0, "min_plas" = 0, "max_plas" = 0, "min_co2" = 0, "max_co2" = 0, "min_n2" = 0, "max_n2" = 0) + minimum_survivable_temperature = 0 + maximum_survivable_temperature = 1200 + + ai_controller = /datum/ai_controller/basic_controller/fish + + diff --git a/monkestation/code/modules/ocean_content/mobs/group_planning.dm b/monkestation/code/modules/ocean_content/mobs/group_planning.dm new file mode 100644 index 000000000000..b65c54d713ca --- /dev/null +++ b/monkestation/code/modules/ocean_content/mobs/group_planning.dm @@ -0,0 +1,68 @@ +/datum/group_planning + ///when our next queuing is done + var/next_action = 0 + ///our cooldown time of actions + var/cooldown_time = 10 SECONDS + ///list of mobs in our group + var/list/group_mobs = list() + ///list of mobs still executing our queued_behavior + var/list/in_progress_mobs = list() + ///list of finished mobs + var/list/finished_mobs = list() + ///our behaviour that we are queing + var/queued_behavior + ///do we need to fetch a new behaviour? + var/fetched_behaviour = FALSE + ///list of all behaviours we can do + var/list/usable_behaviours = list() + ///our current_target + var/atom/target + +/datum/group_planning/proc/bulk_queue() + for(var/mob/living/basic/listed as anything in group_mobs) + if(!istype(listed) || !listed.ai_controller || listed.stat == DEAD) //cull dead members that shouldn't exist anymore + if(isbasicmob(listed) && listed.ai_controller && (BB_GROUP_DATUM in listed.ai_controller.blackboard)) + listed.ai_controller.blackboard[BB_GROUP_DATUM] = null + group_mobs -= listed + continue + listed.ai_controller.queue_behavior(queued_behavior) + in_progress_mobs |= listed + +/datum/group_planning/proc/decide_next_action() + if(length(in_progress_mobs)) + return /// we are still doing an action + if(!length(usable_behaviours)) + return //how did this happen + queued_behavior = pick(usable_behaviours) + fetched_behaviour = TRUE + +/datum/group_planning/proc/add_to_current_action(datum/ai_controller/controller) + controller.queue_behavior(queued_behavior) + in_progress_mobs |= controller.pawn + + +/datum/group_planning/proc/finish_action(datum/ai_controller/controller) + if(controller.pawn in in_progress_mobs) + in_progress_mobs -= controller.pawn + finished_mobs += controller.pawn + if(!length(in_progress_mobs)) + next_action = world.time + cooldown_time + fetched_behaviour = FALSE + finished_mobs = list() + +/datum/group_planning/fish + cooldown_time = 25 SECONDS + usable_behaviours = list(/datum/ai_behavior/step_towards_turf/group_movement) + +/datum/group_planning/fish/decide_next_action() + . = ..() + var/mob/living/basic/picked_mob = pick(group_mobs) + + var/list/turfs = view(7, picked_mob) + var/turf/picked + var/sanity = 25 + + while(!isopenturf(picked) && sanity > 0) + sanity-- + picked = get_turf(pick(turfs)) + target = picked diff --git a/tgstation.dme b/tgstation.dme index 287bc5821cff..c6849d09446e 100644 --- a/tgstation.dme +++ b/tgstation.dme @@ -5976,6 +5976,12 @@ #include "monkestation\code\modules\ocean_content\hotspot_machines\dousing_rod.dm" #include "monkestation\code\modules\ocean_content\hotspot_machines\hotspot_vents.dm" #include "monkestation\code\modules\ocean_content\hotspot_machines\stomper.dm" +#include "monkestation\code\modules\ocean_content\mobs\fish_base.dm" +#include "monkestation\code\modules\ocean_content\mobs\group_planning.dm" +#include "monkestation\code\modules\ocean_content\mobs\ai\controller.dm" +#include "monkestation\code\modules\ocean_content\mobs\ai\behaviours\attempt_group_find.dm" +#include "monkestation\code\modules\ocean_content\mobs\ai\behaviours\group_move_towards.dm" +#include "monkestation\code\modules\ocean_content\mobs\ai\subtrees\simple_try_attach_group.dm" #include "monkestation\code\modules\outdoors\code\admin_commands.dm" #include "monkestation\code\modules\outdoors\code\misc_procs.dm" #include "monkestation\code\modules\outdoors\code\new_vars.dm"