/// <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 }
/// <summary> /// Clears a slot by the storing the current item. We'll use the /// store motion if it exists /// </summary> /// <param name="rSlotID">Slot that is being cleared</param> /// <returns></returns> protected virtual IEnumerator Internal_StoreItem(string rSlotID) { BasicInventorySlot lSlot = GetInventorySlot(rSlotID); if (lSlot != null) { BasicInventoryItem lItem = GetInventoryItem(lSlot.ItemID); if (lItem != null) { // Run the unequip motion if (lItem.StoreMotion.Length > 0) { // If we have a motion to unequip, activate it MotionControllerMotion lMotion = mMotionController.GetMotion(lItem.StoreMotion); if (lMotion != null) { // This is an extra test so we don't try to sheathe a weapons we just // unsheathed... until we're totally done with the transitions while (lMotion.MotionLayer._AnimatorTransitionID != 0) { yield return(null); } IEquipStoreMotion lEquipStoreMotion = lMotion as IEquipStoreMotion; if (lEquipStoreMotion != null) { lEquipStoreMotion.OverrideItemID = lItem.ID; lEquipStoreMotion.OverrideSlotID = lSlot.ID; } // Now sheathe mMotionController.ActivateMotion(lMotion); while (lMotion.IsActive || lMotion.QueueActivation) { yield return(null); } } } // Otherwise, simply unequip else { StoreItem(lSlot.ID); } } // Clear the slot lSlot.ItemID = ""; } }
/// <summary> /// Coroutine to play the death animation and disable the actor after a couple of seconds /// </summary> /// <param name="rDamageValue">Amount of damage to take</param> /// <param name="rDamageType">Damage type taken</param> /// <param name="rAttackAngle">Angle that the damage came from releative to the actor's forward</param> /// <param name="rBone">Transform that the damage it... if known</param> /// <returns></returns> protected virtual IEnumerator InternalDeath(float rDamageValue = 0, int rDamageType = 0, float rAttackAngle = 0f, Transform rBone = null) { MotionController lMC = gameObject.GetComponent <MotionController>(); if (lMC != null) { // Wait for any transition to finish while (lMC.ActiveMotion != null && lMC.ActiveMotion.MotionLayer.AnimatorTransitionID != 0) { yield return(null); } // Trigger the death animation lMC.ActivateMotion(DeathMotion, (int)rAttackAngle); yield return(new WaitForSeconds(3.5f)); // Shut down the MC lMC.enabled = false; lMC.ActorController.enabled = false; Collider[] lColliders = gameObject.GetComponents <Collider>(); for (int i = 0; i < lColliders.Length; i++) { lColliders[i].enabled = false; } } }
/// <summary> /// Called when the actor takes damage. This allows the actor to respond. /// Damage Type 0 = Physical melee /// Damage Type 1 = Physical ranged /// </summary> /// <param name="rDamageValue">Amount of damage to take</param> /// <param name="rDamageType">Damage type taken</param> /// <param name="rAttackAngle">Angle that the damage came from releative to the actor's forward</param> /// <returns>Determines if the damage was applied</returns> public virtual bool OnDamaged(float rDamageValue, int rDamageType = 0, float rAttackAngle = 0f, Transform rBone = null) { if (!IsAlive) { return(true); } float lRemainingHealth = 0f; if (AttributeSource != null) { lRemainingHealth = AttributeSource.GetAttributeValue(HealthID) - rDamageValue; AttributeSource.SetAttributeValue(HealthID, lRemainingHealth); } if (lRemainingHealth <= 0f) { OnDeath(rDamageValue, rDamageType, rAttackAngle, rBone); } else { MotionController lMC = gameObject.GetComponent <MotionController>(); if (lMC != null) { lMC.ActivateMotion(DamagedMotion, (int)rAttackAngle); } } return(true); }
/// <summary> /// Activates the motion on the specified target /// </summary> /// <param name="rTarget">GameObject to activate the motion on</param> /// <returns>Bool that determines if the motion was activated</returns> public bool ActivateInstance(GameObject rTarget) { bool lIsActivated = false; // Check if we have a motion controller and activate the motion MotionController lMotionController = rTarget.GetComponent <MotionController>(); if (lMotionController != null) { mMotion = lMotionController.ActivateMotion(MotionName); if (mMotion != null) { lIsActivated = true; // Clear out any event first, then add our event if (TargetTypeIndex == 0 || TargetTypeIndex == 1) { mMotion.OnDeactivatedEvent -= OnMotionDeactivated; mMotion.OnDeactivatedEvent += OnMotionDeactivated; } } // Grab the state as needed if (ExitState.Length > 0) { mExitStateID = lMotionController.AddAnimatorName(ExitState); } } return(lIsActivated); }
/// <summary> /// Coroutine to play the death animation and disable the actor after a couple of seconds /// </summary> /// <param name="rDamageValue">Amount of damage to take</param> /// <param name="rDamageType">Damage type taken</param> /// <param name="rAttackAngle">Angle that the damage came from releative to the actor's forward</param> /// <param name="rBone">Transform that the damage it... if known</param> /// <returns></returns> protected virtual IEnumerator InternalDeath(IMessage rMessage) { ActorController lActorController = gameObject.GetComponent <ActorController>(); MotionController lMotionController = gameObject.GetComponent <MotionController>(); // Run the death animation if we can if (rMessage != null && lMotionController != null) { // Send the message to the MC to let it activate rMessage.ID = CombatMessage.MSG_DEFENDER_KILLED; lMotionController.SendMessage(rMessage); if (!rMessage.IsHandled && DeathMotion.Length > 0) { MotionControllerMotion lMotion = lMotionController.GetMotion(DeathMotion); if (lMotion != null) { lMotionController.ActivateMotion(lMotion); } else { int lID = Animator.StringToHash(DeathMotion); if (lID != 0) { Animator lAnimator = gameObject.GetComponent <Animator>(); if (lAnimator != null) { try { lAnimator.CrossFade(DeathMotion, 0.25f, 0); } catch { } } } } } // Trigger the death animation yield return(new WaitForSeconds(3.0f)); // Shut down the MC lMotionController.enabled = false; lMotionController.ActorController.enabled = false; } // Disable all colliders Collider[] lColliders = gameObject.GetComponents <Collider>(); for (int i = 0; i < lColliders.Length; i++) { lColliders[i].enabled = false; } if (lActorController != null) { lActorController.RemoveBodyShapes(); } }
/// <summary> /// Activate the hand pose motion /// </summary> /// <param name="rHandPose"></param> protected void SetHandPose(BasicHandPose rHandPose) { if (rHandPose == null) { return; } //Debug.Log("[BasicHandPoseReactor] Setting " + rHandPose.Name); mMotionController.ActivateMotion(rHandPose); }
/// <summary> /// Update is called every frame, if the MonoBehaviour is enabled. /// </summary> protected virtual void Update() { // Check if we should cast a spell if (_ActionAlias.Length > 0 && _InputSource != null && _DefaultSpellIndex > 0 && _DefaultSpellIndex < _Spells.Count) { if (_InputSource.IsJustPressed(_ActionAlias)) { bool lCast = false; // Activate the spell through the motion MotionController lMotionController = gameObject.GetComponent <MotionController>(); if (lMotionController != null) { PMP_BasicSpellCastings lCastMotion = lMotionController.GetMotion <PMP_BasicSpellCastings>(); if (lCastMotion != null) { lCast = true; lMotionController.ActivateMotion(lCastMotion, _DefaultSpellIndex); } } // If we couldn't activate the motion, activate the spell directly if (!lCast) { InstantiateSpell(_DefaultSpellIndex); } } } // Update each active spell for (int i = 0; i < _ActiveSpells.Count; i++) { _ActiveSpells[i].Update(); } // Release the completed spells for (int i = _ActiveSpells.Count - 1; i >= 0; i--) { Spell lSpell = _ActiveSpells[i]; if (lSpell.State == EnumSpellState.COMPLETED) { lSpell.Release(); _ActiveSpells.RemoveAt(i); } } }
void MotionPlay() { GameObject go = Fsm.GetOwnerDefaultTarget(gameObject); if (go == null) { return; } mMotionController = go.GetComponent <MotionController>(); if (mMotionController != null) { MotionControllerMotion lMotion = mMotionController.GetMotion(mLayer.Value, motionName.Value); mMotionController.ActivateMotion(lMotion); } }
private void OnGUI() { if (MotionController == null || SpellInventory == null) { GUI.Label(new Rect(10, 10, 300, 20), "No Motion Controller or Spell Inventory Set!"); return; } float lWidth = 60f; float lHeight = 45f; float lSpacer = 10f; int lSpellCount = Mathf.Min(SpellInventory._Spells.Count, SpellIndexes.Count); float lBarWidth = (lSpellCount * lWidth) + ((lSpellCount - 1) * lSpacer); float lBarX = (Screen.width - lBarWidth) * 0.5f; float lBarY = (Screen.height - lHeight - lSpacer); for (int i = 0; i < lSpellCount; i++) { int lIndex = SpellIndexes[i]; string lName = SpellInventory._Spells[lIndex].Name.Replace(" ", "\n"); if (GUI.Button(new Rect(lBarX + ((lWidth + lSpacer) * i), lBarY, lWidth, lHeight), lName)) { BasicSpellCasting lCastMotion = MotionController.GetMotion <BasicSpellCasting>(); if (!lCastMotion.IsActive && (!lCastMotion.RequiresStance || MotionController.ActorController.State.Stance == EnumControllerStance.SPELL_CASTING)) { MotionController.ActivateMotion(lCastMotion, lIndex); } } } //if (GUI.Button(new Rect(10f, lHeight + lSpacer, lWidth, lHeight), "Interrupt")) //{ // MotionControllerMotion lMotion = MotionController.GetActiveMotion(0); // lMotion.Interrupt(null); //} }
void SpellCast() { GameObject go = Fsm.GetOwnerDefaultTarget(gameObject); if (go == null) { return; } mMotionController = go.GetComponent <MotionController>(); mSpellInventory = go.GetComponent <SpellInventory>(); if (mMotionController != null && mSpellInventory != null) { PMP_BasicSpellCastings lCastMotion = mMotionController.GetMotion <PMP_BasicSpellCastings>(); if (!lCastMotion.IsActive && (!lCastMotion.RequiresStance || mMotionController.ActorController.State.Stance == EnumControllerStance.SPELL_CASTING)) { mMotionController.ActivateMotion(lCastMotion, spellIndex.Value); } Debug.Log("Cast Spell " + GetSpellName()); } }
/// <summary> /// Coroutine for moving the actor to the right position /// </summary> /// <param name="rMotion"></param> /// <returns></returns> public virtual IEnumerator MoveToTargetInternal(IInteractableCore rInteractableCore) { bool lStoredWalkRunMotionEnabled = false; bool lStoredUseTransformPosition = false; bool lStoredUseTransformRotation = false; MotionController lMotionController = mMotionController; ActorController lActorController = lMotionController._ActorController; // Enable AC positioning lStoredUseTransformPosition = lActorController.UseTransformPosition; lActorController.UseTransformPosition = true; lStoredUseTransformRotation = lActorController.UseTransformRotation; lActorController.UseTransformRotation = true; // Enable our strafing motion MotionControllerMotion lWalkRunMotion = lMotionController.GetMotion(_WalkRunMotion, true); if (lWalkRunMotion != null) { lStoredWalkRunMotionEnabled = lWalkRunMotion.IsEnabled; lWalkRunMotion.IsEnabled = true; } Vector3 lTargetPosition = lActorController._Transform.position; if (rInteractableCore.ForcePosition) { if (rInteractableCore.TargetLocation != null) { lTargetPosition = rInteractableCore.TargetLocation.position; } else if (rInteractableCore.TargetDistance > 0f) { Vector3 lInteractablePosition = rInteractableCore.gameObject.transform.position; lInteractablePosition.y = lActorController._Transform.position.y; lTargetPosition = lInteractablePosition + ((lActorController._Transform.position - lInteractablePosition).normalized * rInteractableCore.TargetDistance); } } Vector3 lTargetForward = lActorController._Transform.forward; if (rInteractableCore.ForceRotation) { if (rInteractableCore.TargetLocation != null) { lTargetForward = rInteractableCore.TargetLocation.forward; } else { Vector3 lInteractablePosition = rInteractableCore.gameObject.transform.position; lInteractablePosition.y = lActorController._Transform.position.y; lTargetForward = (lInteractablePosition - lActorController._Transform.position).normalized; } } // Move to the target position and rotation Vector3 lDirection = lTargetPosition - lActorController._Transform.position; float lAngle = Vector3Ext.HorizontalAngleTo(lActorController._Transform.forward, lTargetForward); while (HorizontalDistance(lActorController._Transform.position, lTargetPosition) > 0.01f || Mathf.Abs(lAngle) > 0.1f) { float lDistance = Mathf.Min(lDirection.magnitude, _WalkSpeed * Time.deltaTime); lActorController._Transform.position = lActorController._Transform.position + (lDirection.normalized * lDistance); float lYaw = Mathf.Sign(lAngle) * Mathf.Min(Mathf.Abs(lAngle), _RotationSpeed * Time.deltaTime); lActorController._Transform.rotation = (lActorController._Transform.rotation * Quaternion.Euler(0f, lYaw, 0f)); yield return(new WaitForEndOfFrame()); lDirection = lTargetPosition - lActorController._Transform.position; lAngle = Vector3Ext.HorizontalAngleTo(lActorController._Transform.forward, lTargetForward); } // Activate BasicInteraction mActiveForm = rInteractableCore.Form; InteractableCore = rInteractableCore; lMotionController.ActivateMotion(this); // Give some final frames to get to the exact position yield return(new WaitForSeconds(0.2f)); // Reset the motion and movement options if (lWalkRunMotion != null) { lWalkRunMotion.IsEnabled = lStoredWalkRunMotionEnabled; } lActorController.UseTransformPosition = lStoredUseTransformPosition; lActorController.UseTransformRotation = lStoredUseTransformRotation; lMotionController.TargetNormalizedSpeed = 1f; }
/// <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)); } }
/// <summary> /// Called when the actor takes damage. This allows the actor to respond. /// Damage Type 0 = Physical melee /// Damage Type 1 = Physical ranged /// </summary> /// <param name="rDamageValue">Amount of damage to take</param> /// <param name="rDamageType">Damage type taken</param> /// <param name="rAttackAngle">Angle that the damage came from releative to the actor's forward</param> /// <param name="rDamagedMotion">Motion to activate due to damage</param> /// <param name="rDeathMotion">Motion to activate due to death</param> /// <returns>Determines if the damage was applied</returns> public virtual bool OnDamaged(IMessage rMessage) { if (!IsAlive) { return(true); } float lRemainingHealth = 0f; if (AttributeSource != null) { if (rMessage is DamageMessage) { lRemainingHealth = AttributeSource.GetAttributeValue(HealthID) - ((DamageMessage)rMessage).Damage; AttributeSource.SetAttributeValue(HealthID, lRemainingHealth); } } if (lRemainingHealth <= 0f) { OnKilled(rMessage); } else if (rMessage != null) { bool lPlayAnimation = true; if (rMessage is DamageMessage) { lPlayAnimation = ((DamageMessage)rMessage).AnimationEnabled; } if (lPlayAnimation) { MotionController lMotionController = gameObject.GetComponent <MotionController>(); if (lMotionController != null) { // Send the message to the MC to let it activate rMessage.ID = CombatMessage.MSG_DEFENDER_DAMAGED; lMotionController.SendMessage(rMessage); } if (!rMessage.IsHandled && DamagedMotion.Length > 0) { MotionControllerMotion lMotion = lMotionController.GetMotion(DamagedMotion); if (lMotion != null) { lMotionController.ActivateMotion(lMotion); } else { Animator lAnimator = gameObject.GetComponent <Animator>(); if (lAnimator != null) { lAnimator.CrossFade(DamagedMotion, 0.25f); } } } } } return(true); }
/// <summary> /// Called when the reactor is first activated /// </summary> /// <returns>Determines if other reactors should process.</returns> public override bool Activate() { base.Activate(); float lRemainingHealth = 0f; if (mActorCore.AttributeSource != null) { lRemainingHealth = mActorCore.AttributeSource.GetAttributeValue <float>(HealthID) - ((DamageMessage)mMessage).Damage; mActorCore.AttributeSource.SetAttributeValue(HealthID, lRemainingHealth); } // Forward to a death reactor if (lRemainingHealth <= 0f) { mMessage.ID = CombatMessage.MSG_DEFENDER_KILLED; mActorCore.SendMessage(mMessage); } // Process the damage else if (mMessage != null) { bool lPlayAnimation = ((DamageMessage)mMessage).AnimationEnabled; if (lPlayAnimation) { MotionController lMotionController = mActorCore.gameObject.GetComponent <MotionController>(); if (lMotionController != null) { // Send the message to the MC to let it activate mMessage.ID = CombatMessage.MSG_DEFENDER_DAMAGED; lMotionController.SendMessage(mMessage); } if (!mMessage.IsHandled && DamagedMotion.Length > 0) { MotionControllerMotion lMotion = null; if (lMotionController != null) { lMotion = lMotionController.GetMotion(DamagedMotion); } if (lMotion != null) { lMotionController.ActivateMotion(lMotion); } else { int lID = Animator.StringToHash(DamagedMotion); if (lID != 0) { Animator lAnimator = mActorCore.gameObject.GetComponent <Animator>(); if (lAnimator != null) { lAnimator.CrossFade(DamagedMotion, 0.25f, 0); } } } } } } // Disable the reactor Deactivate(); // Allow other reactors to continue return(true); }