// 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); }
// 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); }
// 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 "basic_attack": case "precise_strike": case "serpent\'s_sting": case "vigilant_strike": case "lethal_strike": { if(victim== null) break; victim.takeDamage(ref info, ref unit, ref map); unit.mana= info.projAttackerStats[1]; if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };return true; case "meditation": { unit.health= info.projAttackerStats[0]; unit.mana= info.projAttackerStats[1]; unit.attack= info.projAttackerStats[2]; unit.originalAttack= info.projAttackerStats[2]; };return true; case "hone_skill": { isSkillHoned= true; };return true; case "sun\'s_might": { if(victim== null) break; victim.takeDamage(ref info, ref unit, ref map); unit.health= Math.Max((int)(unit.health+(0.15f*info.damage)), unit.originalHealth); unit.mana= Math.Max((int)(info.projAttackerStats[1]+(0.15f*info.damage)), unit.originalMana); if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };return true; } return false; }
public virtual bool makeUnitAttack(int[] unitID, int targetx, int targety, AttackInfo info) { return makeUnitAttack(unitID[0], unitID[1], targetx, targety, ref info); }
// Makes the unit attack public virtual bool makeUnitAttack(int teamID, int unitID, int targetx, int targety, ref AttackInfo info) { if(!tiles.items[targetx, targety].item.hasUnit) { // Variables Unit nounit= null; return teams.items[teamID].units.items[unitID].attackUnit( true, ref nounit, targetx, targety, ref info, this ); } return teams.items[teamID].units.items[unitID].attackUnit( true, ref teams.items[tiles.items[targetx, targety].item.unitID[0]].units.items[tiles.items[targetx, targety].item.unitID[1]], targetx, targety, ref info, this ); }
public void aiSearch(int x, int y, int radius, int range, bool isUncontrollable, int teamID, AttackInfo info) { aiSearch(x, y, radius, range, isUncontrollable, teamID, info, new int[] { -1, -1 }); }
// Does a dijkstra type search for ai public void aiSearch(int x, int y, int radius, int range, bool isUncontrollable, int teamID, AttackInfo info, int[] target) { p_aiSearch(x, y, 0, ref x, ref y, ref radius, ref range, ref isUncontrollable, ref teamID, ref info, ref target); }
// Does a dijkstra type search for ai private void p_aiSearch(int x, int y, int radius, ref int originalX, ref int originalY, ref int maxRadius, ref int range, ref bool isUncontrollable, ref int teamID, ref AttackInfo info, ref int[] target) { if(ai_canStopSearch(ref x, ref y, ref radius, ref maxRadius, ref range, ref teamID)) return; if(radius<= maxRadius) { tiles.items[x, y].path= radius; if(isUncontrollable) { tiles.items[x, y].t= ((target[0]== -1) ? getClosestEnemy(x, y, -1) : target); tiles.items[x, y].d= -1; tiles.items[x, y].w= -1; tiles.items[x, y].e= getNearbyEnemies(x, y, -1).size; tiles.items[x, y].a= 0; tiles.items[x, y].r= getEnemiesWithinRange(x, y, info.range[0], info.range[1], -1).size; tiles.items[x, y].s= 0; } else { tiles.items[x, y].t= ((target[0]== -1) ? getClosestEnemy(x, y, teamID) : target); tiles.items[x, y].d= getHeuristic(originalX, originalY, getUnitXY(getClosestAlly(x, y, teamID))); tiles.items[x, y].w= getHeuristic(x, y, getUnitXY(getClosestAlly(x, y, teamID))); tiles.items[x, y].e= getNearbyEnemies(x, y, teamID).size; tiles.items[x, y].a= getNearbyAllies(x, y, teamID).size; tiles.items[x, y].r= getEnemiesWithinRange(x, y, info.range[0], info.range[1], teamID).size; tiles.items[x, y].s= getAlliesWithinRange(x, y, info.range[0], info.range[1], teamID).size; } tiles.items[x, y].p= getHeuristic(originalX, originalY, getUnitXY(tiles.items[x, y].t)); tiles.items[x, y].q= getHeuristic(x, y, getUnitXY(tiles.items[x, y].t)); tiles.items[x, y].i= teamID; } else { tiles.items[x, y].f= radius; } p_aiSearch(x, y+1, radius+1, ref originalX, ref originalY, ref maxRadius, ref range, ref isUncontrollable, ref teamID, ref info, ref target); p_aiSearch(x+1, y, radius+1, ref originalX, ref originalY, ref maxRadius, ref range, ref isUncontrollable, ref teamID, ref info, ref target); p_aiSearch(x, y-1, radius+1, ref originalX, ref originalY, ref maxRadius, ref range, ref isUncontrollable, ref teamID, ref info, ref target); p_aiSearch(x-1, y, radius+1, ref originalX, ref originalY, ref maxRadius, ref range, ref isUncontrollable, ref teamID, ref info, ref target); }
// 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; }
// Creates a basic attack info public static AttackInfo create(string skillID, int[] attackerID, int[] defenderID, ref BattleMap map) { // Variables AttackInfo info= new AttackInfo(); info.skillID= skillID; info.missed= false; info.criticalHit= false; info.range= new int[]{1, 1}; info.attackerID= attackerID; if(info.hasAttacker()) { info.attackerName= map.teams.items[attackerID[0]].units.items[attackerID[1]].name; info.attackerStats= getStats(ref map.teams.items[attackerID[0]].units.items[attackerID[1]]); info.projAttackerStats= getStats(ref map.teams.items[attackerID[0]].units.items[attackerID[1]]); } info.defenderID= defenderID; if(info.hasDefender()) { info.defenderName= map.teams.items[defenderID[0]].units.items[defenderID[1]].name; info.defenderStats= getStats(ref map.teams.items[defenderID[0]].units.items[defenderID[1]]); info.projDefenderStats= getStats(ref map.teams.items[defenderID[0]].units.items[defenderID[1]]); } if(info.hasAttacker() && info.hasDefender()) { info.accuracy= calculateAccuracy( ref map.teams.items[attackerID[0]].units.items[attackerID[1]], ref map.teams.items[defenderID[0]].units.items[defenderID[1]], ref map ); } else info.accuracy= 1f; if(info.hasAttacker() && info.hasDefender()) { info.criticalChance= calculateCriticalChance( ref map.teams.items[attackerID[0]].units.items[attackerID[1]], ref map.teams.items[defenderID[0]].units.items[defenderID[1]] ); } else info.criticalChance= 0.2f; info.isTrap= false; info.trap= null; info.trapRadius= -1; 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 virtual bool attackUnit(bool initiatedAttack, ref Unit victim, int x, int y, ref AttackInfo info, ref BattleMap map) { return prof.attackUnit(this, initiatedAttack, ref victim, x, y, ref info, ref map); }
// Opens up the gui public void open(ref AttackInfo pmInfo) { // Variables int charHeight= (int)(lpName.font.MeasureString("x").Y); info= pmInfo; // Left Panel's Name lpName.bounds= new Rectangle(leftPanel.bounds.Width/2-(int)(lpName.font.MeasureString(info.attackerName).X/2f), 8, 0, 0); lpName.text= info.attackerName; for(int i= 0; i< lpStats.Length; i++) { lpStats[i].canHover= false; rpStats[i].canHover= false; lpStats[i].font= game.fonts.get("default_font"); rpStats[i].font= game.fonts.get("default_font"); lpStats[i].textAlignment= TextAlignment.LeftVerticalAlign; rpStats[i].textAlignment= TextAlignment.LeftVerticalAlign; switch(i) { case 0: // HP lpStats[i].text= "HP: "; rpStats[i].text= "HP: "; break; case 1: // Mana lpStats[i].text= "Mana: "; rpStats[i].text= "Mana: "; break; case 2: // Attack lpStats[i].text= "Atk: "; rpStats[i].text= "Atk: "; break; case 3: // Defense lpStats[i].text= "Def: "; rpStats[i].text= "Def: "; break; case 4: // Magic lpStats[i].text= "Mag: "; rpStats[i].text= "Mag: "; break; case 5: // Resistance lpStats[i].text= "Res: "; rpStats[i].text= "Res: "; break; case 6: // Speed lpStats[i].text= "Spd: "; rpStats[i].text= "Spd: "; break; case 7: // Movement lpStats[i].text= "Move: "; rpStats[i].text= "Move: "; break; } lpStats[i].text+= info.attackerStats[i]+getEvenAmountOfSpace(info.attackerStats[i]); rpStats[i].text+= info.defenderStats[i]+getEvenAmountOfSpace(info.defenderStats[i]); if(info.projAttackerStats[i]-info.attackerStats[i]!= 0) // Highlight! { if(info.projAttackerStats[i]-info.attackerStats[i]> 0) { lpStats[i].text+= "+"; lpStats[i].backColorStates.normal= game.getColor("palegreen"); } else lpStats[i].backColorStates.normal= game.getColor("tomato"); lpStats[i].text+= (info.projAttackerStats[i]-info.attackerStats[i]).ToString(); lpStats[i].setState(ControlState.Normal); } else { lpStats[i].backColorStates.normal= game.getColor("white"); lpStats[i].setState(ControlState.Normal); } if(info.projDefenderStats[i]-info.defenderStats[i]!= 0) // Highlight! { if(info.projDefenderStats[i]-info.defenderStats[i]> 0) { rpStats[i].text+= "+"; rpStats[i].backColorStates.normal= game.getColor("palegreen"); } else rpStats[i].backColorStates.normal= game.getColor("tomato"); rpStats[i].text+= (info.projDefenderStats[i]-info.defenderStats[i]).ToString(); rpStats[i].setState(ControlState.Normal); } else { rpStats[i].backColorStates.normal= game.getColor("white"); rpStats[i].setState(ControlState.Normal); } lpStats[i].bounds= new Rectangle(8, charHeight*(i+1)+8, leftPanel.bounds.Width-16, charHeight); rpStats[i].bounds= new Rectangle(8, charHeight*(i+1)+8, rightPanel.bounds.Width-16, charHeight); lpStats[i].texture= game.textures.get("white_background"); rpStats[i].texture= game.textures.get("white_background"); } // Right Panel's Name rpName.bounds= new Rectangle(rightPanel.bounds.Width/2-(int)(lpName.font.MeasureString(info.defenderName).X/2f), 8, 0, 0); rpName.text= info.defenderName; // Accuracy accuracy.text= ((int)(100f*info.accuracy))+"%"; // Critical crit.text= ((int)(100f*info.criticalChance))+"%"; // Damage dmg.text= info.damage.ToString(); game.gui.open("attack_decision"); }
// 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 virtual bool attackUnit(Unit unit, bool initiatedAttack, ref Unit victim, int x, int y, ref AttackInfo info, ref BattleMap map) { if(victim== null) return false; if(info.skillID== "basic_attack") { victim.takeDamage(ref info, ref unit, ref map); if(unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); } return true; }
// 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) { default: case "basic_attack": case "piercing_jab": case "counter_swipe": { if(victim== null) break; victim.takeDamage(ref info, ref unit, ref map); if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };return true; case "enrage": { unit.addStatEffect( new StatEffect( EffectType.Buff, "Enrage", "+25% +4 Atk for 3 turns", enrageSE, 3 ), ref map ); unit.addStatEffect(StatEffect.create(StatusEffect.Enraged, 3), ref map); if(!unit.isAI) unit.gainExp(ref unit, ref map); };return true; case "furious_slash": { if(victim== null) break; victim.takeDamage(ref info, ref unit, ref map); unit.addStatEffect(StatEffect.create(StatusEffect.Enraged, 3), ref map); if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };return true; case "let_loose": { if(victim== null) break; victim.takeDamage(ref info, ref unit, ref map); unit.addStatEffect(StatEffect.create(StatusEffect.Enraged, 3), ref map); unit.addStatEffect( new StatEffect( EffectType.Debuff, "Let Loose", "-25% Def for 3 turns", letLooseSE, 3 ), ref map ); if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };return true; case "intimidate": { if(victim== null) break; victim.addStatEffect( new StatEffect( EffectType.Debuff, "Intimidated", "-12% Atk, Def, and Res for 3 turns", intimidateSE, 3 ), ref map ); if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };return true; case "stockpile_rage": { stockpiled+= 0.12f; if(!unit.isAI) unit.gainExp(ref unit, ref map); };return true; case "suicidal_slash": { if(victim== null) break; unit.defense= (int)(unit.defense*0.96f); unit.originalDefense= (int)(unit.originalDefense*0.96f); victim.takeDamage(ref info, ref unit, ref map); if(!info.missed && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };return true; case "fury_swipes": { if(victim== null) break; // Variables bool hit= false; info.damage/= 3; for(int i= 0; i< 3; i++) { victim.takeDamage(ref info, ref unit, ref map); if(!hit && !info.missed) hit= true; } if(hit && unit.isAlive && !unit.isAI) unit.gainExp(ref victim, ref map); };return true; } return false; }
// --- Inherited Methods --- // Called when the game state is being initiated protected override void onInit() { game.clearColor= game.getColor("#101820"); holds= new bool[6]; ticks= new int[1]; map= new BattleMap(ref game, this, 24, 24); cursorArrow= new CursorArrow(game, Vector3.Zero); currAttackInfo= new AttackInfo(); camSpline= new Spline(); camTween= new Tween(0f, 1f, 500f); for(int i= 0; i< holds.Length; i++) holds[i]= false; for(int i= 0; i< ticks.Length; i++) ticks[i]= 0; playerTeamID= 0; stage= 0; prevStage= 0; selUnit= new int[] {-1, -1}; map.tiles.forEach(delegate(GridNode<Tile> node, int x, int y) { node.item= new Tile(game, new Vector3(-x*Tile.size, 0f, y*Tile.size), ref map); }); //map.createFromBitmap("maps/map_test.bmp"); map.tiles.items[0, 2].item.startZoneID= 0; map.tiles.items[2, 5].item.startZoneID= 0; map.tiles.items[1, 5].item.startZoneID= 0; map.tiles.items[0, 1].item.startZoneID= 1; // Ally team map.addTeam(new Team(game, false, Unit.create("Paul", game, new Cardinal(game), 30, "undying_morale"), Unit.create("George", game, new Berserker(game), 30), Unit.create("Lillianna", game, new Cardinal(game), 30, "evil\'s_bane") )); // Enemy Team map.addTeam(new Team(game, true, Unit.create("Terrence", game, new Berserker(game), 30), Unit.create("Gjoran", game, new Samurai(game), 30), Unit.create("Lorance", game, new Cardinal(game), 30), Unit.create("Monte", game, new Cardinal(game), 30) ), true); map.injectTeams(); forward= new Vector3(0f, -256f/((float)(Math.Tan(GSGameplay.deg30)+Math.Tan(3.14159f/12f))), 0f); forward.Z= -1f*(float)(forward.Y*Math.Tan(GSGameplay.deg30)); game.cameras.current.target= new Vector3(0f, 0f, 512f); game.cameras.current.pos= new Vector3(0f, 512f, 0f); camSel= new int[] { map.width/2, map.height/2 }; moveCameraTo(5, 5); isPlayer= false; isUsingGamepad= false; bCenterOverride= false; setupGui(); }
public bool attackUnit(bool initiatedAttack, ref Unit victim, int x, int y, AttackInfo info, BattleMap map) { return attackUnit(initiatedAttack, ref victim, x, y, ref info, ref map); }
// Does things with the tile public void interactWithTile(ref GridNode<Tile> node, ref InputArgs args) { if(holds[5]) { holds[5]= false; return; } switch(stage) { case 0: { if(node.item.unitID[0]== -1) return; stage= 1; selUnit= node.item.unitID; if(node.item.unitID[0]!= playerTeamID) { isPlayer= false; enemyUnitGui.openFirst(args); return; } isPlayer= true; playerUnitGui.open(); };break; case 2: { if(node.path== -1) return; if(node.item.unitID!= selUnit && node.item.hasUnit) return; map.moveUnit(selUnit, camSel[0], camSel[1]); map.destroyPaths(); if(!map.teams.items[selUnit[0]].units.items[selUnit[1]].isAttackingDone) { stage= 1; map.endUnitWalking(selUnit); playerUnitGui.open(); } else { game.gui.close("player_unit_menu"); stage= 0; map.endUnitWalking(selUnit); } };break; case 3: { if(node.path== -1) return; if(!node.item.hasUnit) return; map.destroyPaths(); currAttackInfo= map.showAttackDecision(selUnit, camSel[0], camSel[1], selSkill); //moveCameraTo(camSel[0], camSel[1]-3); openAttackDecisionGui(); stage= 1; };break; } }
// 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; }