//Casts spell from NPC (enemy or ally) public List <CastData> cast(SpellData spell, ICaster[] targets, int selected, ICaster[] allies, int position, out List <Transform> noTargetPositions) { noTargetPositions = new List <Transform>(); ICaster caster = allies[position]; Spell s = spells[spell.root]; Spell c = createSpellFromType(s.type); s.copyInto(c); int wordCount = 1; string[] animData = { null, s.animationID, null }; string[] sfxData = { null, s.sfxID, null }; ElementMod e = null; StyleMod st = null; if (spell.element != null) { e = elements[spell.element]; sfxData[2] = e.sfxID; animData[2] = e.animationID; ++wordCount; } if (spell.style != null) { st = styles[spell.style]; sfxData[0] = st.sfxID; animData[0] = st.animationID; ++wordCount; } c.Modify(e, st); List <ICaster> toCastAt = c.target(targets, selected, allies, position); List <CastData> data = new List <CastData>(); foreach (ICaster target in toCastAt) { if (target == null) { continue; } if (target.Is_dead) { noTargetPositions.Add(target.Transform); continue; } CastData castData = c.cast(target, caster); animData.CopyTo(castData.animData, 0); sfxData.CopyTo(castData.sfxData, 0); castData.wordCount = wordCount; if (castData.repel == true) { castData.setLocationData(caster, target); } else { castData.setLocationData(target, caster); } data.Add(castData); } return(data); }
EdgeInfo FindEdge(CastData minCast, CastData maxCast) { float minAngle = minCast.angle; float maxAngle = maxCast.angle; Vector3 minPoint = Vector3.zero; Vector3 maxPoint = Vector3.zero; for (int i = 0; i < edgeResolveIterations; i++) { float angle = (minAngle + maxAngle) / 2; CastData newViewCast = ViewCast(angle); bool edgeDistanceThresholdExceeded = Mathf.Abs(minCast.distance - newViewCast.distance) > edgeDistanceThreshold; if (newViewCast.hit == minCast.hit && !edgeDistanceThresholdExceeded) { minAngle = angle; minPoint = newViewCast.point; } else { maxAngle = angle; maxPoint = newViewCast.point; } } return(new EdgeInfo(minPoint, maxPoint)); }
void DrawFieldOfView() { int stepCount = Mathf.RoundToInt(viewAngle * meshResolution); float stepAngleSize = viewAngle / stepCount; List <Vector3> viewPoints = new List <Vector3>(); CastData oldViewCast = new CastData(); for (int i = 0; i <= stepCount; i++) { float angle = transform.eulerAngles.y - viewAngle / 2 + stepAngleSize * i; CastData newViewCast = ViewCast(angle); if (i > 0) { bool edgeDistanceThresholdExceeded = Mathf.Abs(oldViewCast.distance - newViewCast.distance) > edgeDistanceThreshold; if (oldViewCast.hit != newViewCast.hit || (oldViewCast.hit && newViewCast.hit && edgeDistanceThresholdExceeded)) { EdgeInfo edge = FindEdge(oldViewCast, newViewCast); if (edge.pointA != Vector3.zero) { viewPoints.Add(edge.pointA); } if (edge.pointB != Vector3.zero) { viewPoints.Add(edge.pointB); } } } viewPoints.Add(newViewCast.point); oldViewCast = newViewCast; } int vertexCount = viewPoints.Count + 1; Vector3[] vertices = new Vector3[vertexCount]; int[] triangles = new int[(vertexCount - 2) * 3]; // NB: Positions of vertices need to be in local space vertices[0] = Vector3.zero; for (int i = 0; i < vertexCount - 1; i++) { vertices[i + 1] = transform.InverseTransformPoint(viewPoints[i]); if (i < vertexCount - 2) { triangles[i * 3] = 0; triangles[i * 3 + 1] = i + 1; triangles[i * 3 + 2] = i + 2; } } viewMesh.Clear(); viewMesh.vertices = vertices; viewMesh.triangles = triangles; viewMesh.RecalculateNormals(); }
public List <CombatItem> GetCastData(ushort key) { if (CastData.TryGetValue(key, out List <CombatItem> res)) { return(res); } return(new List <CombatItem>());; }
//Play a spell animation without really doing anything public IEnumerator playSpellEffects(SpellData s, CastData dummyValues) { dummyValues.animData = spellDict.getAnimData(s); dummyValues.sfxData = spellDict.getSfxData(s); dummyValues.element = Elements.fromString(s.element); dummyValues.damageInflicted = spellDict.getSpell(s).power * 2; yield return(StartCoroutine(spellEffects.playEffects(dummyValues, s))); }
public List <CombatItem> GetCastData(ushort key, long start, long end) { if (CastData.TryGetValue(key, out List <CombatItem> res)) { return(res.Where(x => x.Time >= start && x.Time <= end).ToList()); } return(new List <CombatItem>());; }
//Returns true if spell inflicts a buff/debuff on target, and inflicts the buff/debuff protected virtual bool buffCheck(CastData data, ICaster target, ICaster caster, int powerMod) { if ((Random.Range(0.0F, 1F) * 100) <= buffPercentage) { data.isBuff = true; data.buffInflicted = buff; inflictBuff(target, caster, powerMod); return(true); } return(false); }
public override CastData cast(ICaster target, ICaster caster) { CastData data = new CastData(); data.element = element; int powerMod; critCheck(data, target, caster, out powerMod); buffCheck(data, target, caster, powerMod); return(data); }
//Applies repel and prints appropriate debug log //Returns true if reflected, false if not. //MAY need fixing for targeting public static bool calcRepel(CastData data, int d, int element, ICaster caster, ICaster target, bool crit, bool repel) { //repel damage to caster if enemy reflects this element (FIX for targeting) if (target.Stats.vsElement[element] == Elements.repel && repel == false) { Debug.Log(target.Stats.name + " reflects " + d + " " + Elements.toString(element) + " damage back at " + caster.Stats.name); data.repel = true; caster.damage(data, d, element, caster, crit, true); return(true); } return(false); }
// be attacked by the player public void damage(CastData data, int d, int element, ICaster caster, bool crit, bool reflect = false) { //Apply repel and return if applicable if (CasterOps.calcRepel(data, d, element, caster, this, crit, reflect)) { return; } CasterOps.calcDamage(data, d, element, caster, this, crit, Is_stunned); //log stun stun actually happens in update condition data.isStun = curr_stagger <= 0 && is_stunned == false; //opacity and death are now updated in updateCondition() was_hit = true; }
public void damage(CastData data, int d, int element, ICaster caster, bool crit, bool reflect = false) { //Apply repel and return if applicable if (CasterOps.calcRepel(data, d, element, caster, this, crit, reflect)) { return; } CasterOps.calcDamage(data, d, element, caster, this, crit); //Apply stun if applicable if (curr_stagger <= 0 && is_stunned == false) { data.isStun = true; stun(); } }
//Return true if spell crits target, else false. Multiplies power by 1.5 if a hit (round up) //Factors in target stunState if checkStun = true //ONLY CALL IN CAST (or after spell has been been properly modified with Modify()) protected virtual bool critCheck(CastData data, ICaster target, ICaster caster, out int newPower) { float accBonus = Mathf.Clamp(((caster.Stats.getModAcc(caster.BuffDebuff) - 1) * (1 - (target.Stats.getModEvade(target.BuffDebuff) * 0.01F))) * 0.2F, 0, 2) * 10; float chance = critPercentage + accBonus; if ((Random.Range(0.0F, 1F) * 100) <= chance) { data.isCrit = true; newPower = Mathf.CeilToInt(power * 1.5F); return(true); } data.isCrit = false; newPower = power; return(false); }
protected override bool buffCheck(CastData data, ICaster target, ICaster caster, int powerMod) { Elements.vsElement vs = target.Stats.getModVsElement(target.BuffDebuff, element); switch (vs) { case Elements.vsElement.REPEL: data.repel = true; inflictBuff(caster, target, powerMod); break; case Elements.vsElement.DRAIN: buff.makeBuff(); inflictBuff(target, caster, powerMod); break; case Elements.vsElement.RESIST: if ((Random.Range(0.0F, 1F) * 100) > 50) { data.isHit = false; return(false); } inflictBuff(target, caster, powerMod); break; case Elements.vsElement.BLOCK: data.isHit = false; return(false); case Elements.vsElement.NEUTRAL: inflictBuff(target, caster, powerMod); break; case Elements.vsElement.WEAK: inflictBuff(target, caster, powerMod * 1.5F); break; case Elements.vsElement.SUPERWEAK: inflictBuff(target, caster, powerMod * 2); break; case Elements.vsElement.INVALID: throw new System.NotImplementedException(); } data.isBuff = true; data.isHit = true; data.buffInflicted = buff; return(true); }
public override CastData cast(ICaster target, ICaster caster) { CastData data = new CastData(); data.element = element; if (hitCheck(data, target, caster, true)) { int powerMod; bool crit = critCheck(data, target, caster, out powerMod); target.damage(data, powerMod, element, caster, crit); if (buff != null) { buffCheck(data, target, caster, powerMod); } } return(data); }
//protected methods //Return true if spell hits target, else false (does not actually apply spell effect) //Factors in target stunState if checkStun = true //ONLY CALL IN CAST (or after spell has been been properly modified with Modify()) protected virtual bool hitCheck(CastData data, ICaster target, ICaster caster, bool checkStun = false) { if (checkStun && target.Is_stunned) { data.isHit = true; return(true); } int chance = Mathf.CeilToInt(hitPercentage * caster.Stats.getModAcc(caster.BuffDebuff)) - target.Stats.getModEvade(target.BuffDebuff); if ((Random.Range(0.0F, 1F) * 100) <= chance) { data.isHit = true; return(true); } data.isHit = false; return(false); }
private IEnumerator frenzyCast() { frenzyCastActive = true; float timeLeft = frenzyCastTime;//a float in case you want to use a bar while (timeLeft > 0) { debugFrenzyCastTime.text = "Time Left: " + Mathf.RoundToInt(timeLeft); yield return(new WaitForEndOfFrame()); timeLeft -= Time.deltaTime; } CastData d = new CastData(); d.isHit = true; d.setLocationData(field.enemy_arr[1], field.Player); d.vsElement = Elements.vsElement.NEUTRAL; setPause(true); BattleEffects.main.setDim(false); debugFrenzyCastTime.gameObject.SetActive(false); debugFrenzyCastInstructions.gameObject.SetActive(false); AudioPlayer.main.playSFX("sfx_speedup3"); foreach (SpellData s in frenzySpells) { yield return(StartCoroutine(castManager.playSpellEffects(s, d))); } AudioPlayer.main.stopMusic(); yield return(StartCoroutine(castManager.spellEffects.finishFrenzyCast(99999999, "anim_spell_slash_big", "sfx_slowmo", d))); AudioPlayer.main.playSFX("sfx_stagger"); AudioPlayer.main.playSFX("sfx_astral_hit"); AudioPlayer.main.playSFX("sfx_blight_hit"); field.enemy_arr[1].Curr_hp = 0; AnimationPlayer.main.playScreenEffect("mega_slash"); yield return(new WaitForSeconds(2f)); frenzyCastActive = false; //updateEnemies(); //setPause(false); BattleEffects.main.setDim(false); endBattle(); GameflowManager.main.next(); }
//ICaster interface overrides //Damage player public void damage(CastData data, int baseDmg, int element, ICaster caster, bool crit, bool reflect = false) { //Apply repel and return if applicable if (CasterOps.calcRepel(data, baseDmg, element, caster, this, crit, reflect)) { return; } bool damaged = CasterOps.calcDamage(data, baseDmg, element, caster, this, crit); if (damaged && element != Elements.@null) { status_manager.inflictCondition(this, element, 0, data.damageInflicted); } if (Curr_hp <= 0) { // check if killed Debug.Log("Player" + " has been slain!"); is_dead = true; } // return Is_dead; }
/// <summary> /// Casts 3 rays from this object to the specified point, and stores the results in list. /// </summary> /// <param name="point">The point to cast the ray to.</param> /// <param name="list">List of ray cast data, used to aggregate results</param> private void TriRayCast(Vector2 point, ref List <CastData> list) { Vector2 origin = new Vector2((int)transform.position.x, (int)transform.position.y); float angle = Mathf.Atan2(point.y - origin.y, point.x - origin.x); CastData[] cast_data = new CastData[3]; cast_data[0] = RayCast(origin, angle - SMALL_DELTA); cast_data[1] = RayCast(origin, angle); cast_data[2] = RayCast(origin, angle + SMALL_DELTA); for (int i = 0; i < 3; i++) { list.Add(cast_data[i]); } // Jittery, went with the less efficient approach for smoothness. // Optimization: collapse if distance is within 1 px //list.Add( cast_data[ 1 ] ); //if ( Mathf.Abs( cast_data[ 1 ].distance - cast_data[ 0 ].distance ) >= 1.0f ) { list.Add( cast_data[ 0 ] ); } //if ( Mathf.Abs( cast_data[ 1 ].distance - cast_data[ 2 ].distance ) >= 1.0f ) { list.Add( cast_data[ 2 ] ); } }
public Castering(CastData obj) { _obj = obj; }
public void PrepareCast(Vector3 lookPoint, GameObject source, Transform castPosition, LayerMask layer) { data = new CastData(lookPoint, source, castPosition, layer); }
//Applies damage formula base on base_power (spell strength) and stats of caster and target) //damages ref stats appropriately (will not go below zero) //Precondition: target.Stats.vsElement[element] != Elements.repel public static bool calcDamage(CastData data, int base_power, int element, ICaster caster, ICaster target, bool crit, bool is_stunned = false) { float dMod = base_power; int staggerDamage = 0; //Apply buff/debuffs here (NOT DONE) CasterStats casterMod = applyBuff(caster); CasterStats targetMod = applyBuff(target); //Apply attack bonus formula here dMod *= casterMod.attack; //Absorb damage if enemy absorbs this type if (targetMod.vsElement[element] == Elements.drain) { Debug.Log(target.Stats.name + " absorbs " + dMod + " " + Elements.toString(element) + " damage"); if (target.Curr_hp + Mathf.CeilToInt(dMod) > target.Stats.max_hp) { target.Curr_hp = target.Stats.max_hp; } else { target.Curr_hp += Mathf.CeilToInt(dMod); } data.damageInflicted = Mathf.CeilToInt(-1 * dMod); data.vsElement = Elements.vsElement.DRAIN; return(false); } //Subtract enemy defense penalty here dMod = dMod - (dMod * targetMod.defense); //Add random modifier here dMod *= Random.Range(0.9F, 1.1F); //Apply crit here if (crit) { staggerDamage++; } //Apply elemental weakness/resistances dMod *= targetMod.vsElement[element]; if (targetMod.vsElement[element] == 0.0F) { data.vsElement = Elements.vsElement.BLOCK; } else if (targetMod.vsElement[element] > 1)//If enemy is weak { if (targetMod.vsElement[element] > 2) { data.vsElement = Elements.vsElement.SUPERWEAK; } else { data.vsElement = Elements.vsElement.WEAK; } staggerDamage++; } else if (targetMod.vsElement[element] < 1) { data.vsElement = Elements.vsElement.RESIST; } else { data.vsElement = Elements.vsElement.NEUTRAL; } //Apply stun damage mod (if stunned) if (is_stunned) { dMod *= (1.25F + (0.25F * staggerDamage)); } //Apply shield if (target.Curr_shield > 0) { if (target.Curr_shield - dMod < 0)//Shield breaks { target.Curr_shield = 0; target.Curr_hp -= Mathf.CeilToInt(dMod - target.Curr_shield); if (staggerDamage >= 1 && is_stunned == false) { target.Curr_stagger--; } } else { target.Curr_shield -= Mathf.CeilToInt(dMod); } } else { target.Curr_hp -= Mathf.CeilToInt(dMod); //Stagger if enemy is actually damaged if (staggerDamage >= 1 && !is_stunned && dMod > 0) { target.Curr_stagger--; } } if (target.Curr_hp < 0) { target.Curr_hp = 0; } if (target.Curr_hp > target.Stats.max_hp) { target.Curr_hp = target.Stats.max_hp; } data.damageInflicted = Mathf.CeilToInt(dMod); return(dMod > 0); }
public IEnumerator finishFrenzyCast(int damage, string animationID, string sfxId, CastData d) { yield return(new WaitForSeconds(0.5f)); AnimationPlayer.main.playFlashEffect("flash"); yield return(new WaitForSeconds(1f)); AudioPlayer.main.setSFX(AudioPlayer.channel_spell_sfx, sfxId); AudioPlayer.main.playSFX(AudioPlayer.channel_spell_sfx); AnimationPlayer.main.playAnimation(animationID, d.Target.Transform.position, 3f); //if (d.Target.CasterType == ICasterType.PLAYER) // BattleEffects.main.screenShake(0.75f, 1f); BattleEffects.main.screenShake(0.75f, 1f); yield return(new WaitForSeconds(0.75F)); d.damageInflicted = damage; spawnDamagePopup(d, 2); yield return(new WaitForSeconds(1F)); }
const float shakeIntensityMod = 0.1f; //The amount to scale each shake by (per keyword) public IEnumerator playEffects(CastData d, SpellData s, float delay = 0) { yield return(new WaitForSeconds(delay)); //caster_cutin_animator.Play ("anim_wave_banner_image"); if (d.isHit == false)//Spell misses { Debug.Log(d.Caster.Stats.name + " missed " + d.Target.Stats.name + "!"); //Process miss graphics popp.spawnSprite("popup_miss", POP_TIMER, d.Target.Transform.position + UNDER_OFFSET); AudioPlayer.main.playSFX("sfx_spell_miss"); BattleEffects.main.spriteShift(d.Target.Transform, 0.3f, 0.1f); // sprite moves to the right as a dodge yield break; } //Process repel if (d.repel) { spawnElementPopup(d.element, Elements.vsElement.REPEL, d.Caster.Transform); AnimationPlayer.main.playAnimation("anim_element_reflect", d.Caster.Transform.position, 2f); yield return(new WaitForSeconds(0.333F)); } float shakeIntensity = 0; //Process hit graphics (if not a repelled attack) for (int i = 0; i < d.animData.Length; ++i) { if (d.animData[i] != null) { AudioPlayer.main.setSFX(AudioPlayer.channel_spell_sfx, d.sfxData[i]); AudioPlayer.main.playSFX(AudioPlayer.channel_spell_sfx); //AnimationPlayer.main.playAnimation(d.animData[i], d.Target.Transform.position, 1); AnimationPlayer.main.playAnimation(d.animData[i], d.Target.Transform.position, 2f); if (d.Target.CasterType == ICasterType.PLAYER) { BattleEffects.main.screenShake(0.15f + shakeIntensity / 8, 0.05f + shakeIntensity); } shakeIntensity += shakeIntensityMod; if (d.repel) { popp.spawnText(s.getWord(i).ToUpper() + "!", POP_TIMER - 1, d.Caster.Transform.position, Color.black, new Color(1, 111f / 255f, 1)); } else { popp.spawnText(s.getWord(i).ToUpper() + "!", POP_TIMER - 1, d.Caster.Transform.position, new Color(1, 111f / 255f, 1), Color.white); } yield return(new WaitForSeconds(0.333F)); } } if (d.isCrit && d.vsElement != Elements.vsElement.BLOCK) //Spell is crit { Debug.Log(d.Caster.Stats.name + " scores a critical with " + s.ToString() + " on " + d.Target.Stats.name); if (d.Target.CasterType == ICasterType.ENEMY) { AudioPlayer.main.playSFX("sfx_enemy_weakcrit_dmg"); if (!d.isStun && !d.Target.Is_stunned) { popp.spawnText("<size=48>-1<size=24>SHIELD</size></size>", POP_TIMER, d.Target.Transform.position + UNDER_OFFSET_2, Color.cyan, Color.white); } if (d.isStun) { popp.spawnText("BREAK!", POP_TIMER, d.Target.Transform.position + UNDER_OFFSET_2, Color.cyan, Color.white); } //if (d.Target.Is_stunned) popp.spawnText ("BONUS DMG!", POP_TIMER, d.Target.Transform.position + UNDER_OFFSET_2, Color.red, Color.white); } else if (d.Target.CasterType == ICasterType.PLAYER || d.Target.CasterType == ICasterType.NPC_ALLY) { AudioPlayer.main.playSFX("sfx_party_weakcrit_dmg"); } } else if ((d.vsElement == Elements.vsElement.WEAK || d.vsElement == Elements.vsElement.SUPERWEAK) && d.damageInflicted > 0) { if (d.Target.CasterType == ICasterType.ENEMY) { AudioPlayer.main.playSFX("sfx_enemy_weakcrit_dmg"); if (!d.isStun && !d.Target.Is_stunned) { popp.spawnText("<size=48>-1<size=24>SHIELD</size></size>", POP_TIMER, d.Target.Transform.position + UNDER_OFFSET_2, Color.cyan, Color.white); } if (d.isStun) { popp.spawnText("BREAK!", POP_TIMER, d.Target.Transform.position + UNDER_OFFSET_2, Color.cyan, Color.white); } } else if (d.Target.CasterType == ICasterType.PLAYER || d.Target.CasterType == ICasterType.NPC_ALLY) { AudioPlayer.main.playSFX("sfx_party_weakcrit_dmg"); } } if (d.isStun) { //Process stun graphics Debug.Log(d.Caster.Stats.name + " stuns " + d.Target.Stats.name); AudioPlayer.main.playSFX("sfx_stagger"); } Debug.Log(d.Target.Stats.name + " was hit for " + d.damageInflicted + " " + Elements.toString(d.element) + " damage: " + d.vsElement); //Process elemental wk/resist/drain/repel graphics if (!((d.vsElement == Elements.vsElement.WEAK || d.vsElement == Elements.vsElement.SUPERWEAK) && d.damageInflicted <= 0)) { spawnElementPopup(d.element, d.vsElement, d.Target.Transform); } //Play block/reflect/drain animations if necessary if (d.vsElement == Elements.vsElement.BLOCK) { AnimationPlayer.main.playAnimation("anim_element_block", d.Target.Transform.position, 2f); yield return(new WaitForSeconds(0.333F)); } else if (d.vsElement == Elements.vsElement.DRAIN) { AnimationPlayer.main.playAnimation("anim_element_drain", d.Target.Transform.position, 2f); yield return(new WaitForSeconds(0.333F)); } //Spawn damage number and some other gubs spawnDamagePopup(d, shakeIntensity); }
//Spawns damage popup with lots of complicated stuff (clean up) private void spawnDamagePopup(CastData d, float shakeIntensity) { //Process damage graphics if (d.damageInflicted > 0) { BattleEffects.main.spriteShake(d.Target.Transform, 0.3f, 0.1f); AudioPlayer.main.playSFX("sfx_spell_hit"); Color dmgNumColor = Color.white; Color dmgNumColorTop = new Color(255f / 255f, 100f / 255f, 220f / 255f); Color dmgNumColorBottom = Color.white; if (d.Target.CasterType == ICasterType.PLAYER) { if (d.repel) { dmgNumColor = new Color(255, 0, 255);//new Color(220, 86, 249); } BattleEffects.main.screenShake(0.15f + shakeIntensity / 2, shakeIntensity + 0.3f); spawnDamageOverlay(d.element); } else if (d.Target.CasterType == ICasterType.ENEMY) { // Gradually lower enemy HP gauge displays BattleManagerS.main.uiManager.setEnabledGauges(true); StartCoroutine(enemy_hp_bars.gradualUpdateDamage(d.Target.Position, d.damageInflicted)); if (d.isStun) { Enemy enemyObj = (Enemy)d.Target; ParticleSystem.EmitParams emitOverride = new ParticleSystem.EmitParams(); emitOverride.startLifetime = 10f; enemyObj.enemy_particle_sys.Emit(emitOverride, 10); } if (!d.isStun && d.Target.Is_stunned) { popp.spawnText("<size=24>DAMAGE BONUS!</size>", POP_TIMER, d.Target.Transform.position + UNDER_OFFSET_2, Color.red, Color.white); } } // Set damage text size based on amount of damage ratios string sizeTagOpen = "<size="; string sizeTagClose = "</size>"; int sizeValueMin = 36; int sizeValueMax = 72; int sizeValueDiff = sizeValueMax - sizeValueMin; float sizeRatio = (float)d.damageInflicted / (float)d.Target.Stats.max_hp; Debug.Log("damage ratio to max hp: " + sizeRatio); int sizeValueCurr = sizeValueMin + Mathf.RoundToInt(((float)sizeValueDiff) * sizeRatio); string damageText = sizeTagOpen + sizeValueCurr + ">" + d.damageInflicted.ToString() + sizeTagClose; popp.spawnText("-" + damageText + "<size=24>HP</size>", POP_TIMER, d.Target.Transform.position + DMGNUM_OFFSET, dmgNumColorBottom, dmgNumColorTop); if (sizeRatio > 0.5) { AudioPlayer.main.playSFX("sfx_fire_hit"); } if ((d.Target.Curr_hp <= 0) && (d.damageInflicted > (d.Target.Stats.max_hp))) { Vector3 ko_offset = new Vector3(0.5f, -0.5f, 0); popp.spawnText("<size=28>OVERKILL!</size>", POP_TIMER, d.Target.Transform.position + DMGNUM_OFFSET + ko_offset, dmgNumColorTop, dmgNumColorBottom); } else if (d.Target.Curr_hp <= 0) { Vector3 ko_offset = new Vector3(0.5f, -0.5f, 0); popp.spawnText("<size=28>K.O.</size>", POP_TIMER, d.Target.Transform.position + DMGNUM_OFFSET + ko_offset, dmgNumColorTop, dmgNumColorBottom); } else if (d.isCrit && d.vsElement != Elements.vsElement.BLOCK) { Vector3 ko_offset = new Vector3(0.5f, -0.5f, 0); popp.spawnText("<size=28>CRITICAL!</size>", POP_TIMER, d.Target.Transform.position + DMGNUM_OFFSET + ko_offset, Color.yellow, Color.white); } } else if (d.damageInflicted < 0) { string heal = "+" + (-1 * (d.damageInflicted)).ToString() + "<size=32>HP</size>"; AudioPlayer.main.playSFX("sfx_heal"); popp.spawnText(heal, POP_TIMER, d.Target.Transform.position + DMGNUM_OFFSET, new Color(27f / 255f, 195f / 255f, 43f / 255f)); if (d.Target.CasterType == ICasterType.PLAYER) { spawnDamageOverlay(-1); } } else { if (d.vsElement == Elements.vsElement.BLOCK) { popp.spawnText("NULL", POP_TIMER, d.Target.Transform.position + DMGNUM_OFFSET, Color.gray); } else { popp.spawnText(d.damageInflicted.ToString(), POP_TIMER, d.Target.Transform.position + DMGNUM_OFFSET); } } }