From 1cd76f1bbb505d55f14cd9fcd3e77d1b3a58a2fe Mon Sep 17 00:00:00 2001 From: Morrow Date: Sun, 29 Oct 2023 22:45:04 -0400 Subject: [PATCH 1/7] lurker crippling strike plus general changes --- .../xenomorph/abilities/general_abilities.dm | 13 +++++++++---- .../abilities/lurker/lurker_abilities.dm | 17 +++++++++++++++++ .../carbon/xenomorph/abilities/xeno_action.dm | 3 +++ .../living/carbon/xenomorph/castes/Lurker.dm | 2 +- 4 files changed, 30 insertions(+), 5 deletions(-) diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm index ce5492adc3..e604a09f96 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/general_abilities.dm @@ -220,11 +220,15 @@ // (note that if a collided atom does not match any of the key types, defaults to the appropriate X_launch_collision proc) default_ai_action = TRUE - var/prob_chance = 80 /datum/action/xeno_action/activable/pounce/process_ai(mob/living/carbon/xenomorph/pouncing_xeno, delta_time) - if(get_dist(pouncing_xeno, pouncing_xeno.current_target) > distance || !DT_PROB(prob_chance, delta_time)) - return + . = ..() + + if(get_dist(pouncing_xeno, pouncing_xeno.current_target) > distance) + return FALSE + + if(!DT_PROB(ai_prob_chance, delta_time)) + return FALSE var/turf/last_turf = pouncing_xeno.loc var/clear = TRUE @@ -240,9 +244,10 @@ pouncing_xeno.remove_temp_pass_flags(PASS_OVER_THROW_MOB) if(!clear) - return + return FALSE use_ability_async(pouncing_xeno.current_target) + return TRUE /datum/action/xeno_action/activable/pounce/New() . = ..() diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm index a769a75df3..e49cc72484 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/lurker/lurker_abilities.dm @@ -72,9 +72,26 @@ action_type = XENO_ACTION_ACTIVATE xeno_cooldown = 100 plasma_cost = 20 + default_ai_action = TRUE var/buff_duration = 50 +/datum/action/xeno_action/onclick/lurker_assassinate/process_ai(mob/living/carbon/xenomorph/using_xeno, delta_time) + . = ..() + + if(using_xeno.next_move <= world.time) + return FALSE + + if(get_dist(using_xeno, using_xeno.current_target) > 1) + return FALSE + + if(!DT_PROB(ai_prob_chance, delta_time)) + return FALSE + + use_ability_async(using_xeno.current_target) + + return TRUE + // VAMP LURKER ABILITIES /datum/action/xeno_action/activable/pounce/rush diff --git a/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm index cd4df54dae..781d958771 100644 --- a/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm +++ b/code/modules/mob/living/carbon/xenomorph/abilities/xeno_action.dm @@ -10,6 +10,9 @@ /// Whether this action gets added to AI xenos var/default_ai_action = FALSE + /// Chance of use per tick applicable tick + var/ai_prob_chance = 80 + // Cooldown /// Cooldown of the ability (do not use the cooldown var) /// Probably should only have the cooldown var, but that is for another rework diff --git a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm index f85a0088fe..7cb060c1c5 100644 --- a/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm +++ b/code/modules/mob/living/carbon/xenomorph/castes/Lurker.dm @@ -141,7 +141,7 @@ to_chat(bound_xeno, SPAN_XENOHIGHDANGER("You significantly strengthen your attack, slowing [target_carbon]!")) to_chat(target_carbon, SPAN_XENOHIGHDANGER("You feel a sharp pain as [bound_xeno] slashes you, slowing you down!")) original_damage *= buffed_slash_damage_ratio - target_carbon.set_effect(get_xeno_stun_duration(target_carbon, 3), SUPERSLOW) + target_carbon.set_effect(get_xeno_stun_duration(target_carbon, 3), SLOW) next_slash_buffed = FALSE var/datum/action/xeno_action/onclick/lurker_assassinate/ability = get_xeno_action_by_type(bound_xeno, /datum/action/xeno_action/onclick/lurker_assassinate) if (ability && istype(ability)) From 4d5cd4d8bc4e1db19caedd350f55ff35e6a215a4 Mon Sep 17 00:00:00 2001 From: Morrow Date: Sun, 29 Oct 2023 22:53:26 -0400 Subject: [PATCH 2/7] revolver buff --- code/datums/ammo/bullet/revolver.dm | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) diff --git a/code/datums/ammo/bullet/revolver.dm b/code/datums/ammo/bullet/revolver.dm index 633bf3e2f7..654aceed7a 100644 --- a/code/datums/ammo/bullet/revolver.dm +++ b/code/datums/ammo/bullet/revolver.dm @@ -8,9 +8,15 @@ name = "revolver bullet" headshot_state = HEADSHOT_OVERLAY_MEDIUM - damage = 55 - penetration = ARMOR_PENETRATION_TIER_1 - accuracy = HIT_ACCURACY_TIER_1 + damage = 70 + penetration = ARMOR_PENETRATION_TIER_3 + accuracy = HIT_ACCURACY_TIER_2 + +/datum/ammo/bullet/revolver/on_hit_mob(mob/entity, obj/projectile/bullet) + . = ..() + + slowdown(entity, bullet) + pushback(entity, bullet, 4) /datum/ammo/bullet/revolver/marksman name = "marksman revolver bullet" From 193bb8880752bdccbdc794ecddade173cf171935 Mon Sep 17 00:00:00 2001 From: Morrow Date: Sun, 29 Oct 2023 22:59:15 -0400 Subject: [PATCH 3/7] roller bed and VP78 tweaks/addition --- code/datums/ammo/bullet/pistol.dm | 8 ++++---- .../vending/vendor_types/squad_prep/squad_prep.dm | 10 ++++++---- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/code/datums/ammo/bullet/pistol.dm b/code/datums/ammo/bullet/pistol.dm index 8be63b0a15..8edb66857d 100644 --- a/code/datums/ammo/bullet/pistol.dm +++ b/code/datums/ammo/bullet/pistol.dm @@ -180,11 +180,11 @@ headshot_state = HEADSHOT_OVERLAY_MEDIUM debilitate = list(0,0,0,0,0,0,0,2) - accuracy = HIT_ACCURACY_TIER_4 - damage = 45 - penetration= ARMOR_PENETRATION_TIER_6 + accuracy = HIT_ACCURACY_TIER_2 + damage = 50 + penetration = ARMOR_PENETRATION_TIER_4 shrapnel_chance = SHRAPNEL_CHANCE_TIER_2 - damage_falloff = DAMAGE_FALLOFF_TIER_6 //"VP78 - the only pistol viable as a primary."-Vampmare, probably. + damage_falloff = DAMAGE_FALLOFF_TIER_3 //"VP78 - the only pistol viable as a primary."-Vampmare, probably. /datum/ammo/bullet/pistol/squash/toxin name = "toxic squash-head pistol bullet" diff --git a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm index 4f382a8f34..a4adbefe89 100644 --- a/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm +++ b/code/game/machinery/vending/vendor_types/squad_prep/squad_prep.dm @@ -274,17 +274,19 @@ list("88 Mod 4 Combat Pistol", round(scale * 2), /obj/item/weapon/gun/pistol/mod88, VENDOR_ITEM_REGULAR), list("M44 Combat Revolver", round(scale * 2), /obj/item/weapon/gun/revolver/m44, VENDOR_ITEM_REGULAR), list("M4A3 Service Pistol", round(scale * 2), /obj/item/weapon/gun/pistol/m4a3, VENDOR_ITEM_REGULAR), + list("VP78 pistol", round(scale * 2), /obj/item/weapon/gun/pistol/vp78, VENDOR_ITEM_REGULAR), list("M82F Flare Gun", round(scale * 1), /obj/item/weapon/gun/flare, VENDOR_ITEM_REGULAR), list("SIDEARM AMMUNITION", -1, null, null), - list("88M4 AP Magazine (9mm)", round(scale * 10), /obj/item/ammo_magazine/pistol/mod88, VENDOR_ITEM_REGULAR), - list("M44 Speedloader (.44)", round(scale * 10), /obj/item/ammo_magazine/revolver, VENDOR_ITEM_REGULAR), - list("M4A3 Magazine (9mm)", round(scale * 10), /obj/item/ammo_magazine/pistol, VENDOR_ITEM_REGULAR), + list("88M4 AP Magazine (9mm)", round(scale * 20), /obj/item/ammo_magazine/pistol/mod88, VENDOR_ITEM_REGULAR), + list("M44 Speedloader (.44)", round(scale * 20), /obj/item/ammo_magazine/revolver, VENDOR_ITEM_REGULAR), + list("M4A3 Magazine (9mm)", round(scale * 20), /obj/item/ammo_magazine/pistol, VENDOR_ITEM_REGULAR), + list("VP78 magazine (9mm)", round(scale * 20), /obj/item/ammo_magazine/pistol/vp78, VENDOR_ITEM_REGULAR), list("MISCELLANEOUS", -1, null, null), list("Extinguisher", round(scale * 5), /obj/item/tool/extinguisher, VENDOR_ITEM_REGULAR), list("Fire Extinguisher (Portable)", round(scale * 1), /obj/item/tool/extinguisher/mini, VENDOR_ITEM_REGULAR), - list("Roller Bed", round(scale * 1), /obj/item/roller, VENDOR_ITEM_REGULAR), + list("Roller Bed", round(scale * 2), /obj/item/roller, VENDOR_ITEM_REGULAR), list("Machete Scabbard (Full)", round(scale * 5), /obj/item/storage/large_holster/machete/full, VENDOR_ITEM_REGULAR), list("Binoculars", round(scale * 1), /obj/item/device/binoculars, VENDOR_ITEM_REGULAR), list("Spare PDT/L Battle Buddy Kit", round(scale * 3), /obj/item/storage/box/pdt_kit, VENDOR_ITEM_REGULAR), From 2eb5b5b47bf28120441660a6acf99e0edd1b9be6 Mon Sep 17 00:00:00 2001 From: Morrow Date: Mon, 30 Oct 2023 04:05:36 -0400 Subject: [PATCH 4/7] every time --- code/datums/components/phone.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/datums/components/phone.dm b/code/datums/components/phone.dm index 49cca0cdf0..e51ebf9d17 100644 --- a/code/datums/components/phone.dm +++ b/code/datums/components/phone.dm @@ -609,7 +609,7 @@ GLOBAL_LIST_EMPTY_TYPED(phones, /datum/component/phone) return COMPONENT_OVERRIDE_DEAD_SPEAK /datum/component/phone/virtual/get_user() - return virtual_user + return virtual_user.mob // TGUI section From f2c048f9518ee65a6b7b109ad4b3c90f161cfbd1 Mon Sep 17 00:00:00 2001 From: Morrow Date: Mon, 30 Oct 2023 05:38:59 -0400 Subject: [PATCH 5/7] Moves to stack --- tgui/packages/tgui/interfaces/GameMaster.js | 275 ++++++++++---------- 1 file changed, 136 insertions(+), 139 deletions(-) diff --git a/tgui/packages/tgui/interfaces/GameMaster.js b/tgui/packages/tgui/interfaces/GameMaster.js index e33fc65b1a..44e7e91b17 100644 --- a/tgui/packages/tgui/interfaces/GameMaster.js +++ b/tgui/packages/tgui/interfaces/GameMaster.js @@ -1,5 +1,5 @@ import { useBackend } from '../backend'; -import { Flex, Dropdown, Button, Section, Slider, Collapsible, Stack, Divider } from '../components'; +import { Dropdown, Button, Section, Slider, Collapsible, Stack, Divider } from '../components'; import { Window } from '../layouts'; export const GameMaster = (props, context) => { @@ -8,144 +8,141 @@ export const GameMaster = (props, context) => { return ( - - -
- - - - - { - act('set_xeno_spawns', { value }); - }} - /> - - - { - act('set_selected_xeno', { new_xeno }); - }} - /> - - - - - - - { - act('xeno_spawn_ai_toggle'); - }} - /> - - -
-
- -
- - -
-
- -
- - -
-
-
+ +
+ + + + + { + act('set_xeno_spawns', { value }); + }} + /> + + + { + act('set_selected_xeno', { new_xeno }); + }} + /> + + + + + + + { + act('xeno_spawn_ai_toggle'); + }} + /> + + +
+
+ + +
+
+ + +
+
); From 071ebd345f04210d1b24e5e26d99cc0c2cc54f50 Mon Sep 17 00:00:00 2001 From: Morrow Date: Mon, 30 Oct 2023 08:06:02 -0400 Subject: [PATCH 6/7] First pass on xeno special behaviors --- code/controllers/subsystem/pathfinding.dm | 2 +- .../attack_override_behavior.dm | 24 ++ .../base_override_behavior.dm | 42 +++ code/modules/admin/game_master/game_master.dm | 134 ++++++-- .../mob/living/carbon/xenomorph/ai/xeno_ai.dm | 23 +- .../carbon/xenomorph/xeno_ai_interaction.dm | 20 +- colonialmarines.dme | 2 + tgui/packages/tgui/interfaces/GameMaster.js | 324 ++++++++++-------- 8 files changed, 394 insertions(+), 177 deletions(-) create mode 100644 code/datums/components/xeno/ai_behavior_overrides/attack_override_behavior.dm create mode 100644 code/datums/components/xeno/ai_behavior_overrides/base_override_behavior.dm diff --git a/code/controllers/subsystem/pathfinding.dm b/code/controllers/subsystem/pathfinding.dm index b87c65d42c..e1310fe200 100644 --- a/code/controllers/subsystem/pathfinding.dm +++ b/code/controllers/subsystem/pathfinding.dm @@ -66,7 +66,7 @@ SUBSYSTEM_DEF(xeno_pathfinding) if(length(L)) for(var/i in L) var/atom/A = i - distance_between += A.xeno_ai_obstacle(X, direction) + distance_between += A.xeno_ai_obstacle(X, direction, target) if(distance_between < distances[neighbor]) distances[neighbor] = distance_between diff --git a/code/datums/components/xeno/ai_behavior_overrides/attack_override_behavior.dm b/code/datums/components/xeno/ai_behavior_overrides/attack_override_behavior.dm new file mode 100644 index 0000000000..16cefe6721 --- /dev/null +++ b/code/datums/components/xeno/ai_behavior_overrides/attack_override_behavior.dm @@ -0,0 +1,24 @@ + +/datum/component/ai_behavior_override/attack + +/datum/component/ai_behavior_override/attack/check_behavior_validity(mob/living/carbon/xenomorph/checked_xeno, distance) + . = ..() + + if(distance > 10) + return FALSE + + return TRUE + + +/datum/component/ai_behavior_override/attack/process_override_behavior(mob/living/carbon/xenomorph/processing_xeno, delta_time) + . = ..() + + if(processing_xeno.current_target == parent) + return FALSE + + processing_xeno.current_target = parent + processing_xeno.resting = FALSE + if(prob(5)) + processing_xeno.emote("hiss") + + return FALSE diff --git a/code/datums/components/xeno/ai_behavior_overrides/base_override_behavior.dm b/code/datums/components/xeno/ai_behavior_overrides/base_override_behavior.dm new file mode 100644 index 0000000000..2a5ee7a7f5 --- /dev/null +++ b/code/datums/components/xeno/ai_behavior_overrides/base_override_behavior.dm @@ -0,0 +1,42 @@ +GLOBAL_LIST_EMPTY(all_ai_behavior_overrides) + +/datum/component/ai_behavior_override + + /// Icon file for the behavior attached to parent as game masters will see it + var/behavior_icon = 'icons/landmarks.dmi' + + /// Specific icon state for the behavior attached to parent as game masters will see it + var/behavior_icon_state = "x2" + + /// The actual image holder that sits on parent for game masters + var/image/behavior_image + +/datum/component/ai_behavior_override/Initialize(...) + . = ..() + + GLOB.all_ai_behavior_overrides += src + + behavior_image = new(behavior_icon, parent, behavior_icon_state, layer = ABOVE_FLY_LAYER) + + for(var/client/game_master in GLOB.game_masters) + game_master.images += behavior_image + +/datum/component/ai_behavior_override/Destroy(force, silent, ...) + GLOB.all_ai_behavior_overrides -= src + + for(var/client/game_master in GLOB.game_masters) + game_master.images -= behavior_image + + QDEL_NULL(behavior_image) + + . = ..() + +/// Override this to check if we want our behavior to be valid for the checked_xeno, passes the common factor of "distance" which is the distance between the checked_xeno and src parent +/datum/component/ai_behavior_override/proc/check_behavior_validity(mob/living/carbon/xenomorph/checked_xeno, distance) + return FALSE + +/// Processes what we want this behavior to do, return FALSE if we want to continue in the process_ai() proc or TRUE if we want to handle everything and have process_ai() return +/datum/component/ai_behavior_override/proc/process_override_behavior(mob/living/carbon/xenomorph/processing_xeno, delta_time) + SHOULD_NOT_SLEEP(TRUE) + + return FALSE diff --git a/code/modules/admin/game_master/game_master.dm b/code/modules/admin/game_master/game_master.dm index 31e5806e32..71ee29d603 100644 --- a/code/modules/admin/game_master/game_master.dm +++ b/code/modules/admin/game_master/game_master.dm @@ -1,5 +1,8 @@ -/// Assoc list that holds our custom game master objectives, formatted as atom = objective_string +/// Holds our active game_masters +GLOBAL_LIST_EMPTY(game_masters) + +/// List of assoc lists that hold "object_name", "objective_info", and "object_ref". Name of the objective, any info typed about the objective, and then a reference to be resolved of the object for passing through TGUI GLOBAL_LIST_EMPTY(game_master_objectives) /// Percentage of characters end up clear when sent via radio message @@ -30,6 +33,11 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) #define DEFAULT_XENO_AMOUNT_TO_SPAWN 1 +// Behavior stuff +#define DEFAULT_BEHAVIOR_STRING "Attack" +#define SELECTABLE_XENO_BEHAVIORS list("Attack") +#define SELECTABLE_XENO_BEHAVIORS_ASSOC list("Attack" = /datum/component/ai_behavior_override/attack) + // Objective stuff #define OBJECTIVE_NUMBER_OPTIONS list("zero", "one", "two", "three", "four", "five", "six", "seven", "eight", "nine") #define OBJECTIVE_COLOR_OPTIONS list("red", "purple", "blue") @@ -37,11 +45,14 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) /// Types of click intercepts used by /datum/game_master variable current_click_intercept_action #define SPAWN_CLICK_INTERCEPT_ACTION "spawn_click_intercept_action" +#define BEHAVIOR_CLICK_INTERCEPT_ACTION "behavior_click_intercept_action" #define OBJECTIVE_CLICK_INTERCEPT_ACTION "objective_click_intercept_action" /datum/game_master + var/client/game_master_client + /// Associated list of game master submenus organized by object_type = game_master_submenu var/list/submenu_types = list( /obj/structure/pipes/vents/scrubber = /datum/game_master_submenu/vents, @@ -51,8 +62,10 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) /// List of current submenus var/list/current_submenus + /// Holds what type of click intercept we are using + var/current_click_intercept_action - /// Spawn stuff + // Spawn stuff /// The xeno selected to be spawned in the spawn section var/selected_xeno = DEFAULT_SPAWN_XENO_STRING @@ -66,36 +79,46 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) /// If we are currently using the click intercept for the spawn section var/spawn_click_intercept = FALSE - /// End Spawn Stuff - /// Objective stuff + // Behavior stuff + + /// The current behavior to add when clicking with behavior_click_intercept on + var/selected_behavior = DEFAULT_BEHAVIOR_STRING + + /// If we are currently using click intercept for the behavior section + var/behavior_click_intercept = FALSE + + + // Objective stuff /// If we are currently using the click intercept for the objective section var/objective_click_intercept = FALSE - /// End Objective Stuff + // Communication stuff - /// Communication stuff - + /// The holder for the game master's virtual phone var/atom/movable/game_master_phone - /// End Communication stuff - - /// Holds what type of click intercept we are using - var/current_click_intercept_action /datum/game_master/New(client/using_client) . = ..() - tgui_interact(using_client.mob) + game_master_client = using_client + + tgui_interact(game_master_client.mob) current_submenus = list() game_master_phone = new(null) game_master_phone.AddComponent(/datum/component/phone/virtual, "Game Master", "white", "Company Command", null, PHONE_DO_NOT_DISTURB_ON, list(FACTION_MARINE, FACTION_COLONIST, FACTION_WY), list(FACTION_MARINE, FACTION_COLONIST, FACTION_WY), null, using_client) - using_client.click_intercept = src + game_master_client.click_intercept = src + + for(var/datum/component/ai_behavior_override/override in GLOB.all_ai_behavior_overrides) + game_master_client.images += override.behavior_image + + GLOB.game_masters += game_master_client /datum/game_master/Destroy(force, ...) . = ..() @@ -103,6 +126,11 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) current_submenus = null QDEL_NULL(game_master_phone) + for(var/datum/component/ai_behavior_override/override in GLOB.all_ai_behavior_overrides) + game_master_client.images -= override.behavior_image + + GLOB.game_masters -= game_master_client + /datum/game_master/ui_data(mob/user) . = ..() @@ -114,6 +142,10 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) data["spawn_click_intercept"] = spawn_click_intercept data["xeno_spawn_count"] = xeno_spawn_count + // Behavior stuff + data["selected_behavior"] = selected_behavior + data["behavior_click_intercept"] = behavior_click_intercept + // Objective stuff data["objective_click_intercept"] = objective_click_intercept data["game_master_objectives"] = length(GLOB.game_master_objectives) ? GLOB.game_master_objectives : "" @@ -130,6 +162,8 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) data["spawnable_xenos"] = GAME_MASTER_AI_XENOS + data["selectable_behaviors"] = SELECTABLE_XENO_BEHAVIORS + return data /datum/game_master/ui_act(action, list/params, datum/tgui/ui, datum/ui_state/state) @@ -138,18 +172,12 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) switch(action) //Spawn Section - if("toggle_click_spawn") - if(spawn_click_intercept) - spawn_click_intercept = FALSE - current_click_intercept_action = null + if("set_xeno_spawns") + var/new_number = text2num(params["value"]) + if(!new_number) return - spawn_click_intercept = TRUE - current_click_intercept_action = SPAWN_CLICK_INTERCEPT_ACTION - return - - if("xeno_spawn_ai_toggle") - spawn_ai = !spawn_ai + xeno_spawn_count = clamp(new_number, 1, 10) return if("set_selected_xeno") @@ -157,12 +185,18 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) xeno_spawn_count = DEFAULT_XENO_AMOUNT_TO_SPAWN return - if("set_xeno_spawns") - var/new_number = text2num(params["value"]) - if(!new_number) + if("xeno_spawn_ai_toggle") + spawn_ai = !spawn_ai + return + + if("toggle_click_spawn") + if(spawn_click_intercept) + reset_click_overrides() return - xeno_spawn_count = clamp(new_number, 1, 10) + reset_click_overrides() + spawn_click_intercept = TRUE + current_click_intercept_action = SPAWN_CLICK_INTERCEPT_ACTION return if("delete_all_xenos") @@ -174,13 +208,28 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) return + //Behavior Section + if("set_selected_behavior") + selected_behavior = params["new_behavior"] + return + + if("toggle_click_behavior") + if(behavior_click_intercept) + reset_click_overrides() + return + + reset_click_overrides() + behavior_click_intercept = TRUE + current_click_intercept_action = BEHAVIOR_CLICK_INTERCEPT_ACTION + return + //Objective Section if("toggle_click_objective") if(objective_click_intercept) - objective_click_intercept = FALSE - current_click_intercept_action = null + reset_click_overrides() return + reset_click_overrides() objective_click_intercept = TRUE current_click_intercept_action = OBJECTIVE_CLICK_INTERCEPT_ACTION return @@ -222,6 +271,7 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) spawn_click_intercept = FALSE objective_click_intercept = FALSE + behavior_click_intercept = FALSE current_click_intercept_action = null /datum/game_master/ui_status(mob/user, datum/ui_state/state) @@ -259,6 +309,18 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) return TRUE + if(BEHAVIOR_CLICK_INTERCEPT_ACTION) + var/behavior_type = SELECTABLE_XENO_BEHAVIORS_ASSOC[selected_behavior] + + if(LAZYACCESS(modifiers, MIDDLE_CLICK)) + if(object.datum_components[behavior_type]) + var/component_to_remove = object.datum_components[behavior_type] + qdel(component_to_remove) + return TRUE + + object.AddComponent(behavior_type) + return TRUE + if(OBJECTIVE_CLICK_INTERCEPT_ACTION) var/turf/object_turf = get_turf(object) @@ -329,6 +391,12 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) return TRUE +/datum/game_master/proc/reset_click_overrides() + spawn_click_intercept = FALSE + objective_click_intercept = FALSE + behavior_click_intercept = FALSE + current_click_intercept_action = null + /datum/game_master/proc/remove_objective(datum/destroying_datum) SIGNAL_HANDLER @@ -338,11 +406,19 @@ GLOBAL_VAR_INIT(radio_communication_clarity, 100) GLOB.game_master_objectives.Remove(list(cycled_objective)) UnregisterSignal(objective_object, COMSIG_PARENT_QDELETING) + + #undef DEFAULT_SPAWN_XENO_STRING #undef GAME_MASTER_AI_XENOS #undef DEFAULT_XENO_AMOUNT_TO_SPAWN + #undef OBJECTIVE_NUMBER_OPTIONS #undef OBJECTIVE_COLOR_OPTIONS #undef OBJECTIVE_COLOR_OPTIONS_ASSOC + +#undef DEFAULT_BEHAVIOR_STRING +#undef SELECTABLE_XENO_BEHAVIORS +#undef SELECTABLE_XENO_BEHAVIORS_ASSOC + #undef SPAWN_CLICK_INTERCEPT_ACTION #undef OBJECTIVE_CLICK_INTERCEPT_ACTION diff --git a/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm b/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm index f52c5276c9..1f1f654ee2 100644 --- a/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm +++ b/code/modules/mob/living/carbon/xenomorph/ai/xeno_ai.dm @@ -67,6 +67,11 @@ GLOBAL_LIST_INIT(ai_target_limbs, list( current_path = null return TRUE + var/datum/component/ai_behavior_override/behavior_override = check_overrides() + + if(behavior_override?.process_override_behavior(src, delta_time)) + return TRUE + var/stat_check = FALSE if(istype(current_target, /mob)) var/mob/current_target_mob = current_target @@ -109,7 +114,7 @@ GLOBAL_LIST_INIT(ai_target_limbs, list( var/list/turf/turfs_to_dist_check = list(get_turf(current_target)) - if(length(current_target.locs) > 1) + if(istype(current_target, /atom/movable) && length(current_target.locs) > 1) turfs_to_dist_check = get_multitile_turfs_to_check() for(var/turf/checked_turf as anything in turfs_to_dist_check) @@ -130,7 +135,9 @@ GLOBAL_LIST_INIT(ai_target_limbs, list( CRASH("No valid movement handler for [src]!") return ai_movement_handler.ai_move_target(delta_time) -/atom/proc/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/atom/proc/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) + if(get_turf(src) == target) + return 0 return INFINITY // Called whenever an obstacle is encountered but xeno_ai_obstacle returned something else than infinite @@ -209,6 +216,18 @@ GLOBAL_LIST_INIT(ai_target_limbs, list( return TRUE +/// Checks and returns the nearest override for behavior +/mob/living/carbon/xenomorph/proc/check_overrides() + var/shortest_distance = INFINITY + var/datum/component/ai_behavior_override/closest_valid_override + for(var/datum/component/ai_behavior_override/cycled_override in GLOB.all_ai_behavior_overrides) + var/distance = get_dist(src, cycled_override.parent) + if(cycled_override.check_behavior_validity(src, distance) && distance < shortest_distance) + shortest_distance = distance + closest_valid_override = cycled_override + + return closest_valid_override + #define EXTRA_CHECK_DISTANCE_MULTIPLIER 0.20 /mob/living/carbon/xenomorph/proc/get_target(range) diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm b/code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm index 587942b41a..e9ab25136a 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm @@ -1,12 +1,12 @@ // MINERAL DOOR -/obj/structure/mineral_door/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/obj/structure/mineral_door/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) return DOOR_PENALTY /obj/structure/mineral_door/xeno_ai_act(mob/living/carbon/xenomorph/X) X.do_click(src, "", list()) return TRUE -/obj/structure/mineral_door/resin/xeno_ai_obstacle(mob/living/carbon/xenomorph/xeno) +/obj/structure/mineral_door/resin/xeno_ai_obstacle(mob/living/carbon/xenomorph/xeno, direction, turf/target) if(xeno.hivenumber != hivenumber) return ..() return 0 @@ -16,7 +16,7 @@ . = ..() // AIRLOCK -/obj/structure/machinery/door/airlock/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/obj/structure/machinery/door/airlock/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) if(locked || welded || isElectrified()) return INFINITY return DOOR_PENALTY @@ -26,7 +26,7 @@ return TRUE // OBJECTS -/obj/structure/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/obj/structure/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) if(!density) return 0 @@ -44,7 +44,7 @@ // HUMANS -/mob/living/carbon/human/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/mob/living/carbon/human/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) if(status_flags & GODMODE) return ..() return HUMAN_PENALTY @@ -56,7 +56,7 @@ return TRUE // VEHICLES -/obj/vehicle/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/obj/vehicle/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) return VEHICLE_PENALTY /obj/vehicle/xeno_ai_act(mob/living/carbon/xenomorph/X) @@ -64,7 +64,7 @@ return TRUE // SENTRY -/obj/structure/machinery/defenses/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/obj/structure/machinery/defenses/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) return VEHICLE_PENALTY /obj/structure/machinery/defenses/xeno_ai_act(mob/living/carbon/xenomorph/X) @@ -72,7 +72,7 @@ return TRUE // WINDOW FRAME -/obj/structure/window_frame/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/obj/structure/window_frame/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) if(X.claw_type == CLAW_TYPE_VERY_SHARP || (X.claw_type >= CLAW_TYPE_SHARP && !reinforced)) return ..() return WINDOW_FRAME_PENALTY @@ -83,11 +83,11 @@ do_climb(X) // Avoid barricades if possible. -/obj/structure/barricade/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction) +/obj/structure/barricade/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) return BARRICADE_PENALTY // FIRE -/obj/flamer_fire/xeno_ai_obstacle(mob/living/carbon/xenomorph/xeno, direction) +/obj/flamer_fire/xeno_ai_obstacle(mob/living/carbon/xenomorph/xeno, direction, turf/target) if(xeno.caste?.fire_immunity & (FIRE_IMMUNITY_NO_IGNITE|FIRE_IMMUNITY_NO_DAMAGE)) return 0 diff --git a/colonialmarines.dme b/colonialmarines.dme index 368466b1ff..06d41c4922 100644 --- a/colonialmarines.dme +++ b/colonialmarines.dme @@ -398,6 +398,8 @@ #include "code\datums\components\autofire\_automated_fire.dm" #include "code\datums\components\autofire\autofire.dm" #include "code\datums\components\xeno\shield_slash.dm" +#include "code\datums\components\xeno\ai_behavior_overrides\attack_override_behavior.dm" +#include "code\datums\components\xeno\ai_behavior_overrides\base_override_behavior.dm" #include "code\datums\construction\construction_template.dm" #include "code\datums\construction\xenomorph\construction_template_xenomorph.dm" #include "code\datums\decorators\decorator.dm" diff --git a/tgui/packages/tgui/interfaces/GameMaster.js b/tgui/packages/tgui/interfaces/GameMaster.js index 44e7e91b17..b0b593425b 100644 --- a/tgui/packages/tgui/interfaces/GameMaster.js +++ b/tgui/packages/tgui/interfaces/GameMaster.js @@ -6,144 +6,198 @@ export const GameMaster = (props, context) => { const { data, act } = useBackend(context); return ( - + - -
- - - - - { - act('set_xeno_spawns', { value }); - }} - /> - - - { - act('set_selected_xeno', { new_xeno }); - }} - /> - - - - - - - { - act('xeno_spawn_ai_toggle'); - }} - /> - - -
-
- - -
-
- - -
+ + + + + + + +
); }; + +export const SpawningPanel = (props, context) => { + const { data, act } = useBackend(context); + + return ( +
+ + + + + { + act('set_xeno_spawns', { value }); + }} + /> + + + { + act('set_selected_xeno', { new_xeno }); + }} + /> + + + + + + + { + act('xeno_spawn_ai_toggle'); + }} + /> + + +
+ ); +}; + +export const BehaviorPanel = (props, context) => { + const { data, act } = useBackend(context); + + return ( +
+ + + { + act('set_selected_behavior', { new_behavior }); + }} + /> + + +
+ ); +}; + +export const ObjectivePanel = (props, context) => { + const { data, act } = useBackend(context); + + return ( +
+ + +
+ ); +}; + +export const CommunicationPanel = (props, context) => { + const { data, act } = useBackend(context); + + return ( +
+ + +
+ ); +}; From a504dfabe7efc9355109184fcb0789339f3fe899 Mon Sep 17 00:00:00 2001 From: Morrow Date: Mon, 30 Oct 2023 08:13:55 -0400 Subject: [PATCH 7/7] another thing that may explode let's see --- code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm b/code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm index e9ab25136a..8aa80e9c22 100644 --- a/code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm +++ b/code/modules/mob/living/carbon/xenomorph/xeno_ai_interaction.dm @@ -18,7 +18,7 @@ // AIRLOCK /obj/structure/machinery/door/airlock/xeno_ai_obstacle(mob/living/carbon/xenomorph/X, direction, turf/target) if(locked || welded || isElectrified()) - return INFINITY + return ..() return DOOR_PENALTY /obj/structure/machinery/door/xeno_ai_act(mob/living/carbon/xenomorph/X)