// FixedUpdate is called once per physics frame private void FixedUpdate() { //print(goal); if (style.status.slain || style.status.unconscious) { BecomeSmall(); pointTargetFrames = 0; attackFrames = 0; evadeFrames = 0; guardFrames = 0; if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; goal = GoalStates.nothing; } if (big && style.stat.MP < 10) { BecomeSmall(); } if (goalDelay > 0) { goalDelay--; } if (pointTargetFrames > 0) { pointTargetFrames--; movementAI.PointTowardTarget(45); } if (attackFrames > 0) { attackFrames--; if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; if (movementAI.toTargetAngle < 10f && movementAI.toTargetAngle > -10f && attackFrames > 2) { attackFrames = 2; } } if (evadeFrames > 0 && style.status.CanMove()) { evadeFrames--; if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; } if (guardFrames > 0) { guardFrames--; if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; } behaviourCounter--; goalCounter--; if (big) { bigAnimator.SetBool("curious", false); } smallAnimator.SetBool("curious", false); if (behaviour == BehaviourStates.defeated && !(style.status.slain || style.status.unconscious)) { if (big) { BecomeSmall(); } style.status.guarding = false; navMesh.speed = maxSpeed * 0.2f; ChangeGoal(GoalStates.retreat); navMesh.enabled = true; navMesh.isStopped = false; goalComplete = false; goalStarted = false; if (Vector3.Distance(transform.position, target.transform.position) > 20 && targetStatus.sheathed && !targetStatus.casting) { pacifiedCounter--; ChangeGoal(GoalStates.nothing); if (big) { bigAnimator.SetBool("curious", true); } smallAnimator.SetBool("curious", true); if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; movementAI.PointTowardTarget(4); } if ((Vector3.Distance(transform.position, target.transform.position) < 5 || !targetStatus.sheathed || targetStatus.casting) && pacifiedCounter < 600) { pacifiedCounter++; } if (pacifiedCounter <= 0) { ChangeBehaviour(BehaviourStates.pacified); } } if (behaviour == BehaviourStates.pacified && !(style.status.slain || style.status.unconscious)) { if (big) { BecomeSmall(); } gameObject.tag = "TgtAlyBosIns"; style.status.guarding = false; //navMesh.speed = maxSpeed * 0.2f; target = stump; movementAI.target = target; if (!castSanctuary) { source.PlayOneShot(howlClipLong, Random.Range(0.4f, 0.6f)); currentSpell = Instantiate(healingSanctuary).GetComponent <Spell>(); currentSpell.duration = 14400; //the Shamanwolf's healing sanctuary is longer, lasting 4 minutes currentSpell.mouseTarget = false; currentSpell.target = target; currentSpell.status = style.status; currentSpell.stat = style.stat; currentSpell.movement = style.movement; currentSpell.animator = style.animator; currentSpell.transform.position = transform.position; currentSpell.transform.rotation = transform.rotation; currentSpell.active = true; currentSpell.ready = 0; currentSpell.Start(); currentSpell.castTime += currentSpell.spellCode.Length * 15; currentSpell.duration = 14400; //the Shamanwolf's healing sanctuary is longer, lasting 4 minutes style.status.castLock = currentSpell.castTime + currentSpell.postCastTime; style.status.channelLock = currentSpell.castTime + currentSpell.postCastTime + currentSpell.channelTime; runningSpells.Add(currentSpell.gameObject); style.ForceSpellcast(currentSpell.castTime + currentSpell.postCastTime + 5); //set the spellcast state for a while castSanctuary = true; } else { if (Vector3.Distance(transform.position, target.transform.position) > 6) { navMesh.enabled = true; navMesh.isStopped = false; goal = GoalStates.approach; goalComplete = false; goalStarted = false; } else { if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; goal = GoalStates.nothing; if (big) { bigAnimator.SetBool("pacified", true); } smallAnimator.SetBool("pacified", true); //have a bit of a lie down } } } else { castSanctuary = false; } if (style.status.IsFloored() && !(style.status.slain || style.status.unconscious)) { ChangeGoal(GoalStates.evade); goalStarted = false; //goalDelay = Random.Range(0, 120); } if (big) { bigCounter--; style.stat.MP -= (style.stat.MPregen + 10) / 60; if ((bigCounter <= 0 || style.stat.MP <= 0) && goalStarted == false) { BecomeSmall(); } } if (style.stat.HP < 80 && behaviour != BehaviourStates.pacified) { ChangeBehaviour(BehaviourStates.defeated); } if (behaviour == BehaviourStates.preBattle && (Vector3.Distance(transform.position, target.transform.position) < 32 || style.stat.HP < style.stat.MaxHP)) { ChangeBehaviour(); ChangeGoal(); } if (targetStatus.unconscious || targetStatus.slain) { ChangeBehaviour(BehaviourStates.pacified); } if (behaviour != BehaviourStates.defeated && behaviour != BehaviourStates.pacified && behaviour != BehaviourStates.preBattle && !(style.status.slain || style.status.unconscious)) { if (behaviourCounter <= 0) //behaviour changes every 30 seconds { CalculateBehaviourPref(); ChangeBehaviour(); behaviourCounter = 1800; } if ((goalCounter <= 0 || goalComplete) && goalDelay <= 0) //goals change every 10 seconds or every time a goal is completed { if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; CalculateGoalPref(); ChangeGoal(); goalCounter = 600; goalComplete = false; goalStarted = false; } } if ((!goalStarted) && goalDelay <= 0) { switch (goal) { case GoalStates.attack: if (style.status.CanMove()) { if (big) { bigAnimator.Play("turn", 0, 0f); } smallAnimator.Play("turn", 0, 0f); } attackFrames = 40; goalStarted = true; break; case GoalStates.cast: if (style.status.CanCast()) { source.PlayOneShot(howlClipShort, Random.Range(0.4f, 0.6f)); goalStarted = true; goalDelay = 40; } break; case GoalStates.big: if (style.status.CanCast()) { source.PlayOneShot(howlClipShort, Random.Range(0.4f, 0.6f)); goalStarted = true; BecomeBig(); bigCounter = Random.Range(10 * 60, 30 * 60); //become big for anywhere between 10 and 30 seconds goalDelay = 120; } break; case GoalStates.approach: if (style.status.CanMove()) { navMesh.enabled = true; navMesh.isStopped = false; navMesh.SetDestination(target.transform.position); navMesh.SetDestination(new Vector3(navMesh.destination.x, 0, navMesh.destination.z)); //get rid of y goalStarted = true; } break; case GoalStates.retreat: if (style.status.CanMove()) { navMesh.enabled = true; navMesh.isStopped = false; retreatDist = Random.Range(Vector3.Distance(transform.position, target.transform.position), 28f); navMesh.SetDestination(transform.position + Vector3.Normalize(transform.position - target.transform.position) * retreatDist); navMesh.SetDestination(new Vector3(navMesh.destination.x, 0, navMesh.destination.z)); //get rid of y goalStarted = true; } break; case GoalStates.evade: if (style.status.CanMove()) { if (big) { bigAnimator.Play("turn", 0, 0f); } smallAnimator.Play("turn", 0, 0f); } evadeFrames = 15; goalStarted = true; break; case GoalStates.guard: guardFrames = Random.Range(60, 180); //guard for between 1 and 2.5 seconds goalStarted = true; break; case GoalStates.parry: if (style.status.CanParry()) { movementAI.PointTowardTarget(60); decider = Random.Range(0, 2); if (decider > 1) { style.FParry(); } else { style.BParry(); } goalStarted = true; } break; } } if (goalStarted && !goalComplete) { switch (goal) { case GoalStates.attack: if (attackFrames > 1) { movementAI.PointTowardTarget(12); } else { if (attackFrames > 0) { if (style.status.CanAttack()) { CalculateAttackPref(); Attack(); } } if (style.instantiatedAttacks.Count <= 0) { goalComplete = true; //once the boss has attacked, the goal is complete } } break; case GoalStates.cast: chosenSpellNumber = Random.Range(0, spellsKnown.Count - 1); if (style.status.CanCast() && style.status.castLock <= 0 && !style.status.casting) { style.status.casting = true; } if (style.status.casting && style.status.channelLock <= 0) { style.ForceSpellcast(1); currentSpellName = spellsKnown[chosenSpellNumber].GetComponent <Spell>().spellName; repeatSpell = false; for (int i2 = 0; i2 < runningSpells.Count; i2++) { if (currentSpellName == runningSpells[i2].GetComponent <Spell>().spellName) { repeatSpell = true; } } if (!repeatSpell) { currentSpell = Instantiate(spellsKnown[chosenSpellNumber]).GetComponent <Spell>(); currentSpell.mouseTarget = false; currentSpell.target = target; currentSpell.status = style.status; currentSpell.stat = style.stat; currentSpell.movement = style.movement; currentSpell.animator = style.animator; currentSpell.transform.position = transform.position; currentSpell.transform.rotation = transform.rotation; currentSpell.active = true; currentSpell.ready = 0; currentSpell.Start(); currentSpell.castTime += currentSpell.spellCode.Length * 15; style.status.castLock = currentSpell.castTime + currentSpell.postCastTime; style.status.channelLock = currentSpell.castTime + currentSpell.postCastTime + currentSpell.channelTime; runningSpells.Add(currentSpell.gameObject); style.ForceSpellcast(currentSpell.castTime + currentSpell.postCastTime + 5); //set the spellcast state for a while } } if (style.status.castLock > 0) { goalComplete = true; style.status.casting = false; } break; case GoalStates.big: if (big) { goalComplete = true; //becoming big happens instantaneously so the goal is completed } break; case GoalStates.approach: if (style.status.CanMove()) { navMesh.enabled = true; navMesh.isStopped = false; } else { if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; } if ((big && Vector3.Distance(transform.position, target.transform.position) < 8) || (!big && Vector3.Distance(transform.position, target.transform.position) < 4) || Vector3.Distance(transform.position, navMesh.destination) < 4) { if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; goalComplete = true; //if the target is more-or-less reached, goal complete } else if (goalCounter < 180 || navMesh.isPathStale /* || navMesh.pathStatus != NavMeshPathStatus.PathComplete*/) //this goal can potentially be recognised as a failure, in which case try to salvage { print("abortApproach"); if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; goalStarted = false; CalculateGoalPref(); approachPref = 0; //welp, messed up last time retreatPref = 10; //prolly don't want to retreat that much ChangeGoal(); goalCounter = 600; } break; case GoalStates.retreat: if (style.status.CanMove()) { navMesh.enabled = true; navMesh.isStopped = false; } else { if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; } if (Vector3.Distance(transform.position, target.transform.position) > 25 || Vector3.Distance(transform.position, navMesh.destination) < 4) { print("distReached"); if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; goalComplete = true; //similar to approach but the wolf has to be far away } else if (goalCounter < 150 || navMesh.isPathStale || navMesh.pathStatus != NavMeshPathStatus.PathComplete) //this goal can potentially be recognised as a failure, in which case try to salvage { print("abortRetreat"); if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; CalculateGoalPref(); if (!big) { bigPref += 50; //big chance of going big if not big } castPref = 1; //very low chance of casting approachPref = 10; //why approach when you can't even get away? retreatPref = 10; //why retreat when you already know you can't? Might have just messed up on distance so fair guardPref += 20; //prefer guard evadePref = 10; //low chance of evading since that's often backwards ChangeGoal(); goalCounter = 600; goalStarted = false; } break; case GoalStates.evade: if (evadeFrames > 0 && style.status.CanMove()) { movementAI.PointAwayFromTarget(Random.Range(3, 5)); } else { if (style.status.CanRoll()) { style.movement.Evade(evadeSpeed, 0, 0.5f); if (big) { bigAnimator.Play("jump", 0, 0f); } smallAnimator.Play("jump", 0, 0f); goalDelay = 45; goalComplete = true; //evade complete } } break; case GoalStates.guard: if (guardFrames <= 0) { goalComplete = true; style.status.guarding = false; } else { if (style.status.CanGuard()) { style.status.guarding = true; if (!style.status.IsGuardStunned()) { movementAI.PointTowardTarget(3); } } else { style.status.guarding = false; } } break; case GoalStates.parry: goalComplete = true; //parry happens instantaneously so it autocompletes break; } } if (navMesh.enabled) { if (!source.isPlaying) { source.Play(); } source.loop = true; if (behaviour == BehaviourStates.defeated) { source.clip = whimperClip; } else { source.clip = moveClip; } } else { source.clip = null; source.loop = false; } if (!style.status.CanGuard()) { style.status.guarding = false; } if (big) { guardBubbleS.material.color = new Color(guardBubbleS.material.color.r, guardBubbleS.material.color.g, guardBubbleS.material.color.b, 0f); parryBubbleS.material.color = new Color(parryBubbleS.material.color.r, parryBubbleS.material.color.g, parryBubbleS.material.color.b, 0f); } else { guardBubbleL.material.color = new Color(guardBubbleL.material.color.r, guardBubbleL.material.color.g, guardBubbleL.material.color.b, 0f); parryBubbleL.material.color = new Color(parryBubbleL.material.color.r, parryBubbleL.material.color.g, parryBubbleL.material.color.b, 0f); } if ((!style.status.CanMove())) { if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; } if (style.status.casting || style.status.channelLock > 0) { if (big) { bigAnimator.SetBool("trueCasting", true); } smallAnimator.SetBool("trueCasting", true); if (navMesh.enabled) { navMesh.isStopped = true; } navMesh.enabled = false; movementAI.PointTowardTarget(30); //point to the target while casting } else { if (big) { bigAnimator.SetBool("trueCasting", false); } smallAnimator.SetBool("trueCasting", false); } if (style.status.spellFlinchTrigger) { StopCasting(); style.status.spellFlinchTrigger = false; } for (int i = 0; i < runningSpells.Count; i++) { runningSpellScript = runningSpells[i].GetComponent <Spell>(); runningSpellScript.castTime--; if (runningSpellScript.castTime <= 0 && runningSpellScript.ready == 0) { runningSpellScript.ready = 1; if (!runningSpellScript.costDeducted) { style.stat.MP -= runningSpellScript.cost; runningSpellScript.costDeducted = true; } } if (runningSpellScript.castTime <= 0 && runningSpellScript.postCastTime > 0) { runningSpellScript.postCastTime--; } if (runningSpellScript.castTime <= 0 && runningSpellScript.postCastTime <= 0 && runningSpellScript.channelTime > 0) { runningSpellScript.channelTime--; } if (runningSpellScript.castTime <= 0 && runningSpellScript.postCastTime <= 0 && runningSpellScript.channelTime <= 0) { runningSpellScript.duration--; } if (runningSpellScript.duration <= 0) { toDestroy = runningSpells[i]; runningSpells.Remove(runningSpells[i]); toDestroy.GetComponent <Spell>().DestroySpell(); } else if (runningSpellScript.ready == 1) { runningSpellScript.CastSpell(); } } }