Component Model + PoC Mob (#13866)

* Initial work on component mobs.

* Revert simple_animal.dm

* Fix movement.

* Component signals are now #defines.

* Fix magic number in atmos.dm

* Added basic melee attacks.

* Get rid of test spam
This commit is contained in:
Rob Nelson
2017-02-25 15:04:06 -08:00
committed by Probe1
parent 3d70cc1a86
commit fe929e5849
24 changed files with 810 additions and 3 deletions

View File

@@ -0,0 +1,51 @@
/datum/component/ai/escape_confinement
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/proc/OnLife()
life_tick++
var/mob/M = container.holder
if(!controller)
controller = GetComponent(/datum/component/controller)
if(controller.getBusy())
return
switch(controller.getState())
if(HOSTILE_STANCE_IDLE)
EscapeConfinement()
if(HOSTILE_STANCE_ATTACK)
if(!(M.flags & INVULNERABLE))
DestroySurroundings()
if(HOSTILE_STANCE_ATTACKING)
if(!(M.flags & INVULNERABLE))
DestroySurroundings()
/datum/component/ai/escape_confinement/proc/EscapeConfinement()
var/atom/A = container.holder
if(istype(A, /mob))
var/mob/M = A
if(M.locked_to)
M.locked_to.attack_animal(A)
if(!isturf(A.loc) && A.loc != null)//Did someone put us in something?
var/atom/locA = A.loc
locA.attack_animal(A)//Bang on it till we get out
/datum/component/ai/escape_confinement/proc/DestroySurroundings()
EscapeConfinement()
var/list/smash_dirs = list(0)
var/atom/target = controller.getTarget()
if(!target || !controller.canAttack(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))
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))
A.attack_animal(src)

View File

@@ -0,0 +1,53 @@
// 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 Bump().
var/life_tick=0
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
/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)
return TRUE

View File

@@ -0,0 +1,7 @@
// This just calls animal_attack() on stuff.
/datum/component/ai/melee/attack_animal/OnAttackingTarget(var/atom/target)
if(..(target))
var/mob/living/L = target
L.attack_animal(container.holder)
return 1 // Accepted
return 0 // Unaccepted

View File

@@ -0,0 +1,19 @@
/datum/component/ai/melee/inject_reagent
var/poison_type = "" // STOXIN, etc
var/poison_per_bite = 0 // Mols to inject
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))
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>")
L.reagents.add_reagent(poison_type, poison_per_bite)
return 1 // Accepted signal
return 0 // Did not accept signal

View File

@@ -0,0 +1,14 @@
/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/proc/OnAttackingTarget(var/atom/target)
if(!isliving(target))
return 0
var/mob/living/L = target
return L.Adjacent(container.holder)