void Start() { //get the ame manager script GameMgr = GameManager.Instance; MvtMgr = MovementManager.Instance; AttackMgr = AttackManager.Instance; //default values for the timers: AttackTimer = 0.0f; SearchTimer = 0.0f; ObjPool = EffectObjPool.Instance; if (AttackAllTypes == false) { //if it can not attack all the units AttackMgr.AssignAttackExceptions(AttackExceptions, ref AttackExceptionList); } //if there's a weapon object: if (WeaponObj) { WeaponIdleRotation.eulerAngles = WeaponIdleAngles; } //get the range type ID from the attack manager RangeTypeID = AttackMgr.GetRangeTypeID(RangeType); }
void Awake() { if (Instance == null) { Instance = this; } else if (Instance != this) { Destroy(gameObject); } }
//Set DoT configs: public void ConfigureTargetDoT(Unit Target) { //DoT settings: Target.DoT = new DoTVars(); Target.DoT.Enabled = true; Target.DoT.Cycle = DoT.Cycle; Target.DoT.Duration = DoT.Duration; Target.DoT.Infinite = DoT.Infinite; Target.DoT.Source = gameObject; TargetUnit.DoT.Damage = AttackManager.GetDamage(AttackTarget, CustomDamage, UnitDamage); }
//a method to laucnh a direct attack void LaunchDirectAttack() { if (AreaDamage == true) { //launch area damage and provide all arguments: AttackMgr.LaunchAreaDamage(AttackTarget.transform.position, this); } else { //Custom event: if (GameMgr.Events) { GameMgr.Events.OnAttackPerformed(this, AttackTarget); } if (DealDamage == true) //Can this attack deal damage directly? { if (DoT.Enabled == true) { //only for units currently? if (TargetUnit) { ConfigureTargetDoT(TargetUnit, AttackManager.GetDamage(AttackTarget, CustomDamage, UnitDamage)); } } else { //if this is no areal damage and no DoT //deal damage to unit/building: if (TargetUnit) { TargetUnit.AddHealth(-AttackManager.GetDamage(AttackTarget, CustomDamage, UnitDamage), this.gameObject); //Spawning the damage effect object: AttackMgr.SpawnEffectObj(TargetUnit.DamageEffect, AttackTarget, AttackTarget.transform.position, 0.0f, true, true); //spawn attack effect object: units only currently AttackMgr.SpawnEffectObj(AttackEffect, AttackTarget, AttackTarget.transform.position, AttackEffectTime, false, true); } else if (TargetBuilding) { TargetBuilding.AddHealth(-AttackManager.GetDamage(AttackTarget, CustomDamage, BuildingDamage), this.gameObject); //Spawning the damage effect object: AttackMgr.SpawnEffectObj(TargetBuilding.DamageEffect, AttackTarget, AttackTarget.transform.position, 0.0f, true, true); } } } } //Play the attack audio: AudioManager.PlayAudio(gameObject, AttackSound, false); FinishAttack(); }
void Start() { //get the ame manager script GameMgr = GameManager.Instance; MvtMgr = MovementManager.Instance; AttackMgr = AttackManager.Instance; //default values for the timers: AttackTimer = 0.0f; SearchTimer = 0.0f; ObjPool = EffectObjPool.Instance; //if there's a weapon object: if (WeaponObj) { WeaponIdleRotation.eulerAngles = WeaponIdleAngles; } //get the range type ID from the attack manager RangeTypeID = AttackMgr.GetRangeTypeID(RangeType); }
//Attack object collision effect: void OnTriggerEnter(Collider other) { if ((DidDamage == false || DamageOnce == false) && DoDamage == true) { //Make sure that the attack obj either didn't do damage when the attack object is allowed to do damage once or if it can do damage multiple times. SelectionObj HitObj = other.gameObject.GetComponent <SelectionObj>(); if (HitObj != null) { Unit HitUnit = HitObj.MainObj.GetComponent <Unit>(); Building HitBuilding = HitObj.MainObj.GetComponent <Building>(); //If the damaged object is a unit: if (HitUnit) { //Check if the unit belongs to the faction that this attack obj is targeted to and if the unit is actually not dead yet: if (HitUnit.FactionID == TargetFactionID && HitUnit.Dead == false) { if (other != null) { DidDamage = true; //Inform the script that the damage has been done if (AreaDamage) { AttackManager.Instance.LaunchAreaDamage(transform.position, Source); } else { //Custom event: if (GameManager.Instance.Events) { GameManager.Instance.Events.OnAttackPerformed(Source, HitUnit.gameObject); } if (DealDamage == true) { if (DoT.Enabled) //if it's DoT { //DoT settings: Source.ConfigureTargetDoT(HitUnit, AttackManager.GetDamage(HitUnit.gameObject, CustomDamage, DefaultUnitDamage)); } else { //Remove health points from the unit: HitUnit.AddHealth(-AttackManager.GetDamage(HitUnit.gameObject, CustomDamage, DefaultUnitDamage), SourceObj); //Attack effect: AttackManager.Instance.SpawnEffectObj(AttackEffect, other.gameObject, AttackEffectTime, false); //Spawning the damage effect object: AttackManager.Instance.SpawnEffectObj(HitUnit.DamageEffect, other.gameObject, 0.0f, true); } } } } } } //If the attack obj hit a building: if (HitBuilding) { //Check if the building belongs to the faction that this attack obj is targeted to and if the building still has health: if (HitBuilding.FactionID == TargetFactionID && HitBuilding.Health >= 0) { if (other != null) { DidDamage = true; //Inform the script that the damage has been done if (AreaDamage) { AttackManager.Instance.LaunchAreaDamage(transform.position, Source); } else { //Custom event: if (GameManager.Instance.Events) { GameManager.Instance.Events.OnAttackPerformed(Source, HitBuilding.gameObject); } if (DealDamage == true) //only if we can deal damage directly { //Remove health points from the unit: HitBuilding.AddHealth(-AttackManager.GetDamage(HitBuilding.gameObject, CustomDamage, DefaultBuildingDamage), SourceObj); //Attack effect: AttackManager.Instance.SpawnEffectObj(AttackEffect, other.gameObject, AttackEffectTime, false); //Spawning the damage effect object: AttackManager.Instance.SpawnEffectObj(HitBuilding.DamageEffect, other.gameObject, 0.0f, true); } } } } } } } }
//Attack object collision effect: void OnTriggerEnter(Collider other) { if ((DidDamage == false || DamageOnce == false) && DoDamage == true) //Make sure that the attack obj either didn't do damage when the attack object is allowed to do damage once or if it can do damage multiple times. { SelectionObj HitObj = other.gameObject.GetComponent <SelectionObj> (); if (HitObj != null) { Unit HitUnit = HitObj.MainObj.GetComponent <Unit> (); Building HitBuilding = HitObj.MainObj.GetComponent <Building> (); //If the damaged object is a unit: if (HitUnit) { //Check if the unit belongs to the faction that this attack obj is targeted to and if the unit is actually not dead yet: if (HitUnit.FactionID == TargetFactionID && HitUnit.Dead == false) { if (other != null) { DidDamage = true; //Inform the script that the damage has been done if (AreaDamage) { AttackManager.Instance.LaunchAreaDamage(transform.position, AttackRanges, SourceFactionID, AttackEffect, AttackEffectTime, AttackCategoriesList, DoT); } else if (DoT.Enabled) //if it's DoT { //DoT settings: HitUnit.DoT = DoT; HitUnit.DoT.Damage = AttackManager.GetDamage(HitUnit.gameObject, DefaultUnitDamage); } else { //Remove health points from the unit: HitUnit.AddHealth(-AttackManager.GetDamage(HitUnit.gameObject, DefaultUnitDamage), Source); //Attack effect: units only currently AttackManager.Instance.SpawnEffectObj(AttackEffect, other.gameObject, AttackEffectTime, false); } //Spawning the damage effect object: AttackManager.Instance.SpawnEffectObj(HitUnit.DamageEffect, other.gameObject, 0.0f, true); } } } //If the attack obj hit a building: if (HitBuilding) { //Check if the building belongs to the faction that this attack obj is targeted to and if the building still has health: if (HitBuilding.FactionID == TargetFactionID && HitBuilding.Health >= 0) { if (other != null) { DidDamage = true; //Inform the script that the damage has been done if (AreaDamage) { AttackManager.Instance.LaunchAreaDamage(transform.position, AttackRanges, SourceFactionID, AttackEffect, AttackEffectTime, AttackCategoriesList, DoT); } else { //Remove health points from the unit: HitBuilding.AddHealth(-AttackManager.GetDamage(HitBuilding.gameObject, DefaultUnitDamage), Source); } //Spawning the damage effect object: AttackManager.Instance.SpawnEffectObj(HitBuilding.DamageEffect, other.gameObject, 0.0f, true); } } } } } }
void Update() { //Unit only: if (Attacker == Attackers.Unit) { //the attack animation timer: if (AttackAnimTimer > 0) { AttackAnimTimer -= Time.deltaTime; } if (AttackAnimTimer < 0) { AttackAnimTimer = 0; //stop showing the attacking animation when the timer is done. if (UnitMgr.AnimMgr) { if (UnitMgr.AnimMgr.GetBool("IsAttacking") == true) { UnitMgr.AnimMgr.SetBool("IsAttacking", false); } } } } //Attack timer: if (AttackTimer > 0) { AttackTimer -= Time.deltaTime; } if (CanAttack() == true) //If the attacker is still not dead/destroyed { if (GameMgr.PeaceTime <= 0) //if we're not in the peace time { if (AttackTarget == null) { //If the target is not set yet if (WeaponObj != null) //if there's a weapon object { if (SmoothRotation == false) { //if the rotation is automatically changed WeaponObj.transform.localRotation = WeaponIdleRotation; } else { //smooth rotation here: WeaponObj.transform.localRotation = Quaternion.Slerp(WeaponObj.transform.localRotation, WeaponIdleRotation, Time.deltaTime * RotationDamping); } } if (GameManager.MultiplayerGame == false || (GameManager.MultiplayerGame == true && GameManager.PlayerFactionID == AttackerFactionID())) { //if this is an offline game or online but this is the local player if (AttackInRange == true) //if the attacker can attack in range ~and it's also in idle state~ { //if the faction is a NPC or a local player and having a target is required. if (GameManager.PlayerFactionID != AttackerFactionID() || (GameManager.PlayerFactionID == AttackerFactionID() && RequireAttackTarget == true)) { //Search timer: if (SearchTimer > 0) { SearchTimer -= Time.deltaTime; } else { //Search if there are enemy units in range: bool Found = false; float Size = SearchEnemyRange; Vector3 SearchFrom = transform.position; Collider[] ObjsInRange = Physics.OverlapSphere(SearchFrom, Size); // ADD LAYERMASK System.Array.Sort(ObjsInRange, DistanceSort); int i = 0; //counter while (i < ObjsInRange.Length && Found == false) { Unit UnitInRange = ObjsInRange[i].gameObject.GetComponent <Unit>(); if (UnitInRange) { //If it's a unit object if (UnitInRange.enabled == true) { //if the unit comp is enabled //If this unit and the target have different teams and make sure it's not dead. if (UnitInRange.FactionID != AttackerFactionID() && UnitInRange.Dead == false) { //if the unit is visible: if (UnitInRange.IsInvisible == false) { if (AttackTarget == null) { if (AttackManager.Instance.CanAttackTarget(this, ObjsInRange[i].gameObject, AttackCategoriesList)) { //if the unit can attack the target. //Set this unit as the target SetAttackTarget(ObjsInRange[i].gameObject); Found = true; } } } } } } i++; } if (Found == false) { SearchTimer = SearchReload; //No enemy units found? search again. } else { //if the attacker is a unit: if (Attacker == Attackers.Unit) { //Follow the target: UnitMgr.CheckUnitPath(Vector3.zero, AttackTarget, AttackRange + AttackTarget.GetComponent <Unit>().NavAgent.radius + UnitMgr.NavAgent.radius, 0, true); } } } } } } } else { //if the target went invisible: //Checking whether the target is dead or not (if it's a unit or a building. bool Dead = false; if (AttackTarget.GetComponent <Unit> ()) { //if the target went invisible: if (AttackTarget.GetComponent <Unit> ().IsInvisible == true) { //stop attacking it: CancelAttack(); return; } else if (AttackTarget.GetComponent <Unit> ().FactionID == AttackerFactionID()) { CancelAttack(); return; } Dead = AttackTarget.GetComponent <Unit> ().Dead; } else if (AttackTarget.GetComponent <Building> ()) { if (AttackTarget.GetComponent <Building> ().FactionID == AttackerFactionID()) { CancelAttack(); return; } //Dead = !(Target.GetComponent<Building> ().Health > 0); } if (Dead == true && AttackTimer <= 0) { //if the target unit is dead, cancel everything CancelAttack(); } else { //If the current unit has a target, if (Vector3.Distance(this.transform.position, AttackTarget.transform.position) > FollowRange && AttackRangeFromCenter == false && AttackTarget.GetComponent <Unit> () && WasInTargetRange == true) //This means that the target has left the follow range of the unit. { CancelAttack(); //This unit doesn't have a target anymore. } else { if (Attacker == Attackers.Unit) //if the attacker is a unit { //if this is the local player in a MP game or simply an offline game: if (GameManager.MultiplayerGame == false || (GameManager.MultiplayerGame == true && GameManager.PlayerFactionID == AttackerFactionID())) { //if the attack target went away: if (Vector3.Distance(UnitMgr.NavAgent.destination, AttackTarget.transform.position) > ChangeMvtDistance && UnitMgr.Moving == true) { UnitMgr.CheckUnitPath(Vector3.zero, AttackTarget, UnitMgr.NavAgent.stoppingDistance, 0, true); } //if destination is reached but the unit is still far away from the target. if (Vector3.Distance(UnitMgr.NavAgent.destination, AttackTarget.transform.position) > UnitMgr.NavAgent.stoppingDistance && UnitMgr.DestinationReached == true) { //THE PROBLEM IS HERE: When unit reaches the destination but max distance is probably more UnitMgr.DestinationReached = false; } if (UnitMgr.DestinationReached == false && UnitMgr.Moving == false) { //If the unit didn't reach its target and it looks like it's not moving: //Follow the target: UnitMgr.CheckUnitPath(Vector3.zero, AttackTarget, UnitMgr.NavAgent.stoppingDistance, 0, true); } } if (!MoveOnAttack && Vector3.Distance(transform.position, AttackTarget.transform.position) <= AttackRange) { UnitMgr.DestinationReached = true; } //if the attacker is in the correct range of his target if (UnitMgr.DestinationReached == true) { if (MoveOnAttack == false && UnitMgr.Moving == true) //if move on attack is disabled and the unit is still moving { return; //stop } } else { return; //if the unit didn't reach the target then don't proceed } } //reaching this stage means that the attacker is in range of the target and it's all good to go: WasInTargetRange = true; //Make the attack object look at the target: if (WeaponObj != null) { Vector3 LookAt = AttackTarget.transform.position - WeaponObj.transform.position; //which axis should not be rotated? if (FreezeRotX == true) { LookAt.x = 0.0f; } if (FreezeRotY == true) { LookAt.y = 0.0f; } if (FreezeRotZ == true) { LookAt.z = 0.0f; } Quaternion TargetRotation = Quaternion.LookRotation(LookAt); if (SmoothRotation == false) { //if the rotation is automatically changed WeaponObj.transform.rotation = TargetRotation; } else { //smooth rotation here: WeaponObj.transform.rotation = Quaternion.Slerp(WeaponObj.transform.rotation, TargetRotation, Time.deltaTime * RotationDamping); } } //Delay timer here: if (DelayTimer > 0) { DelayTimer -= Time.deltaTime; } if (Attacker == Attackers.Unit) { //Playing animation: if (UnitMgr.AnimMgr && (PlayAnimInDelay == true || (PlayAnimInDelay == false && DelayTimer <= 0.0f && AttackTriggered == true))) { if (UnitMgr.AnimMgr.GetBool("IsAttacking") == false) { UnitMgr.AnimMgr.SetBool("IsAttacking", true); } } } //If the attack delay is over, launch the attack if (DelayTimer <= 0.0f && AttackTriggered == true) { if (AttackTimer <= 0) { //if the attack timer is ready: //Custom event: if (GameMgr.Events) { GameMgr.Events.OnAttackPerformed(this, AttackTarget, AttackID); } //Is this a direct attack (no use of attack objects)? if (DirectAttack == true) { if (AreaDamage == true) { //launch area damage and provide all arguments: AttackManager.Instance.LaunchAreaDamage(AttackTarget.transform.position, AttackRanges, AttackerFactionID(), AttackEffect, AttackEffectTime, AttackCategoriesList, DoT); } else if (DoT.Enabled == true) { Unit TargetUnit = AttackTarget.GetComponent <Unit>(); //only for units currently? if (TargetUnit) { //DoT settings: TargetUnit.DoT = DoT; TargetUnit.DoT.Damage = AttackManager.GetDamage(AttackTarget, UnitDamage); } } else { //if this is no areal damage and no DoT //deal damage to unit/building: if (AttackTarget.GetComponent <Unit>()) { AttackTarget.GetComponent <Unit>().AddHealth(-AttackManager.GetDamage(AttackTarget, UnitDamage), this.gameObject); //Spawning the damage effect object: AttackManager.Instance.SpawnEffectObj(AttackTarget.GetComponent <Unit>().DamageEffect, AttackTarget, 0.0f, true); //spawn attack effect object: units only currently AttackManager.Instance.SpawnEffectObj(AttackEffect, AttackTarget, AttackEffectTime, false); } else if (AttackTarget.GetComponent <Building>()) { AttackTarget.GetComponent <Building>().AddHealth(-AttackManager.GetDamage(AttackTarget, UnitDamage), this.gameObject); //Spawning the damage effect object: AttackManager.Instance.SpawnEffectObj(AttackTarget.GetComponent <Building>().DamageEffect, AttackTarget, 0.0f, true); } } //Play the attack audio: AudioManager.PlayAudio(gameObject, AttackSound, false); if (Attacker == Attackers.Unit) { UnitMgr.SetAnimState(UnitAnimState.Attacking); } //reload the timers AttackTimer = AttackReload; AttackAnimTimer = AttackAnimTime; } else { //If the unit can launch attack objs towards the target unit if (AttackStep < AttackSources.Length && AttackSources.Length > 0) { //if we haven't already launched attacks from all sources if (AttackStepTimer > 0) { AttackStepTimer -= Time.deltaTime; } if (AttackStepTimer <= 0) { AttackTimer = AttackReload; AttackAnimTimer = AttackAnimTime; AttackObject AttackObj = ObjPool.GetEffectObj(EffectObjPool.EffectObjTypes.AttackObj, AttackSources[AttackStep].AttackObj).GetComponent <AttackObject>(); AttackObj.transform.position = AttackSources[AttackStep].AttackObjSource.transform.position; //Set the attack object's position: AttackObj.gameObject.SetActive(true); //Activate the attack object AttackObj.DefaultUnitDamage = UnitDamage; AttackObj.DefaultBuildingDamage = BuildingDamage; AttackObj.CustomDamage = CustomDamage; Vector3 TargetPos = AttackTarget.transform.position; if (AttackTarget.GetComponent <Unit>()) { AttackObj.TargetFactionID = AttackTarget.GetComponent <Unit>().FactionID; //TargetPos = AttackTarget.GetComponent<Unit>().PlayerSelection.transform.position; } else if (AttackTarget.GetComponent <Building>()) { AttackObj.TargetFactionID = AttackTarget.GetComponent <Building>().FactionID; //TargetPos = AttackTarget.GetComponent<Building>().PlayerSelection.transform.position; } if (AttackSources[AttackStep].FollowTarget) { AttackObj.FollowTarget = AttackSources[AttackStep].FollowTarget; AttackObj.Target = AttackTarget.transform; } AttackObj.DamageOnce = AttackSources[AttackStep].DamageOnce; AttackObj.DestroyOnDamage = AttackSources[AttackStep].DestroyAttackObjOnDamage; AttackObj.Source = gameObject; AttackObj.SourceFactionID = AttackerFactionID(); if (AreaDamage == false) { AttackObj.DidDamage = false; AttackObj.DoDamage = !DirectAttack; AttackObj.AreaDamage = false; } else { AttackObj.DamageOnce = true; AttackObj.DidDamage = false; AttackObj.AreaDamage = true; AttackObj.AttackRanges = AttackRanges; AttackObj.AttackCategoriesList = AttackCategoriesList; } //Damage over time: AttackObj.DoT = DoT; //Attack object movement: AttackObj.MvtVector = (TargetPos - AttackSources[AttackStep].AttackObjSource.transform.position) / Vector3.Distance(AttackTarget.transform.position, AttackSources[AttackStep].AttackObjSource.transform.position); AttackObj.Speed = AttackSources[AttackStep].AttackObjSpeed; //Set the attack obj's rotation so that it looks at the target: AttackObj.transform.rotation = Quaternion.LookRotation(TargetPos - AttackObj.transform.position); //Hide the attack object after some time: AttackObj.DestroyTimer = AttackSources[AttackStep].AttackObjDestroyTime; AttackObj.ShowAttackObjEffect(); //Play the attack audio: AudioManager.PlayAudio(gameObject, AttackSound, false); //----------------------------------------------------------------------------------------------- //search for the next attack object: if (AttackType == AttackTypes.InOrder) { //if the attack types is in order AttackStep++; } if (AttackStep >= AttackSources.Length || AttackType == AttackTypes.Random) { //end of attack round: //Reload the attack timer: AttackStep = 0; AttackStepTimer = AttackSources[AttackStep].AttackDelay; } else { AttackStepTimer = AttackSources[AttackStep].AttackDelay; } } } } } } } } } } } }
//a method to laucnh a direct attack void LaunchDirectAttack() { if (AreaDamage == true) { //launch area damage and provide all arguments: AttackMgr.LaunchAreaDamage(AttackTarget.transform.position, this); } else { //Custom event: if (GameMgr.Events) { GameMgr.Events.OnAttackPerformed(this, AttackTarget); } if (DealDamage == true) //Can this attack deal damage directly? { if (DoT.Enabled == true) { //only for units currently? if (TargetUnit) { ConfigureTargetDoT(TargetUnit, AttackManager.GetDamage(AttackTarget, CustomDamage, UnitDamage)); } } else { //if this is no areal damage and no DoT //deal damage to unit/building: if (TargetUnit) { TargetUnit.AddHealth(-AttackManager.GetDamage(AttackTarget, CustomDamage, UnitDamage), this.gameObject); //Spawning the damage effect object: AttackMgr.SpawnEffectObj(TargetUnit.DamageEffect, AttackTarget, 0.0f, true); //spawn attack effect object: units only currently AttackMgr.SpawnEffectObj(AttackEffect, AttackTarget, AttackEffectTime, false); } else if (TargetBuilding) { TargetBuilding.AddHealth(-AttackManager.GetDamage(AttackTarget, CustomDamage, BuildingDamage), this.gameObject); //Spawning the damage effect object: AttackMgr.SpawnEffectObj(TargetBuilding.DamageEffect, AttackTarget, 0.0f, true); } } } } //Play the attack audio: AudioManager.PlayAudio(gameObject, AttackSound, false); AttackTimer = AttackReload; CanPlayAnim = true; //If this not the basic attack then revert back to the basic attack after done if (BasicAttack == false && MultipleAttacksMgr != null) { MultipleAttacksMgr.EnableAttackType(MultipleAttacksMgr.BasicAttackID); } //Cooldown: StartCoolDown(); //Attack once? cancel attack to prevent source from attacking again if (AttackOnce == true) { CancelAttack(); } ReloadAttackDelay(); }