コード例 #1
0
 public bool CheckAttack(Unit target, UNIT_ATTACK type)
 {
     if (target == null || this == target) return false;
     if (Player.player_is_ally(this.player, target.player)) return false;
     if (((this.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING) &&
         (target.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
         if (this.sel_prop.rng == 0)
             if (this.x != target.x || this.y != target.y)
                 return false; /* range 0 means above unit for an aircraft */
     /* if the target flys and the unit is ground with a range of 0 the aircraft
        may only be harmed when above unit */
     if (((this.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING) &&
         (target.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING)
         if (this.sel_prop.rng == 0)
             if (this.x != target.x || this.y != target.y)
                 return false;
     /* only destroyers may harm submarines */
     if (((target.sel_prop.flags & UnitFlags.DIVING) == UnitFlags.DIVING) &&
         (this.sel_prop.flags & UnitFlags.DESTROYER) != UnitFlags.DESTROYER) return false;
     if ((Engine.terrain.weatherTypes[Scenario.cur_weather].flags & WEATHER_FLAGS.NO_AIR_ATTACK) == WEATHER_FLAGS.NO_AIR_ATTACK)
     {
         if ((this.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING) return false;
         if ((target.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING) return false;
     }
     if (type == UNIT_ATTACK.UNIT_ACTIVE_ATTACK)
     {
         /* agressor */
         if (this.cur_ammo <= 0) return false;
         if (this.sel_prop.atks[target.sel_prop.trgt_type] <= 0) return false;
         if (this.cur_atk_count == 0) return false;
         if (!this.IsClose(target) && Misc.get_dist(this.x, this.y, target.x, target.y) > this.sel_prop.rng) return false;
     }
     else
         if (type == UNIT_ATTACK.UNIT_DEFENSIVE_ATTACK)
         {
             /* defensive fire */
             if (this.sel_prop.atks[target.sel_prop.trgt_type] <= 0) return false;
             if (this.cur_ammo <= 0) return false;
             if ((this.sel_prop.flags & (UnitFlags.INTERCEPTOR | UnitFlags.ARTILLERY | UnitFlags.AIR_DEFENSE)) == 0) return false;
             if ((target.sel_prop.flags & (UnitFlags.ARTILLERY | UnitFlags.AIR_DEFENSE | UnitFlags.SWIMMING)) != 0) return false;
             if ((this.sel_prop.flags & UnitFlags.INTERCEPTOR) == UnitFlags.INTERCEPTOR)
             {
                 /* the interceptor is propably not beside the attacker so the range check is different
                  * can't be done here because the unit the target attacks isn't passed so
                  *  GetDefensiveFireUnits() must have a look itself
                  */
             }
             else
                 if (Misc.get_dist(this.x, this.y, target.x, target.y) > this.sel_prop.rng) return false;
         }
         else
         {
             /* counter-attack */
             if (this.cur_ammo <= 0) return false;
             if (!this.IsClose(target) && Misc.get_dist(this.x, this.y, target.x, target.y) > this.sel_prop.rng) return false;
             if (this.sel_prop.atks[target.sel_prop.trgt_type] == 0) return false;
             /* artillery may only defend against close units */
             if ((this.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY)
                 if (!this.IsClose(target))
                     return false;
             /* you may defend against artillery only when close */
             if ((target.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY)
                 if (!this.IsClose(target))
                     return false;
         }
     return true;
 }
コード例 #2
0
 /*
 ====================================================================
 Compute damage/supression the target takes when unit attacks
 the target. No properties will be changed. If 'real' is set
 the dices are rolled else it's a stochastical prediction.
 ====================================================================
 */
 public static void GetDamage(Unit aggressor, Unit unit, Unit target,
                       UNIT_ATTACK type,
                       bool real, bool rugged_def,
                       out int damage, out int suppr)
 {
     int atk_strength, max_roll, min_roll, die_mod;
     int atk_grade, def_grade, diff, result;
     float suppr_chance, kill_chance;
     /* use PG's formula to compute the attack/defense grade*/
     /* basic attack */
     atk_grade = Math.Abs(unit.sel_prop.atks[target.sel_prop.trgt_type]);
     #if DEBUG
     if (real) Console.WriteLine("{0} attacks:", unit.name);
     if (real) Console.WriteLine("  base:   {0}", atk_grade);
     if (real) Console.WriteLine("  exp:    +{0}", unit.exp_level);
     #endif
     /* experience */
     atk_grade += unit.exp_level;
     /* target on a river? */
     if ((target.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
         if ((target.terrain.flags[Scenario.cur_weather] & Terrain_flags.RIVER) == Terrain_flags.RIVER)
         {
             atk_grade += 4;
     #if DEBUG
             if (real) Console.WriteLine("  river:  +4");
     #endif
         }
     /* counterattack of rugged defense unit? */
     if (type == UNIT_ATTACK.UNIT_PASSIVE_ATTACK && rugged_def)
     {
         atk_grade += 4;
     #if DEBUG
         if (real) Console.WriteLine("  rugdef: +4");
     #endif
     }
     #if DEBUG
     if (real) Console.WriteLine("---\n{0} defends:", target.name);
     #endif
     /* basic defense */
     if ((unit.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING)
         def_grade = target.sel_prop.def_air;
     else
     {
         def_grade = target.sel_prop.def_grnd;
         /* apply close defense? */
         if ((unit.sel_prop.flags & UnitFlags.INFANTRY) == UnitFlags.INFANTRY)
             if ((target.sel_prop.flags & UnitFlags.INFANTRY) != UnitFlags.INFANTRY)
                 if ((target.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
                     if ((target.sel_prop.flags & UnitFlags.SWIMMING) != UnitFlags.SWIMMING)
                     {
                         if (target == aggressor)
                             if ((unit.terrain.flags[Scenario.cur_weather] & Terrain_flags.INF_CLOSE_DEF) == Terrain_flags.INF_CLOSE_DEF)
                                 def_grade = target.sel_prop.def_cls;
                         if (unit == aggressor)
                             if ((target.terrain.flags[Scenario.cur_weather] & Terrain_flags.INF_CLOSE_DEF) == Terrain_flags.INF_CLOSE_DEF)
                                 def_grade = target.sel_prop.def_cls;
                     }
     }
     #if DEBUG
     if (real) Console.WriteLine("  base:   {0}", def_grade);
     if (real) Console.WriteLine("  exp:    +{0}", target.exp_level);
     #endif
     /* experience */
     def_grade += target.exp_level;
     /* attacker on a river or swamp? */
     if ((unit.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
         if ((unit.sel_prop.flags & UnitFlags.SWIMMING) != UnitFlags.SWIMMING)
             if ((target.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
             {
                 if ((unit.terrain.flags[Scenario.cur_weather] & Terrain_flags.SWAMP) == Terrain_flags.SWAMP)
                 {
                     def_grade += 4;
     #if DEBUG
                     if (real) Console.WriteLine("  swamp:  +4");
     #endif
                 }
                 else
                     if ((unit.terrain.flags[Scenario.cur_weather] & Terrain_flags.RIVER) == Terrain_flags.RIVER)
                     {
                         def_grade += 4;
     #if DEBUG
                         if (real) Console.WriteLine("  river:  +4");
     #endif
                     }
             }
     /* rugged defense? */
     if (type == UNIT_ATTACK.UNIT_ACTIVE_ATTACK && rugged_def)
     {
         def_grade += 4;
     #if DEBUG
         if (real) Console.WriteLine("  rugdef: +4");
     #endif
     }
     /* entrenchment */
     if ((unit.sel_prop.flags & UnitFlags.IGNORE_ENTR) == UnitFlags.IGNORE_ENTR)
         def_grade += 0;
     else
     {
         if ((unit.sel_prop.flags & UnitFlags.INFANTRY) == UnitFlags.INFANTRY)
             def_grade += target.entr / 2;
         else
             def_grade += target.entr;
     #if DEBUG
         if (real) Console.WriteLine("  entr:   +{0}",
         ((unit.sel_prop.flags & UnitFlags.INFANTRY) == UnitFlags.INFANTRY) ? target.entr / 2 : target.entr);
     #endif
     }
     /* naval vs ground unit */
     if ((unit.sel_prop.flags & UnitFlags.SWIMMING) != UnitFlags.SWIMMING)
         if ((unit.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
             if ((target.sel_prop.flags & UnitFlags.SWIMMING) == UnitFlags.SWIMMING)
             {
                 def_grade += 8;
     #if DEBUG
                 if (real) Console.WriteLine("  naval: +8");
     #endif
             }
     /* bad weather? */
     if (unit.sel_prop.rng > 0)
         if ((Engine.terrain.weatherTypes[Scenario.cur_weather].flags & WEATHER_FLAGS.BAD_SIGHT) == WEATHER_FLAGS.BAD_SIGHT)
         {
             def_grade += 3;
     #if DEBUG
             if (real) Console.WriteLine("  sight: +3");
     #endif
         }
     /* initiating attack against artillery? */
     if (type == UNIT_ATTACK.UNIT_PASSIVE_ATTACK)
         if ((unit.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY)
         {
             def_grade += 3;
     #if DEBUG
             if (real) Console.WriteLine("  def vs art: +3");
     #endif
         }
     /* infantry versus anti_tank? */
     if ((target.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY)
         if ((unit.sel_prop.flags & UnitFlags.ANTI_TANK) == UnitFlags.ANTI_TANK)
         {
             def_grade += 2;
     #if DEBUG
             if (real) Console.WriteLine("  antitnk:+2");
     #endif
         }
     /* no fuel makes attacker less effective */
     if (unit.CheckFuelUsage() && unit.cur_fuel == 0)
     {
         def_grade += 4;
     #if DEBUG
         if (real) Console.WriteLine("  lowfuel:+4");
     #endif
     }
     /* attacker strength */
     atk_strength = unit_get_cur_str(unit);
     #if DEBUG
     if (real && atk_strength != unit_get_cur_str(unit))
         Console.WriteLine("---\n{0} with half strength", unit.name);
     #endif
     /*  PG's formula:
     get difference between attack and defense
     strike for each strength point with
       if ( diff <= 4 )
       D20 + diff
       else
       D20 + 4 + 0.4 * ( diff - 4 )
     suppr_fire flag set: 1-10 miss, 11-18 suppr, 19+ kill
     normal: 1-10 miss, 11-12 suppr, 13+ kill */
     diff = atk_grade - def_grade; if (diff < -7) diff = -7;
     damage = 0;
     suppr = 0;
     #if DEBUG
     if (real)
     {
         Console.WriteLine("---\n{0} x {1} -. {2} x {3}",
                 atk_strength, atk_grade, unit_get_cur_str(target), def_grade);
     }
     #endif
     /* get the chances for suppression and kills (computed here
        to use also for debug info */
     suppr_chance = kill_chance = 0;
     die_mod = (diff <= 4 ? diff : 4 + 2 * (diff - 4) / 5);
     min_roll = 1 + die_mod; max_roll = 20 + die_mod;
     /* get chances for suppression and kills */
     if ((unit.sel_prop.flags & UnitFlags.SUPPR_FIRE) == UnitFlags.SUPPR_FIRE)
     {
         int limit = (type == UNIT_ATTACK.UNIT_DEFENSIVE_ATTACK) ? 20 : 18;
         if (limit - min_roll >= 0)
             suppr_chance = 0.05f * (Math.Min(limit, max_roll) - Math.Max(11, min_roll) + 1);
         if (max_roll > limit)
             kill_chance = 0.05f * (max_roll - Math.Max(limit + 1, min_roll) + 1);
     }
     else
     {
         if (12 - min_roll >= 0)
             suppr_chance = 0.05f * (Math.Min(12, max_roll) - Math.Max(11, min_roll) + 1);
         if (max_roll > 12)
             kill_chance = 0.05f * (max_roll - Math.Max(13, min_roll) + 1);
     }
     if (suppr_chance < 0) suppr_chance = 0; if (kill_chance < 0) kill_chance = 0;
     if (real)
     {
     #if DEBUG
         Console.WriteLine("Roll: D20 + {0} (Kill: {1}, Suppr: {2})",
         diff <= 4 ? diff : 4 + 2 * (diff - 4) / 5,
         (int)(100 * kill_chance), (int)(100 * suppr_chance));
     #endif
         while (atk_strength-- > 0)
         {
             if (diff <= 4)
                 result = Misc.DICE(20) + diff;
             else
                 result = Misc.DICE(20) + 4 + 2 * (diff - 4) / 5;
             if ((unit.sel_prop.flags & UnitFlags.SUPPR_FIRE) == UnitFlags.SUPPR_FIRE)
             {
                 int limit = (type == UNIT_ATTACK.UNIT_DEFENSIVE_ATTACK) ? 20 : 18;
                 if (result >= 11 && result <= limit)
                     suppr++;
                 else
                     if (result >= limit + 1)
                         damage++;
             }
             else
             {
                 if (result >= 11 && result <= 12)
                     suppr++;
                 else
                     if (result >= 13)
                         damage++;
             }
         }
     #if DEBUG
         Console.WriteLine("Kills: {0}, Suppression: {1}", damage, suppr);
     #endif
     }
     else
     {
         suppr = (int)(suppr_chance * atk_strength);
         damage = (int)(kill_chance * atk_strength);
     }
 }
コード例 #3
0
 public FIGHT_TYPES Attack(Unit target, UNIT_ATTACK type, bool real, bool force_rugged)
 {
     int unit_old_str = this.str;//, target_old_str = target.str;
     int unit_old_ini = this.sel_prop.ini, target_old_ini = target.sel_prop.ini;
     int unit_dam = 0, unit_suppr = 0, target_dam = 0, target_suppr = 0;
     int rugged_chance;
     bool rugged_def = false;
     int exp_mod;
     FIGHT_TYPES ret = FIGHT_TYPES.AR_NONE; /* clear flags */
     ATTACK_FLAGS strike;
     /* check if rugged defense occurs */
     if (real && type == UNIT_ATTACK.UNIT_ACTIVE_ATTACK)
         if (this.CheckRuggedDefense(target) || (force_rugged && this.IsClose(target)))
         {
             rugged_chance = this.GetRuggedDefenseChance(target);
             if (Misc.DICE(100) <= rugged_chance || force_rugged)
                 rugged_def = true;
         }
     /* PG's formula for initiative is
        min { base initiative, terrain max initiative } +
        ( exp_level + 1 ) / 2 + D3 */
     /* against aircrafts the initiative is used since terrain does not matter */
     /* target's terrain is used for fight */
     if ((this.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING &&
         (target.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
     {
         this.sel_prop.ini = Math.Min(this.sel_prop.ini, target.terrain.max_ini);
         target.sel_prop.ini = Math.Min(target.sel_prop.ini, target.terrain.max_ini);
     }
     this.sel_prop.ini += (this.exp_level + 1) / 2;
     target.sel_prop.ini += (target.exp_level + 1) / 2;
     /* special initiative rules:
        antitank inits attack tank|recon: atk 0, def 99
        tank inits attack against anti-tank: atk 0, def 99
        defensive fire: atk 99, def 0
        submarine attacks: atk 99, def 0
        ranged attack: atk 99, def 0
        rugged defense: atk 0
        air unit attacks air defense: atk = def
        non-art vs art: atk 0, def 99 */
     if ((this.sel_prop.flags & UnitFlags.ANTI_TANK) == UnitFlags.ANTI_TANK)
         if ((target.sel_prop.flags & UnitFlags.TANK) == UnitFlags.TANK)
         {
             this.sel_prop.ini = 0;
             target.sel_prop.ini = 99;
         }
     if (((this.sel_prop.flags & UnitFlags.DIVING) == UnitFlags.DIVING) ||
          ((this.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY) ||
          ((this.sel_prop.flags & UnitFlags.AIR_DEFENSE) == UnitFlags.AIR_DEFENSE) ||
          type == UNIT_ATTACK.UNIT_DEFENSIVE_ATTACK
     )
     {
         this.sel_prop.ini = 99;
         target.sel_prop.ini = 0;
     }
     if ((this.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING)
         if ((target.sel_prop.flags & UnitFlags.AIR_DEFENSE) == UnitFlags.AIR_DEFENSE)
             this.sel_prop.ini = target.sel_prop.ini;
     if (rugged_def)
         this.sel_prop.ini = 0;
     if (force_rugged)
         target.sel_prop.ini = 99;
     /* the dice is rolled after these changes */
     if (real)
     {
         this.sel_prop.ini += Misc.DICE(3);
         target.sel_prop.ini += Misc.DICE(3);
     }
     #if DEBUG
     if (real)
     {
         Console.WriteLine("{0} Initiative: {1}", this.name, this.sel_prop.ini);
         Console.WriteLine("{0} Initiative: {1}", target.name, target.sel_prop.ini);
         if (this.CheckRuggedDefense(target))
             Console.WriteLine("Rugged Defense: {0} ({1})",
                     rugged_def ? "yes" : "no",
                     this.GetRuggedDefenseChance(target));
     }
     #endif
     /* in a real combat a submarine may evade */
     if (real && type == UNIT_ATTACK.UNIT_ACTIVE_ATTACK && ((target.sel_prop.flags & UnitFlags.DIVING) == UnitFlags.DIVING))
     {
         if (Misc.DICE(10) <= 7 + (target.exp_level - this.exp_level) / 2)
         {
             strike = ATTACK_FLAGS.ATK_NO_STRIKE;
             ret |= FIGHT_TYPES.AR_EVADED;
         }
         else
             strike = ATTACK_FLAGS.ATK_UNIT_FIRST;
     #if DEBUG
         Console.WriteLine("\nSubmarine Evasion: {0} ({1}%)\n",
          (strike == ATTACK_FLAGS.ATK_NO_STRIKE) ? "yes" : "no",
          10 * (7 + (target.exp_level - this.exp_level) / 2));
     #endif
     }
     else
         /* who is first? */
         if (this.sel_prop.ini == target.sel_prop.ini)
             strike = ATTACK_FLAGS.ATK_BOTH_STRIKE;
         else
             if (this.sel_prop.ini > target.sel_prop.ini)
                 strike = ATTACK_FLAGS.ATK_UNIT_FIRST;
             else
                 strike = ATTACK_FLAGS.ATK_TARGET_FIRST;
     /* the one with the highest initiative begins first if not defensive fire or artillery */
     if (strike == ATTACK_FLAGS.ATK_BOTH_STRIKE)
     {
         /* both strike at the same time */
         GetDamage(this, this, target, type, real, rugged_def, out target_dam, out target_suppr);
         if (target.CheckAttack(this, UNIT_ATTACK.UNIT_PASSIVE_ATTACK))
             GetDamage(this, target, this, UNIT_ATTACK.UNIT_PASSIVE_ATTACK, real, rugged_def, out unit_dam, out unit_suppr);
         target.ApplyDamage(target_dam, target_suppr, this);
         this.ApplyDamage(unit_dam, unit_suppr, target);
     }
     else
         if (strike == ATTACK_FLAGS.ATK_UNIT_FIRST)
         {
             /* unit strikes first */
             GetDamage(this, this, target, type, real, rugged_def, out target_dam, out target_suppr);
             if (target.ApplyDamage(target_dam, target_suppr, this) != 0)
                 if (target.CheckAttack(this, UNIT_ATTACK.UNIT_PASSIVE_ATTACK) && type != UNIT_ATTACK.UNIT_DEFENSIVE_ATTACK)
                 {
                     GetDamage(this, target, this, UNIT_ATTACK.UNIT_PASSIVE_ATTACK, real, rugged_def, out unit_dam, out unit_suppr);
                     this.ApplyDamage(unit_dam, unit_suppr, target);
                 }
         }
         else
             if (strike == ATTACK_FLAGS.ATK_TARGET_FIRST)
             {
                 /* target strikes first */
                 if (target.CheckAttack(this, UNIT_ATTACK.UNIT_PASSIVE_ATTACK))
                 {
                     GetDamage(this, target, this, UNIT_ATTACK.UNIT_PASSIVE_ATTACK, real, rugged_def, out unit_dam, out unit_suppr);
                     if (this.ApplyDamage(unit_dam, unit_suppr, target) == 0)
                         ret |= FIGHT_TYPES.AR_UNIT_ATTACK_BROKEN_UP;
                 }
                 if (unit_get_cur_str(this) > 0)
                 {
                     GetDamage(this, this, target, type, real, rugged_def, out target_dam, out target_suppr);
                     target.ApplyDamage(target_dam, target_suppr, this);
                 }
             }
     /* check return value */
     if (this.str == 0)
         ret |= FIGHT_TYPES.AR_UNIT_KILLED;
     else
         if (unit_get_cur_str(this) == 0)
             ret |= FIGHT_TYPES.AR_UNIT_SUPPRESSED;
     if (target.str == 0)
         ret |= FIGHT_TYPES.AR_TARGET_KILLED;
     else
         if (unit_get_cur_str(target) == 0)
             ret |= FIGHT_TYPES.AR_TARGET_SUPPRESSED;
     if (rugged_def)
         ret |= FIGHT_TYPES.AR_RUGGED_DEFENSE;
     if (real)
     {
         /* cost ammo */
         if (Config.supply)
         {
             //if (DICE(10)<=target_old_str)
             this.cur_ammo--;
             if (target.CheckAttack(this, UNIT_ATTACK.UNIT_PASSIVE_ATTACK) && target.cur_ammo > 0)
                 //if (DICE(10)<=unit_old_str)
                 target.cur_ammo--;
         }
         /* costs attack */
         if (this.cur_atk_count > 0) this.cur_atk_count--;
         /* target: loose entrenchment if damage was taken or with a unit.str*10% chance */
         if (target.entr > 0)
             if (target_dam > 0 || Misc.DICE(10) <= unit_old_str)
                 target.entr--;
         /* attacker looses entrenchment if it got hurt */
         if (this.entr > 0 && unit_dam > 0)
             this.entr--;
         /* gain experience */
         exp_mod = target.exp_level - this.exp_level;
         if (exp_mod < 1) exp_mod = 1;
         this.AddExperience(exp_mod * target_dam + unit_dam);
         exp_mod = this.exp_level - target.exp_level;
         if (exp_mod < 1) exp_mod = 1;
         target.AddExperience(exp_mod * unit_dam + target_dam);
         if (this.IsClose(target))
         {
             this.AddExperience(10);
             target.AddExperience(10);
         }
         /* adjust life bars */
         update_bar(this);
         update_bar(target);
     }
     this.sel_prop.ini = unit_old_ini;
     target.sel_prop.ini = target_old_ini;
     return ret;
 }
コード例 #4
0
 public FIGHT_TYPES NormalAttack(Unit target, UNIT_ATTACK type)
 {
     return this.Attack(target, type, true, false);
 }