diff --git a/Assets/Prefabs/GameManager.prefab b/Assets/Prefabs/GameManager.prefab index 7eefad21..07801a6c 100644 --- a/Assets/Prefabs/GameManager.prefab +++ b/Assets/Prefabs/GameManager.prefab @@ -126,6 +126,8 @@ MonoBehaviour: serializedVersion: 2 m_Bits: 13569 drawLineFromGun: 0 + projectilePrefab: {fileID: 8038540346792760480, guid: 858b1226127ef9f4e8d16c9610e691b6, + type: 3} --- !u!114 &114529712737653322 MonoBehaviour: m_ObjectHideFlags: 0 diff --git a/Assets/Prefabs/Projectile.prefab b/Assets/Prefabs/Projectile.prefab new file mode 100644 index 00000000..60b4e531 --- /dev/null +++ b/Assets/Prefabs/Projectile.prefab @@ -0,0 +1,229 @@ +%YAML 1.1 +%TAG !u! tag:unity3d.com,2011: +--- !u!1 &8038540346792760480 +GameObject: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + serializedVersion: 6 + m_Component: + - component: {fileID: 6625053217720877913} + - component: {fileID: 8562802475590220373} + - component: {fileID: 223436154079187918} + - component: {fileID: 5633959673307472571} + - component: {fileID: 7377119322491791788} + - component: {fileID: 1832386804146413524} + - component: {fileID: 1740834482409443228} + m_Layer: 0 + m_Name: Projectile + m_TagString: Untagged + m_Icon: {fileID: 0} + m_NavMeshLayer: 0 + m_StaticEditorFlags: 0 + m_IsActive: 1 +--- !u!4 &6625053217720877913 +Transform: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8038540346792760480} + m_LocalRotation: {x: 0, y: 0, z: 0, w: 1} + m_LocalPosition: {x: 2797.694, y: 33.489048, z: 1567.7346} + m_LocalScale: {x: 0.2, y: 0.2, z: 0.2} + m_Children: [] + m_Father: {fileID: 0} + m_RootOrder: 0 + m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0} +--- !u!114 &8562802475590220373 +MonoBehaviour: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8038540346792760480} + m_Enabled: 1 + m_EditorHideFlags: 0 + m_Script: {fileID: 11500000, guid: ec78359df717b4b468d7394c6be40dcc, type: 3} + m_Name: + m_EditorClassIdentifier: + explosionPrefab: {fileID: 100010, guid: 2894e2899fe860745afbc810459e2cc2, type: 3} + explosionDamageAmount: 1000 + explosionDamageRadius: 5 + collisionLayerMask: + serializedVersion: 2 + m_Bits: 4294967295 + speed: 15 + lifeTime: 30 +--- !u!136 &223436154079187918 +CapsuleCollider: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8038540346792760480} + m_Material: {fileID: 0} + m_IsTrigger: 0 + m_Enabled: 1 + m_Radius: 0.5 + m_Height: 2 + m_Direction: 1 + m_Center: {x: 0, y: 0, z: 0} +--- !u!54 &5633959673307472571 +Rigidbody: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8038540346792760480} + serializedVersion: 2 + m_Mass: 10 + m_Drag: 0 + m_AngularDrag: 0.05 + m_UseGravity: 0 + m_IsKinematic: 0 + m_Interpolate: 0 + m_Constraints: 0 + m_CollisionDetection: 0 +--- !u!33 &7377119322491791788 +MeshFilter: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8038540346792760480} + m_Mesh: {fileID: 10208, guid: 0000000000000000e000000000000000, type: 0} +--- !u!23 &1832386804146413524 +MeshRenderer: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8038540346792760480} + m_Enabled: 1 + m_CastShadows: 1 + m_ReceiveShadows: 1 + m_DynamicOccludee: 1 + m_MotionVectors: 1 + m_LightProbeUsage: 1 + m_ReflectionProbeUsage: 1 + m_RenderingLayerMask: 1 + m_RendererPriority: 0 + m_Materials: + - {fileID: 0} + m_StaticBatchInfo: + firstSubMesh: 0 + subMeshCount: 0 + m_StaticBatchRoot: {fileID: 0} + m_ProbeAnchor: {fileID: 0} + m_LightProbeVolumeOverride: {fileID: 0} + m_ScaleInLightmap: 1 + m_PreserveUVs: 0 + m_IgnoreNormalsForChartDetection: 0 + m_ImportantGI: 0 + m_StitchLightmapSeams: 0 + m_SelectedEditorRenderState: 3 + m_MinimumChartSize: 4 + m_AutoUVMaxDistance: 0.5 + m_AutoUVMaxAngle: 89 + m_LightmapParameters: {fileID: 0} + m_SortingLayerID: 0 + m_SortingLayer: 0 + m_SortingOrder: 0 +--- !u!82 &1740834482409443228 +AudioSource: + m_ObjectHideFlags: 0 + m_CorrespondingSourceObject: {fileID: 0} + m_PrefabInstance: {fileID: 0} + m_PrefabAsset: {fileID: 0} + m_GameObject: {fileID: 8038540346792760480} + m_Enabled: 1 + serializedVersion: 4 + OutputAudioMixerGroup: {fileID: 0} + m_audioClip: {fileID: 0} + m_PlayOnAwake: 1 + m_Volume: 1 + m_Pitch: 1 + Loop: 0 + Mute: 0 + Spatialize: 0 + SpatializePostEffects: 0 + Priority: 128 + DopplerLevel: 1 + MinDistance: 1 + MaxDistance: 500 + Pan2D: 0 + rolloffMode: 0 + BypassEffects: 0 + BypassListenerEffects: 0 + BypassReverbZones: 0 + rolloffCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + - serializedVersion: 3 + time: 1 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + panLevelCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + spreadCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 0 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 + reverbZoneMixCustomCurve: + serializedVersion: 2 + m_Curve: + - serializedVersion: 3 + time: 0 + value: 1 + inSlope: 0 + outSlope: 0 + tangentMode: 0 + weightedMode: 0 + inWeight: 0.33333334 + outWeight: 0.33333334 + m_PreInfinity: 2 + m_PostInfinity: 2 + m_RotationOrder: 4 diff --git a/Assets/Prefabs/Projectile.prefab.meta b/Assets/Prefabs/Projectile.prefab.meta new file mode 100644 index 00000000..138eef40 --- /dev/null +++ b/Assets/Prefabs/Projectile.prefab.meta @@ -0,0 +1,7 @@ +fileFormatVersion: 2 +guid: 858b1226127ef9f4e8d16c9610e691b6 +PrefabImporter: + externalObjects: {} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Behaviours/Projectile.cs b/Assets/Scripts/Behaviours/Projectile.cs new file mode 100644 index 00000000..bacd2666 --- /dev/null +++ b/Assets/Scripts/Behaviours/Projectile.cs @@ -0,0 +1,87 @@ +using SanAndreasUnity.Behaviours.Vehicles; +using SanAndreasUnity.Net; +using SanAndreasUnity.Utilities; +using UnityEngine; +using Object = UnityEngine.Object; + +public class Projectile : MonoBehaviour +{ + public GameObject explosionPrefab; + public float explosionDamageAmount = 1000; + public float explosionDamageRadius = 5; + public LayerMask collisionLayerMask; + public float speed = 10; + public float lifeTime = 30; + + private bool m_alreadyExploded = false; + private Rigidbody m_rigidBody; + private AudioSource m_audioSource; + + + public static Projectile Create( + GameObject prefab, Vector3 position, Quaternion rotation, AudioClip audioClip) + { + var go = Instantiate(prefab, position, rotation); + + var projectile = go.GetComponentOrThrow(); + + if (audioClip != null) + { + projectile.m_audioSource.clip = audioClip; + projectile.m_audioSource.Play(); + } + + + + return projectile; + } + + void Awake() + { + m_rigidBody = this.GetComponentOrThrow(); + m_audioSource = this.GetComponentOrThrow(); + } + + private void Start() + { + Destroy(this.gameObject, this.lifeTime); + m_rigidBody.velocity = this.transform.forward * this.speed; + } + + private void OnCollisionEnter(Collision other) + { + if (m_alreadyExploded) + return; + + if (((1 << other.gameObject.layer) & this.collisionLayerMask.value) == 0) + return; + + m_alreadyExploded = true; + + Object.Destroy(this.gameObject); + + Vector3 contactPoint = other.contacts[0].point; + + // inflict damage to nearby objects + Damageable.InflictDamageToObjectsInArea( + contactPoint, + this.explosionDamageRadius, + this.explosionDamageAmount, + VehicleManager.Instance.explosionDamageOverDistanceCurve, + DamageType.Explosion); + + // create explosion - this includes effects, physics force, sound + + GameObject explosionGo = Object.Instantiate( + this.explosionPrefab, + contactPoint, + this.transform.rotation); + + if (NetStatus.IsServer) + NetManager.Spawn(explosionGo); + + // assign explosion sound + F.RunExceptionSafe(() => Vehicle.AssignExplosionSound(explosionGo)); + + } +} diff --git a/Assets/Scripts/Behaviours/Projectile.cs.meta b/Assets/Scripts/Behaviours/Projectile.cs.meta new file mode 100644 index 00000000..4d5c3d63 --- /dev/null +++ b/Assets/Scripts/Behaviours/Projectile.cs.meta @@ -0,0 +1,11 @@ +fileFormatVersion: 2 +guid: ec78359df717b4b468d7394c6be40dcc +MonoImporter: + externalObjects: {} + serializedVersion: 2 + defaultReferences: [] + executionOrder: 0 + icon: {instanceID: 0} + userData: + assetBundleName: + assetBundleVariant: diff --git a/Assets/Scripts/Behaviours/Weapon.cs b/Assets/Scripts/Behaviours/Weapon.cs index 6d9ca4e5..1cba51e9 100644 --- a/Assets/Scripts/Behaviours/Weapon.cs +++ b/Assets/Scripts/Behaviours/Weapon.cs @@ -159,6 +159,12 @@ namespace SanAndreasUnity.Behaviours WeaponAttackParams m_lastRaycastWeaponAttackParams = WeaponAttackParams.Default; + static readonly HashSet s_weaponsUsingProjectile = new HashSet() + { + WeaponId.RocketLauncher, + WeaponId.RocketLauncherHS, + }; + static Weapon () @@ -361,6 +367,10 @@ namespace SanAndreasUnity.Behaviours this.CrouchSpineRotationOffset = WeaponsSettings.crouchSpineRotationOffset; + this.FiresProjectile = s_weaponsUsingProjectile.Contains(this.Data.modelId1); + if (this.FiresProjectile) + this.ProjectilePrefab = WeaponsSettings.projectilePrefab; + } protected virtual void Start () @@ -507,6 +517,13 @@ namespace SanAndreasUnity.Behaviours public Vector3 CrouchSpineRotationOffset { get; set; } + /// + /// True if weapon doesn't inflict damage instantly, but instead fires a projectile. + /// + public bool FiresProjectile { get; set; } = false; + + public GameObject ProjectilePrefab { get; set; } + // TODO: this function should be removed, and new one should be created: OnAnimsUpdated public virtual void UpdateAnimWhileHolding () @@ -615,6 +632,12 @@ namespace SanAndreasUnity.Behaviours this.LastTimeWhenFired = Time.time; + if (this.FiresProjectile) + { + Projectile.Create(this.ProjectilePrefab, firePos, Quaternion.LookRotation(fireDir), null); + return; + } + // raycast against all (non-breakable ?) objects RaycastHit hit; diff --git a/Assets/Scripts/Behaviours/Weapons/WeaponsManager.cs b/Assets/Scripts/Behaviours/Weapons/WeaponsManager.cs index 93cfa6fc..fd5063f1 100644 --- a/Assets/Scripts/Behaviours/Weapons/WeaponsManager.cs +++ b/Assets/Scripts/Behaviours/Weapons/WeaponsManager.cs @@ -50,6 +50,8 @@ namespace SanAndreasUnity.Behaviours.Weapons public bool drawLineFromGun = false; + public GameObject projectilePrefab; + public static WeaponsManager Instance { get; private set; }