private void OnIsAliveChanged(bool alive) { m_IsActive &= alive; if (alive) { return; } CombatMessage message = CombatMessage.Allocate(); if (message != null) { message.ID = EnumMessageID.MSG_COMBAT_DEFENDER_KILLED; message.StyleIndex = -1; // Random message.Defender = m_MotionController.gameObject; m_MotionController.SendMessage(message); message.Release(); } if (m_NavMeshAgent != null) { m_NavMeshAgent.isStopped = true; } if (message.IsHandled) { m_DeathMotion = message.Recipient as MotionControllerMotion; } }
/// <summary> /// Tells the actor when to block /// </summary> public void DetermineBlock() { if (_Target == null) { return; } #if USE_SWORD_SHIELD_MP || OOTII_SSMP Vector3 lToTarget = _Target.transform.position - transform.position; float lToTargetDistance = lToTarget.magnitude; BasicMeleeBlock lMeleeBlock = mMotionController.GetMotion <BasicMeleeBlock>(); if (lMeleeBlock != null) { if (lMeleeBlock.IsActive) { if (lMeleeBlock.Age > 1f) { CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = CombatMessage.MSG_COMBATANT_CANCEL; lMessage.Defender = gameObject; lMeleeBlock.OnMessageReceived(lMessage); CombatMessage.Release(lMessage); mActorCore.SetStateValue("State", IDLE); } } else { BasicMeleeAttack lMeleeAttack = mTargetMotionController.GetMotion <BasicMeleeAttack>(); if (lMeleeAttack != null && lMeleeAttack.IsActive) { if (lMeleeAttack.Age < 0.1f && !lMeleeBlock.IsActive) { if (mActorCore.GetStateValue("Stance") == EnumControllerStance.COMBAT_MELEE) { mMotionController.ActivateMotion(lMeleeBlock); mActorCore.SetStateValue("State", BLOCKING); } } } #if USE_ARCHERY_MP || OOTII_AYMP BasicRangedAttack lRangedAttack = mTargetMotionController.GetMotion <BasicRangedAttack>(); if (lRangedAttack != null && lRangedAttack.IsActive) { } #endif } } #endif }
private void HandleMeleeAttackMotion(GameObject target) { CombatMessage message = CombatMessage.Allocate(); if (message != null) { message.ID = CombatMessage.MSG_COMBATANT_ATTACK; message.Attacker = m_Owner; message.Defender = target; m_MotionController.SendMessage(message); CombatMessage.Release(message); } }
private IEnumerator HandleDamageMotion(float damage) { CombatMessage message = CombatMessage.Allocate(); if (message != null) { message.ID = EnumMessageID.MSG_COMBAT_DEFENDER_DAMAGED; message.Damage = damage * m_Multiplier; message.Defender = gameObject; m_MotionController.SendMessage(message); message.Release(); } yield return null; }
/// <summary> /// Called when the action is first activated /// <param name="rPreviousSpellActionState">State of the action prior to this one activating</param> public override void Activate(int rPreviousSpellActionState = -1, object rData = null) { base.Activate(rPreviousSpellActionState, rData); MotionController lMotionController = _Spell.Owner.GetComponent <MotionController>(); if (lMotionController != null) { CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = MessageID; lMotionController.SendMessage(lMessage); lMessage.Release(); } base.Deactivate(); }
/// <summary> /// Called each frame /// </summary> private void Update() { if (!IsActive) { return; } if (mCombatant == null) { return; } if (Target == null) { return; } MotionControllerMotion lMotion = mMotionController.ActiveMotion; if (lMotion == null) { return; } MotionControllerMotion lTargetMotion = mTargetMotionController.ActiveMotion; // Determine if we rotate to the target bool lRotate = true; // Ensure our weapon is equipped //if (!mBasicInventory.IsWeaponSetEquipped(2)) //{ // if (mLastEquipTime + AttackDelay < Time.time) // { // mBasicInventory.EquipWeaponSet(2); // mLastEquipTime = Time.time; // } //} //// The main AI loop //else //{ Vector3 lToTarget = Target._Transform.position - transform.position; lToTarget.y = 0f; Vector3 lToTargetDirection = lToTarget.normalized; float lToTargetDistance = lToTarget.magnitude; bool lIsTargetAimingAtMe = false; #if USE_ARCHERY_MP || OOTII_AYMP //float lTargetToMeHorizontalAngle = NumberHelper.GetHorizontalAngle(Target._Transform.forward, -lToTargetDirection, Target._Transform.up); //lIsTargetAimingAtMe = ((lTargetMotion is Bow_WalkRunTarget || lTargetMotion is Bow_BasicAttacks) && Mathf.Abs(lTargetToMeHorizontalAngle) < 10f); #endif // Determine if we should move to the target float lRange = Range; if (!mFollow && lToTargetDistance > lRange + 1f) { mFollow = true; } if (mFollow && lToTargetDistance <= lRange) { mFollow = false; } if (mFollow && (lMotion.Category != EnumMotionCategories.IDLE && lMotion.Category != EnumMotionCategories.WALK)) { mFollow = false; } if (mFollow && lIsTargetAimingAtMe) { mFollow = false; } if (!Move) { mFollow = false; } // Ensure we're not casting if (mMotionController.ActiveMotion is BasicSpellCasting) { } // Cast a healing spell else if (Cast && mLastCastTime + CastDelay < Time.time && mBasicAttributes != null && mBasicAttributes.GetAttributeValue <float>("Health", 100f) < 40f && mSpellInventory != null && mSpellInventory.GetSpellIndex("Heal Self") >= 0) { int lSpellIndex = mSpellInventory.GetSpellIndex("Heal Self"); if (lSpellIndex >= 0) { BasicSpellCasting lCastMotion = mMotionController.GetMotion <BasicSpellCasting>(); mMotionController.ActivateMotion(lCastMotion, lSpellIndex); mLastCastTime = Time.time; } } // Move to the target else if (mFollow) { float lSpeed = Mathf.Min(MovementSpeed * Time.deltaTime, lToTargetDistance); transform.position = transform.position + (lToTargetDirection * lSpeed); } // If we're being shot at, block else if (Block && lIsTargetAimingAtMe) { mFollow = false; CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = CombatMessage.MSG_COMBATANT_BLOCK; lMessage.Attacker = null; lMessage.Defender = gameObject; mMotionController.SendMessage(lMessage); CombatMessage.Release(lMessage); } // Let the movement finish up else if (lMotion.Category == EnumMotionCategories.WALK) { } // Attack with the sword else if (Attack && lMotion.Category == EnumMotionCategories.IDLE && (mLastAttackTime + AttackDelay < Time.time)) { CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = CombatMessage.MSG_COMBATANT_ATTACK; lMessage.Attacker = gameObject; lMessage.Defender = Target.gameObject; mMotionController.SendMessage(lMessage); CombatMessage.Release(lMessage); mLastAttackTime = Time.time; } // Block with the shield else if (Block && lMotion.Category == EnumMotionCategories.IDLE && lMotion.Age > 0.5f) { CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = CombatMessage.MSG_COMBATANT_BLOCK; lMessage.Attacker = null; lMessage.Defender = gameObject; mMotionController.SendMessage(lMessage); CombatMessage.Release(lMessage); } // Free the block else if (lMotion.Category == EnumMotionCategories.COMBAT_MELEE_BLOCK && (lToTargetDistance > lRange + 1f || lMotion.Age > BlockHold)) { CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = CombatMessage.MSG_COMBATANT_CANCEL; lMessage.Attacker = null; lMessage.Defender = gameObject; mMotionController.SendMessage(lMessage); CombatMessage.Release(lMessage); } // Allow rotation only if (mMotionController.enabled && lRotate) { float lAngle = NumberHelper.GetHorizontalAngle(transform.forward, lToTargetDirection, transform.up); if (lAngle != 0f) { float lRotationSpeed = Mathf.Sign(lAngle) * Mathf.Min(RotationSpeed * Time.deltaTime, Mathf.Abs(lAngle)); transform.rotation = transform.rotation * Quaternion.AngleAxis(lRotationSpeed, transform.up); } } //} // If we're dead, we can just stop if (lMotion.Category == EnumMotionCategories.DEATH) { IsActive = false; } // Clear the target if they are dead else if (Target != null && !Target.enabled) { Target = null; //StartCoroutine(WaitAndStoreEquipment(2f)); } }
protected virtual void Update() { if (!IsActive) { return; } MotionControllerMotion lMotion = mMotionController.ActiveMotion; if (lMotion == null) { return; } // Ensure the weapon is equipped if (mCombatant.PrimaryWeapon == null) { EquipWeapon(); return; } Vector3 lToTarget = Target._Transform.position - transform.position; lToTarget.y = 0f; Vector3 lToTargetDirection = lToTarget.normalized; float lToTargetDistance = lToTarget.magnitude; float lRange = mCombatant.MinMeleeReach + mCombatant.PrimaryWeapon.MaxRange; if (lToTargetDistance < StopDistance) { mDoMove = false; } else { mDoMove = true; } if (mDoMove) { MoveToTarget(); } else { mNavMeshAgent.isStopped = true; } // Attack with the sword if (Attack && lMotion.Category == EnumMotionCategories.IDLE && (mLastAttackTime + AttackDelay < Time.time))//&& lMotion.Category == EnumMotionCategories.IDLE { CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = CombatMessage.MSG_COMBATANT_ATTACK; lMessage.Attacker = gameObject; lMessage.Defender = Target.gameObject; mMotionController.SendMessage(lMessage); CombatMessage.Release(lMessage); mLastAttackTime = Time.time; } // Block with shield else if (Block && lMotion.Category == EnumMotionCategories.IDLE && lMotion.Age > 0.5f) { CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = CombatMessage.MSG_COMBATANT_BLOCK; lMessage.Attacker = null; lMessage.Defender = gameObject; mMotionController.SendMessage(lMessage); CombatMessage.Release(lMessage); } // Release the shield block else if (lMotion.Category == EnumMotionCategories.COMBAT_MELEE_BLOCK && (lToTargetDistance > lRange + 1f || lMotion.Age > BlockHold)) { CombatMessage lMessage = CombatMessage.Allocate(); lMessage.ID = CombatMessage.MSG_COMBATANT_CANCEL; lMessage.Attacker = null; lMessage.Defender = gameObject; mMotionController.SendMessage(lMessage); CombatMessage.Release(lMessage); } // If we're dead, we can just stop if (lMotion.Category == EnumMotionCategories.DEATH) { IsActive = false; } // Clear the target if they are dead else if (Target != null && !Target.enabled) { Target = null; StartCoroutine(WaitAndStoreEquipment(2f)); } }
/// <summary> /// Raised when the impact occurs /// </summary> /// <param name="rHitInfo">CombatHit structure detailing the hit information.</param> /// <param name="rAttackStyle">ICombatStyle that details the combat style being used.</param> protected override void OnImpact(CombatHit rHitInfo, ICombatStyle rAttackStyle = null) { // Test impact is now rolling up to the parent object but this means we are trying to apply the damage to the actorcore rather than the collider actually hit // see Test impact below IHealthManager lHealthManager = rHitInfo.Collider.gameObject.GetComponentInParent <IHealthManager>(); GameObject defender = ((MonoBehaviour)lHealthManager).gameObject; mDefenders.Add(defender); mImpactCount++; Transform lHitTransform = GetClosestTransform(rHitInfo.Point, rHitInfo.Collider.transform); Vector3 lHitDirection = Quaternion.Inverse(lHitTransform.rotation) * (rHitInfo.Point - lHitTransform.position).normalized; CombatMessage lMessage = CombatMessage.Allocate(); lMessage.Attacker = mOwner; lMessage.Defender = rHitInfo.Collider.gameObject; lMessage.Weapon = this; lMessage.Damage = GetAttackDamage(Random.value, (rAttackStyle != null ? rAttackStyle.DamageModifier : 1f)); lMessage.ImpactPower = GetAttackImpactPower(); lMessage.HitPoint = rHitInfo.Point; lMessage.HitDirection = lHitDirection; lMessage.HitVector = rHitInfo.Vector; lMessage.HitTransform = lHitTransform; lMessage.AttackIndex = mAttackStyleIndex; lMessage.CombatStyle = rAttackStyle; ActorCore lAttackerCore = (mOwner != null ? mOwner.GetComponentInParent <ActorCore>() : null); ActorCore lDefenderCore = defender.gameObject.GetComponentInParent <ActorCore>(); lMessage.ID = CombatMessage.MSG_ATTACKER_ATTACKED; if (lAttackerCore != null) { lAttackerCore.SendMessage(lMessage); } #if USE_MESSAGE_DISPATCHER || OOTII_MD MessageDispatcher.SendMessage(lMessage); #endif lMessage.ID = CombatMessage.MSG_DEFENDER_ATTACKED; if (lDefenderCore != null) { lDefenderCore.SendMessage(lMessage); #if USE_MESSAGE_DISPATCHER || OOTII_MD MessageDispatcher.SendMessage(lMessage); #endif } if (lAttackerCore != null) { lAttackerCore.SendMessage(lMessage); #if USE_MESSAGE_DISPATCHER || OOTII_MD MessageDispatcher.SendMessage(lMessage); #endif } OnImpactComplete(lMessage); CombatMessage.Release(lMessage); }
/// <summary> /// Raised when the impact occurs /// </summary> /// <param name="rHitInfo">CombatHit structure detailing the hit information.</param> /// <param name="rAttackStyle">ICombatStyle that details the combat style being used.</param> protected virtual void OnImpact(CombatHit rHitInfo, ICombatStyle rAttackStyle = null) { // If we get here, there's an impact mImpactCount++; // Extract out information about the hit Transform lHitTransform = GetClosestTransform(rHitInfo.Point, rHitInfo.Collider.transform); Vector3 lHitDirection = Quaternion.Inverse(lHitTransform.rotation) * (rHitInfo.Point - lHitTransform.position).normalized; // Put together the combat info. This will will be modified over time CombatMessage lMessage = CombatMessage.Allocate(); lMessage.Attacker = mOwner; lMessage.Defender = rHitInfo.Collider.gameObject; lMessage.Weapon = this; lMessage.Damage = GetAttackDamage(1f, (rAttackStyle != null ? rAttackStyle.DamageModifier : 1f)); lMessage.ImpactPower = GetAttackImpactPower(); lMessage.HitPoint = rHitInfo.Point; lMessage.HitDirection = lHitDirection; lMessage.HitVector = rHitInfo.Vector; lMessage.HitTransform = lHitTransform; // Grab cores for processing ActorCore lAttackerCore = (mOwner != null ? mOwner.GetComponent <ActorCore>() : null); ActorCore lDefenderCore = rHitInfo.Collider.gameObject.GetComponent <ActorCore>(); // Pre-Attack lMessage.ID = CombatMessage.MSG_ATTACKER_ATTACKED; if (lAttackerCore != null) { lAttackerCore.SendMessage(lMessage); } #if USE_MESSAGE_DISPATCHER || OOTII_MD MessageDispatcher.SendMessage(lMessage); #endif // Attack Defender lMessage.ID = CombatMessage.MSG_DEFENDER_ATTACKED; if (lDefenderCore != null) { ICombatant lDefenderCombatant = rHitInfo.Collider.gameObject.GetComponent <ICombatant>(); if (lDefenderCombatant != null) { lMessage.HitDirection = Quaternion.Inverse(lDefenderCore.Transform.rotation) * (rHitInfo.Point - lDefenderCombatant.CombatOrigin).normalized; } lDefenderCore.SendMessage(lMessage); #if USE_MESSAGE_DISPATCHER || OOTII_MD MessageDispatcher.SendMessage(lMessage); #endif } else { lMessage.HitDirection = Quaternion.Inverse(lHitTransform.rotation) * (rHitInfo.Point - lHitTransform.position).normalized; IDamageable lDefenderDamageable = rHitInfo.Collider.gameObject.GetComponent <IDamageable>(); if (lDefenderDamageable != null) { lDefenderDamageable.OnDamaged(lMessage); } Rigidbody lRigidBody = rHitInfo.Collider.gameObject.GetComponent <Rigidbody>(); if (lRigidBody != null) { lRigidBody.AddForceAtPosition(rHitInfo.Vector * lMessage.ImpactPower, rHitInfo.Point, ForceMode.Impulse); } } // Attacker response if (lAttackerCore != null) { lAttackerCore.SendMessage(lMessage); #if USE_MESSAGE_DISPATCHER || OOTII_MD MessageDispatcher.SendMessage(lMessage); #endif } // Finish up any impact processing (like sound) OnImpactComplete(lMessage); // Release the combatant to the pool CombatMessage.Release(lMessage); }
/// <summary> /// Activates the action on a single target /// </summary> /// <param name="rTarget">Target to activate on</param> protected void ActivateInstance(GameObject rTarget) { Vector3 lPoint = rTarget.transform.position; Vector3 lForward = rTarget.transform.forward; // Combatant that is attacking ICombatant lAttacker = (_Spell.Owner != null ? _Spell.Owner.GetComponent <ICombatant>() : null); // Determine who we're colliding with IActorCore lDefenderCore = rTarget.GetComponent <IActorCore>(); IDamageable lDamageable = rTarget.GetComponent <IDamageable>(); if (lDefenderCore == null) { IWeaponCore lWeaponCore = rTarget.GetComponent <IWeaponCore>(); if (lWeaponCore != null) { lDefenderCore = lWeaponCore.Owner.GetComponent <IActorCore>(); if (lDamageable == null) { lDamageable = lWeaponCore.Owner.GetComponent <IDamageable>(); } } } // Save the hit information Transform lHitTransform = GetClosestTransform(lPoint, rTarget.transform); Vector3 lCombatCenter = lHitTransform.position; Vector3 lHitDirection = Vector3.zero; if (lDefenderCore != null) { ICombatant lDefenderCombatant = lDefenderCore.gameObject.GetComponent <ICombatant>(); if (lDefenderCombatant != null) { lHitDirection = Quaternion.Inverse(lDefenderCore.Transform.rotation) * (lPoint - lDefenderCombatant.CombatOrigin).normalized; } } else { lHitDirection = Quaternion.Inverse(lHitTransform.rotation) * (lPoint - lCombatCenter).normalized; } // Determine the damage float lDamage = UnityEngine.Random.Range(_MinDamage, _MaxDamage); if (_DamageFloatValueIndex >= 0 && _Spell.Data.FloatValues != null) { lDamage = _Spell.Data.FloatValues[_DamageFloatValueIndex]; } // Put together the combat round info CombatMessage lCombatMessage = CombatMessage.Allocate(); lCombatMessage.ID = CombatMessage.MSG_DEFENDER_ATTACKED; lCombatMessage.Attacker = (lAttacker != null ? lAttacker.Transform.gameObject : _Spell.Owner); lCombatMessage.Defender = (lDefenderCore != null ? lDefenderCore.Transform.gameObject : rTarget); lCombatMessage.Weapon = null; lCombatMessage.DamageType = _DamageType; lCombatMessage.ImpactType = _ImpactType; lCombatMessage.Damage = lDamage; lCombatMessage.AnimationEnabled = _PlayAnimation; lCombatMessage.HitPoint = lPoint; lCombatMessage.HitDirection = lHitDirection; lCombatMessage.HitVector = lForward; lCombatMessage.HitTransform = lHitTransform; // Let the defender react to the damage if (lDefenderCore != null) { lDefenderCore.SendMessage(lCombatMessage); } // If needed, send the damage directly to the actor core else if (lDamageable != null) { lDamageable.OnDamaged(lCombatMessage); } // Without an actor core, check if we can set attributes else { IAttributeSource lAttributeSource = rTarget.GetComponent <IAttributeSource>(); if (lAttributeSource != null) { float lHealth = lAttributeSource.GetAttributeValue <float>(EnumAttributeIDs.HEALTH); lAttributeSource.SetAttributeValue(EnumAttributeIDs.HEALTH, Mathf.Max(lHealth - lCombatMessage.Damage, 0f)); } } // Release the message lCombatMessage.Release(); }