using System; using System.Collections; using System.Collections.Generic; using Photon.Pun; using Sirenix.OdinInspector; using SoundImplementation; using UnityEngine; public class Gun : Weapon { [Header("Sound Player Settings")] public SoundGun soundGun = new SoundGun(); [Header("Sound Card Settings")] public SoundShotModifier soundShotModifier; public SoundImpactModifier soundImpactModifier; public bool soundDisableRayHitBulletSound; [Header("Settings")] public float recoil; public float bodyRecoil; public float shake; public bool forceSpecificShake; public ProjectilesToSpawn[] projectiles; private Rigidbody2D rig; public Transform shootPosition; [HideInInspector] public Player player; [HideInInspector] public bool isReloading; [Header("Multiply")] [FoldoutGroup("Stats", 0)] public float damage = 1f; [FoldoutGroup("Stats", 0)] public float reloadTime = 1f; [FoldoutGroup("Stats", 0)] public float reloadTimeAdd; [FoldoutGroup("Stats", 0)] public float recoilMuiltiplier = 1f; [FoldoutGroup("Stats", 0)] public float knockback = 1f; [FoldoutGroup("Stats", 0)] public float attackSpeed = 1f; [FoldoutGroup("Stats", 0)] public float projectileSpeed = 1f; [FoldoutGroup("Stats", 0)] public float projectielSimulatonSpeed = 1f; [FoldoutGroup("Stats", 0)] public float gravity = 1f; [FoldoutGroup("Stats", 0)] public float damageAfterDistanceMultiplier = 1f; [FoldoutGroup("Stats", 0)] public float bulletDamageMultiplier = 1f; [FoldoutGroup("Stats", 0)] public float multiplySpread = 1f; [FoldoutGroup("Stats", 0)] public float shakeM = 1f; [Header("Add")] [FoldoutGroup("Stats", 0)] public int ammo; [FoldoutGroup("Stats", 0)] public float ammoReg; [FoldoutGroup("Stats", 0)] public float size; [FoldoutGroup("Stats", 0)] public float overheatMultiplier; [FoldoutGroup("Stats", 0)] public float timeToReachFullMovementMultiplier; [FoldoutGroup("Stats", 0)] public int numberOfProjectiles; [FoldoutGroup("Stats", 0)] public int bursts; [FoldoutGroup("Stats", 0)] public int reflects; [FoldoutGroup("Stats", 0)] public int smartBounce; [FoldoutGroup("Stats", 0)] public int bulletPortal; [FoldoutGroup("Stats", 0)] public int randomBounces; [FoldoutGroup("Stats", 0)] public float timeBetweenBullets; [FoldoutGroup("Stats", 0)] public float projectileSize; [FoldoutGroup("Stats", 0)] public float speedMOnBounce = 1f; [FoldoutGroup("Stats", 0)] public float dmgMOnBounce = 1f; [FoldoutGroup("Stats", 0)] public float drag; [FoldoutGroup("Stats", 0)] public float dragMinSpeed = 1f; [FoldoutGroup("Stats", 0)] public float spread; [FoldoutGroup("Stats", 0)] public float evenSpread; [FoldoutGroup("Stats", 0)] public float percentageDamage; [FoldoutGroup("Stats", 0)] public float cos; [FoldoutGroup("Stats", 0)] public float slow; [FoldoutGroup("Stats", 0)] [Header("Charge Multiply")] public float chargeDamageMultiplier = 1f; [FoldoutGroup("Stats", 0)] [Header("(1 + Charge * x) Multiply")] public float chargeSpreadTo; [FoldoutGroup("Stats", 0)] public float chargeEvenSpreadTo; [FoldoutGroup("Stats", 0)] public float chargeSpeedTo; [FoldoutGroup("Stats", 0)] public float chargeRecoilTo; [FoldoutGroup("Stats", 0)] [Header("(1 + Charge * x) Add")] public float chargeNumberOfProjectilesTo; [FoldoutGroup("Stats", 0)] [Header("Special")] public float destroyBulletAfter; [FoldoutGroup("Stats", 0)] public float forceSpecificAttackSpeed; [FoldoutGroup("Stats", 0)] public bool lockGunToDefault; [FoldoutGroup("Stats", 0)] public bool unblockable; [FoldoutGroup("Stats", 0)] public bool ignoreWalls; [HideInInspector] public float currentCharge; public bool useCharge; public bool dontAllowAutoFire; public ObjectsToSpawn[] objectsToSpawn; public Color projectileColor = Color.black; public bool waveMovement; public bool teleport; public bool spawnSkelletonSquare; public float explodeNearEnemyRange; public float explodeNearEnemyDamage; public float hitMovementMultiplier = 1f; private Action attackAction; [HideInInspector] public bool isProjectileGun; [HideInInspector] public float defaultCooldown = 1f; [HideInInspector] public int attackID = -1; public float attackSpeedMultiplier = 1f; private int gunID = -1; private GunAmmo gunAmmo; private Vector3 spawnPos; public Action ShootPojectileAction; private float spreadOfLastBullet; private SpawnedAttack spawnedAttack; [HideInInspector] internal Vector3 forceShootDir; private float usedCooldown { get { if (!lockGunToDefault) { return attackSpeed; } return defaultCooldown; } } internal float GetRangeCompensation(float distance) { return Mathf.Pow(distance, 2f) * 0.015f / projectileSpeed; } internal void ResetStats() { isReloading = false; damage = 1f; reloadTime = 1f; reloadTimeAdd = 0f; recoilMuiltiplier = 1f; gunAmmo.reloadTimeMultiplier = 1f; gunAmmo.reloadTimeAdd = 0f; knockback = 1f; attackSpeed = 0.3f; projectileSpeed = 1f; projectielSimulatonSpeed = 1f; gravity = 1f; damageAfterDistanceMultiplier = 1f; bulletDamageMultiplier = 1f; multiplySpread = 1f; shakeM = 1f; ammo = 0; ammoReg = 0f; size = 0f; overheatMultiplier = 0f; timeToReachFullMovementMultiplier = 0f; numberOfProjectiles = 1; bursts = 0; reflects = 0; smartBounce = 0; bulletPortal = 0; randomBounces = 0; timeBetweenBullets = 0f; projectileSize = 0f; speedMOnBounce = 1f; dmgMOnBounce = 1f; drag = 0f; dragMinSpeed = 1f; spread = 0f; evenSpread = 0f; percentageDamage = 0f; cos = 0f; slow = 0f; chargeNumberOfProjectilesTo = 0f; destroyBulletAfter = 0f; forceSpecificAttackSpeed = 0f; lockGunToDefault = false; unblockable = false; ignoreWalls = false; currentCharge = 0f; useCharge = false; waveMovement = false; teleport = false; spawnSkelletonSquare = false; explodeNearEnemyRange = 0f; explodeNearEnemyDamage = 0f; hitMovementMultiplier = 1f; isProjectileGun = false; defaultCooldown = 1f; attackSpeedMultiplier = 1f; objectsToSpawn = new ObjectsToSpawn[0]; GetComponentInChildren().maxAmmo = 3; GetComponentInChildren().ReDrawTotalBullets(); projectileColor = Color.black; } private void Start() { gunAmmo = GetComponentInChildren(); Gun[] componentsInChildren = base.transform.root.GetComponentsInChildren(); for (int i = 0; i < componentsInChildren.Length; i++) { if (componentsInChildren[i] == this) { gunID = i; } } if (!player) { player = GetComponentInParent(); } if (!player) { ProjectileHit componentInParent = GetComponentInParent(); if ((bool)componentInParent) { player = componentInParent.ownPlayer; } } if (!player) { SpawnedAttack component = base.transform.root.GetComponent(); if ((bool)component) { player = component.spawner; } } holdable = GetComponent(); defaultCooldown = usedCooldown; ShootPos componentInChildren = GetComponentInChildren(); if ((bool)componentInChildren) { shootPosition = componentInChildren.transform; } else { shootPosition = base.transform; } rig = GetComponent(); soundGun.SetGun(this); soundGun.SetGunTransform(base.transform); soundGun.RefreshSoundModifiers(); } private void Update() { if ((bool)holdable && (bool)holdable.holder && (bool)holdable.holder.player) { player = holdable.holder.player; } sinceAttack += TimeHandler.deltaTime * attackSpeedMultiplier; if (!GameManager.instance.battleOngoing || (player != null && (!player.data.isPlaying || player.data.dead))) { soundGun.StopAutoPlayTail(); } } private void OnDestroy() { soundGun.StopAutoPlayTail(); } public bool IsReady(float readuIn = 0f) { return sinceAttack + readuIn * attackSpeedMultiplier > usedCooldown; } public float ReadyAmount() { return sinceAttack / usedCooldown; } public override bool Attack(float charge, bool forceAttack = false, float damageM = 1f, float recoilM = 1f, bool useAmmo = true) { if (sinceAttack < usedCooldown && !forceAttack) { return false; } if (isReloading && !forceAttack) { return false; } sinceAttack = 0f; int attacks = Mathf.Clamp(Mathf.RoundToInt(0.5f * charge / attackSpeed), 1, 10); if (lockGunToDefault) { attacks = 1; } StartCoroutine(DoAttacks(charge, forceAttack, damageM, attacks, recoilM, useAmmo)); return true; } private IEnumerator DoAttacks(float charge, bool forceAttack = false, float damageM = 1f, int attacks = 1, float recoilM = 1f, bool useAmmo = true) { for (int i = 0; i < attacks; i++) { DoAttack(charge, forceAttack, damageM, recoilM, useAmmo); yield return new WaitForSeconds(0.3f / (float)attacks); } } private void DoAttack(float charge, bool forceAttack = false, float damageM = 1f, float recoilM = 1f, bool useAmmo = true) { float num = 1f * (1f + charge * chargeRecoilTo) * recoilM; if ((bool)rig) { rig.AddForce(rig.mass * recoil * Mathf.Clamp(usedCooldown, 0f, 1f) * -base.transform.up, ForceMode2D.Impulse); } _ = (bool)holdable; if (attackAction != null) { attackAction(); } StartCoroutine(FireBurst(charge, forceAttack, damageM, recoilM, useAmmo)); } private bool CheckIsMine() { bool result = false; if ((bool)holdable && (bool)holdable.holder) { result = holdable.holder.player.data.view.IsMine; } else { Player componentInParent = GetComponentInParent(); if ((bool)componentInParent) { result = componentInParent.data.view.IsMine; } } return result; } private IEnumerator FireBurst(float charge, bool forceAttack = false, float damageM = 1f, float recoilM = 1f, bool useAmmo = true) { int currentNumberOfProjectiles = (lockGunToDefault ? 1 : (numberOfProjectiles + Mathf.RoundToInt(chargeNumberOfProjectilesTo * charge))); if (!lockGunToDefault) { _ = currentNumberOfProjectiles; } if (timeBetweenBullets == 0f) { GamefeelManager.GameFeel(base.transform.up * shake); soundGun.PlayShot(currentNumberOfProjectiles); } for (int ii = 0; ii < Mathf.Clamp(bursts, 1, 100); ii++) { for (int i = 0; i < projectiles.Length; i++) { for (int j = 0; j < currentNumberOfProjectiles; j++) { if (CheckIsMine()) { spawnPos = base.transform.position; if ((bool)player) { player.GetComponent().SetStacks(); if ((bool)holdable) { spawnPos = player.transform.position; } } GameObject gameObject = PhotonNetwork.Instantiate(projectiles[i].objectToSpawn.gameObject.name, spawnPos, getShootRotation(j, currentNumberOfProjectiles, charge), 0); if ((bool)holdable) { if (useAmmo) { if (PhotonNetwork.OfflineMode) { gameObject.GetComponent().OFFLINE_Init(holdable.holder.player.playerID, currentNumberOfProjectiles, damageM, UnityEngine.Random.Range(0f, 1f)); } else { gameObject.GetComponent().RPC("RPCA_Init", RpcTarget.All, holdable.holder.view.OwnerActorNr, currentNumberOfProjectiles, damageM, UnityEngine.Random.Range(0f, 1f)); } } else if (PhotonNetwork.OfflineMode) { gameObject.GetComponent().OFFLINE_Init_noAmmoUse(holdable.holder.player.playerID, currentNumberOfProjectiles, damageM, UnityEngine.Random.Range(0f, 1f)); } else { gameObject.GetComponent().RPC("RPCA_Init_noAmmoUse", RpcTarget.All, holdable.holder.view.OwnerActorNr, currentNumberOfProjectiles, damageM, UnityEngine.Random.Range(0f, 1f)); } } else if (PhotonNetwork.OfflineMode) { gameObject.GetComponent().OFFLINE_Init_SeparateGun(GetComponentInParent().playerID, gunID, currentNumberOfProjectiles, damageM, UnityEngine.Random.Range(0f, 1f)); } else { gameObject.GetComponent().RPC("RPCA_Init_SeparateGun", RpcTarget.All, GetComponentInParent().view.OwnerActorNr, gunID, currentNumberOfProjectiles, damageM, UnityEngine.Random.Range(0f, 1f)); } } if (timeBetweenBullets != 0f) { GamefeelManager.GameFeel(base.transform.up * shake); soundGun.PlayShot(currentNumberOfProjectiles); } } } if (bursts > 1 && ii + 1 == Mathf.Clamp(bursts, 1, 100)) { soundGun.StopAutoPlayTail(); } if (timeBetweenBullets > 0f) { yield return new WaitForSeconds(timeBetweenBullets); } } } public void BulletInit(GameObject bullet, int usedNumberOfProjectiles, float damageM, float randomSeed, bool useAmmo = true) { spawnedAttack = bullet.GetComponent(); if (!spawnedAttack) { spawnedAttack = bullet.AddComponent(); } if (!bullet.GetComponentInChildren()) { ApplyProjectileStats(bullet, usedNumberOfProjectiles, damageM, randomSeed); } if (soundDisableRayHitBulletSound) { RayHitBulletSound component = bullet.GetComponent(); if (component != null) { component.disableImpact = true; } } ApplyPlayerStuff(bullet); if (ShootPojectileAction != null) { ShootPojectileAction(bullet); } if (useAmmo && (bool)gunAmmo) { gunAmmo.Shoot(bullet); } } private Quaternion getShootRotation(int bulletID, int numOfProj, float charge) { Vector3 forward = shootPosition.forward; if (forceShootDir != Vector3.zero) { forward = forceShootDir; } float num = multiplySpread * Mathf.Clamp(1f + charge * chargeSpreadTo, 0f, float.PositiveInfinity); float num2 = UnityEngine.Random.Range(0f - spread, spread); num2 /= (1f + projectileSpeed * 0.5f) * 0.5f; forward += Vector3.Cross(forward, Vector3.forward) * num2 * num; return Quaternion.LookRotation(lockGunToDefault ? shootPosition.forward : forward); } private void ApplyPlayerStuff(GameObject obj) { ProjectileHit component = obj.GetComponent(); component.ownWeapon = base.gameObject; if ((bool)player) { component.ownPlayer = player; } spawnedAttack.spawner = player; spawnedAttack.attackID = attackID; } private void ApplyProjectileStats(GameObject obj, int numOfProj = 1, float damageM = 1f, float randomSeed = 0f) { ProjectileHit component = obj.GetComponent(); component.dealDamageMultiplierr *= bulletDamageMultiplier; component.damage *= damage * damageM; component.percentageDamage = percentageDamage; component.stun = component.damage / 150f; component.force *= knockback; component.movementSlow = slow; component.hasControl = CheckIsMine(); component.projectileColor = projectileColor; component.unblockable = unblockable; RayCastTrail component2 = obj.GetComponent(); if (ignoreWalls) { component2.mask = component2.ignoreWallsMask; } if ((bool)component2) { component2.extraSize += size; } if ((bool)player) { PlayerSkin teamColor = (component.team = PlayerSkinBank.GetPlayerSkinColors(player.playerID)); obj.GetComponent().teamID = player.playerID; SetTeamColor.TeamColorThis(obj, teamColor); } List list = new List(); for (int i = 0; i < objectsToSpawn.Length; i++) { list.Add(objectsToSpawn[i]); if (!objectsToSpawn[i].AddToProjectile || ((bool)objectsToSpawn[i].AddToProjectile.gameObject.GetComponent() && isProjectileGun)) { continue; } GameObject gameObject = UnityEngine.Object.Instantiate(objectsToSpawn[i].AddToProjectile, component.transform.position, component.transform.rotation, component.transform); gameObject.transform.localScale *= 1f * (1f - objectsToSpawn[i].scaleFromDamage) + component.damage / 55f * objectsToSpawn[i].scaleFromDamage; if (objectsToSpawn[i].scaleStacks) { gameObject.transform.localScale *= 1f + (float)objectsToSpawn[i].stacks * objectsToSpawn[i].scaleStackM; } if (!objectsToSpawn[i].removeScriptsFromProjectileObject) { continue; } MonoBehaviour[] componentsInChildren = gameObject.GetComponentsInChildren(); for (int j = 0; j < componentsInChildren.Length; j++) { if (componentsInChildren[j].GetType().ToString() != "SoundImplementation.SoundUnityEventPlayer") { UnityEngine.Object.Destroy(componentsInChildren[j]); } Debug.Log(componentsInChildren[j].GetType().ToString()); } } component.objectsToSpawn = list.ToArray(); if (reflects > 0) { RayHitReflect rayHitReflect = obj.gameObject.AddComponent(); rayHitReflect.reflects = reflects; rayHitReflect.speedM = speedMOnBounce; rayHitReflect.dmgM = dmgMOnBounce; } if (!forceSpecificShake) { float num = component.damage / 100f * ((1f + usedCooldown) / 2f) / ((1f + (float)numOfProj) / 2f) * 2f; float num2 = Mathf.Clamp((0.2f + component.damage * (((float)numberOfProjectiles + 2f) / 2f) / 100f * ((1f + usedCooldown) / 2f)) * 1f, 0f, 3f); component.shake = num * shakeM; shake = num2; } MoveTransform component3 = obj.GetComponent(); component3.localForce *= projectileSpeed; component3.simulationSpeed *= projectielSimulatonSpeed; component3.gravity *= gravity; component3.worldForce *= gravity; component3.drag = drag; component3.drag = Mathf.Clamp(component3.drag, 0f, 45f); component3.velocitySpread = Mathf.Clamp(spread * 50f, 0f, 50f); component3.dragMinSpeed = dragMinSpeed; component3.localForce *= Mathf.Lerp(1f - component3.velocitySpread * 0.01f, 1f + component3.velocitySpread * 0.01f, randomSeed); component3.selectedSpread = 0f; if (damageAfterDistanceMultiplier != 1f) { obj.AddComponent().muiltiplier = damageAfterDistanceMultiplier; } if (cos > 0f) { obj.gameObject.AddComponent().multiplier = cos; } if (destroyBulletAfter != 0f) { obj.GetComponent().seconds = destroyBulletAfter; } if ((bool)spawnedAttack && projectileColor != Color.black) { spawnedAttack.SetColor(projectileColor); } } public void AddAttackAction(Action action) { attackAction = (Action)Delegate.Combine(attackAction, action); } internal void RemoveAttackAction(Action action) { attackAction = (Action)Delegate.Remove(attackAction, action); } }