Files
VOREStation/code/modules/ai/ai_holder_cooperation.dm
T
Cameron Lennox 84dc5535dc var/global/list -> GLOB. conversion (#17928)
* These two are easy

* !!!runlevel_flags

the fact it was global.runlevel_flags.len has me a bit...iffy on this.

* !!!json_cache

Same as above. used global.

* player_list & observer_mob_list

* mechas_list

* this wasn't even used

* surgery_steps

* event_triggers

* landmarks_list

* dead_mob_list

* living_mob_list

* ai_list

* cable_list

* cleanbot_reserved_turfs

* listening_objects

* silicon_mob_list

* human_mob_list

* Update global_lists.dm

* joblist

* mob_list

* Update global_lists.dm

* holomap_markers

* mapping_units

* mapping_beacons

* hair_styles_list

* facial_hair_styles_list

* Update global_lists.dm

* facial_hair_styles_male_list

* facial_hair_styles_female_list

* body_marking_styles_list

* body_marking_nopersist_list

* ear_styles_list

* hair_styles_male_list

* tail_styles_list

* wing_styles_list

* escape_list & rune_list & endgame_exits

these were all really small

* endgame_safespawns

* stool_cache

* emotes_by_key

* random_maps & map_count

* item_tf_spawnpoints

* narsie_list

* active_radio_jammers

* unused

* paikeys

* pai_software_by_key & default_pai_software

* plant_seed_sprites

* magazine_icondata_keys  & magazine_icondata_states

* unused

* ashtray_cache

* light_type_cache

* HOLIDAY!!!

this one was annoying

* faction stuff (red?!)

* Update preferences_factions.dm

* vs edit removal

* backbaglist, pdachoicelist, exclude_jobs

* item_digestion_blacklist, edible_tech, blacklisted_artifact_effect, selectable_footstep, hexNums, syndicate_access

* string_slot_flags and hexdigits->hexNums

* possible_changeling_IDs

* vr_mob_tf_options

* vr_mob_spawner_options

* pipe_colors

* vr_mob_spawner_options

* common_tools

* newscaster_standard_feeds

* Update periodic_news.dm

* changeling_fabricated_clothing

* semirandom_mob_spawner_decisions

* id_card_states

* Update syndicate_ids.dm

* overlay_cache & gear_distributed_to

* more

* radio_channels_by_freq

* Update global_lists.dm

* proper

* default_medbay_channels & default_internal_channels

default_internal_channels is weird as it has a mapbased proc() but that proc is never called...

* valid_ringtones

* move this

* possible_plants

* more

* separate these

moves xeno2chemlist from a hook to a new global list.

* tube_dir_list

* valid_bloodreagents & monitor_states

* Junk

* valid_bloodtypes

* breach_burn_descriptors & burn

* more!!

appliance_available_recipes seems uber cursed, re-look at later

* Appliance code is cursed

* wide_chassis & flying_chassis

* allows_eye_color

* all_tooltip_styles

* direction_table

* gun_choices

* severity_to_string

* old event_viruses

* description_icons

* MOVE_KEY_MAPPINGS

* more more

* pai & robot modules

* Update global_lists.dm

* GEOSAMPLES

Also swaps a .len to LAZYLEN()

* shieldgens

* reagent recipies

* global ammo types

* rad collector

* old file and unused global

* nif_look_messages

* FESH

* nifsoft

* chamelion

* the death of sortAtom

* globulins

* lazylen that

* Update global_lists.dm

* LAZY

* Theese too

* quick fix

---------

Co-authored-by: Kashargul <144968721+Kashargul@users.noreply.github.com>
2025-07-14 20:14:31 +02:00

118 lines
5.7 KiB
Plaintext

// Involves cooperating with other ai_holders.
/datum/ai_holder
var/cooperative = FALSE // If true, asks allies to help when fighting something.
var/call_distance = 14 // How far away calls for help will go for.
var/last_helpask_time = 0 // world.time when a mob asked for help.
var/list/faction_friends = list() // List of all mobs inside the faction with ai_holders that have cooperate on, to call for help without using range().
// Note that this is only used for sending calls out. Receiving calls doesn't care about this list, only if the mob is in the faction.
// This means the AI could respond to a player's call for help, if a way to do so was implemented.
// These vars don't do anything currently. They did before but an optimization made them nonfunctional.
// It was probably worth it.
var/call_players = FALSE // (Currently nonfunctional) If true, players get notified of an allied mob calling for help.
var/called_player_message = "needs help!" // (Currently nonfunctional) Part of a message used when above var is true. Full message is "\The [holder] [called_player_message]"
/datum/ai_holder/New(new_holder)
..()
if(cooperative)
build_faction_friends()
/datum/ai_holder/Destroy()
if(faction_friends)
if(faction_friends.len) //This list is shared amongst the faction
faction_friends -= src
return ..()
// Handles everything about that list.
// Call on initialization or if something weird happened like the mob switched factions.
/datum/ai_holder/proc/build_faction_friends()
if(faction_friends.len) // Already have a list.
// Assume we're moving to a new faction.
faction_friends -= src // Get us out of the current list shared by everyone else.
faction_friends = list() // Then make our list empty and unshared in case we become a loner.
// Find another AI-controlled mob in the same faction if possible.
var/mob/living/first_friend
for(var/mob/living/L in GLOB.living_mob_list)
if(L.faction == holder.faction && L.ai_holder)
first_friend = L
break
if(first_friend) // Joining an already established faction.
faction_friends = first_friend.ai_holder.faction_friends
faction_friends |= holder
else // We're the 'founder' (first and/or only member) of this faction.
faction_friends |= holder
// Requests help in combat from other mobs possessing ai_holders.
/datum/ai_holder/proc/request_help()
ai_log("request_help() : Entering.", AI_LOG_DEBUG)
if(!cooperative || ((world.time - last_helpask_time) < 10 SECONDS))
return
ai_log("request_help() : Asking for help.", AI_LOG_INFO)
last_helpask_time = world.time
// for(var/mob/living/L in range(call_distance, holder))
for(var/mob/living/L in faction_friends)
if(L == holder) // Lets not call ourselves.
continue
if(holder.z != L.z) // On seperate z-level.
continue
if(get_dist(L, holder) > call_distance) // Too far to 'hear' the call for help.
continue
if(holder.IIsAlly(L))
// This will currently never run sadly, until faction_friends is made to accept players too.
// That might be for the best since I can imagine it getting spammy in a big fight.
if(L.client && call_players) // Dealing with a player.
ai_log("request_help() : Asking [L] (Player) for help.", AI_LOG_INFO)
to_chat(L, span_critical("\The [holder] [called_player_message]"))
else if(L.ai_holder) // Dealing with an AI.
ai_log("request_help() : Asking [L] (AI) for help.", AI_LOG_INFO)
L.ai_holder.help_requested(holder)
ai_log("request_help() : Exiting.", AI_LOG_DEBUG)
// What allies receive when someone else is calling for help.1
/datum/ai_holder/proc/help_requested(mob/living/friend)
ai_log("help_requested() : Entering.", AI_LOG_DEBUG)
if(stance == STANCE_SLEEP)
ai_log("help_requested() : Help requested by [friend] but we are asleep.", AI_LOG_INFO)
return
if(!cooperative)
ai_log("help_requested() : Help requested by [friend] but we're not cooperative.", AI_LOG_INFO)
return
if(stance in STANCES_COMBAT)
ai_log("help_requested() : Help requested by [friend] but we are busy fighting something else.", AI_LOG_INFO)
return
if(!can_act())
ai_log("help_requested() : Help requested by [friend] but cannot act (stunned or dead).", AI_LOG_INFO)
return
if(!holder.IIsAlly(friend)) // Extra sanity.
ai_log("help_requested() : Help requested by [friend] but we hate them.", AI_LOG_INFO)
return
var/their_target = friend?.ai_holder?.target
if(their_target) // They have a target and aren't just shouting for no reason
if(!can_attack(their_target, vision_required = FALSE))
ai_log("help_requested() : Help requested by [friend] but we don't want to fight their target.", AI_LOG_INFO)
return
if(get_dist(holder, friend) <= follow_distance)
ai_log("help_requested() : Help requested by [friend] but we're already here.", AI_LOG_INFO)
return
if(get_dist(holder, friend) <= vision_range) // Within our sight.
ai_log("help_requested() : Help requested by [friend], and within target sharing range.", AI_LOG_INFO)
last_conflict_time = world.time // So we attack immediately and not threaten.
give_target(their_target, urgent = TRUE) // This will set us to the appropiate stance.
ai_log("help_requested() : Given target [target] by [friend]. Exiting", AI_LOG_DEBUG)
return
// Otherwise they're outside our sight, lack a target, or aren't AI controlled, but within call range.
// So assuming we're AI controlled, we'll go to them and see whats wrong.
ai_log("help_requested() : Help requested by [friend], going to go to friend.", AI_LOG_INFO)
if(their_target)
add_attacker(their_target) // We won't wait and 'warn' them while they're stabbing our ally
set_follow(friend, 10 SECONDS)
ai_log("help_requested() : Exiting.", AI_LOG_DEBUG)