From 85bcb6b423e81ef1dde36025b7528355e74d1d5a Mon Sep 17 00:00:00 2001 From: RedRoryOTheGlen Date: Tue, 31 Mar 2026 16:40:43 +0800 Subject: [PATCH 1/7] Implemented PR #2472 as is. Additionally "Ignore Raycast" is now excluded from the LayerMask --- Assets/Prefabs/Missiles/ArrowMissile.prefab | 46 --------- Assets/Prefabs/Missiles/ColdMissile.prefab | 31 ------ Assets/Prefabs/Missiles/FireMissile.prefab | 31 ------ Assets/Prefabs/Missiles/MagicMissile.prefab | 31 ------ Assets/Prefabs/Missiles/PoisonMissile.prefab | 31 ------ Assets/Prefabs/Missiles/ShockMissile.prefab | 31 ------ Assets/Scripts/Game/DaggerfallMissile.cs | 99 +++++++++----------- 7 files changed, 46 insertions(+), 254 deletions(-) diff --git a/Assets/Prefabs/Missiles/ArrowMissile.prefab b/Assets/Prefabs/Missiles/ArrowMissile.prefab index a51b28ad9b..f1a01fe33f 100644 --- a/Assets/Prefabs/Missiles/ArrowMissile.prefab +++ b/Assets/Prefabs/Missiles/ArrowMissile.prefab @@ -11,11 +11,8 @@ GameObject: - component: {fileID: 4928002457579466} - component: {fileID: 82343321333735398} - component: {fileID: 114835290752812540} - - component: {fileID: 135236093773449130} - component: {fileID: 108732554255048532} - component: {fileID: 114624404217668130} - - component: {fileID: 54102960107042576} - - component: {fileID: 64298782196861766} m_Layer: 14 m_Name: ArrowMissile m_TagString: Untagged @@ -150,19 +147,6 @@ MonoBehaviour: PreviewIndex: 0 PreviewID: 3 PreviewClip: 0 ---- !u!135 &135236093773449130 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1712884651827938} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 0 - serializedVersion: 2 - m_Radius: 0.4 - m_Center: {x: 0, y: 0, z: 0} --- !u!108 &108732554255048532 Light: m_ObjectHideFlags: 0 @@ -250,33 +234,3 @@ MonoBehaviour: PostImpactLifespanInSeconds: 0.6 PostImpactLightMultiplier: 1.5 ImpactSound: 4 ---- !u!54 &54102960107042576 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1712884651827938} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 0 - m_IsKinematic: 1 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 ---- !u!64 &64298782196861766 -MeshCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1712884651827938} - m_Material: {fileID: 0} - m_IsTrigger: 1 - m_Enabled: 0 - serializedVersion: 4 - m_Convex: 1 - m_CookingOptions: 30 - m_Mesh: {fileID: 0} diff --git a/Assets/Prefabs/Missiles/ColdMissile.prefab b/Assets/Prefabs/Missiles/ColdMissile.prefab index 8799a3630d..4e809aa1ff 100644 --- a/Assets/Prefabs/Missiles/ColdMissile.prefab +++ b/Assets/Prefabs/Missiles/ColdMissile.prefab @@ -11,10 +11,8 @@ GameObject: - component: {fileID: 4187251767156800} - component: {fileID: 82507643407150988} - component: {fileID: 114467433757248316} - - component: {fileID: 135961771109985534} - component: {fileID: 108958489047367644} - component: {fileID: 114701158002484598} - - component: {fileID: 54482902062701562} m_Layer: 14 m_Name: ColdMissile m_TagString: Untagged @@ -149,19 +147,6 @@ MonoBehaviour: PreviewIndex: 0 PreviewID: 3 PreviewClip: 0 ---- !u!135 &135961771109985534 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.4 - m_Center: {x: 0, y: 0, z: 0} --- !u!108 &108958489047367644 Light: m_ObjectHideFlags: 0 @@ -249,19 +234,3 @@ MonoBehaviour: PostImpactLifespanInSeconds: 0.6 PostImpactLightMultiplier: 1.5 ImpactSound: 90 ---- !u!54 &54482902062701562 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 0 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 diff --git a/Assets/Prefabs/Missiles/FireMissile.prefab b/Assets/Prefabs/Missiles/FireMissile.prefab index 4792974a82..16596d5d30 100644 --- a/Assets/Prefabs/Missiles/FireMissile.prefab +++ b/Assets/Prefabs/Missiles/FireMissile.prefab @@ -11,10 +11,8 @@ GameObject: - component: {fileID: 4187251767156800} - component: {fileID: 82507643407150988} - component: {fileID: 114467433757248316} - - component: {fileID: 135961771109985534} - component: {fileID: 108958489047367644} - component: {fileID: 114701158002484598} - - component: {fileID: 54482902062701562} m_Layer: 14 m_Name: FireMissile m_TagString: Untagged @@ -149,19 +147,6 @@ MonoBehaviour: PreviewIndex: 0 PreviewID: 3 PreviewClip: 0 ---- !u!135 &135961771109985534 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.4 - m_Center: {x: 0, y: 0, z: 0} --- !u!108 &108958489047367644 Light: m_ObjectHideFlags: 0 @@ -249,19 +234,3 @@ MonoBehaviour: PostImpactLifespanInSeconds: 0.6 PostImpactLightMultiplier: 1.5 ImpactSound: 89 ---- !u!54 &54482902062701562 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 0 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 diff --git a/Assets/Prefabs/Missiles/MagicMissile.prefab b/Assets/Prefabs/Missiles/MagicMissile.prefab index 801c2d8225..17ee11dc8d 100644 --- a/Assets/Prefabs/Missiles/MagicMissile.prefab +++ b/Assets/Prefabs/Missiles/MagicMissile.prefab @@ -11,10 +11,8 @@ GameObject: - component: {fileID: 4187251767156800} - component: {fileID: 82507643407150988} - component: {fileID: 114467433757248316} - - component: {fileID: 135961771109985534} - component: {fileID: 108958489047367644} - component: {fileID: 114701158002484598} - - component: {fileID: 54482902062701562} m_Layer: 14 m_Name: MagicMissile m_TagString: Untagged @@ -149,19 +147,6 @@ MonoBehaviour: PreviewIndex: 0 PreviewID: 3 PreviewClip: 0 ---- !u!135 &135961771109985534 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.4 - m_Center: {x: 0, y: 0, z: 0} --- !u!108 &108958489047367644 Light: m_ObjectHideFlags: 0 @@ -249,19 +234,3 @@ MonoBehaviour: PostImpactLifespanInSeconds: 0.6 PostImpactLightMultiplier: 1.5 ImpactSound: 86 ---- !u!54 &54482902062701562 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 0 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 diff --git a/Assets/Prefabs/Missiles/PoisonMissile.prefab b/Assets/Prefabs/Missiles/PoisonMissile.prefab index c3d9e374d7..08eed308c7 100644 --- a/Assets/Prefabs/Missiles/PoisonMissile.prefab +++ b/Assets/Prefabs/Missiles/PoisonMissile.prefab @@ -11,10 +11,8 @@ GameObject: - component: {fileID: 4187251767156800} - component: {fileID: 82507643407150988} - component: {fileID: 114467433757248316} - - component: {fileID: 135961771109985534} - component: {fileID: 108958489047367644} - component: {fileID: 114701158002484598} - - component: {fileID: 54482902062701562} m_Layer: 14 m_Name: PoisonMissile m_TagString: Untagged @@ -149,19 +147,6 @@ MonoBehaviour: PreviewIndex: 0 PreviewID: 3 PreviewClip: 0 ---- !u!135 &135961771109985534 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.4 - m_Center: {x: 0, y: 0, z: 0} --- !u!108 &108958489047367644 Light: m_ObjectHideFlags: 0 @@ -249,19 +234,3 @@ MonoBehaviour: PostImpactLifespanInSeconds: 0.6 PostImpactLightMultiplier: 1.5 ImpactSound: 87 ---- !u!54 &54482902062701562 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 0 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 diff --git a/Assets/Prefabs/Missiles/ShockMissile.prefab b/Assets/Prefabs/Missiles/ShockMissile.prefab index ac61e7d00a..99abed7622 100644 --- a/Assets/Prefabs/Missiles/ShockMissile.prefab +++ b/Assets/Prefabs/Missiles/ShockMissile.prefab @@ -11,10 +11,8 @@ GameObject: - component: {fileID: 4187251767156800} - component: {fileID: 82507643407150988} - component: {fileID: 114467433757248316} - - component: {fileID: 135961771109985534} - component: {fileID: 108958489047367644} - component: {fileID: 114701158002484598} - - component: {fileID: 54482902062701562} m_Layer: 14 m_Name: ShockMissile m_TagString: Untagged @@ -149,19 +147,6 @@ MonoBehaviour: PreviewIndex: 0 PreviewID: 3 PreviewClip: 0 ---- !u!135 &135961771109985534 -SphereCollider: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - m_Material: {fileID: 0} - m_IsTrigger: 0 - m_Enabled: 1 - serializedVersion: 2 - m_Radius: 0.4 - m_Center: {x: 0, y: 0, z: 0} --- !u!108 &108958489047367644 Light: m_ObjectHideFlags: 0 @@ -249,19 +234,3 @@ MonoBehaviour: PostImpactLifespanInSeconds: 0.6 PostImpactLightMultiplier: 1.5 ImpactSound: 88 ---- !u!54 &54482902062701562 -Rigidbody: - m_ObjectHideFlags: 0 - m_CorrespondingSourceObject: {fileID: 0} - m_PrefabInstance: {fileID: 0} - m_PrefabAsset: {fileID: 0} - m_GameObject: {fileID: 1770169996000996} - serializedVersion: 2 - m_Mass: 1 - m_Drag: 0 - m_AngularDrag: 0.05 - m_UseGravity: 0 - m_IsKinematic: 0 - m_Interpolate: 0 - m_Constraints: 0 - m_CollisionDetection: 0 diff --git a/Assets/Scripts/Game/DaggerfallMissile.cs b/Assets/Scripts/Game/DaggerfallMissile.cs index e19184f823..80133a5a99 100644 --- a/Assets/Scripts/Game/DaggerfallMissile.cs +++ b/Assets/Scripts/Game/DaggerfallMissile.cs @@ -4,7 +4,7 @@ // License: MIT License (http://www.opensource.org/licenses/mit-license.php) // Source Code: https://github.com/Interkarma/daggerfall-unity // Original Author: Gavin Clayton (interkarma@dfworkshop.net) -// Contributors: Allofich +// Contributors: Allofich, Numidium // // Notes: // @@ -27,9 +27,6 @@ namespace DaggerfallWorkshop.Game /// Currently ranged missiles can only move in a straight line as per classic. /// [RequireComponent(typeof(Light))] - [RequireComponent(typeof(SphereCollider))] - [RequireComponent(typeof(MeshCollider))] - [RequireComponent(typeof(Rigidbody))] [RequireComponent(typeof(DaggerfallAudioSource))] public class DaggerfallMissile : MonoBehaviour { @@ -64,11 +61,11 @@ public class DaggerfallMissile : MonoBehaviour public const float SphereCastRadius = 0.25f; public const float TouchRange = 3.0f; + Vector3 colliderPosition; + Vector3 direction; Light myLight; - SphereCollider myCollider; DaggerfallAudioSource audioSource; - Rigidbody myRigidbody; Billboard myBillboard; bool forceDisableSpellLighting; bool noSpellsSpatialBlend = false; @@ -88,6 +85,8 @@ public class DaggerfallMissile : MonoBehaviour GameObject goModel = null; EnemySenses enemySenses; + int layerMask; + List targetEntities = new List(); @@ -182,14 +181,6 @@ private void Start() initialRange = myLight.range; initialIntensity = myLight.intensity; - // Setup collider - myCollider = GetComponent(); - myCollider.radius = ColliderRadius; - - // Setup rigidbody - myRigidbody = GetComponent(); - myRigidbody.useGravity = false; - // Use payload when available if (payload != null) { @@ -216,11 +207,7 @@ private void Start() if (isArrow) { // Create and orient 3d arrow - goModel = GameObjectHelper.CreateDaggerfallMeshGameObject(99800, transform); - MeshCollider arrowCollider = goModel.GetComponent(); - arrowCollider.sharedMesh = goModel.GetComponent().sharedMesh; - arrowCollider.convex = true; - arrowCollider.isTrigger = true; + goModel = GameObjectHelper.CreateDaggerfallMeshGameObject(99800, transform, ignoreCollider: true); // Offset up so it comes from same place LOS check is done from Vector3 adjust; @@ -234,8 +221,6 @@ private void Start() { // Adjust slightly downward to match bow animation adjust = (GameManager.Instance.MainCamera.transform.rotation * -Caster.transform.up) * 0.11f; - // Offset forward to avoid collision with player - adjust += GameManager.Instance.MainCamera.transform.forward * 0.6f; // Adjust to the right or left to match bow animation if (!GameManager.Instance.WeaponManager.ScreenWeapon.FlipHorizontal) adjust += GameManager.Instance.MainCamera.transform.right * 0.15f; @@ -248,9 +233,14 @@ private void Start() goModel.layer = gameObject.layer; } - // Ignore missile collision with caster (this is a different check to AOE targets) - if (caster) - Physics.IgnoreCollision(caster.GetComponent(), this.GetComponent()); + string layerName; + if (caster && caster != GameManager.Instance.PlayerEntityBehaviour) + layerName = "SpellMissiles"; + else + layerName = "Player"; + + layerMask = ~(1 << LayerMask.NameToLayer(layerName)); + layerMask = layerMask & ~(1 << LayerMask.NameToLayer("Ignore Raycast")); } private void Update() @@ -283,12 +273,13 @@ private void Update() transform.position += (direction * MovementSpeed) * Time.deltaTime; // Update lifespan and self-destruct if expired (e.g. spell fired straight up and will never hit anything) - lifespan += Time.deltaTime; if (lifespan > LifespanInSeconds) Destroy(gameObject); } else { + transform.position = colliderPosition; + // Notify listeners work is done and automatically assign impact if (!impactAssigned) { @@ -313,19 +304,35 @@ private void Update() UpdateLight(); } - #endregion - - #region Collision Handling - - private void OnCollisionEnter(Collision collision) + private void FixedUpdate() { - DoCollision(collision, null); + if (!missileReleased || impactDetected) + return; + lifespan += Time.fixedDeltaTime; + // Do fixed-interval transformation with raycast lookahead. + var displacement = (direction * MovementSpeed) * Time.fixedDeltaTime; + RaycastHit hitInfo; + bool castFoundHit; + if (isArrow || lifespan == Time.fixedDeltaTime) // First test should always be a raycast in case the caster is hugging a wall. + castFoundHit = Physics.Raycast(colliderPosition, direction, out hitInfo, displacement.magnitude + ColliderRadius, layerMask); + else + castFoundHit = Physics.SphereCast(colliderPosition, ColliderRadius, direction, out hitInfo, displacement.magnitude + ColliderRadius, layerMask); + if (castFoundHit) + { + // Place self at meeting point with collider and do collision logic. + if (isArrow) + colliderPosition = hitInfo.point - transform.forward * ColliderRadius; + else + colliderPosition += direction.normalized * hitInfo.distance; // Stop at center of sphere cast. + DoCollision(null, hitInfo.collider); + } + else + colliderPosition += displacement; } - private void OnTriggerEnter(Collider other) - { - DoCollision(null, other); - } + #endregion + + #region Collision Handling void DoCollision(Collision collision, Collider other) { @@ -333,16 +340,6 @@ void DoCollision(Collision collision, Collider other) if (impactDetected) return; - // Set my collider to trigger and rigidbody to kinematic immediately after impact - // This helps prevent mobiles from walking over low missiles or the missile bouncing off in some other direction - // Seems to eliminate the combined worst-case scenario where mobile will "ride" a missile bounce, throwing them high into the air - // Now the worst that seems to happen is mobile will "bump" over low missiles occasionally - // TODO: Review later and find a better way to eliminate issue other than this quick workaround - if (myCollider) - myCollider.isTrigger = true; - if (myRigidbody) - myRigidbody.isKinematic = true; - // Play spell impact animation, this replaces spell missile animation if (elementType != ElementTypes.None && targetType != TargetTypes.ByTouch) { @@ -380,7 +377,7 @@ void DoCollision(Collision collision, Collider other) // If missile is area at range if (targetType == TargetTypes.AreaAtRange) { - DoAreaOfEffect(transform.position); + DoAreaOfEffect(colliderPosition); } } @@ -410,11 +407,6 @@ void DoTouch() { transform.position = caster.transform.position; - // Touch does not use default missile collider - // This prevent touch missile check colliding with self and blocking spell transfer - if (myCollider) - myCollider.enabled = false; - DaggerfallEntityBehaviour entityBehaviour = GetEntityTargetInTouchRange(GetAimPosition(), GetAimDirection()); if (entityBehaviour && entityBehaviour != caster) { @@ -431,7 +423,8 @@ void DoTouch() void DoMissile() { direction = GetAimDirection(); - transform.position = GetAimPosition() + direction * ArmLength; + transform.position = GetAimPosition(); + colliderPosition = transform.position; missileReleased = true; } @@ -440,7 +433,7 @@ void DoAreaOfEffect(Vector3 position, bool ignoreCaster = false) { List entities = new List(); - transform.position = position; + colliderPosition = position; // Collect AOE targets and ignore duplicates Collider[] overlaps = Physics.OverlapSphere(position, ExplosionRadius); From 1da9ef3989fe654180c595b1db7a747a017813da Mon Sep 17 00:00:00 2001 From: RedRoryOTheGlen Date: Tue, 31 Mar 2026 18:44:53 +0800 Subject: [PATCH 2/7] Revised layer mask initialization so it only happens once. Applied layer mask to Touch spell target detection as in PR #2770. Removed the aimPosition offset to prevent the player's pre-cast check detecting their own collider as a target. --- Assets/Scripts/Game/DaggerfallMissile.cs | 42 +++++++++++++++++++----- 1 file changed, 33 insertions(+), 9 deletions(-) diff --git a/Assets/Scripts/Game/DaggerfallMissile.cs b/Assets/Scripts/Game/DaggerfallMissile.cs index 80133a5a99..cc80093e46 100644 --- a/Assets/Scripts/Game/DaggerfallMissile.cs +++ b/Assets/Scripts/Game/DaggerfallMissile.cs @@ -85,6 +85,8 @@ public class DaggerfallMissile : MonoBehaviour GameObject goModel = null; EnemySenses enemySenses; + private static int layerMaskDefault = -1; + private static int layerMaskPlayer = -1; int layerMask; List targetEntities = new List(); @@ -233,14 +235,27 @@ private void Start() goModel.layer = gameObject.layer; } - string layerName; + //if layer mask has not yet been initialized, do it now + if (layerMaskDefault == -1) + InitializeLayerMasks(); + + //assign layer mask if (caster && caster != GameManager.Instance.PlayerEntityBehaviour) - layerName = "SpellMissiles"; + layerMask = layerMaskDefault; else - layerName = "Player"; + layerMask = layerMaskPlayer; + } - layerMask = ~(1 << LayerMask.NameToLayer(layerName)); - layerMask = layerMask & ~(1 << LayerMask.NameToLayer("Ignore Raycast")); + static void InitializeLayerMasks() + { + layerMaskDefault = Physics.DefaultRaycastLayers; + layerMaskDefault &= ~(1 << Physics.IgnoreRaycastLayer); + layerMaskDefault &= ~(1 << LayerMask.NameToLayer("Automap")); + + layerMaskPlayer = Physics.DefaultRaycastLayers; + layerMaskPlayer &= ~(1 << Physics.IgnoreRaycastLayer); + layerMaskPlayer &= ~(1 << LayerMask.NameToLayer("Player")); + layerMaskPlayer &= ~(1 << LayerMask.NameToLayer("Automap")); } private void Update() @@ -385,14 +400,23 @@ void DoCollision(Collision collision, Collider other) #region Static Methods - public static DaggerfallEntityBehaviour GetEntityTargetInTouchRange(Vector3 aimPosition, Vector3 aimDirection) + public static DaggerfallEntityBehaviour GetEntityTargetInTouchRange(Vector3 aimPosition, Vector3 aimDirection, int layerMaskTouch = -1) { + //set the default layer mask if none was passed + if (layerMaskTouch == -1) + { + //Initialize the layer masks if they're still not + if (layerMaskDefault == -1) + InitializeLayerMasks(); + + layerMaskTouch = layerMaskDefault; + } + // Fire ray along caster facing // Origin point of ray is set back slightly to fix issue where strikes against target capsules touching caster capsule do not connect RaycastHit hit; - aimPosition -= aimDirection * 0.1f; Ray ray = new Ray(aimPosition, aimDirection); - if (Physics.SphereCast(ray, SphereCastRadius, out hit, TouchRange)) + if (Physics.SphereCast(ray, SphereCastRadius, out hit, TouchRange, layerMaskTouch)) return hit.transform.GetComponent(); else return null; @@ -407,7 +431,7 @@ void DoTouch() { transform.position = caster.transform.position; - DaggerfallEntityBehaviour entityBehaviour = GetEntityTargetInTouchRange(GetAimPosition(), GetAimDirection()); + DaggerfallEntityBehaviour entityBehaviour = GetEntityTargetInTouchRange(GetAimPosition(), GetAimDirection(), layerMask); if (entityBehaviour && entityBehaviour != caster) { targetEntities.Add(entityBehaviour); From a581e30549c7f9ed62f4aa7cb3361b640cf5a40d Mon Sep 17 00:00:00 2001 From: RedRoryOTheGlen Date: Tue, 31 Mar 2026 19:55:50 +0800 Subject: [PATCH 3/7] Fixed arrow model offset from center of projectile object to align it with the origin of collision checks. Moved the isArrow offset code into GetAimPosition method so the arrow still spawns in the same place it did before. --- Assets/Scripts/Game/DaggerfallMissile.cs | 46 +++++++++++++----------- 1 file changed, 26 insertions(+), 20 deletions(-) diff --git a/Assets/Scripts/Game/DaggerfallMissile.cs b/Assets/Scripts/Game/DaggerfallMissile.cs index cc80093e46..3214ab836e 100644 --- a/Assets/Scripts/Game/DaggerfallMissile.cs +++ b/Assets/Scripts/Game/DaggerfallMissile.cs @@ -211,26 +211,7 @@ private void Start() // Create and orient 3d arrow goModel = GameObjectHelper.CreateDaggerfallMeshGameObject(99800, transform, ignoreCollider: true); - // Offset up so it comes from same place LOS check is done from - Vector3 adjust; - if (caster != GameManager.Instance.PlayerEntityBehaviour) - { - CharacterController controller = caster.transform.GetComponent(); - adjust = caster.transform.forward * 0.6f; - adjust.y += controller.height / 3; - } - else - { - // Adjust slightly downward to match bow animation - adjust = (GameManager.Instance.MainCamera.transform.rotation * -Caster.transform.up) * 0.11f; - // Adjust to the right or left to match bow animation - if (!GameManager.Instance.WeaponManager.ScreenWeapon.FlipHorizontal) - adjust += GameManager.Instance.MainCamera.transform.right * 0.15f; - else - adjust -= GameManager.Instance.MainCamera.transform.right * 0.15f; - } - - goModel.transform.localPosition = adjust; + goModel.transform.localPosition = Vector3.zero; goModel.transform.rotation = Quaternion.LookRotation(GetAimDirection()); goModel.layer = gameObject.layer; } @@ -332,6 +313,7 @@ private void FixedUpdate() castFoundHit = Physics.Raycast(colliderPosition, direction, out hitInfo, displacement.magnitude + ColliderRadius, layerMask); else castFoundHit = Physics.SphereCast(colliderPosition, ColliderRadius, direction, out hitInfo, displacement.magnitude + ColliderRadius, layerMask); + if (castFoundHit) { // Place self at meeting point with collider and do collision logic. @@ -498,6 +480,30 @@ Vector3 GetAimPosition() aimPosition = GameManager.Instance.MainCamera.transform.position; } + //projectile offset code moved here for accuracy + if (isArrow) + { + // Offset up so it comes from same place LOS check is done from + Vector3 adjust; + if (caster != GameManager.Instance.PlayerEntityBehaviour) + { + CharacterController controller = caster.transform.GetComponent(); + adjust = caster.transform.forward * 0.6f; + adjust.y += controller.height / 3; + } + else + { + // Adjust slightly downward to match bow animation + adjust = (GameManager.Instance.MainCamera.transform.rotation * -Caster.transform.up) * 0.11f; + // Adjust to the right or left to match bow animation + if (!GameManager.Instance.WeaponManager.ScreenWeapon.FlipHorizontal) + adjust += GameManager.Instance.MainCamera.transform.right * 0.15f; + else + adjust -= GameManager.Instance.MainCamera.transform.right * 0.15f; + } + aimPosition += adjust; + } + return aimPosition; } From 9b8496c394c1d7f93f283e8a09dc7ccf1dd6cf7f Mon Sep 17 00:00:00 2001 From: RedRoryOTheGlen Date: Tue, 31 Mar 2026 20:53:15 +0800 Subject: [PATCH 4/7] Incorporated optimizations to DaggerfallMissile and WeaponManager from #2770 as well as the WeaponManager layer mask fix. Removed the explicit exclusion of IgnoreRaycast layer from the layer mask initialization because DefaultRaycastLayer apparently already excludes it. --- Assets/Scripts/Game/DaggerfallMissile.cs | 110 +++++++++++++++-------- Assets/Scripts/Game/WeaponManager.cs | 8 +- 2 files changed, 81 insertions(+), 37 deletions(-) diff --git a/Assets/Scripts/Game/DaggerfallMissile.cs b/Assets/Scripts/Game/DaggerfallMissile.cs index 3214ab836e..22b275a021 100644 --- a/Assets/Scripts/Game/DaggerfallMissile.cs +++ b/Assets/Scripts/Game/DaggerfallMissile.cs @@ -61,6 +61,18 @@ public class DaggerfallMissile : MonoBehaviour public const float SphereCastRadius = 0.25f; public const float TouchRange = 3.0f; + private static readonly Collider[] aoeBuffer = new Collider[64]; + private readonly List tmpTargets = new List(32); + + // Cached references + private GameManager gm; + private Camera mainCamera; + private WeaponManager weaponManager; + private Collider casterCollider; + private EnemySenses cachedEnemySenses; + private EnemyAttack cachedEnemyAttack; + private CharacterController casterController; + Vector3 colliderPosition; Vector3 direction; @@ -170,39 +182,53 @@ public DaggerfallEntityBehaviour[] Targets private void Awake() { audioSource = transform.GetComponent(); + + gm = GameManager.Instance; + mainCamera = gm.MainCamera; + weaponManager = gm.WeaponManager; + audioSource = GetComponent(); } private void Start() { // Setup light and shadows myLight = GetComponent(); - myLight.enabled = EnableLight; + myLight.enabled = EnableLight && DaggerfallUnity.Settings.EnableSpellLighting; forceDisableSpellLighting = !DaggerfallUnity.Settings.EnableSpellLighting; - if (forceDisableSpellLighting) myLight.enabled = false; - if (!DaggerfallUnity.Settings.EnableSpellShadows) myLight.shadows = LightShadows.None; + if (!DaggerfallUnity.Settings.EnableSpellShadows) + { + myLight.shadows = LightShadows.None; + } + initialRange = myLight.range; initialIntensity = myLight.intensity; // Use payload when available if (payload != null) { - // Set payload missile properties caster = payload.CasterEntityBehaviour; targetType = payload.Settings.TargetType; elementType = payload.Settings.ElementType; // Set spell billboard anims automatically from payload for mobile missiles - if (targetType == TargetTypes.SingleTargetAtRange || - targetType == TargetTypes.AreaAtRange) + if (targetType == TargetTypes.SingleTargetAtRange || targetType == TargetTypes.AreaAtRange) { UseSpellBillboardAnims(); } } // Setup senses - if (caster && caster != GameManager.Instance.PlayerEntityBehaviour) + if (caster) { - enemySenses = caster.GetComponent(); + casterCollider = caster.GetComponent(); + cachedEnemySenses = caster.GetComponent(); + cachedEnemyAttack = caster.GetComponent(); + casterController = caster.GetComponent(); + } + + if (caster && caster != gm.PlayerEntityBehaviour) + { + enemySenses = cachedEnemySenses; } // Setup arrow @@ -230,13 +256,11 @@ private void Start() static void InitializeLayerMasks() { layerMaskDefault = Physics.DefaultRaycastLayers; - layerMaskDefault &= ~(1 << Physics.IgnoreRaycastLayer); layerMaskDefault &= ~(1 << LayerMask.NameToLayer("Automap")); layerMaskPlayer = Physics.DefaultRaycastLayers; - layerMaskPlayer &= ~(1 << Physics.IgnoreRaycastLayer); - layerMaskPlayer &= ~(1 << LayerMask.NameToLayer("Player")); layerMaskPlayer &= ~(1 << LayerMask.NameToLayer("Automap")); + layerMaskPlayer &= ~(1 << LayerMask.NameToLayer("Player")); } private void Update() @@ -398,10 +422,12 @@ public static DaggerfallEntityBehaviour GetEntityTargetInTouchRange(Vector3 aimP // Origin point of ray is set back slightly to fix issue where strikes against target capsules touching caster capsule do not connect RaycastHit hit; Ray ray = new Ray(aimPosition, aimDirection); - if (Physics.SphereCast(ray, SphereCastRadius, out hit, TouchRange, layerMaskTouch)) + if (Physics.SphereCast(ray, SphereCastRadius, out hit, TouchRange, layerMaskTouch, QueryTriggerInteraction.Ignore)) + { return hit.transform.GetComponent(); - else - return null; + } + + return null; } #endregion @@ -437,29 +463,34 @@ void DoMissile() // AOE can strike any number of targets within range with an option to exclude caster void DoAreaOfEffect(Vector3 position, bool ignoreCaster = false) { - List entities = new List(); - colliderPosition = position; - // Collect AOE targets and ignore duplicates - Collider[] overlaps = Physics.OverlapSphere(position, ExplosionRadius); - for (int i = 0; i < overlaps.Length; i++) + int count = Physics.OverlapSphereNonAlloc(position, ExplosionRadius, aoeBuffer, layerMaskDefault, QueryTriggerInteraction.Ignore); + tmpTargets.Clear(); + + for (int i = 0; i < count; i++) { - DaggerfallEntityBehaviour aoeEntity = overlaps[i].GetComponent(); + var beh = aoeBuffer[i].GetComponent(); + if (!beh) + { + continue; + } - if (ignoreCaster && aoeEntity == caster) + if (ignoreCaster && beh == caster) + { continue; + } - if (aoeEntity && !targetEntities.Contains(aoeEntity)) + if (!targetEntities.Contains(beh)) { - entities.Add(aoeEntity); - //Debug.LogFormat("Missile hit target {0} by AOE", aoeEntity.name); + tmpTargets.Add(beh); } } - // Add collection to target entities - if (entities.Count > 0) - targetEntities.AddRange(entities); + if (tmpTargets.Count > 0) + { + targetEntities.AddRange(tmpTargets); + } impactDetected = true; missileReleased = true; @@ -485,21 +516,24 @@ Vector3 GetAimPosition() { // Offset up so it comes from same place LOS check is done from Vector3 adjust; - if (caster != GameManager.Instance.PlayerEntityBehaviour) + if (caster != gm.PlayerEntityBehaviour) { - CharacterController controller = caster.transform.GetComponent(); adjust = caster.transform.forward * 0.6f; - adjust.y += controller.height / 3; + if (casterController) + { + adjust.y += casterController.height / 3; + } } else { // Adjust slightly downward to match bow animation - adjust = (GameManager.Instance.MainCamera.transform.rotation * -Caster.transform.up) * 0.11f; + adjust = (gm.MainCamera.transform.rotation * -caster.transform.up) * 0.11f; // Adjust to the right or left to match bow animation - if (!GameManager.Instance.WeaponManager.ScreenWeapon.FlipHorizontal) - adjust += GameManager.Instance.MainCamera.transform.right * 0.15f; + var right = gm.MainCamera.transform.right * 0.15f; + if (!gm.WeaponManager.ScreenWeapon.FlipHorizontal) + adjust += right; else - adjust -= GameManager.Instance.MainCamera.transform.right * 0.15f; + adjust -= right; } aimPosition += adjust; } @@ -631,7 +665,13 @@ void AssignBowDamageToTarget(Collider arrowHitCollider) else { Transform hitTransform = arrowHitCollider.gameObject.transform; - GameManager.Instance.WeaponManager.WeaponDamage(GameManager.Instance.WeaponManager.LastBowUsed, true, isArrowSummoned, hitTransform, hitTransform.position, goModel.transform.forward); + GameManager.Instance.WeaponManager.WeaponDamage( + GameManager.Instance.WeaponManager.LastBowUsed, + true, + isArrowSummoned, + hitTransform, + hitTransform.position, + goModel.transform.forward); } } diff --git a/Assets/Scripts/Game/WeaponManager.cs b/Assets/Scripts/Game/WeaponManager.cs index f26f276ad6..64d0c51d9e 100644 --- a/Assets/Scripts/Game/WeaponManager.cs +++ b/Assets/Scripts/Game/WeaponManager.cs @@ -196,9 +196,13 @@ void Start() //weaponSensitivity = DaggerfallUnity.Settings.WeaponSensitivity; mainCamera = GameObject.FindGameObjectWithTag("MainCamera"); player = transform.gameObject; - playerLayerMask = ~(1 << LayerMask.NameToLayer("Player")); + + playerLayerMask = Physics.DefaultRaycastLayers; + playerLayerMask &= ~(1 << LayerMask.NameToLayer("Player")); + playerLayerMask &= ~(1 << LayerMask.NameToLayer("Automap")); + _gesture = new Gesture(); - _longestDim = Math.Max(Screen.width, Screen.height); + _longestDim = Mathf.Max(Screen.width, Screen.height); SetMelee(ScreenWeapon); } From 59e1893c0999e3aa2b610f49af3e6722f7ebaa7e Mon Sep 17 00:00:00 2001 From: RedRoryOTheGlen Date: Wed, 1 Apr 2026 12:20:25 +0800 Subject: [PATCH 5/7] Fixed an oversight from #2472 that caused missiles with null caster to use the Player-excluding layer mask. Now the Player-excluding layer mask is only assigned if the caster is the Player. --- Assets/Scripts/Game/DaggerfallMissile.cs | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/Assets/Scripts/Game/DaggerfallMissile.cs b/Assets/Scripts/Game/DaggerfallMissile.cs index 22b275a021..d1b6f17e24 100644 --- a/Assets/Scripts/Game/DaggerfallMissile.cs +++ b/Assets/Scripts/Game/DaggerfallMissile.cs @@ -247,10 +247,10 @@ private void Start() InitializeLayerMasks(); //assign layer mask - if (caster && caster != GameManager.Instance.PlayerEntityBehaviour) - layerMask = layerMaskDefault; - else + if (caster && caster == gm.PlayerEntityBehaviour) layerMask = layerMaskPlayer; + else + layerMask = layerMaskDefault; } static void InitializeLayerMasks() @@ -506,9 +506,9 @@ Vector3 GetAimPosition() // Aim position is from eye level for player or origin for other mobile // Player must aim from camera position or it feels out of alignment Vector3 aimPosition = caster.transform.position; - if (caster == GameManager.Instance.PlayerEntityBehaviour) + if (caster == gm.PlayerEntityBehaviour) { - aimPosition = GameManager.Instance.MainCamera.transform.position; + aimPosition = gm.MainCamera.transform.position; } //projectile offset code moved here for accuracy @@ -550,9 +550,9 @@ Vector3 GetAimDirection() // Aim direction should be from camera for player or facing for other mobile Vector3 aimDirection = Vector3.zero; - if (caster == GameManager.Instance.PlayerEntityBehaviour) + if (caster == gm.PlayerEntityBehaviour) { - aimDirection = GameManager.Instance.MainCamera.transform.forward; + aimDirection = gm.MainCamera.transform.forward; } else if (enemySenses) { @@ -568,7 +568,7 @@ Vector3 GetAimDirection() aimDirection = (predictedPosition - caster.transform.position).normalized; // Enemy archers must aim lower to compensate for crouched player capsule - if (IsArrow && enemySenses.Target?.EntityType == EntityTypes.Player && GameManager.Instance.PlayerMotor.IsCrouching) + if (IsArrow && enemySenses.Target?.EntityType == EntityTypes.Player && gm.PlayerMotor.IsCrouching) aimDirection += Vector3.down * 0.05f; } @@ -651,7 +651,7 @@ void AssignBowDamageToTarget(Collider arrowHitCollider) return; } - if (caster != GameManager.Instance.PlayerEntityBehaviour) + if (caster != gm.PlayerEntityBehaviour) { if (targetEntities[0] == caster.GetComponent().Target) { @@ -665,8 +665,8 @@ void AssignBowDamageToTarget(Collider arrowHitCollider) else { Transform hitTransform = arrowHitCollider.gameObject.transform; - GameManager.Instance.WeaponManager.WeaponDamage( - GameManager.Instance.WeaponManager.LastBowUsed, + gm.WeaponManager.WeaponDamage( + gm.WeaponManager.LastBowUsed, true, isArrowSummoned, hitTransform, From ce6561874d7067fdf3a7f10e8b52dd17d2256d8d Mon Sep 17 00:00:00 2001 From: RedRoryOTheGlen Date: Sun, 5 Apr 2026 23:02:49 +0800 Subject: [PATCH 6/7] Added a public static method to DaggerfallMissile allowing external classes to use the appropriate layer mask (and initialize it if it isn't). Applied this new method to the player Touch targeting check in EntityEffectsManager.CastReadySpell to completely prevent self-targeting with Touch spells. --- Assets/Scripts/Game/DaggerfallMissile.cs | 13 +++++++++++++ .../Game/MagicAndEffects/EntityEffectManager.cs | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/Assets/Scripts/Game/DaggerfallMissile.cs b/Assets/Scripts/Game/DaggerfallMissile.cs index d1b6f17e24..2646ebd4b9 100644 --- a/Assets/Scripts/Game/DaggerfallMissile.cs +++ b/Assets/Scripts/Game/DaggerfallMissile.cs @@ -430,6 +430,19 @@ public static DaggerfallEntityBehaviour GetEntityTargetInTouchRange(Vector3 aimP return null; } + //allow other classes to use the layer masks + public static int GetLayerMask(bool player) + { + //Initialize the layer masks if they're still not + if (layerMaskDefault == -1) + InitializeLayerMasks(); + + if (player) + return layerMaskPlayer; + + return layerMaskDefault; + } + #endregion #region Private Methods diff --git a/Assets/Scripts/Game/MagicAndEffects/EntityEffectManager.cs b/Assets/Scripts/Game/MagicAndEffects/EntityEffectManager.cs index 0d6d2c94b3..2067ccc103 100644 --- a/Assets/Scripts/Game/MagicAndEffects/EntityEffectManager.cs +++ b/Assets/Scripts/Game/MagicAndEffects/EntityEffectManager.cs @@ -414,7 +414,7 @@ public void CastReadySpell() { Vector3 aimPosition = GameManager.Instance.MainCamera.transform.position; Vector3 aimDirection = GameManager.Instance.MainCamera.transform.forward; - if (DaggerfallMissile.GetEntityTargetInTouchRange(aimPosition, aimDirection) == null) + if (DaggerfallMissile.GetEntityTargetInTouchRange(aimPosition, aimDirection, DaggerfallMissile.GetLayerMask(true)) == null) { //Debug.Log("Target entity not in range for touch spell."); return; From a9658d4c0ecd0a76a2dead6e1ed2e56315d3f023 Mon Sep 17 00:00:00 2001 From: RedRoryOTheGlen Date: Tue, 7 Apr 2026 14:28:02 +0800 Subject: [PATCH 7/7] Implemented bounding box-based weapon collision. Added settings to Advanced Settings menu under Gameplay tab and to in-game Advanced Controls window. --- .../Internal_Settings Shared Data.asset | 12 ++ .../StringTables/Internal_Settings_en.asset | 14 ++ Assets/Resources/defaults.ini.txt | 4 + .../DaggerfallAdvancedSettingsWindow.cs | 11 + .../DaggerfallUnityMouseControlsWindow.cs | 8 + Assets/Scripts/Game/WeaponManager.cs | 188 +++++++++++++++++- Assets/Scripts/SettingsManager.cs | 11 + Assets/StreamingAssets/Text/GameSettings.txt | 5 + 8 files changed, 245 insertions(+), 8 deletions(-) diff --git a/Assets/Localization/StringTables/Internal_Settings Shared Data.asset b/Assets/Localization/StringTables/Internal_Settings Shared Data.asset index 8cab8ab634..48d990a20f 100644 --- a/Assets/Localization/StringTables/Internal_Settings Shared Data.asset +++ b/Assets/Localization/StringTables/Internal_Settings Shared Data.asset @@ -143,6 +143,18 @@ MonoBehaviour: m_Key: textureArrayInfo m_Metadata: m_Items: [] + - m_Id: 392878225761951744 + m_Key: meleeAttackDetectionModes + m_Metadata: + m_Items: [] + - m_Id: 392920400377864192 + m_Key: meleeAttackDetection + m_Metadata: + m_Items: [] + - m_Id: 392920453876211712 + m_Key: meleeAttackFriendlyProtection + m_Metadata: + m_Items: [] m_Metadata: m_Items: [] m_KeyGenerator: diff --git a/Assets/Localization/StringTables/Internal_Settings_en.asset b/Assets/Localization/StringTables/Internal_Settings_en.asset index 9918e0d13d..314b45962a 100644 --- a/Assets/Localization/StringTables/Internal_Settings_en.asset +++ b/Assets/Localization/StringTables/Internal_Settings_en.asset @@ -236,5 +236,19 @@ MonoBehaviour: and modding support m_Metadata: m_Items: [] + - m_Id: 392878225761951744 + m_Localized: 'Performance + + Quality' + m_Metadata: + m_Items: [] + - m_Id: 392920400377864192 + m_Localized: Hit Detection + m_Metadata: + m_Items: [] + - m_Id: 392920453876211712 + m_Localized: Protect Friendlies and Neutrals + m_Metadata: + m_Items: [] references: version: 1 diff --git a/Assets/Resources/defaults.ini.txt b/Assets/Resources/defaults.ini.txt index 25fec25626..ffb1dfe247 100644 --- a/Assets/Resources/defaults.ini.txt +++ b/Assets/Resources/defaults.ini.txt @@ -118,6 +118,10 @@ QuestRumorWeight = 50 DisableEnemyDeathAlert=False HideLoginName=False +[MeleeAttacks] +MeleeAttackDetection=0 +MeleeAttackFriendlyProtection=True + [Spells] EnableSpellLighting=True EnableSpellShadows=True diff --git a/Assets/Scripts/Game/UserInterfaceWindows/DaggerfallAdvancedSettingsWindow.cs b/Assets/Scripts/Game/UserInterfaceWindows/DaggerfallAdvancedSettingsWindow.cs index 0b6b6db336..9c1f00f30c 100644 --- a/Assets/Scripts/Game/UserInterfaceWindows/DaggerfallAdvancedSettingsWindow.cs +++ b/Assets/Scripts/Game/UserInterfaceWindows/DaggerfallAdvancedSettingsWindow.cs @@ -140,6 +140,8 @@ enum IconsPositioningSchemes { classic, medium, small, smalldeckleft, smalldeckr HorizontalSlider dungeonAmbientLightScale; HorizontalSlider nightAmbientLightScale; HorizontalSlider playerTorchLightScale; + HorizontalSlider meleeAttackDetection; + Checkbox meleeAttackFriendlyProtection; // Video HorizontalSlider resolution; @@ -271,6 +273,12 @@ private void Gameplay(Panel leftPanel, Panel rightPanel) musicVolume.DisplayUnits = 100; musicVolume.OnScroll += MusicVolume_OnScroll; + // Melee Attacks + AddSectionTitle(rightPanel, "meleeAttacks"); + meleeAttackDetection = AddSlider(rightPanel, "meleeAttackDetection", + DaggerfallUnity.Settings.MeleeAttackDetection, TextManager.Instance.GetLocalizedTextList("meleeAttackDetectionModes", TextCollections.TextSettings)); + meleeAttackFriendlyProtection = AddCheckbox(rightPanel, "meleeAttackFriendlyProtection", DaggerfallUnity.Settings.MeleeAttackFriendlyProtection); + // Spells AddSectionTitle(rightPanel, "spells"); spellLighting = AddCheckbox(rightPanel, "spellLighting", DaggerfallUnity.Settings.EnableSpellLighting); @@ -444,6 +452,9 @@ private void SaveSettings() DaggerfallUnity.Settings.EnableSpellLighting = spellLighting.IsChecked; DaggerfallUnity.Settings.EnableSpellShadows = spellShadows.IsChecked; + DaggerfallUnity.Settings.MeleeAttackDetection = meleeAttackDetection.ScrollIndex; + DaggerfallUnity.Settings.MeleeAttackFriendlyProtection = meleeAttackFriendlyProtection.IsChecked; + /* GUI */ DaggerfallUnity.Settings.EnableToolTips = toolTips.IsChecked; diff --git a/Assets/Scripts/Game/UserInterfaceWindows/DaggerfallUnityMouseControlsWindow.cs b/Assets/Scripts/Game/UserInterfaceWindows/DaggerfallUnityMouseControlsWindow.cs index 62308afa6b..fbf8cf3383 100644 --- a/Assets/Scripts/Game/UserInterfaceWindows/DaggerfallUnityMouseControlsWindow.cs +++ b/Assets/Scripts/Game/UserInterfaceWindows/DaggerfallUnityMouseControlsWindow.cs @@ -49,6 +49,9 @@ public class DaggerfallUnityMouseControlsWindow : DaggerfallPopupWindow protected TextBox weaponAttackThresholdTextbox; protected Button continueButton; + protected HorizontalSlider meleeAttackDetectionSlider; + protected Checkbox meleeAttackFriendlyProtectionCheckbox; + protected List