// Attacks the unit public virtual void ai_attackUnit(Unit unit, BattleMap map, AttackInfo info, bool isUncontrollable) { map.attackSearch(unit.mapPos[0], unit.mapPos[1], info.range[0], info.range[1]); System.Threading.Thread.Sleep(1000); map.gstate.attackDecisionGui.open(ref info); System.Threading.Thread.Sleep(2500); game.gui.close("attack_decision"); map.gstate.stage= 0; map.makeUnitAttack(map.getFullUnitID(unit.mapPos), map.getUnitX(info.defenderID), map.getUnitY(info.defenderID), ref info); }
// Takes the given amount of damage public virtual int takeDamage(ref AttackInfo info, ref Unit instigator, ref BattleMap map) { // Variables int oldHealth= health; int amount= info.damage; if((float)(Start.rng.NextDouble())<= info.accuracy) { amount= instigator.onDealtDamage(health, amount, this, ref map); if((float)(Start.rng.NextDouble())<= info.criticalChance) { // Animate Critical Console.WriteLine("Critical Hit!"); info.criticalHit= true; amount= instigator.onCriticalHit(health, amount, this, ref map); amount= onHitByCritical(health, amount, this, ref map); } else { // Animate regular } amount= onTakeDamage(oldHealth, health, amount, ref instigator, ref map); health-= amount; } else { Console.WriteLine("Missed!"); // Animate Miss info.missed= true; onDodgedAttack(amount, ref instigator, ref map); instigator.onMissedAttack(amount, this, ref map); } if(health== 0) map.removeUnit(map.getFullUnitID(mapPos)); return health; }
// Shows the player if he/she should attack public override AttackInfo showAttackDecision(string skillID, Unit unit, ref Unit defender, ref BattleMap map) { if(skillID== "basic_attack") { // Variables AttackInfo infoba= AttackInfo.createBasicAttack(map.getFullUnitID(unit.mapPos), map.getFullUnitID(defender.mapPos), ref map); infoba.projAttackerStats[1]= 0; return infoba; } // Variables AttackInfo info= AttackInfo.create(skillID, map.getFullUnitID(unit.mapPos), map.getFullUnitID(defender.mapPos), ref map); float tsDmg= ((hasPassive("tiger_stance") && ((float)(unit.mana)/(float)(unit.originalMana))> 0.5f) ? 0.2f : 0f); if(!hasPassive("lion_stance") || Start.rng.Next(0, 20)>= 3) info.projAttackerStats[1]= 0; if(hasPassive("cobra_stance")) info.criticalChance= Math.Max(info.criticalChance+0.15f, 1f); switch(skillID) { case "precise_strike": if(isSkillHoned) { unit.attack= (int)(1.25f*unit.attack); info.criticalChance= Math.Max(1.15f*info.criticalChance, 1f); isSkillHoned= false; } if(((float)(unit.mana)/(float)(unit.originalMana))> 0.5f) { info.damage= info.calculateDamage(1.15f+tsDmg, 0f, 1f, 1f, ref map); info.projDefenderStats[0]-= info.damage; info.accuracy= 1f; } else info.damage= info.calculateDamage(0.95f, 0f, 1f, 1f, ref map); break; case "sun\'s_might": if(isSkillHoned) { unit.attack= (int)(1.25f*unit.attack); info.criticalChance= Math.Max(1.15f*info.criticalChance, 1f); isSkillHoned= false; } info.damage= info.calculateDamage(1f+tsDmg, 0f, 1f, 1f, ref map); info.projAttackerStats[0]= Math.Max(info.projAttackerStats[0]+(int)(0.15f*info.damage), unit.originalHealth); info.projAttackerStats[1]= Math.Max(info.projAttackerStats[1]+(int)(0.15f*info.damage), unit.originalMana); info.projDefenderStats[0]-= info.damage; break; case "meditation": info.projAttackerStats[0]= Math.Max(info.projAttackerStats[0]+(int)(0.1f*unit.originalHealth), unit.originalHealth); info.projAttackerStats[1]= Math.Max(info.projAttackerStats[1]+(int)(0.1f*unit.originalMana), unit.originalMana); info.projAttackerStats[2]= (int)(1.05f*info.projAttackerStats[2]); info.projAttackerStats[1]= info.attackerStats[1]; break; case "serpent\'s_sting": if(isSkillHoned) { unit.attack= (int)(1.25f*unit.attack); info.criticalChance= Math.Max(1.15f*info.criticalChance, 1f); isSkillHoned= false; } info.damage= info.calculateDamage(1f+tsDmg, 0f, 0.8f, 1f, ref map); info.projDefenderStats[0]-= info.damage; if(((float)(unit.mana)/(float)(unit.originalMana))< 0.5f) info.accuracy= Math.Max(info.accuracy-0.2f, 0f); break; case "hone_skill": info.projAttackerStats[1]= info.attackerStats[1]; break; case "vigilant_strike": if(isSkillHoned) { unit.attack= (int)(1.25f*unit.attack); info.criticalChance= Math.Max(1.15f*info.criticalChance, 1f); isSkillHoned= false; } info.damage= info.calculateDamage(1.5f+tsDmg, 0f, 1f, 1f, ref map); info.projDefenderStats[0]-= info.damage; break; case "lethal_strike": if(isSkillHoned) { unit.attack= (int)(1.25f*unit.attack); info.criticalChance= Math.Max(1.15f*info.criticalChance, 1f); isSkillHoned= false; } info.damage= info.defenderStats[0]; info.projDefenderStats[0]= 0; info.accuracy= 0.22f; break; } return info; }
// Moves the unit public virtual void ai_moveUnit(Unit unit, BattleMap map, int[] spotToMoveTo, bool isUncontrollable) { map.walkSearch(unit.mapPos[0], unit.mapPos[1], unit.move, ((isUncontrollable) ? -1 :map.getTeamID(unit.mapPos))); System.Threading.Thread.Sleep(1000); map.moveUnit(map.getFullUnitID(unit.mapPos), spotToMoveTo[0], spotToMoveTo[1]); }
// Gets the target public virtual void ai_getTarget(Unit unit, BattleMap map, bool isUncontrollable, out int[] target, out int[] spotToMoveTo, out AttackInfo info) { info= new AttackInfo(); info.range= new int[] {1, 1}; map.aiSearch(unit.mapPos[0], unit.mapPos[1], unit.move, info.range[1], isUncontrollable, map.getTeamID(unit.mapPos), info); spotToMoveTo= map.findAISpot(unit.mapPos[0], unit.mapPos[1], info.range, map.aggressiveAI); target= map.tiles.items[spotToMoveTo[0], spotToMoveTo[1]].t; info= AttackInfo.createBasicAttack(map.getFullUnitID(unit.mapPos), target, ref map); }
// Updates the ai normally public virtual void updateAINormal(Unit unit, BattleMap map) { // Variables int[] spot; int[] target= map.getClosestEnemy(unit.mapPos[0], unit.mapPos[1], map.getTeamID(unit.mapPos)); AttackInfo info= AttackInfo.createBasicAttack(map.getFullUnitID(unit.mapPos), target, ref map); int heuristic; // Get Target info.range= new int[] {1, 1}; map.aiSearch(unit.mapPos[0], unit.mapPos[1], unit.move, info.range[1], false, map.getTeamID(unit.mapPos), info, target); spot= map.findAISpot(unit.mapPos[0], unit.mapPos[1], info.range, map.aggressiveAI); if(!unit.isWalkingDone) { ai_moveUnit(unit, map, spot, false); map.destroyPaths(); map.endUnitWalking(map.getFullUnitID(unit.mapPos)); if(unit.isTurnEnded) return; } heuristic= map.getHeuristic(unit.mapPos, map.getUnitXY(target)); if(!unit.isAttackingDone && heuristic>= info.range[0] && heuristic<= info.range[1]) { ai_attackUnit(unit, map, info, false); map.destroyPaths(); map.endUnitAttacking(map.getFullUnitID(unit.mapPos)); if(unit.isTurnEnded) return; } }
// Shows the player if he/she should attack public virtual AttackInfo showAttackDecision(string skillID, Unit unit, ref Unit defender, ref BattleMap map) { return AttackInfo.createBasicAttack(map.getFullUnitID(unit.mapPos), map.getFullUnitID(defender.mapPos), ref map); }
// Shows the player if he/she should attack public override AttackInfo showAttackDecision(string skillID, Unit unit, ref Unit defender, ref BattleMap map) { if(skillID== "basic_attack") return base.showAttackDecision(skillID, unit, ref defender, ref map); // Variables AttackInfo info= AttackInfo.create(skillID, map.getFullUnitID(unit.mapPos), map.getFullUnitID(defender.mapPos), ref map); if(hasPassive("critical_rage")) info.criticalChance= Math.Max(info.criticalChance+0.05f, 1f); switch(skillID) { case "enrage": info.accuracy= 1f; info.criticalChance= 0f; info.projAttackerStats[2]= (int)(info.projAttackerStats[2]*1.25f+4f); info.projAttackerStats[2]= (int)(info.projAttackerStats[2]*(1.25f+stockpiled+((hasPassive("adrenaline_rush")) ? 0.1f : 0f))); info.projAttackerStats[3]= (int)(info.projAttackerStats[3]*0.80f); info.projDefenderStats[2]= (int)(info.projDefenderStats[2]*1.25f+4f); info.projDefenderStats[2]= (int)(info.projDefenderStats[2]*(1.25f+stockpiled+((hasPassive("adrenaline_rush")) ? 0.1f : 0f))); info.projDefenderStats[3]= (int)(info.projDefenderStats[3]*0.80f); break; case "furious_slash": info.damage= info.calculateDamage(1.1f, 0f, 1f, 1f, ref map); info.projAttackerStats[2]= (int)(info.projAttackerStats[2]*(1.25f+stockpiled+((hasPassive("adrenaline_rush")) ? 0.1f : 0f))); info.projAttackerStats[3]= (int)(info.projAttackerStats[3]*0.80f); info.projDefenderStats[0]-= info.damage; break; case "let_loose": info.damage= info.calculateDamage(ref map); if(defender.getDefensePerc()== 0f) info.damage+= (int)(unit.defense*0.5f); else info.damage+= Math.Max((int)(unit.defense*0.5f-defender.defense*defender.getDefensePerc()*0.5f), 4); info.projDefenderStats[0]-= info.damage; info.projAttackerStats[2]= (int)(info.projAttackerStats[2]*(1.25f+stockpiled+((hasPassive("adrenaline_rush")) ? 0.1f : 0f))); info.projAttackerStats[3]= (int)(info.projAttackerStats[3]*0.80f); info.projAttackerStats[3]= (int)(info.projAttackerStats[3]*0.75f); info.criticalChance= 0f; break; case "intimidate": info.projDefenderStats[2]= (int)(info.projDefenderStats[2]*0.88f); info.projDefenderStats[3]= (int)(info.projDefenderStats[3]*0.88f); info.projDefenderStats[5]= (int)(info.projDefenderStats[5]*0.88f); info.criticalChance= 0f; break; case "stockpile_rage": info.accuracy= 1f; info.criticalChance= 0f; break; case "suicidal_slash": info.damage= info.calculateDamage(1.2f, 0f, 1f, 1f, ref map); info.projAttackerStats[3]= (int)(info.projAttackerStats[3]*0.96f); info.projDefenderStats[0]-= info.damage; break; case "piercing_jab": info.damage= info.calculateDamage(1f, 0f, 0.5f, 1f, ref map); info.projDefenderStats[0]-= info.damage; info.accuracy= Math.Max(info.accuracy-0.2f, 0f); break; case "counter_swipe": info.damage= info.calculateDamage(0.75f, 0f, 1f, 1f, ref map); if(defender.getDefensePerc()== 0f) info.damage+= (int)(defender.attack*0.25f); else info.damage+= Math.Max((int)(defender.attack*0.25f-defender.defense*defender.getDefensePerc()), 4); info.projDefenderStats[0]-= info.damage; break; case "fury_swipes": info.damage= info.calculateDamage(0.5f, 0f, 1f, 1f, ref map); info.damage*= 3; info.projDefenderStats[0]-= info.damage; break; case "raging_battlecry": info.projAttackerStats[2]= (int)(info.projAttackerStats[2]*(1.25f+stockpiled+((hasPassive("adrenaline_rush")) ? 0.1f : 0f))); info.projAttackerStats[3]= (int)(info.projAttackerStats[3]*0.80f); if(info.attackerID== info.defenderID) info.projDefenderStats[2]= (int)(info.projDefenderStats[2]*(1.25f+stockpiled+((hasPassive("adrenaline_rush")) ? 0.1f : 0f))); else info.projDefenderStats[2]= (int)(info.projDefenderStats[2]*1.25f); info.projDefenderStats[3]= (int)(info.projDefenderStats[3]*0.80f); break; } return info; }
// Makes the unit attack the given unit, given that unit's coords on the map, the name of the attack, and a reference to the map public override bool attackUnit(Unit unit, bool initiatedAttack, ref Unit victim, int x, int y, ref AttackInfo info, ref BattleMap map) { switch(info.skillID) { case "smite": case "basic_attack": { if(victim== null) return false; victim.takeDamage(ref info, ref unit, ref map); if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };break; case "multicure": { // Variables List<int[]> allies= map.findAllies(unit.mapPos[0], unit.mapPos[1], 1, 2, map.getTeamID(unit.mapPos)); for(int i= 0; i< allies.size; i++) map.teams.items[allies.items[i][0]].units.items[allies.items[i][1]].heal(-1*info.damage, ref unit, ref map); if(unit.isAlive && !unit.isAI) unit.gainExp(64*allies.size, ref map); };break; case "armor_of_god": { if(victim== null) return false; unit.addStatEffect( new StatEffect( EffectType.Buff, "Armor of God", "+35 Def and Res", armorOfGodSE, 2 ), ref map ); if(unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };break; case "rally_spirit": { // Variables List<int[]> allies= map.findAllies(unit.mapPos[0], unit.mapPos[1], 0, 2, map.getTeamID(unit.mapPos)); for(int i= 0; i< allies.size; i++) { map.teams.items[allies.items[i][0]].units.items[allies.items[i][1]].addStatEffect( new StatEffect( EffectType.Buff, "Rally Spirit", "+10% to all stats", rallySpiritSE, 3 ), ref map ); } if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(32*allies.size, ref map); };break; case "rejuvinate": { if(victim== null) return false; if(victim.getStatusEffect()== null) victim.clearDebuffs(); else { if(!victim.clearStatusEffect()) info.missed= false; } if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };break; case "healing_prayer": { // Variables List<int[]> allies= map.findAllAllies(map.getTeamID(unit.mapPos)); for(int i= 0; i< allies.size; i++) { map.teams.items[allies.items[i][0]].units.items[allies.items[i][1]].heal( map.teams.items[allies.items[i][0]].units.items[allies.items[i][1]].originalHealth, ref unit, ref map ); } unit.addStatEffect( new StatEffect( EffectType.Debuff, "Humility", "-75% to all stats", healingPrayerSE, 2 ), ref map ); if(unit.isAlive && !unit.isAI) unit.gainExp(256*allies.size, ref map); };break; case "mend": { if(victim== null) return false; victim.heal(-1*info.damage, ref unit, ref map); if(unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };break; case "prophetic_reap": { if(activatedPropheticReap) return false; activatedPropheticReap= true; unit.addStatEffect( new StatEffect( EffectType.Buff, "Prophetic Prayer", "Deal "+((float)(unit.magic)/7f)+" damage to all enemies once dissipated", propheticReapSE, 3 ), ref map ); };break; case "banish_spirits": { if(victim== null) return false; victim.addStatEffect( new StatEffect( EffectType.Buff, "Banish Spirits", "+10% Atk", positiveBanishSpiritsSE, 3 ), ref map ); victim.addStatEffect( new StatEffect( EffectType.Debuff, "Banish Spirits", "-15% Def and Res", negativeBanishSpiritsSE, 3 ), ref map ); victim.addStatEffect( StatEffect.create(StatusEffect.Enraged, 3), ref map ); };break; case "rest_in_god": { if(victim== null) return false; victim.addStatEffect( new StatEffect( EffectType.Buff, "God\'s Blessing", "+20 to all stats", restInGodSE, 1 ), ref map ); map.endUnitWalking(map.getFullUnitID(unit.mapPos)); };break; } return true; }
// Shows the player if he/she should attack public override AttackInfo showAttackDecision(string skillID, Unit unit, ref Unit defender, ref BattleMap map) { if(skillID== "basic_attack") return AttackInfo.createBasicAttack(map.getFullUnitID(unit.mapPos), map.getFullUnitID(defender.mapPos), ref map); // Variables AttackInfo info= AttackInfo.create(skillID, map.getFullUnitID(unit.mapPos), map.getFullUnitID(defender.mapPos), ref map); switch(skillID) { case "multicure": info.damage= -1*getLargest(roundUp((float)(unit.level)/2f), roundUp((float)(unit.magic)/3f), 10); info.projDefenderStats[0]-= info.damage; if(hasPassive("mana_restoration")) info.projDefenderStats[1]+= (info.damage/2); break; case "armor_of_god": info.projDefenderStats[3]+= 35; info.projDefenderStats[5]+= 35; break; case "smite": info.damage= info.calculateDamage(ref map); info.damage+= (int)(Math.Max(0.25f*unit.resistance-0.25f*defender.resistance, 0f)); info.projDefenderStats[0]-= info.damage; break; case "rally_spirit": case "rejuvinate": case "prophetic_reap": info.accuracy= 1f; info.criticalChance= 0f; break; case "healing_prayer": if(hasPassive("mana_restoration")) info.projDefenderStats[1]+= (info.damage/2); info.accuracy= 1f; info.criticalChance= 0f; break; case "mend": info.damage= ((hasPassive("evil\'s_bane") && map.getTeamID(unit.mapPos)!= map.getTeamID(defender.mapPos)) ? 1 : -1)*getLargest(2*unit.level, roundUp((float)(unit.magic)/2f), 15); info.damage+= (4*(map.findAllies(unit.mapPos[0], unit.mapPos[1], 0, 2, map.getTeamID(unit.mapPos))).size); info.projDefenderStats[0]-= info.damage; if(hasPassive("mana_restoration")) info.projDefenderStats[1]+= (info.damage/2); info.criticalChance= 0f; break; case "banish_spirits": info.projDefenderStats[2]= (int)(info.projDefenderStats[2]*1.1f); info.projDefenderStats[3]= (int)(info.projDefenderStats[3]*0.85f); info.projDefenderStats[5]= (int)(info.projDefenderStats[5]*0.85f); break; case "rest_in_god": info.projDefenderStats[2]+= 20; info.projDefenderStats[3]+= 20; info.projDefenderStats[4]+= 20; info.projDefenderStats[5]+= 20; info.projDefenderStats[6]+= 20; break; } return info; }
// Called when the unit has just finished with a stat effect public override void onDoneWithStatEffect(Unit unit, ref StatEffect statEffect, ref BattleMap map) { if(statEffect.name== "Prophetic Prayer") { // Variables List<int[]> enemies= map.findAllEnemies(map.getTeamID(unit.mapPos)); AttackInfo info; int[] unitID= map.getFullUnitID(unit.mapPos); for(int i= 0; i< enemies.size; i++) { info= AttackInfo.create("prophetic_reap", unitID, enemies.items[i], ref map); info.damage= (int)((float)(unit.magic)/7f); info.accuracy= 1f; info.criticalChance= 0f; map.teams.items[enemies.items[i][0]].units.items[enemies.items[i][1]].takeDamage(ref info, ref unit, ref map); } activatedPropheticReap= false; } base.onDoneWithStatEffect(unit, ref statEffect, ref map); }