Basic Human AI (#15172)

* Adds a basic NPC AI for humans, capable of feeding itself when hungry and clothing itself.

* Does more stuff.

* Adds some more stuff.

* Forgot this.
This commit is contained in:
Shadowmech88
2017-06-17 07:35:19 -05:00
committed by Skullyton
parent c3f57ba687
commit d52ec77972
13 changed files with 376 additions and 1 deletions

View File

@@ -6,6 +6,10 @@
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"]
M.ClickOn(A)
if(COMSIG_MOVE) // list("loc"=turf)
// list("dir"=NORTH)
if("loc" in args)
@@ -16,6 +20,9 @@
// walk(M, get_dir(src,M), MISSILE_SPEED)
walk(M, args["dir"], walk_delay)
if(COMSIG_STEP)
step(M, args["dir"], walk_delay)
if(COMSIG_ADJUST_BODYTEMP) // list("temp"=TEMP_IN_KELVIN)
M.bodytemperature += args["temp"]

View File

@@ -0,0 +1,210 @@
//Basic thought processes
/datum/component/ai/human_brain
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
var/list/desired_items = list() //Specific items
var/list/personal_desires = list() //General desires for events/situations/types of items
var/list/friendly_factions = list()
var/list/enemy_factions = list()
var/list/enemy_types = list()
var/list/enemy_species = list("Tajaran")
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/proc/OnLife()
life_tick++
if(!target_holder)
target_holder = GetComponent(/datum/component/ai/target_holder)
if(!controller)
controller = GetComponent(/datum/component/controller)
if(controller.getBusy())
return
if(!ishuman(container.holder))
return
var/mob/living/carbon/human/H = container.holder
if(H.stat != CONSCIOUS || !H.canmove || !isturf(H.loc))
SendSignal(COMSIG_MOVE, list("dir" = 0))
current_target = target_holder.GetBestTarget(src, "target_evaluator")
if(!isnull(current_target))
personal_desires.Add(DESIRE_CONFLICT)
SendSignal(COMSIG_TARGET, list("target"=current_target))
if(IsBetterWeapon(H))
personal_desires.Add(DESIRE_HAVE_WEAPON)
if(IsBetterWeapon(H, H.contents))
if(WieldBestWeapon(H))
personal_desires.Remove(DESIRE_HAVE_WEAPON)
AssessNeeds(H)
var/obj/item/I = AttainExternalItemGoal(H)
if(I)
if(H.Adjacent(I))
AcquireItem(H, I)
SendSignal(COMSIG_MOVE, list("dir" = 0))
else
if(H.stat == CONSCIOUS && H.canmove && isturf(H.loc))
SendSignal(COMSIG_MOVE, list("loc" = get_turf(I)))
return
if(!isnull(current_target))
container.SendSignalToFirst(/datum/component/ai, COMSIG_ATTACKING, 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))
return
else
personal_desires.Remove(DESIRE_CONFLICT)
if(wander && prob(70))
var/dir = pick(NORTH,SOUTH,EAST,WEST)
if(lastdir)
var/roll = rand(1,100)
if(roll <= 50)
dir = lastdir
else if(roll <= 90)
dir = pick(turn(lastdir,90),turn(lastdir,270))
else
dir = turn(lastdir, 180)
if(H.stat == CONSCIOUS && H.canmove && isturf(H.loc))
SendSignal(COMSIG_STEP, list("dir" = dir))
lastdir = dir
/datum/component/ai/human_brain/proc/AssessNeeds(mob/living/carbon/human/H)
personal_desires = list()
if(H.nutrition < 250)
personal_desires.Add(DESIRE_FOOD)
if(!H.get_item_by_slot(slot_w_uniform))
personal_desires.Add(DESIRE_UNDERCLOTHING)
if(!H.get_item_by_slot(slot_shoes))
personal_desires.Add(DESIRE_SHOES)
if(!H.get_item_by_slot(slot_back))
personal_desires.Add(DESIRE_BACK)
if(!H.get_item_by_slot(slot_gloves))
personal_desires.Add(DESIRE_GLOVES)
if(!H.get_item_by_slot(slot_head))
personal_desires.Add(DESIRE_HAT)
if(!H.get_item_by_slot(slot_belt))
personal_desires.Add(DESIRE_BELT)
if(!H.get_item_by_slot(slot_wear_suit))
personal_desires.Add(DESIRE_EXOSUIT)
if(!H.get_item_by_slot(slot_glasses))
personal_desires.Add(DESIRE_GLASSES)
if(!H.get_item_by_slot(slot_wear_mask))
personal_desires.Add(DESIRE_MASK)
if(!H.get_item_by_slot(slot_wear_id))
personal_desires.Add(DESIRE_ID)
/datum/component/ai/human_brain/proc/AttainExternalItemGoal(mob/living/carbon/human/H)
var/obj/item/goal = null
processing_desires:
for(var/D in desire_ranks)
if(D in personal_desires)
for(var/obj/item/I in view(H))
if(I in H.contents)
continue
switch(D)
if(DESIRE_HAVE_WEAPON)
if((!goal && I.force > 2) || (goal && (I.force > goal.force || (I.force == goal.force && I.sharpness > goal.sharpness))))
goal = I
if(DESIRE_CONFLICT)
break processing_desires
if(DESIRE_FOOD)
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks))
goal = I
if(DESIRE_UNDERCLOTHING)
if((I.slot_flags & SLOT_ICLOTHING) && I.mob_can_equip(H, slot_w_uniform))
goal = I
if(DESIRE_SHOES)
if((I.slot_flags & SLOT_FEET) && I.mob_can_equip(H, slot_shoes))
goal = I
if(DESIRE_BACK)
if((I.slot_flags & SLOT_BACK) && I.mob_can_equip(H, slot_back))
goal = I
if(DESIRE_GLOVES)
if((I.slot_flags & SLOT_GLOVES) && I.mob_can_equip(H, slot_gloves))
goal = I
if(DESIRE_HAT)
if((I.slot_flags & SLOT_HEAD) && I.mob_can_equip(H, slot_head))
goal = I
if(DESIRE_BELT)
if((I.slot_flags & SLOT_BELT) && I.mob_can_equip(H, slot_belt))
goal = I
if(DESIRE_EXOSUIT)
if((I.slot_flags & SLOT_OCLOTHING) && I.mob_can_equip(H, slot_wear_suit))
goal = I
if(DESIRE_GLASSES)
if((I.slot_flags & SLOT_EYES) && I.mob_can_equip(H, slot_glasses))
goal = I
if(DESIRE_MASK)
if((I.slot_flags & SLOT_MASK) && I.mob_can_equip(H, slot_wear_mask))
goal = I
if(DESIRE_ID)
if((I.slot_flags & SLOT_ID) && I.mob_can_equip(H, slot_wear_id))
goal = I
if(goal)
break
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))
if(istype(I, /obj/item/weapon/reagent_containers/food/snacks))
ConsumeFood(H, I)
else
SendSignal(COMSIG_EQUIPACTVHAND, list())
/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())
sleep(1)
SendSignal(COMSIG_DROP, list())
/datum/component/ai/human_brain/proc/target_evaluator(var/atom/target)
return TRUE
/datum/component/ai/human_brain/proc/WieldBestWeapon(mob/living/carbon/human/H, var/list/excluded)
SendSignal(COMSIG_ACTVEMPTYHAND, list())
if(H.get_active_hand())
SendSignal(COMSIG_DROP, list())
if(H.get_active_hand())
return 1
if(!excluded)
excluded = list()
var/obj/item/current_candidate = null
for(var/obj/item/I in H.contents)
if(!current_candidate)
if(I.force > 2)
current_candidate = I
else
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))
if(current_candidate != H.get_active_hand())
excluded.Add(current_candidate)
.(H, excluded)
else
return 1
else
return 0
/datum/component/ai/human_brain/proc/IsBetterWeapon(mob/living/carbon/human/H, var/list/search_location)
if(!search_location)
search_location = view(H)
var/obj/item/O = H.get_active_hand()
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

View File

@@ -0,0 +1,32 @@
/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)

View File

@@ -0,0 +1,10 @@
/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
SendSignal(COMSIG_CLICKON, list("target" = target))
return 1 // Accepted
return 0 // Unaccepted

View File

@@ -0,0 +1,21 @@
/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)
var/list/o = list()
for(var/mob/M in view(range, container.holder))
if(is_type_in_list(M, exclude_types))
continue
if(M.stat)
continue
if((M in B.enemies) || (M.faction && M.faction in B.enemy_factions) || (M.type in B.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)
o += M
return o