public static List <int> targets_in_range(int min_range, int max_range, HashSet <Vector2> move_range, List <int> units, bool walls) { List <int> result = new List <int>(); foreach (Vector2 loc in move_range) { // If all units have been checked, break if (units.Count == 0) { break; } // Loop through units int i = 0; while (i < units.Count) { int id = units[i]; Combat_Map_Object target = Global.game_map.attackable_map_object(id); int dist = manhatten_dist(loc, target.loc) / 10; if (dist <= max_range && dist >= min_range && (walls ? clear_firing_line(loc, target.loc) : true)) { result.Add(id); units.Remove(id); } else { i++; } } } return(result); }
private void add_attacks( Game_Unit battler_1, Combat_Map_Object battler_2, int i, Data_Weapon weapon) { #if DEBUG System.Diagnostics.Debug.Assert(i == 1 || i == 2); #endif Game_Unit attacker = i == 2 ? battler_2 as Game_Unit : battler_1; Combat_Map_Object target = i == 2 ? battler_1 : battler_2; int num_hits = 1; if (!attacker.is_brave_blocked()) { // If only single hits against terrain if (!(target != null && !target.is_unit() && Constants.Combat.BRAVE_BLOCKED_AGAINST_DESTROYABLE)) { num_hits = weapon.HitsPerAttack; } } for (int j = 0; j < num_hits; j++) { add_attacks(battler_1, battler_2, i); } }
protected override int combat_attacks(Game_Unit battler_1, Combat_Map_Object battler_2, out int numAttacks1, out int numAttacks2) { // Only one attack per target for area of effect numAttacks1 = 1; numAttacks2 = 0; return(Math.Max(numAttacks1, numAttacks2)); }
public Terrain_Round_Data(Game_Unit battler_1, Combat_Map_Object battler_2, int distance) { Battler1 = battler_1; TargetTerrain = battler_2; List <int?> ary = combat_stats(distance); Stats = ary; }
private void add_attacks( Game_Unit battler_1, Combat_Map_Object battler_2, int i) { Game_Unit attacker = battler_1; Combat_Map_Object target = battler_2; if (i == 2) { if (!battler_2.is_unit()) { return; } attacker = battler_2 as Game_Unit; target = battler_1; } bool cont = false; while (!cont) { int attacker_index = 0; bool attack_occurs = attackable(attacker, target); if (attack_occurs) { attacker_index = i; if (Skip_Attack.Contains(attacker_index)) { attacker_index = 0; Skip_Attack.pop(); } } if (attacker_index > 0) { if (battler_2 == null) { add_solo_attack(battler_1, attacker_index); } else if (battler_2.is_unit()) { add_attack(battler_1, battler_2 as Game_Unit, attacker_index); } else { add_attack(battler_1, battler_2 as Combat_Map_Object, attacker_index); } } cont = true; // If an added attack is buffered if (Add_Attack.Count > 0) { attacker_index = Add_Attack.pop(); cont = false; } } }
public override void apply_combat(bool immediate_level, bool skip_exp) { // Prevents data from being applied multiple times if (Applied) { return; } Applied = true; Game_Unit battler_1 = Global.game_map.units[Battler_1_Id]; Combat_Map_Object battler_2 = Global.game_map.get_map_object((int)Battler_2_Id) as Combat_Map_Object; int battler_1_hp = battler_1.hp; int battler_2_hp = battler_2 != null ? battler_2.hp : -1; for (int i = 0; i < Data.Count; i++) { Combat_Round_Data data = Data[i].Key; data.cause_damage(); } Global.game_state.add_combat_metric(Metrics.CombatTypes.DestroyableTerrain, Battler_1_Id, Battler_2_Id, battler_1_hp, battler_2_hp, Weapon_1_Id, Weapon_2_Id, Data.Where(x => x.Key.Attacker == 1).Count(), Data.Where(x => x.Key.Attacker != 1).Count()); use_weapons(battler_1, null); battler_1.actor.clear_added_attacks(); if (skip_exp) { Exp_Gain1 = 0; Exp_Gain2 = 0; } else { exp_gain(battler_1.actor, Exp_Gain1); if (battler_1.is_player_team) { if (Global.game_state.is_battle_map && !Global.game_system.In_Arena) { Global.game_system.chapter_exp_gain += Exp_Gain1; } } } if (Wexp1 > 0) { TactileLibrary.WeaponType type = battler_1.actor.valid_weapon_type_of(Global.data_weapons[Weapon_1_Id]); battler_1.actor.wexp_gain(type, Wexp1); } if (immediate_level) { if (battler_1.actor.needed_levels > 0) { battler_1.actor.level_up(); } battler_1.actor.clear_wlvl_up(); } }
protected override void process_attacks(Game_Unit battler_1, Combat_Map_Object battler_2) { if (Global.game_temp.scripted_battle_stats != null) { process_scripted_attacks(battler_1, battler_2, Global.game_temp.scripted_battle_stats); } else { base.process_attacks(battler_1, battler_2); } }
protected virtual int combat_attacks(Game_Unit battler_1, Combat_Map_Object battler_2, out int numAttacks1, out int numAttacks2) { numAttacks1 = battler_1.attacks_per_round(battler_2, Distance); numAttacks2 = 0; if (battler_2 != null && battler_2.is_unit()) { numAttacks2 = (battler_2 as Game_Unit).attacks_per_round(battler_1, Distance); } return(Math.Max(numAttacks1, numAttacks2)); }
protected override int combat_attacks(Game_Unit battler_1, Combat_Map_Object battler_2, out int numAttacks1, out int numAttacks2) { // No double casting numAttacks1 = 1; numAttacks2 = 0; if (battler_2 != null && battler_2.is_unit()) { numAttacks2 = 1; } return(Math.Max(numAttacks1, numAttacks2)); }
public static void SetWeaponTriangle( Weapon_Triangle_Arrow wta, Game_Unit attacker, Combat_Map_Object target, TactileLibrary.Data_Weapon weapon1, TactileLibrary.Data_Weapon weapon2, int distance) { SetWeaponTriangle( wta, null, attacker, target, weapon1, weapon2, distance); }
protected virtual void set_variables(Game_Unit battler_1, Combat_Map_Object battler_2) { Hp1 = battler_1.actor.hp; MaxHp1 = battler_1.actor.maxhp; Team1 = battler_1.team; Name1 = battler_1.actor.name; Exp1 = battler_1.actor.exp; Weapon_1_Id = battler_1.actor.weapon_id; if (battler_2 != null) { Hp2 = battler_2.hp; MaxHp2 = battler_2.maxhp; Team2 = battler_2.team; Name2 = battler_2.name; Exp2 = 0; Weapon_2_Id = -1; } }
public int get_multi(Game_Unit unit, Combat_Map_Object target, TactileLibrary.Data_Weapon weapon, int distance) { int multi = 0; if (!target.is_unit()) { return(0); } if (weapon.Brave() && !unit.is_brave_blocked()) { multi += 4; } if (unit.can_double_attack(target, distance)) { multi += 2; } return(multi / 2); }
public static void SetWeaponTriangle( Weapon_Triangle_Arrow wta1, Weapon_Triangle_Arrow wta2, Game_Unit attacker, Combat_Map_Object target, TactileLibrary.Data_Weapon weapon1, TactileLibrary.Data_Weapon weapon2, int distance) { //@Yeti: use in all the places weapon triangle arrow is used Game_Unit targetUnit = null; if (target.is_unit()) { targetUnit = target as Game_Unit; } ResetWeaponTriangle(wta1, wta2); WeaponTriangle tri = WeaponTriangle.Nothing; if (targetUnit != null) { tri = Combat.weapon_triangle(attacker, targetUnit, weapon1, weapon2, distance); } if (tri != WeaponTriangle.Nothing) { wta1.value = tri; if (wta2 != null && weapon2 != null) { wta2.value = Combat.reverse_wta(tri); } } float effectiveness = weapon1.effective_multiplier(attacker, targetUnit, false); wta1.set_effectiveness((int)effectiveness, targetUnit != null && targetUnit.halve_effectiveness()); if (wta2 != null && weapon2 != null) { effectiveness = weapon2.effective_multiplier(targetUnit, attacker, false); wta2.set_effectiveness((int)effectiveness, attacker.halve_effectiveness()); } }
protected void process_attacks(Game_Unit battler_1, Combat_Map_Object battler_2, int targetId) { battler_1.start_attack(-1, battler_2); if (battler_2 is Game_Unit) { (battler_2 as Game_Unit).start_attack(-1, battler_1); } bool ambush = battler_2 != null && battler_2.is_unit() && Global.game_map.units[targetId].counters_first(Global.game_map.units[Battler_1_Id]); int num_attacks1, num_attacks2; for (int i = 0; i < combat_attacks( battler_1, battler_2, out num_attacks1, out num_attacks2); i++) { if (ambush) { if (battler_2 != null && battler_2.is_unit() && i < num_attacks2 && this.weapon2 != null) { add_attacks(battler_1, battler_2, 2, this.weapon2); } } // Add hits for battler_1 in this attack if (i < num_attacks1) { if (i < num_attacks1) { add_attacks(battler_1, battler_2, 1, this.weapon1); } } if (!ambush) { if (battler_2 != null && battler_2.is_unit() && i < num_attacks2 && this.weapon2 != null) { add_attacks(battler_1, battler_2, 2, this.weapon2); } } } }
protected void cause_damage(Combat_Map_Object attacker, Combat_Map_Object target, bool test) { // If the attack didn't backfire, cause damage as normal then apply on-hit healing here if (!Result.backfire) { target.combat_damage(Result.dmg, attacker, Result.state_change, Result.backfire, test); attacker.hp += Result.immediate_life_steal; } // Else it backfired, and damage is caused else { attacker.combat_damage(Result.dmg - Result.immediate_life_steal, target, Result.state_change, Result.backfire, test); } // Then apply is delayed life gain, such as from Resire or Nosferatu if (Result.delayed_life_steal && !attacker.is_dead) { attacker.hp += Result.delayed_life_steal_amount; } }
protected override void setup() { Game_Unit battler_1 = Global.game_map.units[Battler_1_Id]; Combat_Map_Object target = Global.game_map.get_map_object((int)Battler_2_Id) as Combat_Map_Object; set_variables(battler_1, target); List <int> attack_array = new List <int>(); battler_1.store_state(); process_attacks(battler_1, target); battler_1.restore_state(); // Set battle end stats if (Data.Count == 0) { throw new NotImplementedException("A battle with no attacks tried to occur"); } Data[Data.Count - 1].Key.end_battle(Distance, Data[Data.Count - 1].Value); // Check if a battler has been killed if (battler_1.is_dead) { Kill = 1; } else if (target.hp <= Data .Select(x => x.Key) .Where(x => (x.Attacker == 1 ^ x.Result.backfire) && x.Result.hit) .Select(x => x.Result.dmg).Sum()) // target.is_dead) //Debug { Kill = 2; } // Exp/Wexp Wexp1 = 0; Wexp2 = 0; Exp_Gain1 = 0; Exp_Gain2 = 0; // Reset HP battler_1.actor.hp = Hp1; target.hp = Hp2; // Reset skills battler_1.actor.reset_skills(true); }
protected void add_attack(Game_Unit battler_1, Combat_Map_Object battler_2, int attacker) { battler_1.start_attack(Data.Count(x => x.Key.Attacker == attacker), battler_2); add_data(battler_1, battler_2); Data[Data.Count - 1].Key.Attacker = attacker; // Checks if this is the first attack of this unit for (int i = 0; i < Data.Count - 1; i++) { if (Data[i].Key.Attacker == Data[Data.Count - 1].Key.Attacker) { Data[Data.Count - 1].Key.First_Attack = false; break; } } if (attacker == 1) { Attacked_1 = true; } else { Attacked_2 = true; } ((Terrain_Round_Data)Data[Data.Count - 1].Key).set_attack(Distance, Data[Data.Count - 1].Value); // Add Attacks if (battler_1.actor.added_attacks.Count > 0) { foreach (int attack in battler_1.actor.added_attacks) { Add_Attack.Add(attack == 1 ? 1 : 2); } } battler_1.actor.clear_added_attacks(); Exp_Gain1 = Math.Max(0, Exp_Gain1); int uses = battler_1.weapon_use_count(Data[Data.Count - 1].Key.Result.hit); add_weapon_uses(ref Weapon_1_Uses, uses, this.weapon1); }
private void process_scripted_attacks(Game_Unit battler_1, Combat_Map_Object battler_2, Scripted_Combat_Script script) { battler_1.start_attack(-1, battler_2); if (battler_2 is Game_Unit) { (battler_2 as Game_Unit).start_attack(-1, battler_1); } for (int i = 0; i < script.Stats.Count; i++) { if (script.Stats[i].Result != Attack_Results.End) { bool cont = false; while (!cont) { cont = true; int attacker = script.Stats[i].Attacker; if (attacker > 0) { if (battler_2 == null) { add_solo_attack(battler_1, attacker); } else if (battler_2.is_unit()) { add_attack(battler_1, battler_2 as Game_Unit, script.Stats[i]); } else { add_attack(battler_1, battler_2 as Combat_Map_Object, attacker); } } } } } Kill = script.kill; }
public virtual void combat_damage(int dmg, Combat_Map_Object attacker, List <KeyValuePair <int, bool> > states, bool backfire, bool test) { hp -= dmg; }
protected override void set_variables(Game_Unit battler_1, Combat_Map_Object battler_2) { base.set_variables(battler_1, battler_2); Mode = get_staff_mode(Weapon_1_Id); }
protected virtual void process_attacks(Game_Unit battler_1, Combat_Map_Object battler_2) { process_attacks(battler_1, battler_2, battler_2 == null ? -1 : (int)Battler_2_Id); }
protected virtual void add_data(Game_Unit battler_1, Combat_Map_Object battler_2) { Data.Add(new KeyValuePair <Combat_Round_Data, List <Combat_Action_Data> >( new Terrain_Round_Data(battler_1, battler_2, Distance), new List <Combat_Action_Data>())); }
protected virtual bool attackable(Game_Unit attacker, Combat_Map_Object target) { // If target doesn't exist because it's a flare use/etc if (target == null) { return(true); } // If attacker is dead return //@Debug: make sure units who are out of hp but technically aren't // dead for whatever reason will stop if (attacker.hp <= 0) //@Debug: .is_dead) { return(false); } bool is_target_unit = false; // If the target is already dead, stop attacking if (target.hp <= 0) { // Don't return if either battler wants the attacks to continue if (!attacker.continue_attacking() && !(target.is_unit() && (target as Game_Unit).continue_attacking())) { return(false); } } Game_Unit target_unit = null; if (target.is_unit()) { is_target_unit = true; target_unit = (Game_Unit)target; } var weapon = attacker.id == Battler_1_Id ? this.weapon1 : this.weapon2; if (weapon == null) { return(false); } // If target is berserk ally and attacker isn't berserk, don't hurt your friend >: if (is_target_unit && attacker.id != Battler_1_Id && !attacker.is_attackable_team(target_unit) && !can_counter_ally(attacker)) { return(false); } int hit, uses; if (attacker.id == Battler_1_Id) { List <int?> ary = Combat.combat_stats(attacker.id, target.id, Distance); hit = 100; uses = Weapon_1_Uses; if (ary[0] == null && !weapon.is_staff()) { return(false); // This is newly added to account for the attacker being put to sleep, did any other cases make hit null? } if (ary[0] != null) { hit = (int)ary[0]; } } else { List <int?> ary = Combat.combat_stats(target.id, attacker.id, Distance); if (ary[4] == null) { return(false); } hit = (int)ary[4]; uses = Weapon_2_Uses; } // Breaks if the attacker can't fight/broke their weapon if (hit < 0 || attacker.is_weapon_broke(uses)) { return(false); } return(true); }