public void Update(MobAIBase aiBase, float dt) { if ((m_currentSearchTime += dt) > MaxSearchTime) { m_currentSearchTime = 0f; aiBase.Brain.Fire(Trigger.Timeout); } if (aiBase.Brain.IsInState(State.MoveToContainer)) { //Common.Dbgl($"State MoveToContainer: {KnownContainers.Peek().name}"); if (KnownContainers.Peek() == null) { aiBase.StopMoving(); KnownContainers.Pop(); aiBase.Brain.Fire(Trigger.Failed); //Common.Dbgl("Container = null"); return; } aiBase.MoveAndAvoidFire(KnownContainers.Peek().transform.position, dt, 0.5f); if (Vector3.Distance(aiBase.Instance.transform.position, KnownContainers.Peek().transform.position) < 2) { aiBase.StopMoving(); aiBase.Brain.Fire(Trigger.ContainerIsClose); //Debug.Log($"{KnownContainers.Peek().name} is close"); } return; } if (aiBase.Brain.IsInState(State.MoveToGroundItem)) { if (m_groundItem == null || m_groundItem?.GetComponent <ZNetView>()?.IsValid() != true) { m_groundItem = null; aiBase.StopMoving(); aiBase.Brain.Fire(Trigger.Failed); //Debug.Log("GroundItem = null"); return; } aiBase.MoveAndAvoidFire(m_groundItem.transform.position, dt, 0.5f); if (Vector3.Distance(aiBase.Instance.transform.position, m_groundItem.transform.position) < 1.5) { aiBase.StopMoving(); aiBase.Brain.Fire(Trigger.GroundItemIsClose); //Debug.Log("GroundItem is close"); } return; } if (aiBase.Brain.IsInState(State.OpenContainer)) { if ((m_openChestTimer += dt) > OpenChestDelay) { //Debug.Log("Open Container"); aiBase.Brain.Fire(Trigger.ContainerOpened); } } }
public void Update(MobAIBase instance, float dt) { m_hungryTimer += dt; if (instance.Brain.State == State.Hungry) { Common.Invoke <BaseAI>(instance.Instance, "RandomMovement", dt, LastKnownFoodPosition); instance.Brain.Fire(UpdateTrigger, dt); } }
public static bool TurnToFacePosition(MobAIBase mob, Vector3 position) { bool isLookingAtTarget = (bool)Invoke <MonsterAI>(mob.Instance, "IsLookingAt", position, 10f); if (isLookingAtTarget) { return(true); } Invoke <MonsterAI>(mob.Instance, "LookAt", position); return(false); }
public void Configure(MobAIBase aiBase, StateMachine <string, string> brain, string parentState) { m_aiBase = aiBase; m_foodsearchtimer = 0f; if (LastKnownFoodPosition == Vector3.zero) { LastKnownFoodPosition = aiBase.Character.transform.position; } UpdateTrigger = brain.SetTriggerParameters <float>(Trigger.Update); LookForItemTrigger = brain.SetTriggerParameters <IEnumerable <ItemDrop.ItemData>, string, string>(Trigger.ItemFound); brain.Configure(State.Hungry) .SubstateOf(parentState) .PermitIf(UpdateTrigger, State.SearchForFood, (dt) => (m_foodsearchtimer += dt) > 10) .OnEntry(t => { aiBase.StopMoving(); aiBase.UpdateAiStatus("Is hungry, no work a do"); }) .OnExit(t => { Debug.LogWarning("Exiting EatingBehaviour"); }); brain.Configure(State.SearchForFood) .SubstateOf(State.Hungry) .PermitDynamic(LookForItemTrigger.Trigger, () => SearchForItemsState) .OnEntry(t => { m_foodsearchtimer = 0f; brain.Fire(LookForItemTrigger, (aiBase.Instance as MonsterAI).m_consumeItems.Select(i => i.m_itemData), State.HaveFoodItem, State.HaveNoFoodItem); }); brain.Configure(State.HaveFoodItem) .SubstateOf(State.Hungry) .PermitDynamic(Trigger.ConsumeItem, () => SuccessState) .OnEntry(t => { aiBase.UpdateAiStatus("*burps*"); (aiBase.Instance as MonsterAI).m_onConsumedItem((aiBase.Instance as MonsterAI).m_consumeItems.FirstOrDefault()); (aiBase.Instance.GetComponent <Character>() as Humanoid).m_consumeItemEffects.Create(aiBase.Instance.transform.position, Quaternion.identity); var animator = aiBase.Instance.GetType().GetField("m_animator", BindingFlags.Instance | BindingFlags.NonPublic).GetValue(aiBase.Instance) as ZSyncAnimation; animator.SetTrigger("consume"); float consumeHeal = aiBase.Character.GetMaxHealth() * HealPercentageOnConsume; Common.Dbgl($"consumeHeal:{consumeHeal}"); if (consumeHeal > 0f) { aiBase.Instance.GetComponent <Character>().Heal(consumeHeal); } m_hungryTimer = 0f; LastKnownFoodPosition = aiBase.Character.transform.position; Debug.LogWarning($"SuccessState:{SuccessState}"); brain.Fire(Trigger.ConsumeItem); }) .OnExit(t => { Debug.LogWarning($"Exiting HaveFoodItem, Trigger:{t.Trigger}"); }); brain.Configure(State.HaveNoFoodItem) .SubstateOf(State.Hungry) .PermitIf(Trigger.ItemNotFound, State.Hungry) .OnEntry(t => { brain.Fire(Trigger.ItemNotFound); }); }
public void Configure(MobAIBase aiBase, StateMachine <string, string> brain, string parentState) { m_aiBase = aiBase; brain.Configure(State.Main) .InitialTransition(State.IdentifyEnemy) .PermitDynamic(Trigger.Flee, () => FailState) .Permit(Trigger.TargetLost, State.IdentifyEnemy) .SubstateOf(parentState) .OnEntry(t => { m_aiBase.UpdateAiStatus("Entered fighting behaviour"); m_startPosition = aiBase.Instance.transform.position; m_viewRange = m_awarenessLevel * 5f; m_circleTargetDistance = m_mobilityLevel * 2 - m_agressionLevel; m_searchTargetMovement = m_mobilityLevel; }) .OnExit(t => { aiBase.StopMoving(); aiBase.TargetCreature = null; }); brain.Configure(State.IdentifyEnemy) .SubstateOf(State.Main) .Permit(Trigger.FoundTarget, State.SelectWeapon) .Permit(Trigger.NoTarget, State.DoneFighting) .OnEntry(t => { //Debug.Log("IdentifyEnemy-Enter"); m_searchTimer = m_agressionLevel * 2; if (aiBase.Attacker != null && aiBase.Instance.CanSenseTarget(aiBase.Attacker)) { aiBase.TargetCreature = aiBase.Attacker; aiBase.Brain.Fire(Trigger.FoundTarget); return; } }); brain.Configure(State.SelectWeapon) .SubstateOf(State.Main) .Permit(Trigger.WeaponSelected, State.TrackingEnemy) .PermitDynamic(Trigger.Failed, () => FailState) .OnEntry(t => { //Debug.Log("SelectWeapon-Enter"); m_weapon = (ItemDrop.ItemData)Common.Invoke <MonsterAI>(aiBase.Instance, "SelectBestAttack", (aiBase.Character as Humanoid), 1.0f); if (m_weapon == null) { //Debug.Log("SelectWeapon-Fail"); brain.Fire(Trigger.Failed); } else { brain.Fire(Trigger.WeaponSelected); } }); brain.Configure(State.TrackingEnemy) .SubstateOf(State.Main) .Permit(Trigger.Attack, State.EngagingEnemy) .Permit(Trigger.NoTarget, State.IdentifyEnemy) .OnEntry(t => { //Debug.Log("TrackingEnemy-Enter"); m_searchTimer = m_agressionLevel * 2; }); brain.Configure(State.EngagingEnemy) .SubstateOf(State.Main) .Permit(Trigger.Attack, State.TrackingEnemy) .Permit(Trigger.NoTarget, State.IdentifyEnemy) .Permit(Trigger.Reposition, State.CirclingEnemy) .OnEntry(t => { m_circleTimer = m_agressionLevel; }); brain.Configure(State.CirclingEnemy) .Permit(Trigger.Attack, State.TrackingEnemy) .SubstateOf(State.Main) .OnEntry(t => { m_circleTimer = 30f / m_agressionLevel; aiBase.Character.Heal(aiBase.Character.GetMaxHealth() / 50); }); brain.Configure(State.DoneFighting) .SubstateOf(State.Main) .PermitDynamic(Trigger.Done, () => SuccessState) .OnEntry(t => { m_aiBase.UpdateAiStatus("Done fighting."); aiBase.Character.Heal(aiBase.Character.GetMaxHealth() / 10); }) .OnExit(t => { aiBase.Attacker = null; aiBase.TimeSinceHurt = 20; }); }
public bool IsBelowHealthThreshold(MobAIBase aiBase) { return(aiBase.Character.GetHealthPercentage() < 1 - m_agressionLevel * 0.08); }
public void Update(MobAIBase aiBase, float dt) { if (IsBelowHealthThreshold(aiBase)) { aiBase.Brain.Fire(Trigger.Flee); return; } if (aiBase.Brain.IsInState(State.IdentifyEnemy)) { m_searchTimer -= dt; Common.Invoke <MonsterAI>(aiBase.Instance, "RandomMovementArroundPoint", dt, m_startPosition, m_circleTargetDistance, true); if (Vector3.Distance(m_startPosition, aiBase.Character.transform.position) > m_viewRange - 5) { return; } aiBase.TargetCreature = BaseAI.FindClosestEnemy(aiBase.Character, m_startPosition, m_viewRange); if (aiBase.TargetCreature != null && Vector3.Distance(m_startPosition, aiBase.TargetCreature.transform.position) < m_viewRange) { Common.Invoke <MonsterAI>(aiBase.Instance, "LookAt", aiBase.TargetCreature.transform.position); //Debug.Log("IdentifyEnemy-FoundTarget"); aiBase.Brain.Fire(Trigger.FoundTarget); return; } if (m_searchTimer <= 0) { //Debug.Log("IdentifyEnemy-NoTarget"); aiBase.StopMoving(); aiBase.Brain.Fire(Trigger.NoTarget); } return; } if (aiBase.TargetCreature == null) { aiBase.Attacker = null; aiBase.Brain.Fire(Trigger.TargetLost); //Debug.Log("TargetLost"); return; } if (aiBase.Brain.IsInState(State.TrackingEnemy)) { m_searchTimer -= dt; if (aiBase.Attacker != null && aiBase.TargetCreature != aiBase.Attacker && aiBase.Instance.CanSenseTarget(aiBase.Attacker)) { aiBase.TargetCreature = aiBase.Attacker; ////Debug.Log("TrackingEnemy-Switch target to Attacker"); } Common.Invoke <MonsterAI>(aiBase.Instance, "LookAt", aiBase.TargetCreature.transform.position); if (Vector3.Distance(m_startPosition, aiBase.Character.transform.position) > m_viewRange && (aiBase.TargetCreature != aiBase.Attacker || m_agressionLevel < 5)) { //Debug.Log("TrackingEnemy-NoTarget(lost track)"); aiBase.TargetCreature = null; aiBase.Attacker = null; aiBase.StopMoving(); aiBase.Brain.Fire(Trigger.NoTarget); return; } //Debug.Log("TrackingEnemy-MoveToTarget"); if (aiBase.MoveAndAvoidFire(aiBase.TargetCreature.transform.position, dt, Math.Max(m_weapon.m_shared.m_aiAttackRange - 0.5f, 1.0f), true)) { aiBase.StopMoving(); //Debug.Log("TrackingEnemy-Attack"); aiBase.Brain.Fire(Trigger.Attack); return; } if (m_searchTimer <= 0) { //Debug.Log("TrackingEnemy-NoTarget(timeout)"); aiBase.TargetCreature = null; aiBase.Attacker = null; aiBase.StopMoving(); aiBase.Brain.Fire(Trigger.NoTarget); } //Debug.Log("TrackingEnemy-End"); return; } if (aiBase.Brain.IsInState(State.EngagingEnemy)) { m_circleTimer -= dt; bool isLookingAtTarget = (bool)Common.Invoke <MonsterAI>(aiBase.Instance, "IsLookingAt", aiBase.TargetCreature.transform.position, 10f); bool isCloseToTarget = Vector3.Distance(aiBase.Instance.transform.position, aiBase.TargetCreature.transform.position) < m_weapon.m_shared.m_aiAttackRange; if (!isCloseToTarget) { //Debug.Log("EngagingEnemy-Attack"); aiBase.Brain.Fire(Trigger.Attack); return; } if (!isLookingAtTarget) { Common.Invoke <MonsterAI>(aiBase.Instance, "LookAt", aiBase.TargetCreature.transform.position); return; } if (m_circleTimer <= 0) { //Debug.Log("EngagingEnemy-Reposition"); aiBase.Brain.Fire(Trigger.Reposition); return; } Common.Invoke <MonsterAI>(aiBase.Instance, "DoAttack", aiBase.TargetCreature, false); //Debug.Log("EngagingEnemy-DoAttack"); return; } if (aiBase.Brain.IsInState(State.CirclingEnemy)) { m_circleTimer -= dt; Common.Invoke <MonsterAI>(aiBase.Instance, "RandomMovementArroundPoint", dt, aiBase.TargetCreature.transform.position, m_circleTargetDistance, true); if (m_circleTimer <= 0) { //Debug.Log("CirclingEnemy-Attack"); aiBase.Brain.Fire(Trigger.Attack); return; } } if (aiBase.Brain.IsInState(State.DoneFighting)) { aiBase.MoveAndAvoidFire(m_startPosition, dt, 0.5f, false); if (Vector3.Distance(m_startPosition, aiBase.Character.transform.position) < 1f) { //Debug.Log("DoneFighting-Done"); aiBase.Brain.Fire(Trigger.Done); } return; } }
public abstract void GotShoutedAtBy(MobAIBase mob);
public void Configure(MobAIBase aiBase, StateMachine <string, string> brain, string parentState) { m_aiBase = aiBase; FoundGroundItemTrigger = brain.SetTriggerParameters <ItemDrop>(Trigger.FoundGroundItem); m_searchRadius = aiBase.Awareness * 5; brain.Configure(State.Main) .InitialTransition(State.SearchItemsOnGround) .SubstateOf(parentState) .PermitDynamic(Trigger.Timeout, () => FailState) .OnEntry(t => { //Debug.Log("Entered SearchForItemsBehaviour"); }) .OnExit(t => { KnownContainers.Peek()?.SetInUse(inUse: false); }); brain.Configure(State.SearchItemsOnGround) .SubstateOf(State.Main) .Permit(FoundGroundItemTrigger.Trigger, State.MoveToGroundItem) .Permit(Trigger.Failed, State.SearchForRandomContainer) .OnEntry(t => { ItemDrop groundItem = Common.GetNearbyItem(m_aiBase.Instance, Items, m_searchRadius); if (groundItem != null) { m_aiBase.UpdateAiStatus($"Look, there is a {groundItem.m_itemData.m_shared.m_name} on da grund"); brain.Fire(FoundGroundItemTrigger, groundItem); return; } m_aiBase.UpdateAiStatus($"I seen nottin on da ground."); brain.Fire(Trigger.Failed); }); brain.Configure(State.SearchForRandomContainer) .SubstateOf(State.Main) .Permit(Trigger.ContainerFound, State.MoveToContainer) .PermitDynamic(Trigger.ContainerNotFound, () => FailState) .PermitDynamic(Trigger.Failed, () => FailState) .OnEntry(t => { if (KnownContainers.Any()) { var matchingContainer = KnownContainers.Where(c => c.GetInventory().GetAllItems().Any(i => Items.Any(it => i.m_shared.m_name == it.m_shared.m_name))).RandomOrDefault(); if (matchingContainer != null) { KnownContainers.Remove(matchingContainer); KnownContainers.Push(matchingContainer); m_aiBase.UpdateAiStatus($"I seen this in that a bin"); brain.Fire(Trigger.ContainerFound); return; } } Container nearbyChest = Common.FindRandomNearbyContainer(m_aiBase.Instance, KnownContainers, AcceptedContainerNames, m_searchRadius); if (nearbyChest != null) { KnownContainers.Push(nearbyChest); m_aiBase.UpdateAiStatus($"Look a bin!"); m_aiBase.Brain.Fire(Trigger.ContainerFound); } else { m_aiBase.UpdateAiStatus($"Me give up, nottin found!"); KnownContainers.Clear(); m_aiBase.Brain.Fire(Trigger.ContainerNotFound); } }); brain.Configure(State.MoveToGroundItem) .SubstateOf(State.Main) .Permit(Trigger.GroundItemIsClose, State.PickUpItemFromGround) .Permit(Trigger.Failed, State.SearchItemsOnGround) .OnEntry(t => { m_groundItem = t.Parameters[0] as ItemDrop; if (m_groundItem == null || Common.GetNView(m_groundItem)?.IsValid() != true) { brain.Fire(Trigger.Failed); return; } m_aiBase.UpdateAiStatus($"Heading to {m_groundItem.m_itemData.m_shared.m_name}"); }); brain.Configure(State.PickUpItemFromGround) .SubstateOf(State.Main) .PermitDynamic(Trigger.ItemFound, () => SuccessState) .Permit(Trigger.Failed, State.SearchItemsOnGround) .OnEntry(t => { FoundItem = m_groundItem.m_itemData; if (m_groundItem == null || Common.GetNView(m_groundItem)?.IsValid() != true) { brain.Fire(Trigger.Failed); return; } m_aiBase.UpdateAiStatus($"Got a {FoundItem.m_shared.m_name} from the ground"); if (m_groundItem.RemoveOne()) { brain.Fire(Trigger.ItemFound); } else { brain.Fire(Trigger.Failed); } }); brain.Configure(State.MoveToContainer) .SubstateOf(State.Main) .Permit(Trigger.ContainerIsClose, State.OpenContainer) .Permit(Trigger.Failed, State.SearchItemsOnGround) .PermitDynamic(Trigger.ContainerNotFound, () => FailState) .OnEntry(t => { m_aiBase.UpdateAiStatus($"Heading to that a bin"); }); brain.Configure(State.OpenContainer) .SubstateOf(State.Main) .Permit(Trigger.ContainerOpened, State.SearchForItem) .Permit(Trigger.Failed, State.SearchItemsOnGround) .OnEntry(t => { if (KnownContainers.Peek() == null || KnownContainers.Peek().IsInUse()) { KnownContainers.Pop(); brain.Fire(Trigger.Failed); } else { KnownContainers.Peek().SetInUse(inUse: true); m_openChestTimer = 0f; } }); brain.Configure(State.SearchForItem) .SubstateOf(State.Main) .PermitDynamic(Trigger.ItemFound, () => SuccessState) .Permit(Trigger.Failed, State.SearchItemsOnGround) .OnEntry(t => { if (KnownContainers.Peek() == null) { brain.Fire(Trigger.Failed); return; } FoundItem = KnownContainers.Peek().GetInventory().GetAllItems().Where(i => Items.Any(it => i.m_shared.m_name == it.m_shared.m_name)).RandomOrDefault(); if (FoundItem != null) { m_aiBase.UpdateAiStatus($"Found {FoundItem.m_shared.m_name} in this a bin!"); KnownContainers.Peek().GetInventory().RemoveItem(FoundItem, 1); Common.Invoke <Container>(KnownContainers.Peek(), "Save"); Common.Invoke <Inventory>(KnownContainers.Peek().GetInventory(), "Changed"); brain.Fire(Trigger.ItemFound); } else { m_aiBase.UpdateAiStatus($"Nottin in this a bin.."); brain.Fire(Trigger.Failed); } }) .OnExit(t => { KnownContainers.Peek().SetInUse(inUse: false); }); }