// Check if raycast hit a generic action component private bool ActionCheck(RaycastHit hitInfo, out DaggerfallAction action) { // Look for action action = hitInfo.transform.GetComponent<DaggerfallAction>(); if (action == null) return false; else return true; }
// Check if raycast hit a generic action component private bool ActionCheck(RaycastHit hitInfo, out DaggerfallAction action) { // Look for action action = hitInfo.transform.GetComponent <DaggerfallAction>(); if (action == null) { return(false); } else { return(true); } }
// Check if raycast hit a generic action component private bool ActionCheck(RaycastHit hitInfo, out DaggerfallAction action) { // Look for action action = hitInfo.transform.GetComponent<DaggerfallAction>(); if (action == null) return false; // Must be root action of chain (no parent) if (action.PreviousObject != null) { action = null; return false; } return true; }
// Check if raycast hit a generic action component private bool ActionCheck(RaycastHit hitInfo, out DaggerfallAction action) { // Look for action action = hitInfo.transform.GetComponent <DaggerfallAction>(); if (action == null) { return(false); } // Must be root action of chain (no parent) if (action.PreviousObject != null) { action = null; return(false); } return(true); }
public override void OnInspectorGUI() { //base.OnInspectorGUI(); DrawDefaultInspector(); DaggerfallAction thisAction = (DaggerfallAction)target; if (GUILayout.Button("Activate") && EditorApplication.isPlaying) { if (thisAction.PreviousObject == null) { thisAction.Play(GameObject.FindGameObjectWithTag("Player")); } else { thisAction.Play(thisAction.PreviousObject); } } }
/// <summary> /// Links action chains together. /// </summary> public static void LinkActionNodes(Dictionary <int, ActionLink> actionLinkDict) { // Exit if no actions if (actionLinkDict.Count == 0) { return; } // Iterate through actions foreach (var item in actionLinkDict) { ActionLink link = item.Value; DaggerfallAction dfAction = link.gameObject.GetComponent <DaggerfallAction>(); if (dfAction == null) { continue; } try { // Link to next node if (actionLinkDict.ContainsKey(link.nextKey)) { dfAction.NextObject = actionLinkDict[link.nextKey].gameObject; } // Link to previous node if (actionLinkDict.ContainsKey(link.prevKey)) { dfAction.PreviousObject = actionLinkDict[link.prevKey].gameObject; } } catch (Exception ex) { DaggerfallUnity.LogMessage(ex.Message, true); DaggerfallUnity.LogMessage(string.Format("Error in LinkActionNodes; {0} : {1} : {2} : {3}", link.gameObject.name, link.nextKey, link.prevKey, dfAction), true); } } }
/// <summary> /// Constructs a Vector3 from magnitude and direction in RDB action resource. /// </summary> private static void GetRotationActionVector(ref DaggerfallAction action, DFBlock.RdbActionAxes axis) { Vector3 vector = Vector3.zero; float magnitude = action.Magnitude; switch (axis) { case DFBlock.RdbActionAxes.NegativeX: vector.x = -magnitude; break; case DFBlock.RdbActionAxes.NegativeY: vector.y = -magnitude; break; case DFBlock.RdbActionAxes.NegativeZ: vector.z = -magnitude; break; case DFBlock.RdbActionAxes.PositiveX: vector.x = magnitude; break; case DFBlock.RdbActionAxes.PositiveY: vector.y = magnitude; break; case DFBlock.RdbActionAxes.PositiveZ: vector.z = magnitude; break; default: magnitude = 0f; break; } action.ActionRotation = vector / BlocksFile.RotationDivisor; }
/// <summary> /// Constructs a Vector3 from magnitude and direction in RDB action resource. /// </summary> private static void GetTranslationActionVector(ref DaggerfallAction action, DFBlock.RdbActionAxes axis) { Vector3 vector = Vector3.zero; float magnitude = action.Magnitude; switch (axis) { case DFBlock.RdbActionAxes.NegativeX: vector.x = magnitude; break; case DFBlock.RdbActionAxes.NegativeY: vector.y = -magnitude; break; case DFBlock.RdbActionAxes.NegativeZ: vector.z = magnitude; break; case DFBlock.RdbActionAxes.PositiveX: vector.x = -magnitude; break; case DFBlock.RdbActionAxes.PositiveY: vector.y = magnitude; break; case DFBlock.RdbActionAxes.PositiveZ: vector.z = -magnitude; break; default: magnitude = 0f; break; } action.ActionTranslation = vector * MeshReader.GlobalScale; }
/// <summary> /// Add action to model. /// </summary> private static void AddAction( GameObject go, DFBlock blockData, DFBlock.RdbObject obj, int modelReference, int groupIndex, Dictionary <int, ActionLink> actionLinkDict) { // Get model action record and description DFBlock.RdbActionResource action = obj.Resources.ModelResource.ActionResource; string description = blockData.RdbBlock.ModelReferenceList[modelReference].Description; // Check for known action types Vector3 actionRotation = Vector3.zero; Vector3 actionTranslation = Vector3.zero; if ((action.Flags & (int)DFBlock.RdbActionFlags.Rotation) == (int)DFBlock.RdbActionFlags.Rotation) { actionRotation = (GetActionVector(ref action) / BlocksFile.RotationDivisor); } if ((action.Flags & (int)DFBlock.RdbActionFlags.Translation) == (int)DFBlock.RdbActionFlags.Translation) { actionTranslation = GetActionVector(ref action) * MeshReader.GlobalScale; } // A quick hack to fix special-case rotation issues. // Currently unknown if there is data indicating different rotation behaviour or if something else is happening. switch (description) { case "LID": actionRotation = new Vector3(0, 0, -90f); // Coffin lids (e.g. Scourg barrow) break; case "WHE": actionRotation = new Vector3(0, -360f, 0); // Wheels (e.g. Direnni Tower) break; } // Create action component DaggerfallAction c = go.AddComponent <DaggerfallAction>(); c.ActionEnabled = true; c.ModelDescription = description; c.ActionRotation = actionRotation; c.ActionTranslation = actionTranslation; c.ActionSoundID = obj.Resources.ModelResource.SoundId; // Using 1/20 of native value in seconds // This seems to match game very closely c.ActionDuration = (float)action.Duration / 20f; c.ActionFlags = action.Flags; // Create action links ActionLink link; link.gameObject = go; link.nextKey = GetActionKey(groupIndex, action.NextObjectIndex); link.prevKey = GetActionKey(groupIndex, action.PreviousObjectIndex); actionLinkDict.Add(GetActionKey(groupIndex, obj.Index), link); // Add sound AddActionAudioSource(go, (uint)c.ActionSoundID); return; }
private void WeaponDamage(FPSWeapon weapon, out bool hitEnemy) { hitEnemy = false; if (!mainCamera || !weapon) { return; } // Fire ray along player facing using weapon range RaycastHit hit; Ray ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward); if (Physics.SphereCast(ray, SphereCastRadius, out hit, weapon.Reach - SphereCastRadius)) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return; } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage = FormulaHelper.CalculateWeaponDamage(playerEntity, enemyEntity, weapon); // Play hit sound and trigger blood splash at hit point if (damage > 0) { weapon.PlayHitSound(); EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } } else { if (!enemyEntity.MobileEnemy.ParrySounds || weapon.WeaponType == WeaponTypes.Melee) { weapon.PlaySwingSound(); } else { weapon.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); hitEnemy = true; // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToPlayer(gameObject); } } } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { // TODO: Create blood splash. weapon.PlayHitSound(); mobileNpc.Motor.gameObject.SetActive(false); //GameManager.Instance.PlayerEntity.TallyCrimeGuildRequirements(false, 5); } } }
// Returns true if hit an enemy entity public bool WeaponDamage(RaycastHit hit, Vector3 direction, Collider arrowHitCollider = null, bool arrowHit = false) { DaggerfallUnityItem strikingWeapon = null; if (!arrowHit) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(true); return(false); } // Check if player hit a static exterior door if (GameManager.Instance.PlayerActivate.AttemptExteriorDoorBash(hit)) { return(false); } } // Set up for use below DaggerfallEntityBehaviour entityBehaviour = null; DaggerfallMobileUnit entityMobileUnit = null; EnemyMotor enemyMotor = null; EnemySounds enemySounds = null; if (!arrowHit) { entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); enemyMotor = hit.transform.GetComponent <EnemyMotor>(); enemySounds = hit.transform.GetComponent <EnemySounds>(); } else if (arrowHitCollider != null) { entityBehaviour = arrowHitCollider.gameObject.transform.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = arrowHitCollider.gameObject.transform.GetComponentInChildren <DaggerfallMobileUnit>(); enemyMotor = arrowHitCollider.gameObject.transform.GetComponent <EnemyMotor>(); enemySounds = arrowHitCollider.gameObject.transform.GetComponent <EnemySounds>(); } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = null; if (!arrowHit) { mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); } else if (arrowHitCollider != null) { mobileNpc = arrowHitCollider.gameObject.transform.GetComponent <MobilePersonNPC>(); } if (mobileNpc) { if (!mobileNpc.Billboard.IsUsingGuardTexture) { EnemyBlood blood = null; if (!arrowHit) { blood = hit.transform.GetComponent <EnemyBlood>(); } else if (arrowHitCollider != null) { blood = arrowHitCollider.gameObject.transform.GetComponent <EnemyBlood>(); } if (blood) { if (!arrowHit) { blood.ShowBloodSplash(0, hit.point); } else { blood.ShowBloodSplash(0, arrowHitCollider.gameObject.transform.position); } } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); // Allow custom race handling of weapon hit against mobile NPCs, e.g. vampire feeding or lycanthrope killing if (entityBehaviour) { entityBehaviour.Entity.SetHealth(0); RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEntity(GameManager.Instance.PlayerEntity, entityBehaviour.Entity); } } } else { playerEntity.CrimeCommitted = PlayerEntity.Crimes.Assault; GameObject guard = playerEntity.SpawnCityGuard(mobileNpc.transform.position, mobileNpc.transform.forward); entityBehaviour = guard.GetComponent <DaggerfallEntityBehaviour>(); entityMobileUnit = guard.GetComponentInChildren <DaggerfallMobileUnit>(); enemyMotor = guard.GetComponent <EnemyMotor>(); enemySounds = guard.GetComponent <EnemySounds>(); } mobileNpc.Motor.gameObject.SetActive(false); } // Check if hit an entity and remove health if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage; if (!arrowHit) { if (usingRightHand) { strikingWeapon = currentRightHandWeapon; } else { strikingWeapon = currentLeftHandWeapon; } } else { strikingWeapon = lastBowUsed; } damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, strikingWeapon, entityMobileUnit.Summary.AnimStateRecord); // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } // Play arrow sound and add arrow to target's inventory if (arrowHit) { DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = null; if (!arrowHit) { blood = hit.transform.GetComponent <EnemyBlood>(); } else if (arrowHitCollider != null) { blood = arrowHitCollider.gameObject.transform.GetComponent <EnemyBlood>(); } if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockbackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float KnockbackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); KnockbackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (KnockbackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { KnockbackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockbackSpeed = KnockbackSpeed; enemyMotor.KnockbackDirection = direction; } } if (DaggerfallUnity.Settings.CombatVoices && entityBehaviour.EntityType == EntityTypes.EnemyClass && Dice100.SuccessRoll(40)) { Genders gender; if (entityMobileUnit.Summary.Enemy.Gender == MobileGender.Male || enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } bool heavyDamage = damage >= enemyEntity.MaxHealth / 4; enemySounds.PlayCombatVoice(gender, false, heavyDamage); } } else { if ((!arrowHit && !enemyEntity.MobileEnemy.ParrySounds) || strikingWeapon == null) { ScreenWeapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Handle weapon striking enchantments - this could change damage amount if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager effectManager = GetComponent <EntityEffectManager>(); if (effectManager) { damage = effectManager.DoItemEnchantmentPayloads(EnchantmentPayloadFlags.Strikes, strikingWeapon, GameManager.Instance.PlayerEntity.Items, enemyEntity.EntityBehaviour, damage); } strikingWeapon.RaiseOnWeaponStrikeEvent(entityBehaviour, damage); } // Remove health enemyEntity.DecreaseHealth(damage); // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToAttacker(GameManager.Instance.PlayerEntityBehaviour); } if (enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch && enemyEntity.CurrentHealth <= 0) { playerEntity.TallyCrimeGuildRequirements(false, 1); playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; } // Allow custom race handling of weapon hit against enemies, e.g. vampire feeding or lycanthrope killing RacialOverrideEffect racialOverride = GameManager.Instance.PlayerEffectManager.GetRacialOverrideEffect(); if (racialOverride != null) { racialOverride.OnWeaponHitEntity(GameManager.Instance.PlayerEntity, entityBehaviour.Entity); } return(true); } } return(false); }
private static void AddAction( GameObject go, string description, int soundID_and_index, float duration, float magnitude, int axis_raw, DFBlock.RdbTriggerFlags triggerFlag, DFBlock.RdbActionFlags actionFlag, long loadID = 0 ) { DaggerfallAction action = go.AddComponent <DaggerfallAction>(); action.ModelDescription = description; action.ActionDuration = duration; action.Magnitude = magnitude; action.Index = soundID_and_index; action.TriggerFlag = triggerFlag; action.ActionFlag = actionFlag; action.LoadID = loadID; // If SaveLoadManager present in game then attach SerializableActionObject if (SaveLoadManager.Instance != null) { go.AddComponent <SerializableActionObject>(); } //if a collision type action or action flat, add DaggerFallActionCollision component if (action.TriggerFlag == DFBlock.RdbTriggerFlags.Collision01 || action.TriggerFlag == DFBlock.RdbTriggerFlags.Collision03 || action.TriggerFlag == DFBlock.RdbTriggerFlags.DualTrigger || action.TriggerFlag == DFBlock.RdbTriggerFlags.Collision09) { DaggerfallActionCollision collision = go.AddComponent <DaggerfallActionCollision>(); collision.isFlat = false; } else if (description == "FLT") { DaggerfallActionCollision collision = go.AddComponent <DaggerfallActionCollision>(); collision.isFlat = true; } switch (action.ActionFlag) { case DFBlock.RdbActionFlags.Translation: { action.Magnitude = magnitude; GetTranslationActionVector(ref action, (DFBlock.RdbActionAxes)axis_raw); } break; case DFBlock.RdbActionFlags.Rotation: { action.Magnitude = magnitude; GetRotationActionVector(ref action, (DFBlock.RdbActionAxes)axis_raw); } break; case DFBlock.RdbActionFlags.PositiveX: { action.ActionDuration = 50; action.Magnitude = axis_raw * 8; GetTranslationActionVector(ref action, DFBlock.RdbActionAxes.PositiveX); } break; case DFBlock.RdbActionFlags.NegativeX: { action.ActionDuration = 50; action.Magnitude = axis_raw * 8; GetTranslationActionVector(ref action, DFBlock.RdbActionAxes.NegativeX); } break; case DFBlock.RdbActionFlags.PositiveY: { action.ActionDuration = 50; action.Magnitude = axis_raw * 8; GetTranslationActionVector(ref action, DFBlock.RdbActionAxes.PositiveY); } break; case DFBlock.RdbActionFlags.NegativeY: { action.ActionDuration = 50; action.Magnitude = axis_raw * 8; GetTranslationActionVector(ref action, DFBlock.RdbActionAxes.NegativeY); } break; case DFBlock.RdbActionFlags.PositiveZ: { action.ActionDuration = 50; action.Magnitude = axis_raw * 8; GetTranslationActionVector(ref action, DFBlock.RdbActionAxes.PositiveZ); } break; case DFBlock.RdbActionFlags.NegativeZ: { action.ActionDuration = 50; action.Magnitude = axis_raw * 8; GetTranslationActionVector(ref action, DFBlock.RdbActionAxes.NegativeZ); } break; default: { //Dmg actions use axis value to modifiy tot. dmg. action.Magnitude = axis_raw; } break; } // A quick hack to fix special-case rotation issues. // Currently unknown if there is data indicating different rotation behaviour or if something else is happening. switch (description) { case "LID": action.ActionRotation = new Vector3(0, 0, -90f); // Coffin lids (e.g. Scourg barrow) break; case "WHE": action.ActionRotation = new Vector3(0, -360f, 0); // Wheels (e.g. Direnni Tower) break; } //Add audio AddActionAudioSource(go, (uint)action.Index); }
private void WeaponDamage(FPSWeapon weapon, out bool hitEnemy) { hitEnemy = false; if (!mainCamera || !weapon) { return; } // Fire ray along player facing using weapon range RaycastHit hit; Ray ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward); if (Physics.SphereCast(ray, SphereCastRadius, out hit, weapon.Reach - SphereCastRadius)) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return; } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage = FormulaHelper.CalculateWeaponDamage(playerEntity, enemyEntity, weapon); // Play hit sound and trigger blood splash at hit point if (damage > 0) { weapon.PlayHitSound(); EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } } else { if (!enemyEntity.MobileEnemy.ParrySounds || weapon.WeaponType == WeaponTypes.Melee) { weapon.PlaySwingSound(); } else { weapon.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); hitEnemy = true; } } } }
private void MeleeDamage(FPSWeapon weapon) { if (!mainCamera || !weapon) return; // Fire ray along player facing using weapon range RaycastHit hit; Ray ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward); if (Physics.SphereCast(ray, SphereCastRadius, out hit, weapon.Reach - SphereCastRadius)) { //check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent<DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent<DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return; } // TODO: Use correct damage based on weapon and swing type // Just using fudge values during development int damage = Random.Range(1, 25); // Check if hit has an EnemyHealth // This is part of the old Demo code and will eventually be removed // For now enemies should either use EnemyHealth (deprecated) or EnemyEntity (current) to track enemy health // Never use both components on same enemy EnemyHealth enemyHealth = hit.transform.gameObject.GetComponent<EnemyHealth>(); if (enemyHealth) { // Example: Play sound based on fake parry mechanics if (Random.value < ChanceToBeParried) { // Parried weapon.PlayParrySound(); return; } else { // Connected weapon.PlayHitSound(); enemyHealth.RemoveHealth(player, damage, hit.point); } } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent<DaggerfallEntityBehaviour>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Trigger blood splash at hit point EnemyBlood blood = hit.transform.GetComponent<EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Remove health and handle death enemyEntity.DecreaseHealth(damage); if (enemyEntity.CurrentHealth <= 0) { // Using SendMessage for now, will replace later hit.transform.SendMessage("Die"); } } } } }
private void WeaponDamage(FPSWeapon weapon, out bool hitEnemy) { hitEnemy = false; DaggerfallUnityItem strikingWeapon = null; if (!mainCamera || !weapon) { return; } // Fire ray along player facing using weapon range // Origin point of ray is set back slightly to fix issue where strikes against enemy capsules touching player capsule do not connect RaycastHit hit; Ray ray = new Ray(mainCamera.transform.position + -mainCamera.transform.forward * 0.1f, mainCamera.transform.forward); if (Physics.SphereCast(ray, SphereCastRadius, out hit, weapon.Reach - SphereCastRadius)) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return; } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); DaggerfallMobileUnit entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage; if (usingRightHand) { damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, (int)(EquipSlots.RightHand), entityMobileUnit.Summary.AnimStateRecord); strikingWeapon = currentRightHandWeapon; } else { damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, (int)(EquipSlots.LeftHand), entityMobileUnit.Summary.AnimStateRecord); strikingWeapon = currentLeftHandWeapon; } // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hit.transform.GetComponent <EnemySounds>(); // Play arrow sound and add arrow to target's inventory if (weapon.WeaponType == WeaponTypes.Bow) { enemySounds.PlayArrowSound(); DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockBackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float knockBackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); knockBackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (knockBackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { knockBackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockBackSpeed = knockBackSpeed; enemyMotor.KnockBackDirection = mainCamera.transform.forward; } } } else { if ((weapon.WeaponType != WeaponTypes.Bow && !enemyEntity.MobileEnemy.ParrySounds) || weapon.WeaponType == WeaponTypes.Melee) { weapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); hitEnemy = true; // Assign "cast when strikes" to target entity if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager enemyEffectManager = enemyEntity.EntityBehaviour.GetComponent <EntityEffectManager>(); if (enemyEffectManager) { enemyEffectManager.StrikeWithItem(strikingWeapon, GameManager.Instance.PlayerEntityBehaviour); } } // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToPlayer(gameObject); } } } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(0, hit.point); } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); // TODO: LOS check from each townsperson. If seen, register crime and start spawning guards as below. playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); } } }
private void WeaponDamage(FPSWeapon weapon, out bool hitEnemy) { hitEnemy = false; if (!mainCamera || !weapon) { return; } // Fire ray along player facing using weapon range RaycastHit hit; Ray ray = new Ray(mainCamera.transform.position, mainCamera.transform.forward); if (Physics.SphereCast(ray, SphereCastRadius, out hit, weapon.Reach - SphereCastRadius)) { // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return; } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); DaggerfallMobileUnit entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage; if (usingRightHand) { damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, (int)(EquipSlots.RightHand), entityMobileUnit.Summary.AnimStateRecord); } else { damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, (int)(EquipSlots.LeftHand), entityMobileUnit.Summary.AnimStateRecord); } EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hit.transform.GetComponent <EnemySounds>(); // Play arrow sound and add arrow to target's inventory if (weapon.WeaponType == WeaponTypes.Bow) { enemySounds.PlayArrowSound(); DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockBackSpeed <= (5 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float knockBackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); knockBackSpeed /= (PlayerMotor.classicToUnitySpeedUnitRatio / 10); if (knockBackSpeed < (15 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10))) { knockBackSpeed = (15 / (PlayerMotor.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockBackSpeed = knockBackSpeed; enemyMotor.KnockBackDirection = mainCamera.transform.forward; } } } else { if ((weapon.WeaponType != WeaponTypes.Bow && !enemyEntity.MobileEnemy.ParrySounds) || weapon.WeaponType == WeaponTypes.Melee) { weapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); hitEnemy = true; // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToPlayer(gameObject); } } } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { // TODO: Create blood splash. mobileNpc.Motor.gameObject.SetActive(false); //GameManager.Instance.PlayerEntity.TallyCrimeGuildRequirements(false, 5); } } }
void Update() { if (GameManager.Instance.PlayerEntity.CurrentHealth < 1 || GameManager.IsGamePaused || GameManager.Instance.PlayerMotor.IsSwimming || GameManager.Instance.PlayerMotor.IsLevitating || GameManager.Instance.PlayerMotor.OnExteriorWater == PlayerMotor.OnExteriorWaterMethod.Swimming) { return; } float distance; if (!playerMotor.IsCrouching) { distance = (controller.height / 2f) - (controller.height * 0.1f); } else { distance = (controller.height / 2f); } if (moveScanner.HeadHitDistance < distance && moveScanner.HeadHitDistance > 0) { // Tests to prevent player being crushed by static geometry, non-action colliders, or currently stationary action objects // Only perform these tests if move scanner head raycast has found a valid transform if (moveScanner.HeadRaycastHit.transform) { // Do nothing if move scanner has detected a static gameobject // This prevents player from being crushed under sloping non-moving geometry found on boat and inside buildings // Also stops player being forced into a crouch from just brushing up against sloping geometry if (GameObjectHelper.IsStaticGeometry(moveScanner.HeadRaycastHit.transform.gameObject)) { return; } // We found a non-static object, but it really an action object (e.g. moving platform)? DaggerfallAction action = moveScanner.HeadRaycastHit.transform.gameObject.GetComponent <DaggerfallAction>(); if (!action) { return; } // Confirm dynamic object actually in motion, not just a stationary action object player happened to bump their head into if (!action.IsMoving) { return; } // Exclude "BOX" to prevent unintended crushing hazard in Mantellan Crux - player instead pushed back by physics if (action.ModelDescription == "BOX") { return; } // This object fits criteria for a crushing object // Player will first be forced into a crouch then killed if they remain under crushing object past threshold height if (!playerMotor.IsCrouching && heightChanger.HeightAction != HeightChangeAction.DoCrouching) { // If player is standing then crushing object forces them into a crouch heightChanger.HeightAction = HeightChangeAction.DoCrouching; } else if (playerMotor.IsCrouching && playerMotor.IsGrounded) { // If player already crouching and on the ground, then kill if (previousHeightHit > 0 && previousHeightHit > moveScanner.HeadHitDistance) { GameManager.Instance.PlayerEntity.SetHealth(0); } } } previousHeightHit = moveScanner.HeadHitDistance; } else { previousHeightHit = 0f; } }
// Returns true if hit an enemy entity public bool WeaponDamage(RaycastHit hit, Vector3 direction, bool arrowHit = false) { DaggerfallUnityItem strikingWeapon = null; // Check if hit has an DaggerfallAction component DaggerfallAction action = hit.transform.gameObject.GetComponent <DaggerfallAction>(); if (action) { action.Receive(player, DaggerfallAction.TriggerTypes.Attack); } // Check if hit has an DaggerfallActionDoor component DaggerfallActionDoor actionDoor = hit.transform.gameObject.GetComponent <DaggerfallActionDoor>(); if (actionDoor) { actionDoor.AttemptBash(); return(false); } // Check if hit an entity and remove health DaggerfallEntityBehaviour entityBehaviour = hit.transform.GetComponent <DaggerfallEntityBehaviour>(); DaggerfallMobileUnit entityMobileUnit = hit.transform.GetComponentInChildren <DaggerfallMobileUnit>(); if (entityBehaviour) { if (entityBehaviour.EntityType == EntityTypes.EnemyMonster || entityBehaviour.EntityType == EntityTypes.EnemyClass) { EnemyEntity enemyEntity = entityBehaviour.Entity as EnemyEntity; // Calculate damage int damage; if (!arrowHit) { if (usingRightHand) { strikingWeapon = currentRightHandWeapon; } else { strikingWeapon = currentLeftHandWeapon; } } else { strikingWeapon = lastBowUsed; } damage = FormulaHelper.CalculateAttackDamage(playerEntity, enemyEntity, strikingWeapon, entityMobileUnit.Summary.AnimStateRecord); // Break any "normal power" concealment effects on player if (playerEntity.IsMagicallyConcealedNormalPower && damage > 0) { EntityEffectManager.BreakNormalPowerConcealmentEffects(GameManager.Instance.PlayerEntityBehaviour); } EnemyMotor enemyMotor = hit.transform.GetComponent <EnemyMotor>(); EnemySounds enemySounds = hit.transform.GetComponent <EnemySounds>(); // Play arrow sound and add arrow to target's inventory if (arrowHit) { DaggerfallUnityItem arrow = ItemBuilder.CreateItem(ItemGroups.Weapons, (int)Weapons.Arrow); enemyEntity.Items.AddItem(arrow); } // Play hit sound and trigger blood splash at hit point if (damage > 0) { if (usingRightHand) { enemySounds.PlayHitSound(currentRightHandWeapon); } else { enemySounds.PlayHitSound(currentLeftHandWeapon); } EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(enemyEntity.MobileEnemy.BloodIndex, hit.point); } // Knock back enemy based on damage and enemy weight if (enemyMotor) { if (enemyMotor.KnockBackSpeed <= (5 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)) && entityBehaviour.EntityType == EntityTypes.EnemyClass || enemyEntity.MobileEnemy.Weight > 0) { float enemyWeight = enemyEntity.GetWeightInClassicUnits(); float tenTimesDamage = damage * 10; float twoTimesDamage = damage * 2; float knockBackAmount = ((tenTimesDamage - enemyWeight) * 256) / (enemyWeight + tenTimesDamage) * twoTimesDamage; float knockBackSpeed = (tenTimesDamage / enemyWeight) * (twoTimesDamage - (knockBackAmount / 256)); knockBackSpeed /= (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10); if (knockBackSpeed < (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10))) { knockBackSpeed = (15 / (PlayerSpeedChanger.classicToUnitySpeedUnitRatio / 10)); } enemyMotor.KnockBackSpeed = knockBackSpeed; enemyMotor.KnockBackDirection = direction; } } if (DaggerfallUnity.Settings.CombatVoices && entityBehaviour.EntityType == EntityTypes.EnemyClass && UnityEngine.Random.Range(1, 101) <= 40) { Genders gender; if (entityMobileUnit.Summary.Enemy.Gender == MobileGender.Male || enemyEntity.MobileEnemy.ID == (int)MobileTypes.Knight_CityWatch) { gender = Genders.Male; } else { gender = Genders.Female; } bool heavyDamage = damage >= enemyEntity.MaxHealth / 4; enemySounds.PlayCombatVoice(gender, false, heavyDamage); } } else { if ((!arrowHit && !enemyEntity.MobileEnemy.ParrySounds) || strikingWeapon == null) { ScreenWeapon.PlaySwingSound(); } else if (enemyEntity.MobileEnemy.ParrySounds) { enemySounds.PlayParrySound(); } } // Remove health enemyEntity.DecreaseHealth(damage); // Assign "cast when strikes" to target entity if (strikingWeapon != null && strikingWeapon.IsEnchanted) { EntityEffectManager enemyEffectManager = enemyEntity.EntityBehaviour.GetComponent <EntityEffectManager>(); if (enemyEffectManager) { enemyEffectManager.StrikeWithItem(strikingWeapon, GameManager.Instance.PlayerEntityBehaviour); } } // Make foe attack their aggressor // Currently this is just player, but should be expanded later // for a wider variety of behaviours if (enemyMotor) { // Make enemies in an area aggressive if player attacked a non-hostile one. if (!enemyMotor.IsHostile) { GameManager.Instance.MakeEnemiesHostile(); } enemyMotor.MakeEnemyHostileToAttacker(GameManager.Instance.PlayerEntityBehaviour); } return(true); } } // Check if hit a mobile NPC MobilePersonNPC mobileNpc = hit.transform.GetComponent <MobilePersonNPC>(); if (mobileNpc) { EnemyBlood blood = hit.transform.GetComponent <EnemyBlood>(); if (blood) { blood.ShowBloodSplash(0, hit.point); } mobileNpc.Motor.gameObject.SetActive(false); playerEntity.TallyCrimeGuildRequirements(false, 5); // TODO: LOS check from each townsperson. If seen, register crime and start spawning guards as below. playerEntity.CrimeCommitted = PlayerEntity.Crimes.Murder; playerEntity.SpawnCityGuards(true); } return(false); }
void Awake() { action = GetComponent<DaggerfallAction>(); if (!action) throw new Exception("DaggerfallAction not found."); }