/// <summary> /// clones this EffectData to a new object /// </summary> public EffectData clone() { EffectData clone = new EffectData(); clone.XMLEffects = XMLEffects; //copy the list of xml effects over so we dont lose it //parse our own effects if needed if (effectsParsed == false) { parseEffects(); } //clone the effects also foreach (IEffect ie in effects) { clone.Add(cloneEffect(ie)); } //dont let the clone parse effects again, since we just did it for them clone.effectsParsed = true; return(clone); }
/// <summary> /// deals damage to the enemy. (make sure to call onExpectedDamage() first to avoid targeting bugs) /// </summary> /// <param name="e">damage event containing information about the attack</param> /// <param name="showParticles">if true, particles will be generated from the attack</param> public void onDamage(DamageEventData e, bool showParticles = true) { //dont bother if we are already dead if (curHealth <= 0) { return; } //trigger enemyDamaged effects if (effectData != null) { foreach (IEffect i in effectData.effects) { if (i.triggersAs(EffectType.enemyDamaged)) { //DEBUG CHECK: actualDamage() should not alter damage value float checkDamage = e.rawDamage; ((IEffectEnemyDamaged)i).actualDamage(ref e); //DEBUG CHECK: actualDamage() should not alter damage value if (checkDamage != e.rawDamage) { Debug.LogWarning(i.XMLName + " has altered rawDamage in actualDamage()!"); } } } } //copy periodic effects from the attack onto this unit so they can take effect, provided they are not forbidden in this context if (e.effects != null) { foreach (IEffect toCopy in e.effects.effects) { if (toCopy.triggersAs(EffectType.periodic)) { if (toCopy.forbiddenInContext(EffectContext.enemyUnit) == false) { //found an effect we need to copy. first make sure we have an object to copy it to. if (effectData == null) { effectData = new EffectData(); } //then copy it effectData.Add(EffectData.cloneEffect(toCopy)); } } } } //take damage int damage = Mathf.CeilToInt(e.rawDamage); damage = System.Math.Min(damage, curHealth); curHealth -= damage; //tell the attacking tower about it so it can keep track if (e.source != null) { e.source.trackDamage(damage); } //provide user feedback if (damage > 0) { //sound int soundToPlay = Random.Range(0, enemyHitSounds.Length); audioSource.clip = enemyHitSounds[soundToPlay]; if (isActiveAndEnabled) { StartCoroutine(playRespectLimit(audioSource)); //plays the sound, if we are not at the sound cap and the object is not disabled } //particles if (showParticles) { damageParticles.Emit(damageParticleBaseCount + Mathf.FloorToInt(damage / damagePerExtraParticle)); } } if (curHealth <= 0) { //catch a recurring issue where the enemy does not get the expected damage event and thus dies without expecting it if (expectedHealth > 0) { Debug.LogWarning("Enemy did not expect to die, but did anyway! This can cause targeting issues as towers attack an enemy that will die anyway."); expectedHealth = 0; EnemyManagerScript.instance.EnemyExpectedDeath(this); } //(bugfix: works around race condition where an enemy is deactivated and then dies immediately afterward if (gameObject.activeSelf == false) { gameObject.SetActive(true); } //and start the death coroutine StartCoroutine(onDeath()); } }
/// <summary> /// copies effects from newEffectData and adds them to the ones already present /// </summary> public void AddEffects(EffectData newEffectData) { //make sure we have an effectData object to add to if (effects == null) { effects = new EffectData(); } //for each effect to add foreach (IEffect newEffect in newEffectData.effects) { //apply upgrade effects if (newEffect.triggersAs(EffectType.upgrade)) { ((IEffectUpgrade)newEffect).upgradeTower(this); } //trigger instant effects if (newEffect.triggersAs(EffectType.instant)) { if (LevelManagerScript.instance.levelLoaded) //skip them while the level is being loaded so we dont trigger card draws, etc. { ((IEffectInstant)newEffect).trigger(); } } //do not copy effects that are forbidden on towers if (newEffect.forbiddenInContext(EffectContext.tower)) { continue; } //tell it about the source, if it wants to know if (newEffect.triggersAs(EffectType.sourceTracked)) { ((IEffectSourceTracked)newEffect).effectSource = this; } //add it effects.Add(EffectData.cloneEffect(newEffect)); } //update tooltip text UpdateTooltipText(); updateLifespanText(); //max tower charge is 1.0 unless an effect overrides it maxCharge = 1.0f; if (effects != null) { if (effects.propertyEffects.maxOvercharge != null) { maxCharge += effects.propertyEffects.maxOvercharge.Value; } } //use the range sprite appropriate to the top targeting effect switch (effects.topTargetingEffect.XMLName) { case "targetMouse": rangeImage.sprite = mouseRangeSprite; rangeImage2.enabled = false; break; case "targetOrthogonal": rangeImage.sprite = orthogonalRangeSprite; rangeImage2.enabled = false; break; default: rangeImage.sprite = defaultRangeSprite; rangeImage2.enabled = false; break; } //make sure the scale is being set right updateRangeImage(); }