protected virtual void Update() { if (this.copycat) { renderer.color = new Color(1f, 134f / 255, 97f / 255); } if (this.state == State.IN_VOID) { Destroy(this.gameObject); } if (this.state == State.SENDING_TO_VOID) { this.MoveToVoidWaypoint(true); if (this.IsAtVoidWaypoint()) { this.state = State.IN_VOID; this.audioSource.PlayOneShot(this.spawnSound); } return; } if (this.state == State.IN_VOID) { this.ReturnOrbs(); this.renderer.enabled = false; } if (this.state == State.SPAWNING_FROM_VOID) { this.MoveToVoidWaypoint(false); if (this.IsAtVoidWaypoint()) { this.state = State.WANDER; this.item.state = Item.State.ON_GROUND; this.transform.localScale = new Vector3(1f, 1f, 1f); this.audioSource.PlayOneShot(this.spawnSound); } return; } if (this.item.state == Item.State.PICKED_UP && !this.ShouldBeDropped()) { this.main.DropItem(); return; } if (this.item.state != Item.State.ON_GROUND) { return; } if (this.state == State.WANDER) { // Sound. this.ambientSoundTimer -= Time.deltaTime; if (this.ambientSoundTimer < 0f) { this.ambientSoundTimer = Random.Range(8f, 14f); this.PlayAmbientSound(); } // Actions. Vector2 displacement = this.waypoint - (Vector2)this.transform.position; if (displacement.magnitude > 0.1) { // Move towards waypoint, avoiding the other monster. this.Accel(this.accel * displacement.normalized); if (this.avoid != null) { Vector2 avoidDisplacement = this.avoid.transform.position - this.transform.position; if (avoidDisplacement.magnitude < this.fleeRadius) { this.Accel(-this.accel * avoidDisplacement.normalized); } } } else { // Choose a new waypoint. if (Random.value > (1 - Time.deltaTime / this.averageWaitTime)) { this.waypoint = this.ChooseWaypoint(this.pen); } } // Transitions. foreach (Monster monster in FindObjectsOfType <Monster>()) { if (monster == this || this.state != State.WANDER || !monster.Initialized() || monster.state != State.WANDER || monster.item.state != Item.State.ON_GROUND) { continue; } Vector2 monsterDisplacement = monster.transform.position - this.transform.position; // Can only interact with monsters smaller than threaten radius. if (monsterDisplacement.magnitude < this.threatenRadius) { State choice = this.ChooseThreatenOffensive(monster); State monsterChoice = monster.ChooseThreatenOffensive(this); if (choice == State.THREATEN || choice == State.LURE) { monsterChoice = monster.ChooseThreatenDefensive(this); } if (monsterChoice == State.THREATEN || monsterChoice == State.LURE) { choice = this.ChooseThreatenDefensive(monster); } bool isThreaten = (choice == State.THREATEN || monsterChoice == State.THREATEN); bool isLure = (choice == State.LURE || monsterChoice == State.LURE); if (!isLure) { if (choice == State.FLEE) { this.state = State.FLEE; this.target = monster; this.audioSource.Stop(); this.audioSource.PlayOneShot(this.fleeSound, 0.75f); } if (monsterChoice == State.FLEE) { monster.state = State.FLEE; monster.target = this; monster.audioSource.Stop(); monster.audioSource.PlayOneShot(monster.fleeSound, 0.75f); } if (choice == State.THREATEN) { this.state = State.THREATEN; this.stateTimer = this.threatenTime; this.target = monster; monster.Avoid(this); this.Avoid(monster); this.audioSource.Stop(); this.audioSource.PlayOneShot(this.threatenSound, 0.75f); } if (monsterChoice == State.THREATEN) { monster.state = State.THREATEN; monster.stateTimer = monster.threatenTime; monster.target = this; this.Avoid(monster); monster.Avoid(this); monster.audioSource.Stop(); monster.audioSource.PlayOneShot(monster.threatenSound, 0.75f); } if (isThreaten) { if (choice == State.IGNORE) { this.state = State.IGNORE; this.target = monster; } if (monsterChoice == State.IGNORE) { monster.state = State.IGNORE; monster.target = this; } } } else { if (choice == State.LURE) { this.state = State.LURE; monster.state = State.MESMERIZED; this.target = monster; monster.target = this; this.audioSource.Stop(); monster.audioSource.Stop(); this.audioSource.PlayOneShot(this.lureSound, 0.75f); } if (monsterChoice == State.LURE) { this.state = State.MESMERIZED; monster.state = State.LURE; this.target = monster; monster.target = this; this.audioSource.Stop(); monster.audioSource.Stop(); monster.audioSource.PlayOneShot(monster.lureSound, 0.75f); } } } } } else if (this.state == State.IGNORE) { Monster monster = this.target; Vector2 displacement = this.waypoint - (Vector2)this.transform.position; if (displacement.magnitude > 0.1) { // Move towards waypoint. this.Accel(this.accel * displacement.normalized); } else { // Choose a new waypoint. if (Random.value > (1 - Time.deltaTime / this.averageWaitTime)) { this.waypoint = this.ChooseWaypoint(this.pen); } } } else if (this.state == State.THREATEN) { if (this.stateTimer < 0f) { Monster monster = this.target; float distance = ((Vector2)monster.transform.position - (Vector2)this.transform.position).magnitude; if (monster.state != State.FLEE) { this.state = State.PRE_FIGHT; } if (distance > this.fleeRadius && distance > monster.fleeRadius) { this.state = State.WANDER; } } } else if (this.state == State.PRE_FIGHT) { Monster monster = this.target; Vector2 displacement = monster.transform.position - this.transform.position; if (displacement.magnitude > 0.1) { this.Accel(this.accel * displacement.normalized); } else { this.state = State.FIGHT; this.stateTimer = Monster.FIGHT_TIME; monster.state = State.FIGHT; monster.stateTimer = Monster.FIGHT_TIME; // Make fight cloud. GameObject fightCloudObj = Instantiate(PrefabManager.FIGHT_CLOUD_PREFAB, this.transform.position, Quaternion.identity); this.fightCloud = fightCloudObj.GetComponent <FightCloud>(); monster.fightCloud = this.fightCloud; this.fightCloud.fighter1 = this; this.fightCloud.fighter2 = monster; this.fightNoiseTimer = 0.2f; monster.fightNoiseTimer = float.PositiveInfinity; } } else if (state == State.FIGHT) { this.fightNoiseTimer -= Time.deltaTime; if (this.fightNoiseTimer < 0f) { this.fightNoiseTimer = Random.Range(0.3f, 0.5f); this.audioSource.pitch = Random.Range(0.9f, 1.1f); this.audioSource.PlayOneShot(this.fightSound, 0.3f); } Monster monster = this.target; this.velocity = Vector2.zero; if (Random.value > 1 - Time.deltaTime / 0.2f) { this.transform.rotation *= Quaternion.Euler(0f, 0f, Random.Range(0, 360f)); } if (this.stateTimer < 0f) { this.transform.rotation = Quaternion.identity; monster.transform.rotation = Quaternion.identity; // Destroy fight cloud. Destroy(this.fightCloud.gameObject); this.fightCloud = null; // Give velocities. monster.Shove(new Vector2( Random.Range(0.4f, 0.6f), Random.Range(-0.1f, 0.1f))); this.Shove(new Vector2( Random.Range(-0.6f, -0.4f), Random.Range(-0.1f, 0.1f))); // Burn if (this.IsFiery()) { monster.Enflame(); } if (monster.IsFiery()) { this.Enflame(); } if (this.KillOpponent(monster)) { monster.state = State.DYING; monster.stateTimer = Monster.DYING_TIME; monster.OnDying(); monster.target = null; monster.audioSource.pitch = 1f; monster.audioSource.Stop(); monster.audioSource.PlayOneShot(monster.deathSound, 0.6f); } else { monster.state = State.POST_FIGHT; monster.stateTimer = Monster.POST_FIGHT_TIME; monster.audioSource.pitch = 1f; } if (monster.KillOpponent(this)) { this.state = State.DYING; this.stateTimer = Monster.DYING_TIME; this.OnDying(); this.target = null; this.audioSource.pitch = 1f; this.audioSource.Stop(); this.audioSource.PlayOneShot(this.deathSound, 0.6f); } else { this.state = State.POST_FIGHT; this.stateTimer = Monster.POST_FIGHT_TIME; this.audioSource.pitch = 1f; } } } else if (this.state == State.POST_FIGHT) { Monster monster = this.target; Vector2 displacement = monster.transform.position - this.transform.position; if (this.stateTimer < 0f) { bool farEnough = (displacement.magnitude > this.fleeRadius && displacement.magnitude > monster.fleeRadius); bool monsterDead = (monster.state == State.DEAD || monster.state == State.DYING); if (farEnough || monsterDead) { this.state = State.WANDER; this.waypoint = this.ChooseWaypoint(this.pen); } } else { if (displacement.magnitude == 0f) { float angle = 2 * Mathf.PI * Random.value; displacement = 0.1f * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); } this.Accel(-this.accel * displacement.normalized); } } else if (this.state == State.LURE) { Monster monster = this.target; float distance = ((Vector2)monster.transform.position - (Vector2)this.transform.position).magnitude; if (distance < 0.5f) { this.state = State.DEVOURING; monster.state = State.BEING_DEVOURED; this.stateTimer = Monster.DEVOUR_TIME; monster.stateTimer = Monster.DEVOUR_TIME; } } else if (this.state == State.MESMERIZED) { Monster monster = this.target; Vector2 displacement = monster.transform.position - this.transform.position; if (displacement.magnitude == 0f) { float angle = 2 * Mathf.PI * Random.value; displacement = 0.1f * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); } this.Accel(this.accel * displacement.normalized); } else if (this.state == State.DEVOURING) { Monster monster = this.target; if (this.stateTimer < 0f) { this.state = State.DIGESTING; this.stateTimer = Monster.DIGEST_TIME; monster.gameObject.SetActive(false); } } else if (this.state == State.BEING_DEVOURED) { Monster monster = this.target; float scale = this.stateTimer / Monster.DEVOUR_TIME; Vector2 mouthPosition = monster.transform.position; Vector2 displacement = mouthPosition - (Vector2)this.transform.position; if (displacement.magnitude == 0f) { float angle = 2 * Mathf.PI * Random.value; displacement = 0.1f * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); } this.velocity = Vector2.zero; this.transform.position = mouthPosition - displacement * scale; this.transform.localScale = new Vector3((scale + 0.2f) / 1.2f, (scale + 0.2f) / 1.2f, 1f); } else if (this.state == State.DIGESTING) { Monster monster = this.target; if (this.stateTimer < 0f) { this.state = State.WANDER; this.target = null; monster.target = null; monster.gameObject.SetActive(true); monster.transform.localScale = new Vector3(1f, 1f, 1f); if (this.KillDigestedOpponent(monster)) { for (int i = 0; i < monster.orbs.Length; i++) { monster.orbs[i].item.transform.position = this.transform.position; monster.orbs[i].item.ReturnToLab(); } Destroy(monster.gameObject); } else { monster.state = State.GOOED; monster.stateTimer = Monster.GOO_TIME; monster.Extinguish(); if (monster.IsFireElemental()) { monster.OnDying(); } GameObject ectoplasmObj = Instantiate(PrefabManager.ECTOPLASM_PREFAB, monster.transform); ectoplasmObj.transform.localPosition = new Vector3(0f, -0.01f, 0f); float angle = 2f * Mathf.PI * Random.value; monster.Shove(Random.Range(0.2f, 0.3f) * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle))); } } } else if (this.state == State.GOOED) { if (this.stateTimer < 0f) { if (this.IsFireElemental()) { this.state = State.DEAD; } else { this.state = State.WANDER; } } } else if (this.state == State.FLEE) { Monster monster = this.target; Vector2 displacement = monster.transform.position - this.transform.position; if (displacement.magnitude == 0f) { float angle = 2 * Mathf.PI * Random.value; displacement = 0.1f * new Vector2(Mathf.Cos(angle), Mathf.Sin(angle)); } this.Accel(-this.accel * displacement.normalized); if (displacement.magnitude > this.fleeRadius && displacement.magnitude > monster.fleeRadius) { this.state = State.WANDER; if (monster.state == State.THREATEN || monster.state == State.FLEE) { monster.state = State.WANDER; } } } else if (this.state == State.DYING) { if (this.stateTimer < 0f) { this.state = State.DEAD; this.deadTime = Time.realtimeSinceStartup; if (this.IsExplosive()) { Instantiate(PrefabManager.EXPLOSION_PREFAB, this.transform.position, Quaternion.identity); } } } else if (this.state == State.DEAD) { if (Time.realtimeSinceStartup - this.deadTime > this.deadWaitTime) { if (this.voido != null) { this.voido.SendToVoid(this); } } } else if (this.state == State.TRAVEL_TO_TRANSFORM_ORB) { if (this.transformOrb == null) { this.state = State.WANDER; } else { Vector2 displacement = this.transformOrb.transform.position - this.transform.position; if (displacement.magnitude > 0.5f) { this.Accel(this.accel * displacement.normalized); } else { this.state = State.TRANSFORM_ORB; this.transformOrbStartTime = Time.realtimeSinceStartup; } } } else if (this.state == State.TRANSFORM_ORB) { float delta = Time.realtimeSinceStartup - this.transformOrbStartTime; if (delta < this.transformOrbTotalTime) { float scale = Mathf.Abs((delta / this.transformOrbTotalTime) - 1); this.transformOrb.transform.localScale = new Vector3(scale, scale, 1f); Vector2 displacement = this.transformOrb.transform.position - this.transform.position; if (displacement.magnitude > 0.01f) { this.transformOrb.transform.position -= (Vector3)displacement * Time.deltaTime / (delta + 0.01f); } //this.transform.localScale = new Vector3(scale, scale, 1f); } else { // time to transform orb this.transformOrb.Extinguish(); this.transformOrb.transform.localScale = new Vector3(1f, 1f, 0f); Orb orb = this.orbManager.MakeGhostOrb(this.transformOrb, this.orbs); this.orbs = new Orb[2]; this.state = State.ORBED; Instantiate(PrefabManager.EXPLOSION_PREFAB, this.transform.position, Quaternion.identity); orb.Extinguish(); } } else if (this.state == State.ORBED) { Destroy(this.gameObject); } else if (this.state == State.IN_VOID) { Destroy(this.gameObject); } this.forgetAvoidTimer -= Time.deltaTime; if (this.forgetAvoidTimer < 0f) { this.avoid = null; } this.stateTimer -= Time.deltaTime; // Physics float gateX = this.gate.transform.position.x + this.gate.width; float speed = this.velocity.magnitude; float maxSpeed = (this.state == State.WANDER || this.state == State.POST_FIGHT || this.state == State.IGNORE || this.state == State.MESMERIZED || this.state == State.TRAVEL_TO_TRANSFORM_ORB) ? this.wanderSpeed : this.sprintSpeed; if (speed != 0f) { Vector2 frictionChange = this.velocity.normalized * this.friction * Time.deltaTime; if (frictionChange.magnitude < speed) { this.velocity -= frictionChange; } else { this.velocity = Vector2.zero; } } speed = this.velocity.magnitude; if (speed > maxSpeed && !this.shoved) { this.velocity *= maxSpeed / speed; } if (speed < maxSpeed) { this.shoved = false; } if (this.transform.position.x < gateX && this.velocity.x < 0) { this.velocity = new Vector2(-0.5f * this.velocity.x, this.velocity.y); } this.transform.position += (Vector3)this.velocity * Time.deltaTime; this.emotion.UpdateFromState(state); // Maintain z ordering. Vector2 pos = this.transform.position; this.transform.position = new Vector3(pos.x, pos.y, pos.y / 300f); }