-
-
Notifications
You must be signed in to change notification settings - Fork 165
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Update lobotomy-corp13.dme Update ai_leadership.dm Update indigo.dm
- Loading branch information
1 parent
482fd7d
commit 2e8a37b
Showing
4 changed files
with
332 additions
and
133 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,291 @@ | ||
/* Component for AI leadership. Ai will leader | ||
other mobs of the listed type. */ | ||
|
||
/datum/component/ai_leadership | ||
dupe_mode = COMPONENT_DUPE_UNIQUE | ||
//Cooldowns for recruitment | ||
var/recruit_cooldown = 0 | ||
var/recruit_delay = 2 SECONDS | ||
//Cooldowns for headcount | ||
var/headcount_cooldown = 0 | ||
var/headcount_delay = 25 SECONDS | ||
//Amount of allowed followers | ||
var/unit_amount | ||
//If the team should only have a certain amount of type. | ||
var/unqiue_team | ||
//If followers will return to a base when disbanded | ||
var/return_to_fob | ||
//Datum that tracks all of the components | ||
var/static/datum/collective_management/follower_tracker | ||
//Allowed types of followers | ||
var/list/possible_followers = list() | ||
//This components current followers. | ||
var/list/followers = list() | ||
|
||
/* This could use some improvement. | ||
Or a full on replacement. */ | ||
/datum/component/ai_leadership/Initialize(allowed_types, amount = 6, unique = FALSE, forwardbase = FALSE) | ||
if(!isatom(parent)) | ||
return COMPONENT_INCOMPATIBLE | ||
|
||
if(!follower_tracker) | ||
follower_tracker = new /datum/collective_management() | ||
var/atom/L = parent | ||
|
||
return_to_fob = forwardbase | ||
unqiue_team = unique | ||
unit_amount = amount | ||
possible_followers += allowed_types | ||
|
||
follower_tracker.AddLeader(L) | ||
ScanLocation() | ||
START_PROCESSING(SSdcs, src) | ||
|
||
/datum/component/ai_leadership/RegisterWithParent() | ||
if(isliving(parent)) | ||
RegisterSignal(parent, COMSIG_LIVING_DEATH, .proc/RemoveLeader) | ||
if(ishostile(parent)) | ||
RegisterSignal(parent, COMSIG_PATROL_START, .proc/HeadCount) | ||
|
||
/datum/component/ai_leadership/UnregisterFromParent() | ||
if(isliving(parent)) | ||
UnregisterSignal(parent, COMSIG_LIVING_DEATH) | ||
if(ishostile(parent)) | ||
UnregisterSignal(parent, COMSIG_PATROL_START) | ||
|
||
//On death remove this component and disband their followers. | ||
/datum/component/ai_leadership/proc/RemoveLeader() | ||
SIGNAL_HANDLER | ||
|
||
follower_tracker.RemoveLeader(parent, followers) | ||
STOP_PROCESSING(SSdcs, src) | ||
qdel(src) | ||
|
||
/datum/component/ai_leadership/process() | ||
//If not a hostile then it would not get a signal. | ||
if(!ishostile(parent) && world.time > headcount_cooldown && followers.len) | ||
HeadCount(parent) | ||
if(world.time > recruit_cooldown && followers.len < unit_amount) | ||
ScanLocation() | ||
recruit_cooldown = world.time + recruit_delay | ||
|
||
/*----------------------- | ||
|~ Main Function Procs ~| | ||
-----------------------*/ | ||
|
||
/*Scan proc for leader. Originally this was a proc | ||
in the hostile found since their targeting | ||
system scans everything all the time. */ | ||
/datum/component/ai_leadership/proc/ScanLocation() | ||
for(var/mob/living/L in view(7, parent)) | ||
if(followers.len >= unit_amount) | ||
break | ||
if(Recruitable(L)) | ||
Recruit(L) | ||
|
||
/*Checks the group of creatures to see if anyone is missing. | ||
Anyone missing will be removed from the group so that | ||
another team can recruit them.*/ | ||
/datum/component/ai_leadership/proc/HeadCount(atom/U) | ||
if(world.time < headcount_cooldown || !followers.len) | ||
return | ||
var/turf/fob | ||
var/list/whosehere = list() | ||
followers = uniqueList(followers) | ||
|
||
for(var/mob/living/L in followers) | ||
if(L.stat != DEAD && !L.client && L.z == U.z && get_dist(U, L) < 10) | ||
whosehere += L | ||
|
||
var/list/absent_troops = difflist(followers, whosehere ,1) | ||
if(absent_troops.len) | ||
if(return_to_fob) | ||
//Only run this once. | ||
fob = get_turf(FindForwardBase()) | ||
for(var/mob/living/S in absent_troops) | ||
Disband(S) | ||
if(ishostile(S)) | ||
var/mob/living/simple_animal/hostile/R = S | ||
if(fob && R.stat != DEAD && !R.target) | ||
walk(R, 0) | ||
R.patrol_to(fob) | ||
headcount_cooldown = world.time + headcount_delay | ||
Regroup() | ||
|
||
/*--------------------- | ||
|~ Follower Commands ~| | ||
---------------------*/ | ||
|
||
//Command follower to follow leader. | ||
/datum/component/ai_leadership/proc/FollowLeader(mob/living/L) | ||
if(ishostile(parent)) | ||
var/mob/living/simple_animal/hostile/H = parent | ||
walk_to(L, parent, 2, H.move_to_delay - 1.5) | ||
if(iscarbon(parent)) | ||
var/mob/living/carbon/H = parent | ||
walk_to(L, parent, 2, H.cached_multiplicative_slowdown - 1.5) | ||
else if(ishostile(L)) | ||
var/mob/living/simple_animal/hostile/R = L | ||
if(!R.target) | ||
walk_to(R, parent, 2, R.move_to_delay) | ||
else | ||
return FALSE | ||
return TRUE | ||
|
||
//Orders all troops to follow the leader. | ||
/datum/component/ai_leadership/proc/Regroup() | ||
for(var/i in followers) | ||
FollowLeader(i) | ||
|
||
/*----------------- | ||
|~ System Checks ~| | ||
-----------------*/ | ||
|
||
/*Determines if the creature is recruitable | ||
based on their current status and faction.*/ | ||
/datum/component/ai_leadership/proc/Recruitable(mob/living/L) | ||
//Are we at maximum followers | ||
if(followers.len >= unit_amount) | ||
return FALSE | ||
//Are they dead? | ||
if(L.stat == DEAD) | ||
return FALSE | ||
//Player controlled, they do not recognize our authroity. | ||
if(L.client) | ||
return FALSE | ||
//If we are a hostile do these checks | ||
if(ishostile(parent)) | ||
var/mob/living/simple_animal/hostile/H = parent | ||
//Are they the same faction as us? | ||
if(!H.faction_check_mob(L)) | ||
return FALSE | ||
//If they currently have a target let them finish up. | ||
if(H.target) | ||
return FALSE | ||
var/recruit_type = CheckUnitType(possible_followers, L) | ||
//Are they a type in our possible follower types? | ||
if(!recruit_type) | ||
return FALSE | ||
//If we only have the command capacity to command more than one of them. | ||
if(unqiue_team) | ||
if(!TeamCheck(L)) | ||
return FALSE | ||
//Are they already a follower of another leader? | ||
if(FollowerLedger(L)) | ||
return FALSE | ||
return TRUE | ||
|
||
//Register recruit with the system | ||
/datum/component/ai_leadership/proc/Recruit(mob/living/L) | ||
followers += L | ||
follower_tracker.RecruitFollower(L) | ||
FollowLeader(L) | ||
|
||
//Releases the recruit from our command | ||
/datum/component/ai_leadership/proc/Disband(mob/living/L) | ||
followers -= L | ||
follower_tracker.DismissFollower(L) | ||
|
||
//Is the recruit already recruited in the system? | ||
/datum/component/ai_leadership/proc/FollowerLedger(mob/living/recruit) | ||
if(follower_tracker.FindRecruit(recruit)) | ||
return TRUE | ||
return FALSE | ||
|
||
//Check the type system | ||
/datum/component/ai_leadership/proc/CheckUnitType(list/type_list, mob/living/unit_type) | ||
for(var/i in type_list) | ||
if(unit_type.type == i) | ||
return i | ||
return null | ||
|
||
//Checks if theres any room for this unit in the team. | ||
/datum/component/ai_leadership/proc/TeamCheck(mob/living/M) | ||
var/many_we_have = CountByTroopType(M) | ||
var/our_capacity = 0 | ||
for(var/i in possible_followers) | ||
if(M.type == i) | ||
our_capacity = possible_followers[i] | ||
break | ||
if(our_capacity <= many_we_have) | ||
return FALSE | ||
return TRUE | ||
|
||
/*Used to be count by type until i realized count by | ||
type includes subtypes when i need a strict type.*/ | ||
/datum/component/ai_leadership/proc/CountByTroopType(mob/living/M) | ||
if(!M) | ||
return 0 | ||
var/counting_dudes = 0 | ||
for(var/mob/living/dude in followers) | ||
if(dude.type == M.type) | ||
counting_dudes++ | ||
return counting_dudes | ||
|
||
//Calculate a base to return to, usually is a department. | ||
/datum/component/ai_leadership/proc/FindForwardBase() | ||
var/mob/living/L = parent | ||
var/turf/second_choice | ||
for(var/turf/T in GLOB.department_centers) | ||
if(T.z != L.z) | ||
continue | ||
second_choice = T | ||
if(istype(get_area(T), /area/department_main/command)) | ||
return T | ||
return second_choice | ||
|
||
/*-----------------------\ | ||
| Group Mind Datum | | ||
\-----------------------*/ | ||
|
||
/datum/collective_management | ||
var/list/leaders = list() | ||
var/list/follower_list = list() | ||
|
||
//Called by component recruit | ||
/datum/collective_management/proc/RecruitFollower(follower) | ||
if(!follower) | ||
return FALSE | ||
LAZYADD(follower_list, follower) | ||
return TRUE | ||
|
||
//Called when a follower is removed from component and list. | ||
/datum/collective_management/proc/DismissFollower(follower) | ||
if(!follower) | ||
return FALSE | ||
CheckLedger() | ||
LAZYREMOVE(follower_list, follower) | ||
return TRUE | ||
|
||
//Registers leader into the system | ||
/datum/collective_management/proc/AddLeader(leader) | ||
if(LAZYFIND(leaders, leader)) | ||
return FALSE | ||
CheckLedger() | ||
LAZYADD(leaders, leader) | ||
return TRUE | ||
|
||
//Removes leader from the ledger | ||
/datum/collective_management/proc/RemoveLeader(leader, followers) | ||
CheckLedger() | ||
LAZYREMOVE(leaders, leader) | ||
for(var/minion in followers) | ||
DismissFollower(minion) | ||
|
||
//Checks to find if recruit is already in the system | ||
/datum/collective_management/proc/FindRecruit(follower) | ||
if(LAZYFIND(follower_list, follower)) | ||
return TRUE | ||
return FALSE | ||
|
||
//Does technical fixes such as remove nulls and duplicates | ||
/datum/collective_management/proc/CheckLedger() | ||
//Remove duplicates. | ||
var/fixed_leader_list = uniqueList(leaders) | ||
var/fixed_follower_list = uniqueList(follower_list) | ||
//Replace list with a sorted fixed version. | ||
leaders = sortNames(fixed_leader_list) | ||
follower_list = sortNames(fixed_follower_list) | ||
//Remove nulls. | ||
listclearnulls(leaders) | ||
listclearnulls(follower_list) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.