mirror of
https://github.com/vgstation-coders/vgstation13.git
synced 2025-12-10 10:21:11 +00:00
Ported component AI to the new component system (#30751)
* wip new component ai * wip 2 * he lives * fixes * comment
This commit is contained in:
@@ -2,7 +2,7 @@
|
||||
var/list/datum_components
|
||||
|
||||
/datum/proc/initialize()
|
||||
return
|
||||
return TRUE
|
||||
|
||||
//Called when a variable is edited by admin powers
|
||||
//Return 1 to block the varedit!
|
||||
|
||||
@@ -14,7 +14,7 @@ var/global/list/cyborg_list = list() //List of all living cyborgs, includin
|
||||
var/global/list/dead_mob_list = list() //List of all dead mobs, including clientless. Excludes /mob/new_player
|
||||
var/list/observers = new/list()
|
||||
var/global/list/areas = list()
|
||||
var/global/list/active_component_containers = list() //List of all component containers that have registered for updating
|
||||
var/global/list/active_components = list() //List of all components that have registered for updating
|
||||
|
||||
var/global/list/chemical_reactions_list //list of all /datum/chemical_reaction datums. Used during chemical reactions
|
||||
var/global/list/chemical_reagents_list //list of all /datum/reagent datums indexed by reagent id. Used by chemistry stuff
|
||||
|
||||
@@ -238,6 +238,28 @@
|
||||
// mob/source: the mob performing the emote
|
||||
/event/emote
|
||||
|
||||
/event/comp_ai_friend_attacked
|
||||
|
||||
/event/comp_ai_cmd_get_best_target
|
||||
/event/comp_ai_cmd_add_target
|
||||
/event/comp_ai_cmd_remove_target
|
||||
/event/comp_ai_cmd_find_targets
|
||||
|
||||
/event/comp_ai_cmd_can_attack
|
||||
/event/comp_ai_cmd_move
|
||||
/event/comp_ai_cmd_attack
|
||||
/event/comp_ai_cmd_evaluate_target
|
||||
/event/comp_ai_cmd_get_damage_type
|
||||
|
||||
/event/comp_ai_cmd_set_busy
|
||||
/event/comp_ai_cmd_get_busy
|
||||
|
||||
/event/comp_ai_cmd_set_target
|
||||
/event/comp_ai_cmd_get_target
|
||||
|
||||
/event/comp_ai_cmd_set_state
|
||||
/event/comp_ai_cmd_get_state
|
||||
|
||||
/datum
|
||||
/// Associative list of type path -> list(),
|
||||
/// where the type path is a descendant of /event_type.
|
||||
@@ -262,12 +284,13 @@
|
||||
if(!length(event_handlers))
|
||||
// This datum does not have any handler registered for this event_type.
|
||||
return
|
||||
. = NONE
|
||||
for(var/key in event_handlers)
|
||||
var/list/handler = event_handlers[key]
|
||||
var/objRef = handler[EVENT_HANDLER_OBJREF_INDEX]
|
||||
var/procName = handler[EVENT_HANDLER_PROCNAME_INDEX]
|
||||
. |= call(objRef, procName)(arglist(arguments))
|
||||
// not |= because `null |= list()` is a runtime error
|
||||
// but `null = null | list()` is not.
|
||||
. = . | call(objRef, procName)(arglist(arguments))
|
||||
|
||||
/**
|
||||
* Registers a proc to be called on an object whenever the specified event_type
|
||||
|
||||
@@ -32,8 +32,7 @@
|
||||
I.attack(src, user, def_zone, originator)
|
||||
else
|
||||
I.attack(src, user, def_zone)
|
||||
if(BrainContainer)
|
||||
BrainContainer.SendSignal(COMSIG_ATTACKEDBY, list("assailant"=user,"damage"=I.force))
|
||||
invoke_event(/event/attackby, list("attacker" = user, "item" = I))
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -15,27 +15,21 @@ var/datum/subsystem/component/SScomp
|
||||
|
||||
|
||||
/datum/subsystem/component/stat_entry()
|
||||
..("P:[active_component_containers.len]")
|
||||
..("P:[active_components.len]")
|
||||
|
||||
|
||||
/datum/subsystem/component/fire(resumed = FALSE)
|
||||
if (!resumed)
|
||||
currentrun = active_component_containers.Copy()
|
||||
currentrun = active_components.Copy()
|
||||
|
||||
while (currentrun.len)
|
||||
var/datum/component_container/C = currentrun[currentrun.len]
|
||||
var/datum/component/C = currentrun[currentrun.len]
|
||||
currentrun.len--
|
||||
|
||||
if(!C || C.gcDestroyed || !C.holder || !C.components.len)
|
||||
if(!C || C.gcDestroyed)
|
||||
continue
|
||||
|
||||
if(isliving(C.holder))
|
||||
var/mob/living/M = C.holder
|
||||
if (!M || M.gcDestroyed || M.timestopped || M.monkeyizing || M.stat == DEAD)
|
||||
continue
|
||||
|
||||
|
||||
C.SendSignal(COMSIG_LIFE, list())
|
||||
C.process()
|
||||
|
||||
if(MC_TICK_CHECK)
|
||||
return
|
||||
|
||||
@@ -78,7 +78,7 @@ var/global/list/pathmakers = list()
|
||||
var/list/closed = new() //the closed list
|
||||
var/list/path = null //the returned path, if any
|
||||
var/PathNode/cur //current processed turf
|
||||
var/proc_to_call //how we can tell the owner the finished path
|
||||
var/callback/callback //how we can tell the owner the finished path
|
||||
|
||||
var/adjacent //How we check which turfs that are adjacent to our checked turf are valid
|
||||
var/dist //How we check the distance between points
|
||||
@@ -90,16 +90,16 @@ var/global/list/pathmakers = list()
|
||||
var/debug = FALSE //Whether we paint our turfs as we calculate
|
||||
var/PM_id //How we will identify PathNodes associated with this, to prevent PathNode conflict
|
||||
|
||||
/datum/path_maker/New(var/nowner, var/nproc_to_call, var/turf/nstart, var/turf/nend, var/atom/ntarget, var/nadjacent, var/ndist, var/nmaxnodes, var/nmaxnodedepth, var/nmintargetdist, var/nid=null, var/turf/nexclude, var/ndebug)
|
||||
/datum/path_maker/New(var/nowner, var/ncallback, var/turf/nstart, var/turf/nend, var/atom/ntarget, var/nadjacent, var/ndist, var/nmaxnodes, var/nmaxnodedepth, var/nmintargetdist, var/nid=null, var/turf/nexclude, var/ndebug)
|
||||
ASSERT(nowner)
|
||||
ASSERT(nstart)
|
||||
ASSERT(nend)
|
||||
ASSERT(nproc_to_call)
|
||||
ASSERT(ncallback)
|
||||
|
||||
owner = nowner
|
||||
start = nstart
|
||||
end = nend
|
||||
proc_to_call = nproc_to_call
|
||||
callback = ncallback
|
||||
target = ntarget
|
||||
adjacent = nadjacent
|
||||
dist = ndist
|
||||
@@ -216,7 +216,7 @@ var/global/list/pathmakers = list()
|
||||
astar_debug("open:[open.List().len]")
|
||||
|
||||
/datum/path_maker/proc/fail()
|
||||
call(owner, proc_to_call)()
|
||||
callback.invoke_async()
|
||||
qdel(src)
|
||||
|
||||
/datum/path_maker/proc/finish()
|
||||
@@ -230,5 +230,5 @@ var/global/list/pathmakers = list()
|
||||
for(var/i = 1; i <= path.len/2; i++)
|
||||
path.Swap(i,path.len-i+1)
|
||||
|
||||
call(owner, proc_to_call)(path.Copy(), target)
|
||||
callback.invoke_async(path.Copy(), target)
|
||||
qdel(src)
|
||||
|
||||
@@ -77,3 +77,6 @@
|
||||
. = get_component(c_type)
|
||||
if(!.)
|
||||
return add_component(arglist(args))
|
||||
|
||||
/datum/component/proc/process()
|
||||
set waitfor = FALSE
|
||||
|
||||
@@ -170,7 +170,7 @@ length to avoid portals or something i guess?? Not that they're counted right no
|
||||
/*
|
||||
* ASTAR
|
||||
* source: the atom which calls this Astar call.TRUE
|
||||
* proc_to_call: the proc to call on the source
|
||||
* callback: the callback to invoke when the path is ready
|
||||
* start: starting atom
|
||||
* end: end of targetted path
|
||||
* Adjacent: the proc which rules what is adjacent for us
|
||||
@@ -180,7 +180,7 @@ length to avoid portals or something i guess?? Not that they're counted right no
|
||||
* Creates a pathmaker datum to process the path if we aren't processing the path.
|
||||
* Returns nothing if this path is already being processed.
|
||||
*/
|
||||
/proc/AStar(source, proc_to_call, start,end,adjacent,dist,maxnodes,maxnodedepth = 30,mintargetdist,minnodedist,id=null, var/turf/exclude=null, var/debug = ASTAR_DEBUG)
|
||||
/proc/AStar(source, callback, start,end,adjacent,dist,maxnodes,maxnodedepth = 30,mintargetdist,minnodedist,id=null, var/turf/exclude=null, var/debug = ASTAR_DEBUG)
|
||||
ASSERT(!istype(end,/area)) //Because yeah some things might be doing this and we want to know what
|
||||
if(start:z != end:z) //if you're feeling ambitious and make something that can ASTAR through z levels, feel free to remove this check
|
||||
return ASTAR_FAIL
|
||||
@@ -191,8 +191,8 @@ length to avoid portals or something i guess?? Not that they're counted right no
|
||||
if(!isturf(end))
|
||||
target = end
|
||||
|
||||
astar_debug("ASTAR called [source] [proc_to_call] [start:x][start:y][start:z] [end:x][end:y][end:z] [adjacent] [dist] [maxnodes] [maxnodedepth] [mintargetdist] [minnodedist] [id] [exclude] [debug]")
|
||||
new /datum/path_maker(source,proc_to_call, get_turf(start), get_turf(end), target, adjacent, dist, maxnodes, maxnodedepth, mintargetdist, id, exclude, debug)
|
||||
astar_debug("ASTAR called [source] [callback] [start:x],[start:y],[start:z] [end:x],[end:y],[end:z] [adjacent] [dist] [maxnodes] [maxnodedepth] [mintargetdist] [minnodedist] [id] [exclude] [debug]")
|
||||
new /datum/path_maker(source,callback, get_turf(start), get_turf(end), target, adjacent, dist, maxnodes, maxnodedepth, mintargetdist, id, exclude, debug)
|
||||
return ASTAR_REGISTERED
|
||||
|
||||
// Only use if you just need to check if a path exists, and is a reasonable length
|
||||
@@ -394,8 +394,8 @@ length to avoid portals or something i guess?? Not that they're counted right no
|
||||
|
||||
/////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/atom/proc/make_astar_path(var/atom/target, var/receiving_proc = .proc/get_astar_path)
|
||||
AStar(src, receiving_proc, get_turf(src), target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 30, 30)
|
||||
/atom/proc/make_astar_path(var/atom/target, var/callback = new /callback(src, .proc/get_astar_path))
|
||||
AStar(src, callback, get_turf(src), target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 30, 30)
|
||||
|
||||
//override when needed to receive your path
|
||||
/atom/proc/get_astar_path(var/list/L)
|
||||
|
||||
@@ -185,7 +185,7 @@
|
||||
if(target)
|
||||
if (waiting_for_path)
|
||||
return 1
|
||||
calc_path(target, .proc/get_path)
|
||||
calc_path(target, new /callback(src, .proc/get_path))
|
||||
if (path && length(path))
|
||||
process_path()
|
||||
return 1
|
||||
@@ -225,7 +225,7 @@
|
||||
if(frustration > 5)
|
||||
summoned = FALSE // Let's not try again.
|
||||
if (target && !target.gcDestroyed)
|
||||
calc_path(target, .proc/get_path, next)
|
||||
calc_path(target, new /callback(src, .proc/get_path), next)
|
||||
else
|
||||
target = null
|
||||
path = list()
|
||||
@@ -306,7 +306,7 @@
|
||||
|
||||
if(patrol_target)
|
||||
waiting_for_patrol = TRUE
|
||||
calc_patrol_path(patrol_target, .proc/get_patrol_path)
|
||||
calc_patrol_path(patrol_target, new /callback(.proc/get_patrol_path))
|
||||
// This proc send out a singal to every beacon listening to the "beacon_freq" variable.
|
||||
// The signal says, "i'm a bot looking for a beacon to patrol to."
|
||||
// Every beacon with the flag "patrol" responds by trasmitting its location.
|
||||
@@ -368,7 +368,7 @@
|
||||
return TRUE
|
||||
if(frustration > 5)
|
||||
if (target && !target.gcDestroyed)
|
||||
calc_path(target, .proc/get_path, next)
|
||||
calc_path(target, new /callback(src, .proc/get_path), next)
|
||||
else
|
||||
target = null
|
||||
patrol_path = list()
|
||||
@@ -484,11 +484,11 @@
|
||||
|
||||
// Caluculate a path between the bot and the target.
|
||||
// Target is the target to go to.
|
||||
// proc_to_call is the proc which is called by the pathmaker once it's done its work and wishes to return a path.
|
||||
// callback gets called by the pathmaker once it's done its work and wishes to return a path.
|
||||
// avoid is a turf the path should NOT go through. (a previous obstacle.) This info is then given to the pathmaker.
|
||||
// Fast bots use quick_AStar method to direcly calculate a path and move on it.
|
||||
/obj/machinery/bot/proc/calc_path(var/target, var/proc_to_call, var/turf/avoid = null)
|
||||
ASSERT(target && proc_to_call)
|
||||
/obj/machinery/bot/proc/calc_path(var/target, var/callback, var/turf/avoid = null)
|
||||
ASSERT(target && callback)
|
||||
var/cardinal_proc = bot_flags & BOT_SPACEWORTHY ? /turf/proc/AdjacentTurfsSpace : /turf/proc/CardinalTurfsWithAccess
|
||||
if ((get_dist(src, target) < 13) && !(bot_flags & BOT_NOT_CHASING)) // For beepers and ED209
|
||||
// IMPORTANT: Quick AStar only takes TURFS as arguments.
|
||||
@@ -497,12 +497,12 @@
|
||||
log_astar_bot("path is [path.len]")
|
||||
return TRUE
|
||||
waiting_for_path = 1
|
||||
. = AStar(src, proc_to_call, src.loc, target, cardinal_proc, /turf/proc/Distance_cardinal, 0, max(10,get_dist(src,target)*3), id=botcard, exclude=avoid)
|
||||
. = AStar(src, callback, src.loc, target, cardinal_proc, /turf/proc/Distance_cardinal, 0, max(10,get_dist(src,target)*3), id=botcard, exclude=avoid)
|
||||
if (!.)
|
||||
waiting_for_path = 0
|
||||
|
||||
/obj/machinery/bot/proc/calc_patrol_path(var/target, var/proc_to_call, var/turf/avoid = null)
|
||||
ASSERT(target && proc_to_call)
|
||||
/obj/machinery/bot/proc/calc_patrol_path(var/target, var/callback, var/turf/avoid = null)
|
||||
ASSERT(target && callback)
|
||||
log_astar_beacon("[new_destination]")
|
||||
var/cardinal_proc = bot_flags & BOT_SPACEWORTHY ? /turf/proc/AdjacentTurfsSpace : /turf/proc/CardinalTurfsWithAccess
|
||||
if ((get_dist(src, target) < 13) && !(bot_flags & BOT_NOT_CHASING)) // For beepers and ED209
|
||||
@@ -510,7 +510,7 @@
|
||||
waiting_for_patrol = FALSE // Case we are calculating a quick path for a patrol.
|
||||
patrol_path = quick_AStar(src.loc, get_turf(target), cardinal_proc, /turf/proc/Distance_cardinal, 0, max(10,get_dist(src,target)*3), id=botcard, exclude=avoid, reference="\ref[src]")
|
||||
return TRUE
|
||||
return AStar(src, proc_to_call, src.loc, target, cardinal_proc, /turf/proc/Distance_cardinal, 0, max(10,get_dist(src,target)*3), id=botcard, exclude=avoid)
|
||||
return AStar(src, callback, src.loc, target, cardinal_proc, /turf/proc/Distance_cardinal, 0, max(10,get_dist(src,target)*3), id=botcard, exclude=avoid)
|
||||
|
||||
|
||||
// This proc is called by the path maker once it has calculated a path.
|
||||
|
||||
@@ -1,13 +1 @@
|
||||
/datum/component/ai
|
||||
var/datum/component/controller/controller
|
||||
|
||||
var/state=0 // AI_STATE_* of the AI.
|
||||
|
||||
/datum/component/ai/RecieveSignal(var/message_type, var/list/args)
|
||||
switch(message_type)
|
||||
if(COMSIG_STATE) // list("name"="statename")
|
||||
state = args["name"]
|
||||
|
||||
/datum/component/ai/New(var/datum/component_container/CC)
|
||||
..(CC)
|
||||
controller=GetComponent(/datum/component/controller)
|
||||
|
||||
@@ -20,30 +20,22 @@
|
||||
|
||||
var/min_overheat_temp=40
|
||||
|
||||
/datum/component/ai/atmos_checker/RecieveSignal(var/message_type, var/list/args)
|
||||
switch(message_type)
|
||||
if("life")
|
||||
OnLife()
|
||||
else
|
||||
..(message_type, args)
|
||||
|
||||
/datum/component/ai/atmos_checker/proc/OnLife()
|
||||
if(!isliving(container.holder))
|
||||
return 1
|
||||
if(container.holder & INVULNERABLE)
|
||||
/datum/component/ai/atmos_checker/process()
|
||||
var/mob/living/dude = parent
|
||||
if(dude.flags & INVULNERABLE)
|
||||
return 1
|
||||
|
||||
var/atmos_suitable = 1
|
||||
|
||||
var/atom/A = container.holder.loc
|
||||
var/atom/A = dude.loc
|
||||
|
||||
if(isturf(A))
|
||||
var/turf/T = A
|
||||
var/datum/gas_mixture/Environment = T.return_air()
|
||||
|
||||
if(Environment)
|
||||
if(abs(Environment.temperature - controller.getBodyTemperature()) > min_overheat_temp)
|
||||
SendSignal(COMSIG_ADJUST_BODYTEMP, list("temp"=((Environment.temperature - controller.getBodyTemperature()) / 5)))
|
||||
if(abs(Environment.temperature - dude.bodytemperature) > min_overheat_temp)
|
||||
dude.bodytemperature = (Environment.temperature - dude.bodytemperature) / 5
|
||||
|
||||
if(min_oxy)
|
||||
if(Environment.molar_density(GAS_OXYGEN) < min_oxy)
|
||||
@@ -84,14 +76,14 @@
|
||||
atmos_suitable = 0
|
||||
|
||||
//Atmos effect
|
||||
if(controller.getBodyTemperature() < minbodytemp)
|
||||
if(dude.bodytemperature < minbodytemp)
|
||||
fire_alert = 2
|
||||
SendSignal(COMSIG_ADJUST_BRUTE, list("amount"=cold_damage_per_tick))
|
||||
else if(controller.getBodyTemperature() > maxbodytemp)
|
||||
dude.adjustBruteLoss(cold_damage_per_tick)
|
||||
else if(dude.bodytemperature > maxbodytemp)
|
||||
fire_alert = 1
|
||||
SendSignal(COMSIG_ADJUST_BRUTE, list("amount"=heat_damage_per_tick))
|
||||
dude.adjustBruteLoss(heat_damage_per_tick)
|
||||
else
|
||||
fire_alert = 0
|
||||
|
||||
if(!atmos_suitable)
|
||||
SendSignal(COMSIG_ADJUST_BRUTE, list("amount"=unsuitable_damage))
|
||||
dude.adjustBruteLoss(unsuitable_damage)
|
||||
|
||||
@@ -1,68 +1,46 @@
|
||||
/datum/component/controller
|
||||
var/atom/holder
|
||||
var/_busy = FALSE
|
||||
var/atom/_target = null
|
||||
|
||||
var/_busy=FALSE
|
||||
var/atom/_target=null
|
||||
var/_state = HOSTILE_STANCE_IDLE
|
||||
|
||||
var/_state=HOSTILE_STANCE_IDLE
|
||||
/datum/component/controller/initialize()
|
||||
parent.register_event(/event/comp_ai_cmd_set_busy, src, .proc/cmd_set_busy)
|
||||
parent.register_event(/event/comp_ai_cmd_get_busy, src, .proc/cmd_get_busy)
|
||||
|
||||
/datum/component/controller/New(var/datum/component_container/container, var/atom/_holder)
|
||||
..(container)
|
||||
holder=_holder
|
||||
parent.register_event(/event/comp_ai_cmd_set_target, src, .proc/cmd_set_target)
|
||||
parent.register_event(/event/comp_ai_cmd_get_target, src, .proc/cmd_get_target)
|
||||
|
||||
parent.register_event(/event/comp_ai_cmd_set_state, src, .proc/cmd_set_state)
|
||||
parent.register_event(/event/comp_ai_cmd_get_state, src, .proc/cmd_get_state)
|
||||
|
||||
return TRUE
|
||||
|
||||
/datum/component/controller/Destroy()
|
||||
holder = null
|
||||
parent.unregister_event(/event/comp_ai_cmd_set_busy, src, .proc/cmd_set_busy)
|
||||
parent.unregister_event(/event/comp_ai_cmd_get_busy, src, .proc/cmd_get_busy)
|
||||
|
||||
parent.unregister_event(/event/comp_ai_cmd_set_target, src, .proc/cmd_set_target)
|
||||
parent.unregister_event(/event/comp_ai_cmd_get_target, src, .proc/cmd_get_target)
|
||||
|
||||
parent.unregister_event(/event/comp_ai_cmd_set_state, src, .proc/cmd_set_state)
|
||||
parent.unregister_event(/event/comp_ai_cmd_get_state, src, .proc/cmd_get_state)
|
||||
return ..()
|
||||
|
||||
// Called when we are bumped by another movable atom.
|
||||
/datum/component/controller/proc/OnBumped(var/atom/A)
|
||||
if(istype(A, /atom/movable))
|
||||
var/atom/movable/AM = A
|
||||
SendSignal(COMSIG_BUMPED, list("movable"=AM))
|
||||
|
||||
// Called when we bump another movable atom.
|
||||
/datum/component/controller/proc/Onto_bump(var/atom/A)
|
||||
if(istype(A, /atom/movable))
|
||||
var/atom/movable/AM = A
|
||||
SendSignal(COMSIG_BUMP, list("movable"=AM))
|
||||
|
||||
// Called when we receive the Life() tick from the MC/scheduler/whatever
|
||||
/datum/component/controller/proc/Life()
|
||||
SendSignal(COMSIG_LIFE, list())
|
||||
|
||||
//* Mob calls these to send signals to components. */
|
||||
/datum/component/controller/proc/AttackTarget(var/atom/A)
|
||||
container.SendSignalToFirst(/datum/component/ai, COMSIG_ATTACKING, list("target"=A))
|
||||
|
||||
/datum/component/controller/proc/setBusy(var/yes)
|
||||
/datum/component/controller/proc/cmd_set_busy(yes)
|
||||
_busy = yes
|
||||
SendSignal(COMSIG_BUSY, list("state"=_busy))
|
||||
|
||||
/datum/component/controller/proc/getBusy()
|
||||
/datum/component/controller/proc/cmd_get_busy()
|
||||
return _busy
|
||||
|
||||
/datum/component/controller/proc/setTarget(var/atom/A)
|
||||
_target = A
|
||||
SendSignal(COMSIG_TARGET, list("target"=_target))
|
||||
/datum/component/controller/proc/cmd_set_target(atom/target)
|
||||
_target = target
|
||||
|
||||
/datum/component/controller/proc/getTarget()
|
||||
/datum/component/controller/proc/cmd_get_target()
|
||||
return _target
|
||||
|
||||
/datum/component/controller/proc/setState(var/new_state)
|
||||
/datum/component/controller/proc/cmd_set_state(new_state)
|
||||
_state = new_state
|
||||
SendSignal(COMSIG_STATE, list("state"=_state))
|
||||
|
||||
/datum/component/controller/proc/getState()
|
||||
/datum/component/controller/proc/cmd_get_state()
|
||||
return _state
|
||||
|
||||
/datum/component/controller/proc/setBodyTemperature(var/temp)
|
||||
SendSignal(COMSIG_SET_BODYTEMP, list("temp"=temp,"from"=src))
|
||||
|
||||
/datum/component/controller/proc/getBodyTemperature()
|
||||
return -1
|
||||
|
||||
/datum/component/controller/proc/canAttack(var/atom/A)
|
||||
if(istype(container.holder, /mob/living/simple_animal))
|
||||
var/mob/living/simple_animal/SA = container.holder
|
||||
return SA.CanAttack(A)
|
||||
return FALSE
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/datum/component/controller/mob
|
||||
var/walk_delay=4
|
||||
|
||||
/datum/component/controller/mob/RecieveSignal(var/message_type, var/list/args)
|
||||
if(isliving(container.holder))
|
||||
var/mob/living/M=container.holder
|
||||
//testing("Got command: \[[message_type]\]: [json_encode(args)]")
|
||||
switch(message_type)
|
||||
if(COMSIG_CLICKON)
|
||||
var/atom/A = args["target"]
|
||||
var/params
|
||||
if(args["def_zone"])
|
||||
var/list/L = list("def_zone" = args["def_zone"])
|
||||
params = list2params(L)
|
||||
M.ClickOn(A, params)
|
||||
if(COMSIG_STEP)
|
||||
step(M, args["dir"], walk_delay)
|
||||
|
||||
if(COMSIG_ADJUST_BODYTEMP) // list("temp"=TEMP_IN_KELVIN)
|
||||
M.bodytemperature += args["temp"]
|
||||
|
||||
if(COMSIG_SET_BODYTEMP) // list("temp"=TEMP_IN_KELVIN)
|
||||
M.bodytemperature = args["temp"]
|
||||
|
||||
if(COMSIG_STATE) // list("state"=HOSTILE_STANCE_ATTACK)
|
||||
setState(args["state"])
|
||||
@@ -1,42 +1,61 @@
|
||||
/datum/component/controller/movement
|
||||
var/walk_delay = 4
|
||||
|
||||
/datum/component/controller/movement/basic/RecieveSignal(var/message_type, var/list/args)
|
||||
if(isliving(container.holder))
|
||||
var/mob/living/M=container.holder
|
||||
switch(message_type)
|
||||
if(COMSIG_MOVE)
|
||||
if("loc" in args)
|
||||
M.start_walk_to(args["loc"], 1, walk_delay)
|
||||
if("dir" in args)
|
||||
M.set_glide_size(DELAY2GLIDESIZE(walk_delay))
|
||||
walk(M, args["dir"], walk_delay)
|
||||
/datum/component/controller/movement/initialize()
|
||||
parent.register_event(/event/comp_ai_cmd_move, src, .proc/cmd_move)
|
||||
return TRUE
|
||||
|
||||
/datum/component/controller/movement/Destroy()
|
||||
parent.unregister_event(/event/comp_ai_cmd_move, src, .proc/cmd_move)
|
||||
..()
|
||||
|
||||
/datum/component/controller/movement/proc/cmd_move(target)
|
||||
CRASH("not implemented")
|
||||
|
||||
/datum/component/controller/movement/basic/cmd_move(target)
|
||||
var/mob/living/dude = parent
|
||||
if(isatom(target))
|
||||
dude.start_walk_to(target, 1, walk_delay)
|
||||
else if(isnum(target))
|
||||
dude.set_glide_size(DELAY2GLIDESIZE(walk_delay))
|
||||
walk(dude, target, walk_delay)
|
||||
else
|
||||
CRASH("target [target] is not an atom or a dir")
|
||||
/datum/component/controller/movement/astar
|
||||
var/list/movement_nodes = list()
|
||||
var/target
|
||||
|
||||
/datum/component/controller/movement/astar/RecieveSignal(var/message_type, var/list/args)
|
||||
if(isliving(container.holder))
|
||||
var/mob/living/M=container.holder
|
||||
if(message_type == COMSIG_MOVE)
|
||||
if("loc" in args)
|
||||
if(args["loc"] == target)
|
||||
return //We're already on our way there
|
||||
target = args["loc"]
|
||||
AStar(src, .proc/receive_path, M, target, /turf/proc/AdjacentTurfsSpace, /turf/proc/Distance, 0, 30, id=M.get_visible_id())
|
||||
if("dir" in args)
|
||||
movement_nodes = list()
|
||||
walk(M, args["dir"], walk_delay)
|
||||
if(message_type == COMSIG_LIFE)
|
||||
if(movement_nodes && movement_nodes.len && target && (target != null))
|
||||
if(movement_nodes.len > 0)
|
||||
step_to(M, movement_nodes[1])
|
||||
movement_nodes -= movement_nodes[1]
|
||||
else if(movement_nodes.len == 1)
|
||||
step_to(src, target)
|
||||
movement_nodes.Cut()
|
||||
return 1
|
||||
/datum/component/controller/movement/astar/initialize()
|
||||
active_components += src
|
||||
return ..()
|
||||
|
||||
/datum/component/controller/movement/astar/Destroy()
|
||||
active_components -= src
|
||||
..()
|
||||
|
||||
/datum/component/controller/movement/astar/cmd_move(target)
|
||||
var/mob/living/dude = parent
|
||||
if(isatom(target))
|
||||
if(src.target == target)
|
||||
return //We're already on our way there
|
||||
src.target = target
|
||||
walk_to(dude, target, 0, walk_delay)
|
||||
else if(isnum(target))
|
||||
movement_nodes = list()
|
||||
dude.set_glide_size(DELAY2GLIDESIZE(walk_delay))
|
||||
walk(dude, target, walk_delay)
|
||||
else
|
||||
CRASH("target [target] is not an atom or a dir")
|
||||
|
||||
/datum/component/controller/movement/astar/process()
|
||||
if(movement_nodes && movement_nodes.len && target)
|
||||
if(movement_nodes.len > 0)
|
||||
step_to(parent, movement_nodes[1])
|
||||
movement_nodes -= movement_nodes[1]
|
||||
else if(movement_nodes.len == 1)
|
||||
step_to(parent, target)
|
||||
movement_nodes.Cut()
|
||||
return 1
|
||||
|
||||
/datum/component/controller/movement/astar/proc/receive_path(var/list/L)
|
||||
if(islist(L))
|
||||
|
||||
@@ -1,8 +1,20 @@
|
||||
/datum/component/controller/simple_animal
|
||||
var/disable_automove_on_busy=1
|
||||
var/disable_automove_on_busy = TRUE
|
||||
|
||||
/datum/component/controller/simple_animal/setBusy(var/yes)
|
||||
..(yes)
|
||||
/datum/component/controller/simple_animal/initialize()
|
||||
parent.register_event(/event/comp_ai_cmd_can_attack, src, .proc/cmd_can_attack)
|
||||
return ..()
|
||||
|
||||
/datum/component/controller/simple_animal/Destroy()
|
||||
parent.unregister_event(/event/comp_ai_cmd_can_attack, src, .proc/cmd_can_attack)
|
||||
..()
|
||||
|
||||
/datum/component/controller/simple_animal/proc/cmd_can_attack(target)
|
||||
var/mob/living/simple_animal/SA = parent
|
||||
return SA.CanAttack(target)
|
||||
|
||||
/datum/component/controller/simple_animal/cmd_set_busy(yes)
|
||||
..()
|
||||
if(disable_automove_on_busy)
|
||||
var/mob/living/simple_animal/SA = holder
|
||||
var/mob/living/simple_animal/SA = parent
|
||||
SA.stop_automated_movement = yes
|
||||
|
||||
@@ -1,14 +1,4 @@
|
||||
/datum/component/ai/targetting_handler/RecieveAndReturnSignal(var/message_type, var/list/args)
|
||||
if(message_type == COMSIG_GETDEFZONE)
|
||||
var/mob/living/target = args["target"]
|
||||
var/damagetype = args["damage_type"]
|
||||
ASSERT(istype(target))
|
||||
return EvaluateTarget(target, damagetype)
|
||||
|
||||
/datum/component/ai/targetting_handler/proc/EvaluateTarget(var/mob/living/target, var/damagetype) //Center mass.
|
||||
return LIMB_CHEST
|
||||
|
||||
/datum/component/ai/targetting_handler/dumb/EvaluateTarget(var/mob/living/target, var/damagetype) //Random
|
||||
/datum/component/ai/targetting_handler
|
||||
var/list/static/potential_targets = list(
|
||||
LIMB_HEAD,
|
||||
LIMB_CHEST,
|
||||
@@ -21,27 +11,31 @@
|
||||
LIMB_RIGHT_LEG,
|
||||
LIMB_LEFT_FOOT,
|
||||
LIMB_RIGHT_FOOT,
|
||||
TARGET_MOUTH)
|
||||
TARGET_MOUTH,
|
||||
)
|
||||
|
||||
/datum/component/ai/targetting_handler/initialize()
|
||||
parent.register_event(/event/comp_ai_cmd_evaluate_target, src, .proc/evaluate_target)
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/targetting_handler/Destroy()
|
||||
parent.unregister_event(/event/comp_ai_cmd_evaluate_target, src, .proc/evaluate_target)
|
||||
..()
|
||||
|
||||
//Center mass.
|
||||
/datum/component/ai/targetting_handler/proc/evaluate_target(mob/living/target, damage_type)
|
||||
return LIMB_CHEST
|
||||
|
||||
//Random
|
||||
/datum/component/ai/targetting_handler/dumb/evaluate_target(mob/living/target, damage_type)
|
||||
return pick(potential_targets)
|
||||
|
||||
/datum/component/ai/targetting_handler/smart/EvaluateTarget(var/mob/living/target, var/damagetype) //Goes for the part with the least armor
|
||||
var/list/static/potential_target = list(
|
||||
LIMB_HEAD,
|
||||
LIMB_CHEST,
|
||||
LIMB_GROIN,
|
||||
LIMB_LEFT_ARM,
|
||||
LIMB_RIGHT_ARM,
|
||||
LIMB_LEFT_HAND,
|
||||
LIMB_RIGHT_HAND,
|
||||
LIMB_LEFT_LEG,
|
||||
LIMB_RIGHT_LEG,
|
||||
LIMB_LEFT_FOOT,
|
||||
LIMB_RIGHT_FOOT,
|
||||
TARGET_MOUTH)
|
||||
//Goes for the part with the least armor
|
||||
/datum/component/ai/targetting_handler/smart/evaluate_target(mob/living/target, damage_type)
|
||||
var/weakpoint
|
||||
var/weakpoint_armor = 100
|
||||
for(var/i in potential_target)
|
||||
var/armor = target.getarmor(i, damagetype)
|
||||
for(var/i in potential_targets)
|
||||
var/armor = target.getarmor(i, damage_type)
|
||||
if(!weakpoint || weakpoint_armor > armor)
|
||||
weakpoint = i
|
||||
|
||||
|
||||
@@ -1,22 +1,23 @@
|
||||
/datum/component/ai/door_opener
|
||||
var/pressure_check=TRUE
|
||||
var/max_pressure_diff=-1
|
||||
var/pressure_check = TRUE
|
||||
var/max_pressure_diff = -1
|
||||
|
||||
/datum/component/ai/door_opener/RecieveSignal(var/message_type, var/list/args)
|
||||
switch(message_type)
|
||||
if(COMSIG_ATTACKING) // list("target"=A)
|
||||
OnAttackingTarget(args["target"])
|
||||
else
|
||||
..(message_type, args)
|
||||
/datum/component/ai/door_opener/initialize()
|
||||
parent.register_event(/event/comp_ai_cmd_attack, src, .proc/cmd_attack)
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/door_opener/proc/OnAttackingTarget(var/atom/target)
|
||||
/datum/component/ai/door_opener/Destroy()
|
||||
parent.unregister_event(/event/comp_ai_cmd_attack, src, .proc/cmd_attack)
|
||||
..()
|
||||
|
||||
/datum/component/ai/door_opener/proc/cmd_attack(atom/target)
|
||||
if(istype(target,/obj/machinery/door))
|
||||
var/obj/machinery/door/D = target
|
||||
if(CanOpenDoor(D))
|
||||
if(get_dist(src, target) > 1)
|
||||
return // keep movin'.
|
||||
controller.setBusy(TRUE)
|
||||
SendSignal(COMSIG_MOVE, list("dir"=0)) // Stop movement?
|
||||
parent.invoke_event(/event/comp_ai_cmd_set_busy, list("yes" = TRUE))
|
||||
parent.invoke_event(/event/comp_ai_cmd_move, list("target" = 0))
|
||||
D.visible_message("<span class='warning'>\The [D]'s motors whine as four arachnid claws begin trying to force it open!</span>")
|
||||
spawn(50)
|
||||
if(CanOpenDoor(D) && prob(25))
|
||||
@@ -29,11 +30,10 @@
|
||||
FD.open(1)
|
||||
|
||||
// Reset targetting
|
||||
controller.setBusy(FALSE)
|
||||
controller.setTarget(null)
|
||||
parent.invoke_event(/event/comp_ai_cmd_set_busy, list("yes" = FALSE))
|
||||
parent.invoke_event(/event/comp_ai_cmd_set_target, list("target" = null))
|
||||
return
|
||||
controller.setBusy(FALSE)
|
||||
return
|
||||
parent.invoke_event(/event/comp_ai_cmd_set_busy, list("yes" = FALSE))
|
||||
|
||||
/datum/component/ai/door_opener/proc/performPressureCheck(var/turf/loc)
|
||||
var/turf/simulated/lT=loc
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
/datum/component/ai/get_def_zone/RecieveAndReturnSignal(var/message_type, var/list/args)
|
||||
if(message_type == COMSIG_GETDAMTYPE)
|
||||
return "melee"
|
||||
//var/mob/M = args["user"]
|
||||
@@ -1,30 +1,31 @@
|
||||
/datum/component/ai/escape_confinement
|
||||
var/life_tick=0
|
||||
var/life_tick = 0
|
||||
|
||||
/datum/component/ai/escape_confinement/RecieveSignal(var/message_type, var/list/args)
|
||||
switch(message_type)
|
||||
if(COMSIG_LIFE)
|
||||
OnLife()
|
||||
/datum/component/ai/escape_confinement/initialize()
|
||||
active_components += src
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/escape_confinement/proc/OnLife()
|
||||
/datum/component/ai/escape_confinement/Destroy()
|
||||
active_components -= src
|
||||
..()
|
||||
|
||||
/datum/component/ai/escape_confinement/process()
|
||||
life_tick++
|
||||
var/mob/M = container.holder
|
||||
if(!controller)
|
||||
controller = GetComponent(/datum/component/controller)
|
||||
if(controller.getBusy())
|
||||
if(parent.invoke_event(/event/comp_ai_cmd_get_busy))
|
||||
return
|
||||
switch(controller.getState())
|
||||
var/atom/parent_atom = parent
|
||||
switch(parent.invoke_event(/event/comp_ai_cmd_get_state))
|
||||
if(HOSTILE_STANCE_IDLE)
|
||||
EscapeConfinement()
|
||||
if(HOSTILE_STANCE_ATTACK)
|
||||
if(!(M.flags & INVULNERABLE))
|
||||
if(!(parent_atom.flags & INVULNERABLE))
|
||||
DestroySurroundings()
|
||||
if(HOSTILE_STANCE_ATTACKING)
|
||||
if(!(M.flags & INVULNERABLE))
|
||||
if(!(parent_atom.flags & INVULNERABLE))
|
||||
DestroySurroundings()
|
||||
|
||||
/datum/component/ai/escape_confinement/proc/EscapeConfinement()
|
||||
var/atom/A = container.holder
|
||||
var/atom/A = parent
|
||||
if(istype(A, /mob))
|
||||
var/mob/M = A
|
||||
if(M.locked_to)
|
||||
@@ -36,16 +37,24 @@
|
||||
/datum/component/ai/escape_confinement/proc/DestroySurroundings()
|
||||
EscapeConfinement()
|
||||
var/list/smash_dirs = list(0)
|
||||
var/atom/target = controller.getTarget()
|
||||
if(!target || !controller.canAttack(target))
|
||||
var/atom/target = parent.invoke_event(/event/comp_ai_cmd_get_target)
|
||||
if(!target || !parent.invoke_event(/event/comp_ai_cmd_can_attack, list("target" = target)))
|
||||
smash_dirs |= alldirs //if no target, attack everywhere
|
||||
else
|
||||
var/targdir = get_dir(src, target)
|
||||
smash_dirs |= widen_dir(targdir) //otherwise smash towards the target
|
||||
for(var/dir in smash_dirs)
|
||||
var/turf/T = get_step(src, dir)
|
||||
if(istype(T, /turf/simulated/wall) && container.holder.Adjacent(T))
|
||||
var/atom/parent_atom = parent
|
||||
if(istype(T, /turf/simulated/wall) && parent_atom.Adjacent(T))
|
||||
T.attack_animal(src)
|
||||
for(var/atom/A in T)
|
||||
if((istype(A, /obj/structure/window) || istype(A, /obj/structure/closet) || istype(A, /obj/structure/table) || istype(A, /obj/structure/grille) || istype(A, /obj/structure/rack)) && container.holder.Adjacent(A))
|
||||
var/static/list/attackable_objs = list(
|
||||
/obj/structure/window,
|
||||
/obj/structure/closet,
|
||||
/obj/structure/table,
|
||||
/obj/structure/grille,
|
||||
/obj/structure/rack,
|
||||
)
|
||||
if(is_type_in_list(A, attackable_objs) && parent_atom.Adjacent(A))
|
||||
A.attack_animal(src)
|
||||
|
||||
@@ -1,53 +1,40 @@
|
||||
// Hunting controller from spiders
|
||||
/datum/component/ai/hunt
|
||||
var/last_dir=0 // cardinal direction
|
||||
var/last_was_bumped=0 // Boolean, indicates whether the last movement resulted in a to_bump().
|
||||
var/life_tick=0
|
||||
var/last_dir = 0 // cardinal direction
|
||||
var/last_was_bumped = 0 // Boolean, indicates whether the last movement resulted in a to_bump().
|
||||
var/life_tick = 0
|
||||
|
||||
var/movement_range=20 // Maximum range of points we move to (20 in spiders)
|
||||
var/movement_range = 20 // Maximum range of points we move to (20 in spiders)
|
||||
|
||||
var/targetfind_delay=10
|
||||
var/datum/component/ai/target_holder/target_holder = null
|
||||
var/targetfind_delay = 10
|
||||
|
||||
/datum/component/ai/hunt/RecieveSignal(var/message_type, var/list/args)
|
||||
switch(message_type)
|
||||
if(COMSIG_LIFE) // no arguments
|
||||
OnLife()
|
||||
|
||||
if(COMSIG_BUMPED) // list("movable"=AM)
|
||||
OnBumped(args["movable"])
|
||||
|
||||
/datum/component/ai/hunt/proc/OnLife()
|
||||
life_tick++
|
||||
//testing("HUNT LIFE, controller=[!isnull(controller)], busy=[controller && controller.getBusy()], state=[controller && controller.getState()]")
|
||||
if(!target_holder)
|
||||
target_holder = GetComponent(/datum/component/ai/target_holder)
|
||||
if(!controller)
|
||||
controller = GetComponent(/datum/component/controller)
|
||||
if(controller.getBusy())
|
||||
return
|
||||
switch(controller.getState())
|
||||
if(HOSTILE_STANCE_IDLE)
|
||||
var/atom/target = target_holder.GetBestTarget(src, "target_evaluator")
|
||||
//testing(" IDLE STANCE, target=\ref[target]")
|
||||
if(!isnull(target))
|
||||
SendSignal(COMSIG_TARGET, list("target"=target))
|
||||
SendSignal(COMSIG_STATE, list("state"=HOSTILE_STANCE_ATTACK))
|
||||
else
|
||||
SendSignal(COMSIG_MOVE, list("loc" = pick(orange(movement_range, src))))
|
||||
if(HOSTILE_STANCE_ATTACK)
|
||||
var/atom/target = target_holder.GetBestTarget(src, "target_evaluator")
|
||||
//testing(" ATTACK STANCE, target=\ref[target]")
|
||||
if(!isnull(target))
|
||||
var/turf/T = get_turf(target)
|
||||
container.SendSignalToFirst(/datum/component/ai, COMSIG_ATTACKING, list("target"=target)) // We're telling the attack modules that we have attack intention. They then individually decide whether to fire.
|
||||
if(T)
|
||||
SendSignal(COMSIG_MOVE, list("loc" = T))
|
||||
return
|
||||
SendSignal(COMSIG_STATE, list("state"=HOSTILE_STANCE_IDLE)) // Lost target
|
||||
|
||||
/datum/component/ai/hunt/proc/OnBumped(var/atom/movable/AM)
|
||||
// TODO
|
||||
|
||||
/datum/component/ai/hunt/proc/target_evaluator(var/atom/target)
|
||||
/datum/component/ai/hunt/initialize()
|
||||
active_components += src
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/hunt/Destroy()
|
||||
active_components -= src
|
||||
..()
|
||||
|
||||
/datum/component/ai/hunt/process()
|
||||
life_tick++
|
||||
if(parent.invoke_event(/event/comp_ai_cmd_get_busy))
|
||||
return
|
||||
switch(parent.invoke_event(/event/comp_ai_cmd_get_state))
|
||||
if(HOSTILE_STANCE_IDLE)
|
||||
var/atom/target = parent.invoke_event(/event/comp_ai_cmd_get_best_target)
|
||||
if(!isnull(target))
|
||||
parent.invoke_event(/event/comp_ai_cmd_set_target, list("target" = target))
|
||||
parent.invoke_event(/event/comp_ai_cmd_set_state, list("new_state" = HOSTILE_STANCE_ATTACK))
|
||||
else
|
||||
parent.invoke_event(/event/comp_ai_cmd_move, list("target" = pick(orange(movement_range, src))))
|
||||
if(HOSTILE_STANCE_ATTACK)
|
||||
var/atom/target = parent.invoke_event(/event/comp_ai_cmd_get_best_target)
|
||||
if(!isnull(target))
|
||||
// We're telling the attack modules that we have attack intention. They then individually decide whether to fire.
|
||||
parent.invoke_event(/event/comp_ai_cmd_attack, list("target" = target))
|
||||
var/turf/T = get_turf(target)
|
||||
if(T)
|
||||
parent.invoke_event(/event/comp_ai_cmd_move, list("target" = T))
|
||||
return
|
||||
parent.invoke_event(/event/comp_ai_cmd_set_state, list("new_state" = HOSTILE_STANCE_IDLE))
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// This just calls animal_attack() on stuff.
|
||||
/datum/component/ai/melee/attack_animal/OnAttackingTarget(var/atom/target)
|
||||
if(..(target))
|
||||
/datum/component/ai/melee/attack_animal/cmd_attack(atom/target)
|
||||
if(can_attack(target))
|
||||
var/mob/living/L = target
|
||||
L.attack_animal(container.holder)
|
||||
L.attack_animal(parent)
|
||||
return 1 // Accepted
|
||||
return 0 // Unaccepted
|
||||
|
||||
@@ -4,16 +4,16 @@
|
||||
var/inject_prob = 0 // Chance to inject, -1 = ALWAYS
|
||||
var/max_poison = 0 // Maximum mols in target's blood. 0 = INF
|
||||
|
||||
/datum/component/ai/melee/inject_reagent/OnAttackingTarget(var/atom/target)
|
||||
if(..(target))
|
||||
/datum/component/ai/melee/inject_reagent/cmd_attack(atom/target)
|
||||
if(can_attack(target))
|
||||
var/mob/living/L = target
|
||||
if(L.reagents)
|
||||
if(inject_prob == -1 || prob(inject_prob))
|
||||
var/curamt = L.reagents.get_reagent_amount(poison_type)
|
||||
var/newamt = max_poison - curamt
|
||||
if(newamt >= 1)
|
||||
// TEXT-FORMATTING FUNCTIONS WHEN BYOND?
|
||||
container.holder.visible_message("<span class='warning'>\The [src] injects something into \the [target]!</span>")
|
||||
var/atom/parent_atom = parent
|
||||
parent_atom.visible_message("<span class='warning'>\The [src] injects something into \the [target]!</span>")
|
||||
L.reagents.add_reagent(poison_type, poison_per_bite)
|
||||
return 1 // Accepted signal
|
||||
return 0 // Did not accept signal
|
||||
|
||||
@@ -1,14 +1,15 @@
|
||||
/datum/component/ai/melee
|
||||
|
||||
/datum/component/ai/melee/RecieveSignal(var/message_type, var/list/args)
|
||||
switch(message_type)
|
||||
if(COMSIG_ATTACKING) // list("target"=A)
|
||||
return OnAttackingTarget(args["target"])
|
||||
else
|
||||
return ..(message_type, args)
|
||||
/datum/component/ai/melee/initialize()
|
||||
parent.register_event(/event/comp_ai_cmd_attack, src, .proc/cmd_attack)
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/melee/proc/OnAttackingTarget(var/atom/target)
|
||||
if(!isliving(target))
|
||||
return 0
|
||||
var/mob/living/L = target
|
||||
return L.Adjacent(container.holder)
|
||||
/datum/component/ai/melee/Destroy()
|
||||
parent.unregister_event(/event/comp_ai_cmd_attack, src, .proc/cmd_attack)
|
||||
..()
|
||||
|
||||
/datum/component/ai/melee/proc/can_attack(atom/target)
|
||||
return target.Adjacent(parent)
|
||||
|
||||
/datum/component/ai/melee/proc/cmd_attack(atom/target)
|
||||
return can_attack(target)
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
//Basic thought processes
|
||||
/datum/component/ai/human_brain
|
||||
var/life_tick=0
|
||||
var/life_tick = 0
|
||||
var/wander = TRUE //Whether the mob will walk around searching for goals, or wait for them to become visible
|
||||
var/lastdir = null
|
||||
|
||||
@@ -14,34 +14,32 @@
|
||||
var/list/friends = list()
|
||||
var/list/enemies = list()
|
||||
|
||||
var/datum/component/ai/target_holder/target_holder = null
|
||||
var/atom/current_target
|
||||
|
||||
/datum/component/ai/human_brain/RecieveSignal(var/message_type, var/list/args)
|
||||
switch(message_type)
|
||||
if(COMSIG_LIFE) // no arguments
|
||||
OnLife()
|
||||
/datum/component/ai/human_brain/initialize()
|
||||
active_components += src
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/human_brain/proc/OnLife()
|
||||
/datum/component/ai/human_brain/Destroy()
|
||||
active_components -= src
|
||||
..()
|
||||
|
||||
/datum/component/ai/human_brain/process()
|
||||
life_tick++
|
||||
if(!target_holder)
|
||||
target_holder = GetComponent(/datum/component/ai/target_holder)
|
||||
if(!controller)
|
||||
controller = GetComponent(/datum/component/controller)
|
||||
if(controller.getBusy())
|
||||
if(parent.invoke_event(/event/comp_ai_cmd_get_busy))
|
||||
return
|
||||
if(!ishuman(container.holder))
|
||||
if(!ishuman(parent))
|
||||
return
|
||||
var/mob/living/carbon/human/H = container.holder
|
||||
var/mob/living/carbon/human/H = parent
|
||||
|
||||
if(H.stat != CONSCIOUS || !H.canmove || !isturf(H.loc))
|
||||
SendSignal(COMSIG_MOVE, list("dir" = 0))
|
||||
parent.invoke_event(/event/comp_ai_cmd_move, list("target" = 0))
|
||||
return
|
||||
|
||||
current_target = target_holder.GetBestTarget(src, "target_evaluator")
|
||||
current_target = parent.invoke_event(/event/comp_ai_cmd_get_best_target)
|
||||
if(!isnull(current_target))
|
||||
personal_desires.Add(DESIRE_CONFLICT)
|
||||
SendSignal(COMSIG_TARGET, list("target"=current_target))
|
||||
parent.invoke_event(/event/comp_ai_cmd_set_target, list("target" = current_target))
|
||||
if(IsBetterWeapon(H))
|
||||
personal_desires.Add(DESIRE_HAVE_WEAPON)
|
||||
if(IsBetterWeapon(H, H.contents))
|
||||
@@ -53,18 +51,18 @@
|
||||
if(I)
|
||||
if(H.Adjacent(I))
|
||||
AcquireItem(H, I)
|
||||
SendSignal(COMSIG_MOVE, list("dir" = 0))
|
||||
parent.invoke_event(/event/comp_ai_cmd_move, list("target" = 0))
|
||||
else
|
||||
if(H.stat == CONSCIOUS && H.canmove && isturf(H.loc))
|
||||
SendSignal(COMSIG_MOVE, list("loc" = get_turf(I)))
|
||||
parent.invoke_event(/event/comp_ai_cmd_move, list("target" = get_turf(I)))
|
||||
return
|
||||
|
||||
if(!isnull(current_target))
|
||||
SendSignal(COMSIG_ATTACKING, list("target"=current_target))
|
||||
parent.invoke_event(/event/comp_ai_cmd_attack, list("target" = current_target))
|
||||
var/turf/T = get_turf(current_target)
|
||||
if(T)
|
||||
if(H.stat == CONSCIOUS && H.canmove && isturf(H.loc))
|
||||
SendSignal(COMSIG_MOVE, list("loc" = T))
|
||||
parent.invoke_event(/event/comp_ai_cmd_move, list("target" = T))
|
||||
return
|
||||
else
|
||||
personal_desires.Remove(DESIRE_CONFLICT)
|
||||
@@ -80,7 +78,7 @@
|
||||
else
|
||||
dir = turn(lastdir, 180)
|
||||
if(H.stat == CONSCIOUS && H.canmove && isturf(H.loc))
|
||||
SendSignal(COMSIG_STEP, list("dir" = dir))
|
||||
parent.invoke_event(/event/comp_ai_cmd_move, list("target" = dir))
|
||||
lastdir = dir
|
||||
|
||||
/datum/component/ai/human_brain/proc/AssessNeeds(mob/living/carbon/human/H)
|
||||
@@ -164,28 +162,29 @@
|
||||
return goal
|
||||
|
||||
/datum/component/ai/human_brain/proc/AcquireItem(mob/living/carbon/human/H, obj/item/I)
|
||||
SendSignal(COMSIG_ACTVEMPTYHAND, list())
|
||||
SendSignal(COMSIG_CLICKON, list("target" = I))
|
||||
H.activate_empty_hand()
|
||||
H.ClickOn(I)
|
||||
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks))
|
||||
ConsumeFood(H, I)
|
||||
else
|
||||
SendSignal(COMSIG_EQUIPACTVHAND, list())
|
||||
var/obj/item/held = H.get_active_hand()
|
||||
if(held)
|
||||
H.equip_to_appropriate_slot(held)
|
||||
|
||||
/datum/component/ai/human_brain/proc/ConsumeFood(mob/living/carbon/human/H, obj/item/I)
|
||||
while(H.nutrition < 250 && !I.gcDestroyed)
|
||||
SendSignal(COMSIG_ITMATKSELF, list())
|
||||
var/obj/item/held = H.get_active_hand()
|
||||
if(held)
|
||||
held.attack_self(H)
|
||||
sleep(1)
|
||||
SendSignal(COMSIG_DROP, list())
|
||||
|
||||
/datum/component/ai/human_brain/proc/target_evaluator(var/atom/target)
|
||||
return TRUE
|
||||
H.drop_item()
|
||||
|
||||
/datum/component/ai/human_brain/proc/WieldBestWeapon(mob/living/carbon/human/H, var/list/excluded)
|
||||
if(H.isStunned()) //We're on the floor, nothing we can do
|
||||
return 0
|
||||
SendSignal(COMSIG_ACTVEMPTYHAND, list())
|
||||
H.activate_empty_hand()
|
||||
if(H.get_active_hand())
|
||||
SendSignal(COMSIG_DROP, list())
|
||||
H.drop_item()
|
||||
if(H.get_active_hand())
|
||||
return 1
|
||||
if(!excluded)
|
||||
@@ -199,7 +198,7 @@
|
||||
if(I.force > current_candidate.force || (I.force == current_candidate.force && I.sharpness > current_candidate.sharpness))
|
||||
current_candidate = I
|
||||
if(current_candidate)
|
||||
SendSignal(COMSIG_CLICKON, list("target" = current_candidate))
|
||||
H.ClickOn(current_candidate)
|
||||
if(current_candidate != H.get_active_hand())
|
||||
excluded.Add(current_candidate)
|
||||
.(H, excluded)
|
||||
@@ -218,4 +217,4 @@
|
||||
return 0
|
||||
for(var/obj/item/I in search_location)
|
||||
if((!O && I.force > 2) || (O && (I.force > O.force || (I.force == O.force && I.sharpness > O.sharpness))))
|
||||
return 1
|
||||
return 1
|
||||
|
||||
@@ -1,32 +0,0 @@
|
||||
/datum/component/ai/hand_control/RecieveSignal(var/message_type, var/list/args)
|
||||
if(iscarbon(container.holder))
|
||||
var/mob/living/carbon/M = container.holder
|
||||
//testing("Got command: \[[message_type]\]: [json_encode(args)]")
|
||||
switch(message_type)
|
||||
if(COMSIG_DROP) // list("pickup" = item)
|
||||
if(M.get_active_hand())
|
||||
M.drop_item()
|
||||
if(COMSIG_ACTVHANDBYITEM) // list("target" = item)
|
||||
var/obj/item/I = args["target"]
|
||||
for(var/j = 1 to M.held_items.len)
|
||||
if(M.held_items[j] == I)
|
||||
M.active_hand = j
|
||||
break
|
||||
if(COMSIG_ACTVEMPTYHAND)
|
||||
for(var/j = 1 to M.held_items.len)
|
||||
if(M.held_items[j] == null)
|
||||
M.active_hand = j
|
||||
break
|
||||
if(COMSIG_THROWAT) // list("target" = atom)
|
||||
var/atom/A = args["target"]
|
||||
M.throw_mode_on()
|
||||
M.ClickOn(A)
|
||||
M.throw_mode_off()
|
||||
if(COMSIG_ITMATKSELF)
|
||||
var/obj/item/I = M.get_active_hand()
|
||||
if(I)
|
||||
I.attack_self(M)
|
||||
if(COMSIG_EQUIPACTVHAND)
|
||||
var/obj/item/I = M.get_active_hand()
|
||||
if(I)
|
||||
M.equip_to_appropriate_slot(I)
|
||||
@@ -1,12 +1,12 @@
|
||||
/datum/component/ai/melee/attack_human
|
||||
// var/datum/component/ai/human_brain/B
|
||||
|
||||
/datum/component/ai/melee/attack_human/OnAttackingTarget(var/atom/target)
|
||||
if(..(target))
|
||||
var/mob/living/carbon/human/H = container.holder
|
||||
H.a_intent = I_HURT
|
||||
var/damage_type = container.ReturnFromSignalFirst(COMSIG_GETDAMTYPE, list("user" = H))
|
||||
var/def_zone = container.ReturnFromSignalFirst(COMSIG_GETDEFZONE, list("target" = target, "damage_type" = damage_type))
|
||||
SendSignal(COMSIG_CLICKON, list("target" = target, "def_zone" = def_zone))
|
||||
return 1 // Accepted
|
||||
return 0 // Unaccepted
|
||||
/datum/component/ai/melee/attack_human/cmd_attack(atom/target)
|
||||
if(!can_attack(target))
|
||||
return FALSE
|
||||
var/mob/living/carbon/human/H = parent
|
||||
H.a_intent = I_HURT
|
||||
var/damage_type = H.invoke_event(/event/comp_ai_cmd_get_damage_type)
|
||||
// TODO make it target the correct def_zone
|
||||
H.invoke_event(/event/comp_ai_cmd_evaluate_target, list("target" = target, "damage_type" = damage_type))
|
||||
H.ClickOn(target)
|
||||
return TRUE
|
||||
|
||||
@@ -1,31 +1,36 @@
|
||||
/datum/component/ai/target_finder/human
|
||||
range = 7
|
||||
var/datum/component/ai/human_brain/B
|
||||
|
||||
/datum/component/ai/target_finder/human/GetTargets()
|
||||
ASSERT(container.holder!=null)
|
||||
if(!B)
|
||||
B = GetComponent(/datum/component/ai/human_brain)
|
||||
/datum/component/ai/target_finder/human/initialize()
|
||||
parent.register_event(/event/attackby, src, .proc/on_attackby)
|
||||
parent.register_event(/event/comp_ai_cmd_find_targets, src, .proc/cmd_find_targets)
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/target_finder/human/Destroy()
|
||||
parent.unregister_event(/event/attackby, src, .proc/on_attackby)
|
||||
parent.unregister_event(/event/comp_ai_cmd_find_targets, src, .proc/cmd_find_targets)
|
||||
..()
|
||||
|
||||
/datum/component/ai/target_finder/human/cmd_find_targets()
|
||||
var/datum/component/ai/human_brain/brain = parent.get_component(/datum/component/ai/human_brain)
|
||||
var/list/o = list()
|
||||
for(var/mob/M in view(range, container.holder))
|
||||
for(var/mob/M in view(range, parent))
|
||||
if(is_type_in_list(M, exclude_types))
|
||||
continue
|
||||
if(M.isUnconscious())
|
||||
continue
|
||||
if((M in B.enemies) || (M.faction && (M.faction in B.enemy_factions)) || (M.type in B.enemy_types))
|
||||
if((M in brain.enemies) || (M.faction && (M.faction in brain.enemy_factions)) || (M.type in brain.enemy_types))
|
||||
o += M
|
||||
else if(ishuman(M))
|
||||
var/mob/living/carbon/human/H = M
|
||||
if(H.species && (H.species.name in B.enemy_species))
|
||||
if(H.species && (H.species.name in brain.enemy_species))
|
||||
o += M
|
||||
return o
|
||||
|
||||
/datum/component/ai/target_finder/human/RecieveSignal(var/message_type, var/list/args)
|
||||
..()
|
||||
if(message_type == COMSIG_ATTACKEDBY) //YOU HAVE JUST MADE AN ENEMY FOR LIFE
|
||||
var/assailant = args["assailant"]
|
||||
var/damage_done = args["damage"]
|
||||
if(damage_done > 15) //Intent to kill!
|
||||
B.friends.Remove(assailant)
|
||||
if(damage_done > 2)
|
||||
B.enemies |= assailant
|
||||
// YOU HAVE JUST MADE AN ENEMY FOR LIFE
|
||||
/datum/component/ai/target_finder/human/proc/on_attackby(mob/attacker, obj/item/item)
|
||||
var/datum/component/ai/human_brain/brain = parent.get_component(/datum/component/ai/human_brain)
|
||||
if(item.force > 15) //Intent to kill!
|
||||
brain.friends.Remove(attacker)
|
||||
if(item.force > 2)
|
||||
brain.enemies |= attacker
|
||||
|
||||
@@ -1,13 +1,18 @@
|
||||
/datum/component/ai/crowd_attack
|
||||
var/datum/component/ai/human_brain/B
|
||||
|
||||
/datum/component/ai/crowd_attack/RecieveSignal(var/message_type, var/list/args)
|
||||
if(!B)
|
||||
B = GetComponent(/datum/component/ai/human_brain)
|
||||
if(B && message_type == COMSIG_ATTACKEDBY)
|
||||
var/assailant = args["assailant"]
|
||||
var/damage_done = args["damage"]
|
||||
for(var/mob/living/M in oview(7, container.holder))
|
||||
if(!M.isUnconscious() || !M.BrainContainer || !(M in B.friends)) //THEY'RE ATTACKING OUR BOY, GET HIM!
|
||||
continue
|
||||
M.BrainContainer.SendSignal(COMSIG_ATTACKEDBY, list("assailant"=assailant,"damage"=damage_done))
|
||||
/datum/component/ai/crowd_attack/initialize()
|
||||
parent.register_event(/event/attackby, src, .proc/on_attackby)
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/crowd_attack/Destroy()
|
||||
parent.unregister_event(/event/attackby, src, .proc/on_attackby)
|
||||
..()
|
||||
|
||||
/datum/component/ai/crowd_attack/proc/on_attackby(mob/attacker, obj/item/item)
|
||||
var/datum/component/ai/human_brain/brain = parent.get_component(/datum/component/ai/human_brain)
|
||||
if(!brain)
|
||||
return
|
||||
for(var/mob/living/M in oview(7, parent))
|
||||
if(!(M in brain.friends)) //THEY'RE ATTACKING OUR BOY, GET HIM!
|
||||
continue
|
||||
M.invoke_event(/event/comp_ai_friend_attacked, list("attacker"=attacker))
|
||||
|
||||
@@ -1,12 +1,14 @@
|
||||
/datum/component/ai/melee/throw_attack
|
||||
|
||||
/datum/component/ai/melee/throw_attack/OnAttackingTarget(var/atom/target)
|
||||
/datum/component/ai/melee/throw_attack/cmd_attack(atom/target)
|
||||
if(!isliving(target))
|
||||
return 0
|
||||
var/mob/M = container.holder
|
||||
var/mob/living/M = parent
|
||||
if(!istype(M))
|
||||
return 0
|
||||
var/obj/item/I = M.get_active_hand()
|
||||
if(I && I.throwforce > I.force && get_dist(M,target) > 2) //Better to throw it at the fucker
|
||||
SendSignal(COMSIG_THROWAT, list("target" = target))
|
||||
return 1
|
||||
M.throw_mode_on()
|
||||
M.ClickOn(target)
|
||||
M.throw_mode_off()
|
||||
return 1
|
||||
|
||||
@@ -4,13 +4,3 @@
|
||||
* See /datum/component and /datum/component_container.
|
||||
*/
|
||||
/mob/living/component
|
||||
|
||||
/mob/living/component/New()
|
||||
..()
|
||||
BrainContainer = new (src)
|
||||
InitializeComponents()
|
||||
BrainContainer.register_for_updates()
|
||||
|
||||
/mob/living/component/proc/InitializeComponents()
|
||||
// Set up components here
|
||||
//var/datum/component/.../ref = container.AddComponent(/datum/component/...)
|
||||
@@ -1,22 +1,22 @@
|
||||
/mob/living/component/giant_spider
|
||||
name="component giant spider"
|
||||
|
||||
name = "component giant spider"
|
||||
icon_state = "guard"
|
||||
icon = 'icons/mob/animal.dmi'
|
||||
|
||||
/mob/living/component/giant_spider/InitializeComponents()
|
||||
BrainContainer.AddComponent(/datum/component/controller/mob)
|
||||
BrainContainer.AddComponent(/datum/component/ai/escape_confinement)
|
||||
BrainContainer.AddComponent(/datum/component/ai/hunt)
|
||||
BrainContainer.AddComponent(/datum/component/ai/melee/attack_animal)
|
||||
var/datum/component/ai/melee/inject_reagent/injector = BrainContainer.AddComponent(/datum/component/ai/melee/inject_reagent)
|
||||
/mob/living/component/giant_spider/New()
|
||||
..()
|
||||
add_component(/datum/component/controller)
|
||||
add_component(/datum/component/ai/escape_confinement)
|
||||
add_component(/datum/component/ai/hunt)
|
||||
add_component(/datum/component/ai/melee/attack_animal)
|
||||
var/datum/component/ai/melee/inject_reagent/injector = add_component(/datum/component/ai/melee/inject_reagent)
|
||||
injector.poison_type = STOXIN
|
||||
injector.poison_per_bite = 5
|
||||
var/datum/component/ai/target_finder/simple_view/sv = BrainContainer.AddComponent(/datum/component/ai/target_finder/simple_view)
|
||||
var/datum/component/ai/target_finder/simple_view/sv = add_component(/datum/component/ai/target_finder/simple_view)
|
||||
sv.range = 5
|
||||
// These two should probably be done on New() based on container.holder.
|
||||
sv.exclude_types += src.type
|
||||
sv.exclude_types += /mob/living/silicon/robot/mommi // Because we wuv dem
|
||||
var/datum/component/ai/target_holder/prioritizing/th = BrainContainer.AddComponent(/datum/component/ai/target_holder/prioritizing)
|
||||
var/datum/component/ai/target_holder/prioritizing/th = add_component(/datum/component/ai/target_holder/prioritizing)
|
||||
th.type_priorities[src.type]=0
|
||||
BrainContainer.AddComponent(/datum/component/ai/door_opener)
|
||||
add_component(/datum/component/ai/door_opener)
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
/datum/component/ai/target_finder/simple_view/GetTargets()
|
||||
ASSERT(container.holder!=null)
|
||||
/datum/component/ai/target_finder/simple_view/cmd_find_targets()
|
||||
var/list/o = list()
|
||||
for(var/atom/A in view(range, container.holder))
|
||||
for(var/atom/A in view(range, parent))
|
||||
if(is_type_in_list(A, exclude_types))
|
||||
continue
|
||||
o += A
|
||||
|
||||
@@ -1,14 +1,18 @@
|
||||
/*
|
||||
var/datum/controller/target_finder/TF = GetComponent(/datum/controller/target_finder)
|
||||
var/list/target = TF.GetTargets()
|
||||
*/
|
||||
/datum/component/ai/target_finder
|
||||
var/range=0
|
||||
var/list/exclude_types=list(
|
||||
/obj/effect,
|
||||
/atom/movable/lighting_overlay,
|
||||
/turf
|
||||
var/range = 0
|
||||
var/list/exclude_types = list(
|
||||
/obj/effect,
|
||||
/atom/movable/lighting_overlay,
|
||||
/turf
|
||||
)
|
||||
|
||||
/datum/component/ai/target_finder/proc/GetTargets()
|
||||
/datum/component/ai/target_finder/initialize()
|
||||
parent.register_event(/event/comp_ai_cmd_find_targets, src, .proc/cmd_find_targets)
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/target_finder/Destroy()
|
||||
parent.unregister_event(/event/comp_ai_cmd_find_targets, src, .proc/cmd_find_targets)
|
||||
..()
|
||||
|
||||
/datum/component/ai/target_finder/proc/cmd_find_targets()
|
||||
return list()
|
||||
|
||||
@@ -1,22 +1,18 @@
|
||||
/datum/component/ai/target_holder/prioritizing
|
||||
var/list/targets= list()
|
||||
var/list/type_priorities = list(
|
||||
/mob/living = 1,
|
||||
// /mob/living/simple_animal/hostile/giant_spider=0,
|
||||
/obj/machinery/door = 2,
|
||||
/obj/machinery/light = 3
|
||||
/mob/living = 1,
|
||||
// /mob/living/simple_animal/hostile/giant_spider=0,
|
||||
/obj/machinery/door = 2,
|
||||
/obj/machinery/light = 3
|
||||
)
|
||||
var/default_priority=2
|
||||
var/default_priority = 2
|
||||
|
||||
var/max_priority=3
|
||||
var/max_priority = 3
|
||||
|
||||
var/datum/component/ai/target_finder/finder = null
|
||||
|
||||
/datum/component/ai/target_holder/prioritizing/proc/attach()
|
||||
if(!finder)
|
||||
finder = GetComponent(/datum/component/ai/target_finder)
|
||||
|
||||
/datum/component/ai/target_holder/prioritizing/AddTarget(var/atom/A)
|
||||
/datum/component/ai/target_holder/prioritizing/cmd_add_target(atom/A)
|
||||
var/priority=-1
|
||||
for(var/priority_type in type_priorities)
|
||||
if(istype(A, priority_type))
|
||||
@@ -31,25 +27,19 @@
|
||||
if(!(A in targets["[priority]"]))
|
||||
targets["[priority]"] += A
|
||||
|
||||
/datum/component/ai/target_holder/prioritizing/RemoveTarget(var/atom/A)
|
||||
/datum/component/ai/target_holder/prioritizing/cmd_remove_target(atom/A)
|
||||
for(var/priority in targets)
|
||||
if(A in targets[priority])
|
||||
targets[priority] -= A
|
||||
|
||||
/datum/component/ai/target_holder/prioritizing/GetBestTarget(var/objRef, var/procName, var/from_finder=1)
|
||||
if(from_finder)
|
||||
attach()
|
||||
targets.Cut() // Clear first
|
||||
//var/n=0
|
||||
for(var/atom/target in finder.GetTargets())
|
||||
AddTarget(target)
|
||||
//n++
|
||||
//testing(" TH: Got [n] targets from TF")
|
||||
for(var/priority=1;priority<=max_priority;priority++)
|
||||
/datum/component/ai/target_holder/prioritizing/cmd_get_best_target()
|
||||
targets.Cut() // Clear first
|
||||
for(var/atom/target in parent.invoke_event(/event/comp_ai_cmd_find_targets))
|
||||
parent.invoke_event(/event/comp_ai_cmd_add_target, list("target" = target))
|
||||
for(var/priority in 1 to max_priority)
|
||||
var/list/priority_targets = targets["[priority]"]
|
||||
if(priority_targets == null)
|
||||
continue
|
||||
for(var/atom/target in sortMerge(priority_targets, cmp=/proc/cmp_dist_asc, associative=0, fromIndex=1, toIndex=priority_targets.len))
|
||||
if(call(objRef, procName)(target))
|
||||
return target
|
||||
return target
|
||||
return null
|
||||
|
||||
@@ -1,19 +1,22 @@
|
||||
/datum/component/ai/target_holder
|
||||
|
||||
/datum/component/ai/target_holder/proc/AddTarget(var/atom/A)
|
||||
/datum/component/ai/target_holder/initialize()
|
||||
parent.register_event(/event/comp_ai_cmd_add_target, src, .proc/cmd_add_target)
|
||||
parent.register_event(/event/comp_ai_cmd_remove_target, src, .proc/cmd_remove_target)
|
||||
parent.register_event(/event/comp_ai_cmd_get_best_target, src, .proc/cmd_get_best_target)
|
||||
return TRUE
|
||||
|
||||
/datum/component/ai/target_holder/proc/cmd_add_target(var/atom/A)
|
||||
return
|
||||
|
||||
/datum/component/ai/target_holder/proc/RemoveTarget(var/atom/A)
|
||||
/datum/component/ai/target_holder/proc/cmd_remove_target(var/atom/A)
|
||||
return
|
||||
|
||||
|
||||
/**
|
||||
* Get the best target
|
||||
*
|
||||
* @param objRef Direct reference to the holding object containing the target validation callback
|
||||
* @param procName Name of the callback proc
|
||||
* @param from_finder Use /datum/component/ai/target_finder.GetTargets()
|
||||
* @return null if not target found, /atom if a target is found.
|
||||
*/
|
||||
/datum/component/ai/target_holder/proc/GetBestTarget(var/objRef, var/procName, var/from_finder=1)
|
||||
/datum/component/ai/target_holder/proc/cmd_get_best_target()
|
||||
return
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
/datum/component
|
||||
var/datum/component_container/container
|
||||
|
||||
// Enables or disables the components
|
||||
var/enabled=1
|
||||
|
||||
/datum/component/New(var/datum/component_container/CC)
|
||||
..()
|
||||
container=CC
|
||||
|
||||
// Override to receive signals.
|
||||
/datum/component/proc/RecieveSignal(var/sigtype, var/list/args)
|
||||
return
|
||||
|
||||
// Send a signal to all other components in the container.
|
||||
/datum/component/proc/SendSignal(var/sigtype, var/list/args)
|
||||
container.SendSignal(sigtype, args)
|
||||
|
||||
// Return first /datum/component that is subtype of c_type.
|
||||
/datum/component/proc/GetComponent(var/c_type)
|
||||
return container.GetComponent(c_type)
|
||||
|
||||
// Returns ALL /datum/components in parent container that are subtypes of c_type.
|
||||
/datum/component/proc/GetComponents(var/c_type)
|
||||
return container.GetComponents(c_type)
|
||||
|
||||
// Returns a value depending on what the signal and args were.
|
||||
/datum/component/proc/RecieveAndReturnSignal(var/sigtype, var/list/args)
|
||||
return 0
|
||||
@@ -1,127 +0,0 @@
|
||||
// Basic multipurpose component container.
|
||||
/datum/component_container
|
||||
|
||||
// Where the components themselves are stored after initialization.
|
||||
var/list/components=list()
|
||||
|
||||
// The types to initialize the holder with. Later, holds unique list of all types in container.
|
||||
var/list/types=list()
|
||||
|
||||
// The entity that holds this datum.
|
||||
var/atom/holder
|
||||
|
||||
// Used for dependency management.
|
||||
|
||||
/datum/component_container/New(var/atom/holder_atom)
|
||||
holder=holder_atom
|
||||
|
||||
/datum/component_container/Destroy()
|
||||
for(var/i in components)
|
||||
qdel(i)
|
||||
components.Cut()
|
||||
|
||||
holder = null
|
||||
unregister_for_updates()
|
||||
..()
|
||||
|
||||
/datum/component_container/proc/AddComponentsByType(var/list/new_types)
|
||||
var/list/newtypes=list()
|
||||
for(var/new_type in new_types)
|
||||
AddComponent(new_type,TRUE)
|
||||
if(!(new_type in newtypes))
|
||||
newtypes.Add(new_type)
|
||||
types=newtypes
|
||||
|
||||
/**
|
||||
* Add component to the container.
|
||||
*
|
||||
* @param new_type The type we wish to instantiate in the component_container.
|
||||
* @param initializing Do not use, only used in container New() for internal purposes.
|
||||
*/
|
||||
/datum/component_container/proc/AddComponent(var/new_type, var/initializing=FALSE)
|
||||
if(!initializing && !(new_type in types))
|
||||
types.Add(new_type)
|
||||
var/datum/component/C = new new_type(src)
|
||||
components.Add(C)
|
||||
SendSignal(COMSIG_COMPONENT_ADDED,list("component"=C))
|
||||
return C
|
||||
|
||||
/**
|
||||
* Removes a component from the container.
|
||||
*
|
||||
* @param C The component to remove
|
||||
*/
|
||||
/datum/component_container/proc/RemoveComponent(var/datum/component/C)
|
||||
SendSignal(COMSIG_COMPONENT_REMOVING,list("component"=C))
|
||||
components.Remove(C)
|
||||
types.Cut()
|
||||
for(var/datum/component/CC in components)
|
||||
if(!(CC.type in types))
|
||||
types.Add(CC.type)
|
||||
//qdel(C) Will most likely get GC'd anyway.
|
||||
|
||||
/**
|
||||
* Send a signal to all components in the container.
|
||||
*
|
||||
* @param message_type Name of the signal.
|
||||
* @param args List of arguments to send with the signal.
|
||||
*/
|
||||
/datum/component_container/proc/SendSignal(var/message_type, var/list/args)
|
||||
for(var/datum/component/C in components)
|
||||
if(C.enabled)
|
||||
C.RecieveSignal(message_type, args)
|
||||
|
||||
/**
|
||||
* Send a signal to the first component of type accepting a signal.
|
||||
*
|
||||
* @param component_type
|
||||
* @param message_type Name of the signal.
|
||||
* @param args List of arguments to send with the signal.
|
||||
*/
|
||||
/datum/component_container/proc/SendSignalToFirst(var/desired_type, var/message_type, var/list/args, var/shuffle=TRUE)
|
||||
var/list/shuffled=list(components) // Copy list so we don't disorder the container.
|
||||
if(shuffle)
|
||||
shuffled=shuffle(shuffled)
|
||||
for(var/datum/component/C in components)
|
||||
if(C.enabled && istype(C, desired_type))
|
||||
if(C.RecieveSignal(message_type, args)) // return 1 to accept signal.
|
||||
return
|
||||
/**
|
||||
* Send a signal, and see if anyone replies with information.
|
||||
*
|
||||
* @param message_type: String(DEFINE): The message to send
|
||||
* @param args: List(ref): The arguments associated with this message
|
||||
*/
|
||||
|
||||
/datum/component_container/proc/ReturnFromSignalFirst(var/message_type, var/list/args)
|
||||
for(var/datum/component/C in components)
|
||||
if(C.enabled)
|
||||
var/received_information = C.RecieveAndReturnSignal(message_type, args)
|
||||
if(received_information)
|
||||
return received_information
|
||||
|
||||
/**
|
||||
* Get the first component matching the specified type.
|
||||
*/
|
||||
/datum/component_container/proc/GetComponent(var/desired_type)
|
||||
for(var/datum/component/C in components)
|
||||
if(istype(C, desired_type))
|
||||
return C
|
||||
return null
|
||||
|
||||
/**
|
||||
* Get the all components matching the specified type.
|
||||
*/
|
||||
/datum/component_container/proc/GetComponents(var/desired_type)
|
||||
. = list()
|
||||
for(var/datum/component/C in components)
|
||||
if(istype(C, desired_type))
|
||||
. += C
|
||||
return .
|
||||
|
||||
|
||||
/datum/component_container/proc/register_for_updates()
|
||||
active_component_containers.Add(src)
|
||||
|
||||
/datum/component_container/proc/unregister_for_updates()
|
||||
active_component_containers.Remove(src)
|
||||
@@ -1,15 +0,0 @@
|
||||
/datum/component/debugger //Exists to shout 'HEY, WE'RE USING THIS SIGNAL'
|
||||
var/spam = 1
|
||||
|
||||
/datum/component/debugger/RecieveSignal(var/message_type, var/list/args)
|
||||
if(spam)
|
||||
to_chat(world, "===================================")
|
||||
to_chat(world, "[container.holder] received [message_type], args are")
|
||||
for(var/i in args)
|
||||
to_chat(world, "[i]: [args[i]]")
|
||||
to_chat(world, "<a HREF='?src=\ref[src];pause=1'>\[Press here to stop and start the spam\]</a>")
|
||||
|
||||
/datum/component/debugger/Topic(href, href_list)
|
||||
.=..()
|
||||
if(href_list["pause"])
|
||||
spam = !spam
|
||||
@@ -60,6 +60,11 @@
|
||||
|
||||
return 0
|
||||
|
||||
/mob/proc/activate_empty_hand()
|
||||
var/empty_hand = find_empty_hand_index()
|
||||
if(empty_hand)
|
||||
activate_hand(empty_hand)
|
||||
|
||||
/mob/proc/empty_hand_indexes_amount()
|
||||
. = 0
|
||||
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
/mob/living/clickbot/ClickOn(var/atom/A, var/params)
|
||||
make_astar_path(A)
|
||||
|
||||
/mob/living/clickbot/make_astar_path(var/atom/target, var/receiving_proc = .get_astar_path)
|
||||
AStar(src, receiving_proc, get_turf(src), target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 30, 30, debug = TRUE)
|
||||
/mob/living/clickbot/make_astar_path(var/atom/target, var/callback = new /callback(src, .get_astar_path))
|
||||
AStar(src, callback, get_turf(src), target, /turf/proc/CardinalTurfsWithAccess, /turf/proc/Distance, 30, 30, debug = TRUE)
|
||||
|
||||
|
||||
/mob/living/clickbot/get_astar_path(var/list/L)
|
||||
|
||||
@@ -1880,21 +1880,17 @@ mob/living/carbon/human/isincrit()
|
||||
else return image(icon = 'icons/mob/attackanims.dmi', icon_state = "default")
|
||||
|
||||
/mob/living/carbon/human/proc/initialize_barebones_NPC_components() //doesn't actually do anything, but contains tools needed for other types to do things
|
||||
BrainContainer = new (src)
|
||||
BrainContainer.AddComponent(/datum/component/controller/mob)
|
||||
BrainContainer.AddComponent(/datum/component/ai/hand_control)
|
||||
BrainContainer.AddComponent(/datum/component/controller/movement/astar)
|
||||
BrainContainer.register_for_updates()
|
||||
add_component(/datum/component/controller/movement/astar)
|
||||
|
||||
/mob/living/carbon/human/proc/initialize_basic_NPC_components() //will wander around
|
||||
initialize_barebones_NPC_components()
|
||||
BrainContainer.AddComponent(/datum/component/ai/human_brain)
|
||||
BrainContainer.AddComponent(/datum/component/ai/target_finder/human)
|
||||
BrainContainer.AddComponent(/datum/component/ai/target_holder/prioritizing)
|
||||
BrainContainer.AddComponent(/datum/component/ai/melee/attack_human)
|
||||
BrainContainer.AddComponent(/datum/component/ai/melee/throw_attack)
|
||||
BrainContainer.AddComponent(/datum/component/ai/crowd_attack)
|
||||
BrainContainer.AddComponent(pick(typesof(/datum/component/ai/targetting_handler)))
|
||||
add_component(/datum/component/ai/human_brain)
|
||||
add_component(/datum/component/ai/target_finder/human)
|
||||
add_component(/datum/component/ai/target_holder/prioritizing)
|
||||
add_component(/datum/component/ai/melee/attack_human)
|
||||
add_component(/datum/component/ai/melee/throw_attack)
|
||||
add_component(/datum/component/ai/crowd_attack)
|
||||
add_component(pick(typesof(/datum/component/ai/targetting_handler)))
|
||||
|
||||
/mob/living/carbon/human/can_show_flavor_text()
|
||||
// Wearing a mask...
|
||||
|
||||
@@ -125,8 +125,6 @@
|
||||
damage += sharpness
|
||||
damage_done = target.apply_damage(damage, damage_type, affecting, armor_block)
|
||||
|
||||
if(target.BrainContainer)
|
||||
target.BrainContainer.SendSignal(COMSIG_ATTACKEDBY, list("assailant"=src,"damage"=damage_done))
|
||||
target.unarmed_attacked(src, damage, damage_type, zone)
|
||||
after_unarmed_attack(target, damage, damage_type, affecting, armor_block)
|
||||
|
||||
|
||||
@@ -34,10 +34,6 @@
|
||||
qdel(B)
|
||||
B = null
|
||||
|
||||
if(BrainContainer)
|
||||
qdel(BrainContainer)
|
||||
BrainContainer = null
|
||||
|
||||
if(immune_system)
|
||||
qdel(immune_system)
|
||||
immune_system = null
|
||||
|
||||
@@ -77,8 +77,6 @@
|
||||
var/calorie_burning_heat_multiplier = 1 //The heat generated from burning calories is multiplied by this value.
|
||||
var/thermal_loss_multiplier = 1 //The heat the mob loses to the environment is multiplied by this value.
|
||||
|
||||
var/datum/component_container/BrainContainer
|
||||
|
||||
var/list/datum/disease2/disease/virus2 = list()
|
||||
var/image/pathogen
|
||||
var/datum/immune_system/immune_system
|
||||
|
||||
@@ -1502,16 +1502,11 @@
|
||||
#include "code\modules\clothing\under\jobs\medsci.dm"
|
||||
#include "code\modules\clothing\under\jobs\security.dm"
|
||||
#include "code\modules\cmc\crew.dm"
|
||||
#include "code\modules\components\component.dm"
|
||||
#include "code\modules\components\component_container.dm"
|
||||
#include "code\modules\components\debugger.dm"
|
||||
#include "code\modules\components\ai\ai_component.dm"
|
||||
#include "code\modules\components\ai\atmos.dm"
|
||||
#include "code\modules\components\ai\controller.dm"
|
||||
#include "code\modules\components\ai\def_zone_handler.dm"
|
||||
#include "code\modules\components\ai\door_opener.dm"
|
||||
#include "code\modules\components\ai\get_damtype.dm"
|
||||
#include "code\modules\components\ai\controllers\mob_controller.dm"
|
||||
#include "code\modules\components\ai\controllers\movement.dm"
|
||||
#include "code\modules\components\ai\controllers\simple_animal.dm"
|
||||
#include "code\modules\components\ai\hostile\escape_confinement.dm"
|
||||
@@ -1520,7 +1515,6 @@
|
||||
#include "code\modules\components\ai\hostile\melee\inject_reagent.dm"
|
||||
#include "code\modules\components\ai\hostile\melee\melee.dm"
|
||||
#include "code\modules\components\ai\human\brain.dm"
|
||||
#include "code\modules\components\ai\human\hand_usage.dm"
|
||||
#include "code\modules\components\ai\human\human_attack.dm"
|
||||
#include "code\modules\components\ai\human\human_target_finder.dm"
|
||||
#include "code\modules\components\ai\human\retaliate.dm"
|
||||
|
||||
Reference in New Issue
Block a user