예제 #1
0
 public static bool ai_get_dist(Unit unit, int x, int y, AI_FIND type, out int dx, out int dy, out int dist)
 {
     bool found = false;
     int length;
     int i, j;
     dist = 999;
     dx = dy = 0;
     for (i = 0; i < Engine.map.map_w; i++)
         for (j = 0; j < Engine.map.map_h; j++)
             if (ai_check_hex_type(unit, type, i, j))
             {
                 length = Misc.get_dist(i, j, x, y);
                 if (dist > length)
                 {
                     dist = length;
                     dx = i;
                     dy = j;
                     found = true;
                 }
             }
     return found;
 }
예제 #2
0
 public static void unit_restore(ref Unit unit)
 {
     if (unit.backup != null && !string.IsNullOrEmpty(unit.backup.prop.id))
     {
         unit = (Unit)unit.backup.MemberwiseClone();
         unit.backup = null;
     }
     else
         Console.WriteLine("{0}: can't restore backup: not set", unit.name);
 }
예제 #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
 /*
 ====================================================================
 CreateAction a unit by passing a Unit struct with the following stuff set:
   x, y, str, entr, exp, delay, orient, nation, player.
 This function will use the passed values to create a Unit struct
 with all values set then.
 ====================================================================
 */
 public static Unit CreateUnit(Unit_Lib_Entry prop, Unit_Lib_Entry trsp_prop, Unit unit_base)
 {
     Unit unit;
     if (prop == null) return null;
     unit = new Unit();
     /* shallow copy of properties */
     unit.prop = prop;
     unit.sel_prop = unit.prop;
     unit.embark = UnitEmbarkTypes.EMBARK_NONE;
     /* assign the passed transporter without any check */
     if (trsp_prop != null && (prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING && (prop.flags & UnitFlags.SWIMMING) != UnitFlags.SWIMMING)
     {
         unit.trsp_prop = trsp_prop;
         /* a sea/air ground transporter is active per default */
         if ((trsp_prop.flags & UnitFlags.SWIMMING) == UnitFlags.SWIMMING)
         {
             unit.embark = UnitEmbarkTypes.EMBARK_SEA;
             unit.sel_prop = unit.trsp_prop;
         }
         if ((trsp_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING)
         {
             unit.embark = UnitEmbarkTypes.EMBARK_AIR;
             unit.sel_prop = unit.trsp_prop;
         }
     }
     /* copy the base values */
     unit.delay = unit_base.delay;
     unit.x = unit_base.x; unit.y = unit_base.y;
     unit.str = unit_base.str; unit.entr = unit_base.entr;
     unit.player = unit_base.player;
     unit.nation = unit_base.nation;
     unit.name = unit_base.name;
     unit.AddExperience(unit_base.exp_level * 100);
     unit.orient = unit_base.orient;
     unit.AdjustIcon();
     unit.unused = true;
     unit.supply_level = 100;
     unit.cur_ammo = unit.prop.ammo;
     unit.cur_fuel = unit.prop.fuel;
     if ((unit.cur_fuel == 0) && (unit.trsp_prop != null) &&
         (!string.IsNullOrEmpty(unit.trsp_prop.id)) && unit.trsp_prop.fuel > 0)
         unit.cur_fuel = unit.trsp_prop.fuel;
     unit.tag = unit_base.tag;
     /* update life bar properties */
     update_bar(unit);
     /* allocate backup mem */
     unit.backup = new Unit();
     return unit;
 }
예제 #5
0
 /*
 ====================================================================
 Go through a complete battle unit vs. target including known(!)
 defensive support stuff and with no random modifications.
 Return the final damage taken by both units.
 As the terrain may have influence the id of the terrain the battle
 takes place (defending unit's hex) is provided.
 ====================================================================
 */
 public static void GetExpectedLosses(Unit unit, Unit target, out int unit_damage, out int target_damage)
 {
     int damage, suppr;
     List<Unit> df_units = new List<Unit>();
     #if DEBUG_ATTACK
     printf( "***********************\n" );
     #endif
     unit.GetDefensiveFireUnits(target, Scenario.vis_units, ref df_units);
     unit_backup(unit);
     unit_backup(target);
     /* let defensive fire go to work (no chance to defend against this) */
     foreach (Unit df in df_units)
     {
         GetDamage(unit, df, unit, UNIT_ATTACK.UNIT_DEFENSIVE_ATTACK, false, false, out damage, out suppr);
         if (unit.ApplyDamage(damage, suppr, null) == 0) break;
     }
     /* actual fight if attack has strength remaining */
     if (unit_get_cur_str(unit) > 0)
         unit.Attack(target, UNIT_ATTACK.UNIT_ACTIVE_ATTACK, false, false);
     /* get done damage */
     unit_damage = unit.str;
     target_damage = target.str;
     unit_restore(ref unit);
     unit_restore(ref target);
     unit_damage = unit.str - unit_damage;
     target_damage = target.str - target_damage;
 }
예제 #6
0
 /// <summary>
 /// Get the current unit strength which is:
 ///   max { 0, unit.str - unit.suppr - unit.turn_suppr }
 /// </summary>
 /// <param name="unit"></param>
 /// <returns></returns>
 static int unit_get_cur_str(Unit unit)
 {
     int cur_str = unit.str - unit.suppr - unit.turn_suppr;
     if (cur_str < 0) cur_str = 0;
     return cur_str;
 }
예제 #7
0
        /*
        ====================================================================
        Merge these two units: unit is the new unit and source must be
        removed from map and memory after this function was called.
        ====================================================================
        */
        public void Merge(Unit unit, Unit source)
        {
            /* units relative weight */
            float weight1, weight2, total;
            int i;
            /* compute weight */
            weight1 = unit.str; weight2 = source.str;
            total = unit.str + source.str;
            /* adjust so weight1 + weigth2 = 1 */
            weight1 /= total; weight2 /= total;
            /* no other actions allowed */
            unit.unused = false; unit.cur_mov = 0; unit.cur_atk_count = 0;
            /* repair damage */
            unit.str += source.str;
            /* reorganization costs some entrenchment: the new units are assumed to have
               entrenchment 0 since they come. new entr is rounded weighted sum */
            unit.entr = (int)Math.Floor((float)unit.entr * weight1 + 0.5); /* + 0 * weight2 */
            /* update experience */
            i = (int)(weight1 * unit.exp + weight2 * source.exp);
            unit.exp = 0; unit.AddExperience(i);
            /* update unit::prop */
            /* related initiative */
            unit.prop.ini = (int)(weight1 * unit.prop.ini + weight2 * source.prop.ini);
            /* minimum movement */
            if (source.prop.mov < unit.prop.mov)
                unit.prop.mov = source.prop.mov;
            /* maximum spotting */
            if (source.prop.spt > unit.prop.spt)
                unit.prop.spt = source.prop.spt;
            /* maximum range */
            if (source.prop.rng > unit.prop.rng)
                unit.prop.rng = source.prop.rng;
            /* relative attack count */
            unit.prop.atk_count = (int)(weight1 * unit.prop.atk_count + weight2 * source.prop.atk_count);
            if (unit.prop.atk_count == 0) unit.prop.atk_count = 1;
            /* relative attacks */
            /* if attack is negative simply use absolute value; only restore negative if both units are negative */
            for (i = 0; i < DB.UnitLib.trgt_type_count; i++)
            {
                bool neg = (unit.prop.atks[i] < 0 && source.prop.atks[i] < 0);
                unit.prop.atks[i] = (int)(weight1 * Math.Abs(unit.prop.atks[i]) + weight2 * (source.prop.atks[i]));
                if (neg) unit.prop.atks[i] *= -1;
            }
            /* relative defence */
            unit.prop.def_grnd = (int)(weight1 * unit.prop.def_grnd + weight2 * source.prop.def_grnd);
            unit.prop.def_air = (int)(weight1 * unit.prop.def_air + weight2 * source.prop.def_air);
            unit.prop.def_cls = (int)(weight1 * unit.prop.def_cls + weight2 * source.prop.def_cls);
            /* relative ammo */
            unit.prop.ammo = (int)(weight1 * unit.prop.ammo + weight2 * source.prop.ammo);
            unit.cur_ammo = (int)(weight1 * unit.cur_ammo + weight2 * source.cur_ammo);
            /* relative fuel */
            unit.prop.fuel = (int)(weight1 * unit.prop.fuel + weight2 * source.prop.fuel);
            unit.cur_fuel = (int)(weight1 * unit.cur_fuel + weight2 * source.cur_fuel);
            /* merge flags */
            unit.prop.flags |= source.prop.flags;
            /* sounds, picture are kept */
            /* unit::trans_prop isn't updated so far: */
            /* transporter of first unit is kept if any else second unit's transporter is used */
            if (string.IsNullOrEmpty(unit.trsp_prop.id) && !string.IsNullOrEmpty(source.trsp_prop.id))
            {
            #if TODO
                memcpy(&unit.trsp_prop, &source.trsp_prop, sizeof(Unit_Lib_Entry));

            #endif

                /* as this must be a ground transporter copy current fuel value */
                unit.cur_fuel = source.cur_fuel;
                throw new NotImplementedException();
            }
            update_bar(unit);
        }
예제 #8
0
 /*
 ====================================================================
 Check if unit stays on top of an enemy flag and capture
 it. Return True if the flag was captured.
 ====================================================================
 */
 public static bool engine_capture_flag(Unit unit)
 {
     if ((unit.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
         if ((unit.sel_prop.flags & UnitFlags.SWIMMING) != UnitFlags.SWIMMING)
             if (Engine.map.map[unit.x, unit.y].nation != null)
                 if (!Player.player_is_ally(Engine.map.map[unit.x, unit.y].player, unit.player))
                 {
                     /* capture */
                     Engine.map.map[unit.x, unit.y].nation = unit.nation;
                     Engine.map.map[unit.x, unit.y].player = unit.player;
                     /* a conquered flag gets deploy ability again after some turns */
                     Engine.map.map[unit.x, unit.y].deploy_center = 3;
                     return true;
                 }
     return false;
 }
예제 #9
0
 /*
 ====================================================================
 Get next combatants assuming that cur_unit attacks cur_target.
 Set cur_atk and cur_def and return True if there are any more
 combatants.
 ====================================================================
 */
 public static bool engine_get_next_combatants()
 {
     bool fight = false;
     string str;
     /* check if there are supporting units; if so initate fight
        between attacker and these units */
     if (df_units.Count > 0)
     {
         cur_atk = df_units[0];
         cur_def = cur_unit;
         fight = true;
         defFire = 1;
         /* set message if seen */
         if (!blind_cpu_turn)
         {
             if ((cur_atk.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY)
                 str = "Defensive Fire";
             else
                 if ((cur_atk.sel_prop.flags & UnitFlags.AIR_DEFENSE) == UnitFlags.AIR_DEFENSE)
                     str = "Air-Defense";
                 else
                     str = "Interceptors";
     #if TODO
     label_write( gui.label, gui.font_error, str );
     #endif
         }
     }
     else
     {
         /* clear info */
     #if TODO
         if (!blind_cpu_turn)
             label_hide(gui.label, 1);
     #endif
         /* normal attack */
         cur_atk = cur_unit;
         cur_def = cur_target;
         fight = true;
         defFire = 0;
     }
     return fight;
 }
예제 #10
0
        public static void EndMove()
        {
            /* fade out sound */
            #if WITH_SOUND
                    audio_fade_out( 0, 500 ); /* move sound channel */
            #endif
            /* decrease fuel for way_pos hex tiles of movement */
            if (move_unit.CheckFuelUsage() && Config.supply)
            {
                move_unit.cur_fuel -= move_unit.CalcFuelUsage(  way_pos);
                if (move_unit.cur_fuel < 0)
                    move_unit.cur_fuel = 0;
            }
            /* clear move buffer image */
            #if TODO
                    if ( !blind_cpu_turn )
                       image_delete( &move_image );
            #endif
            /* run surprise contact */
            if (surp_unit != null)
            {
                cur_unit = move_unit;
                cur_target = surp_unit;
                surp_contact = true;
                surp_unit = null;
                if (engine_get_next_combatants())
                {
                    status = STATUS.STATUS_ATTACK;
                    phase = PHASE.PHASE_INIT_ATK;
                    if (!blind_cpu_turn)
                    {
            #if TODO
                                image_hide( gui.cursors, 1 );
            #endif
                        draw_map = true;
            #if TODO_RR
                        form.Draw();
            #endif
                    }
                }
                return;
            }
            /* reselect unit -- cur_unit may differ from move_unit! */
            if (cur_ctrl == PLAYERCONTROL.PLAYER_CTRL_HUMAN)
                engine_select_unit(cur_unit);
            /* status */
            engine_set_status(STATUS.STATUS_NONE);
            phase = PHASE.PHASE_NONE;
            AI_Enemy.Action.action_queue(EngineActionsTypes.ACTION_NONE);
            //stateMachine.Send(EngineActionsTypes.ACTION_NONE);

            /* allow new human/cpu input */
            if (!blind_cpu_turn)
            {
                if (cur_ctrl == PLAYERCONTROL.PLAYER_CTRL_HUMAN)
                {
            #if TODO
                            gui_set_cursor( CURSOR_STD );
                            image_hide( gui.cursors, 0 );
                            old_mx = old_my = -1;
            #endif
                }
                draw_map = true;
            #if TODO_RR
                form.Draw();
            #endif
            }
        }
예제 #11
0
 /*
 ====================================================================
 Backup data that will be restored when unit move was undone.
 (destination flag, spot mask, unit position)
 If x != -1 the flag at x,y will be saved.
 ====================================================================
 */
 public static void engine_backup_move(Unit unit, int x, int y)
 {
     if (!move_backup.used)
     {
         move_backup.used = true;
         move_backup.unit = unit;
         map.map_backup_spot_mask();
     }
     if (x != -1)
     {
         move_backup.dest_nation = map.map[x, y].nation;
         move_backup.dest_player = map.map[x, y].player;
         move_backup.flag_saved = true;
     }
     else
         move_backup.flag_saved = false;
 }
예제 #12
0
        public static void CheckResult()
        {
            bool broken_up = false;
            bool reset = false;
            bool was_final_fight = false;
            bool surrender = false;
            try
            {
                UNIT_END_COMBAT type = UNIT_END_COMBAT.UNIT_STAYS;
                int dx, dy;

                surp_contact = false;

                /* check attack result */
                if ((atk_result & Unit.FIGHT_TYPES.AR_UNIT_KILLED) == Unit.FIGHT_TYPES.AR_UNIT_KILLED)
                {
                    Scenario.scen_inc_casualties_for_unit(cur_atk);
                    engine_remove_unit(cur_atk);
                    cur_atk = null;
                }
                if ((atk_result & Unit.FIGHT_TYPES.AR_TARGET_KILLED) == Unit.FIGHT_TYPES.AR_TARGET_KILLED)
                {
                    Scenario.scen_inc_casualties_for_unit(cur_def);
                    engine_remove_unit(cur_def);
                    cur_def = null;
                }
                /* CHECK IF SCENARIO IS FINISHED DUE TO UNITS_KILLED OR UNITS_SAVED */
                if (Scenario.scen_check_result(false))
                {
                    engine_finish_scenario();
                    return;
                }
                reset = true;
                if (df_units.Count > 0)
                {
                    if (((atk_result & Unit.FIGHT_TYPES.AR_TARGET_SUPPRESSED) == Unit.FIGHT_TYPES.AR_TARGET_SUPPRESSED) ||
                        ((atk_result & Unit.FIGHT_TYPES.AR_TARGET_KILLED) == Unit.FIGHT_TYPES.AR_TARGET_KILLED))
                    {
                        df_units.Clear();
                        if ((atk_result & Unit.FIGHT_TYPES.AR_TARGET_KILLED) == Unit.FIGHT_TYPES.AR_TARGET_KILLED)
                            cur_unit = null;
                        else
                        {
                            /* supressed unit looses its actions */
                            cur_unit.cur_mov = 0;
                            cur_unit.cur_atk_count = 0;
                            cur_unit.unused = false;
                            broken_up = true;
                        }
                    }
                    else
                    {
                        reset = false;
                        df_units.RemoveAt(0);
                    }
                }
                else
                    was_final_fight = true;
                if (!reset)
                {
                    /* continue fights */
                    if (engine_get_next_combatants())
                    {
                        status = STATUS.STATUS_ATTACK;
                        phase = PHASE.PHASE_INIT_ATK;
                    }
                    else
                        Console.WriteLine("Deadlock! No remaining combatants but supposed to continue fighting? How is this supposed to work????");
                }
                else
                {
                    /* clear suppression from defensive fire */
                    if (cur_atk != null)
                    {
                        cur_atk.suppr = 0;
                        cur_atk.unused = false;
                    }
                    if (cur_def != null)
                        cur_def.suppr = 0;
                    /* if this was the final fight between selected unit and selected target
                       check if one of these units was completely suppressed and surrenders
                       or flees */
                    if (was_final_fight)
                    {
                        engine_clear_backup(); /* no undo allowed after attack */
                        if (cur_atk != null && cur_def != null)
                        {
                            if ((atk_result & Unit.FIGHT_TYPES.AR_UNIT_ATTACK_BROKEN_UP) == Unit.FIGHT_TYPES.AR_UNIT_ATTACK_BROKEN_UP)
                            {
                                /* unit broke up the attack */
                                broken_up = true;
                            }
                            else
                                /* total suppression may only cause fleeing or
                                   surrender if: both units are ground/naval units in
                                   close combat: the unit that causes suppr must
                                   have range 0 (melee)
                                   inf . fort (fort may surrender)
                                   fort . adjacent inf (inf will not flee) */
                                if (((cur_atk.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING) &&
                                    (cur_def.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
                                {
                                    if ((atk_result & Unit.FIGHT_TYPES.AR_UNIT_SUPPRESSED) == Unit.FIGHT_TYPES.AR_UNIT_SUPPRESSED &&
                                         ((atk_result & Unit.FIGHT_TYPES.AR_TARGET_SUPPRESSED) != Unit.FIGHT_TYPES.AR_TARGET_SUPPRESSED) &&
                                         cur_def.sel_prop.rng == 0)
                                    {
                                        /* cur_unit is suppressed */
                                        engine_handle_suppr(cur_atk, out type, out dx, out dy);
                                        if (type == UNIT_END_COMBAT.UNIT_FLEES)
                                        {
                                            status = STATUS.STATUS_MOVE;
                                            phase = PHASE.PHASE_INIT_MOVE;
                                            move_unit = cur_atk;
                                            fleeing_unit = 1;
                                            dest_x = dx; dest_y = dy;
                                            return;
                                        }
                                        else
                                            if (type == UNIT_END_COMBAT.UNIT_SURRENDERS)
                                            {
                                                surrender = true;
                                                surrender_unit = cur_atk;
                                            }
                                    }
                                    else
                                        if ((atk_result & Unit.FIGHT_TYPES.AR_TARGET_SUPPRESSED) == Unit.FIGHT_TYPES.AR_TARGET_SUPPRESSED &&
                                             (atk_result & Unit.FIGHT_TYPES.AR_UNIT_SUPPRESSED) != Unit.FIGHT_TYPES.AR_UNIT_SUPPRESSED &&
                                             cur_atk.sel_prop.rng == 0)
                                        {
                                            /* cur_target is suppressed */
                                            engine_handle_suppr(cur_def, out type, out dx, out dy);
                                            if (type == UNIT_END_COMBAT.UNIT_FLEES)
                                            {
                                                status = STATUS.STATUS_MOVE;
                                                phase = PHASE.PHASE_INIT_MOVE;
                                                move_unit = cur_def;
                                                fleeing_unit = 1;
                                                dest_x = dx; dest_y = dy;
                                                return;
                                            }
                                            else
                                                if (type == UNIT_END_COMBAT.UNIT_SURRENDERS)
                                                {
                                                    surrender = true;
                                                    surrender_unit = cur_def;
                                                }
                                        }
                                }
                        }
                        /* clear pointers */
                        if (cur_atk == null) cur_unit = null;
                        if (cur_def == null) cur_target = null;
                    }
                    if (broken_up)
                    {
                        phase = PHASE.PHASE_BROKEN_UP_MSG;
                        Console.WriteLine("Attack Broken Up!");
                        return;
                    }
                    if (surrender)
                    {
                        string msg = (surrender_unit.sel_prop.flags & UnitFlags.SWIMMING) == UnitFlags.SWIMMING ?
                            "Ship is scuttled!" : "Surrenders!";
                        phase = PHASE.PHASE_SURRENDER_MSG;
                        Console.WriteLine(msg);
                        return;
                    }
                    phase = PHASE.PHASE_END_COMBAT;
                }
            }
            finally
            {
                AI_Enemy.Action.action_queue(EngineActionsTypes.ACTION_END_COMBAT);
                //stateMachine.Send(EngineActionsTypes.ACTION_END_COMBAT);
            }
        }
예제 #13
0
 public static void ActionAttack(object[] args)
 {
     AI_Enemy.Action action = (AI_Enemy.Action)args[0];
     if (!action.unit.CheckAttack( action.target, Unit.UNIT_ATTACK.UNIT_ACTIVE_ATTACK))
     {
         Console.WriteLine("'{0}' ({1},{2}) can not attack '{3}' ({4},{5})",
                  action.unit.name, action.unit.x, action.unit.y,
                  action.target.name, action.target.x, action.target.y);
         return;
     }
     if (!Engine.map.mask[action.target.x, action.target.y].spot)
     {
         Console.WriteLine("'%{0}' may not attack unit '{1}' (not visible)", action.unit.name, action.target.name);
         return;
     }
     Engine.cur_unit = action.unit;
     Engine.cur_target = action.target;
     Engine.cur_unit.GetDefensiveFireUnits(Engine.cur_target, Scenario.units, ref Engine.df_units);
     if (Engine.engine_get_next_combatants())
     {
         Engine.status = STATUS.STATUS_ATTACK;
         Engine.phase = PHASE.PHASE_INIT_ATK;
         AI_Enemy.Action.action_queue(EngineActionsTypes.ACTION_INIT_ATTACK);
         //stateMachine.Send(EngineActionsTypes.ACTION_INIT_ATTACK);
         Engine.engine_clear_danger_mask();
     #if TODO
         if (Engine.cur_ctrl == PLAYER_CTRL_HUMAN)
             image_hide(gui.cursors, 1);
     #endif
     }
 }
예제 #14
0
 /*
 ====================================================================
 Check the supply level of a unit. (hex tiles with SUPPLY_GROUND
 have 100% supply.
 ====================================================================
 */
 public static void scen_adjust_unit_supply_level(Unit unit)
 {
     unit.supply_level = Engine.map.map_get_unit_supply_level(unit.x, unit.y, unit);
 }
예제 #15
0
 public FIGHT_TYPES SurpriseAttack(Unit target)
 {
     return this.Attack(target, UNIT_ATTACK.UNIT_ACTIVE_ATTACK, true, true);
 }
예제 #16
0
 /*
 ====================================================================
 Check if these two units are allowed to merge with each other.
 ====================================================================
 */
 public bool CheckMerge(Unit source)
 {
     /* units must not be sea/air embarked */
     if (this.embark != UnitEmbarkTypes.EMBARK_NONE || source.embark != UnitEmbarkTypes.EMBARK_NONE) return false;
     /* same class */
     if (this.prop.unit_class != source.prop.unit_class) return false;
     /* same player */
     if (!Player.player_is_ally(this.player, source.player)) return false;
     /* first unit must not have moved so far */
     if (!this.unused) return false;
     /* both units must have same movement type */
     if (this.prop.mov_type != source.prop.mov_type) return false;
     /* the unit strength must not exceed limit */
     if (this.str + source.str > 13) return false;
     /* fortresses (unit-class 7) could not merge */
     if (this.prop.unit_class == 7) return false;
     /* artillery with different ranges may not merge */
     if (((this.prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY) &&
         (this.prop.rng != source.prop.rng))
         return false;
     /* not failed so far: allow merge */
     return true;
 }
예제 #17
0
 /*
 ====================================================================
 Update unit bar.
 ====================================================================
 */
 public void UpdateBar(Unit unit)
 {
     update_bar(unit);
 }
예제 #18
0
 /*
 ====================================================================
 Check if target may do rugged defense
 ====================================================================
 */
 public bool CheckRuggedDefense(Unit target)
 {
     if (((this.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING) ||
         ((target.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING))
         return false;
     if (((this.sel_prop.flags & UnitFlags.SWIMMING) == UnitFlags.SWIMMING) ||
         ((target.sel_prop.flags & UnitFlags.SWIMMING) == UnitFlags.SWIMMING))
         return false;
     if ((this.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY) return false; /* no rugged def against range attack */
     if ((this.sel_prop.flags & UnitFlags.IGNORE_ENTR) == UnitFlags.IGNORE_ENTR) return false; /* no rugged def for pioneers and such */
     if (!this.IsClose(target)) return false;
     if (target.entr == 0) return false;
     return true;
 }
예제 #19
0
 /// <summary>
 /// Update unit's bar info according to strength.
 /// </summary>
 /// <param name="unit"></param>
 static void update_bar(Unit unit)
 {
     /* bar width */
     unit.damage_bar_width = unit.str * BAR_TILE_WIDTH;
     if (unit.damage_bar_width == 0 && unit.str > 0)
         unit.damage_bar_width = BAR_TILE_WIDTH;
     /* bar color is defined by vertical offset in map.life_icons */
     if (unit.str > 4)
         unit.damage_bar_offset = 0;
     else
         if (unit.str > 2)
             unit.damage_bar_offset = BAR_TILE_HEIGHT;
         else
             unit.damage_bar_offset = BAR_TILE_HEIGHT * 2;
 }
예제 #20
0
 /*
 ====================================================================
 Delete a unit. Pass the pointer as void* to allow usage as
 callback for a list.
 ====================================================================
 */
 public void DeleteUnit(Unit ptr)
 {
     throw new NotImplementedException();
 }
예제 #21
0
 /*
 ====================================================================
 Duplicate the unit.
 ====================================================================
 */
 public Unit Duplicate()
 {
     Unit newUnit = new Unit();
     newUnit = (Unit)this.MemberwiseClone();
     newUnit.SetGenericName(Scenario.units.Count + 1, this.prop.name);
     if (this.sel_prop == this.prop)
         newUnit.sel_prop = newUnit.prop;
     else
         newUnit.sel_prop = newUnit.trsp_prop;
     newUnit.backup = new Unit();
     /* terrain can't be updated here */
     return newUnit;
 }
예제 #22
0
 /*
 ====================================================================
 This function checks 'units' for supporters of 'target'
 that will give defensive fire to before the real battle
 'unit' vs 'target' takes place. These units are put to 'df_units'
 (which is not created here)
 ====================================================================
 */
 public void GetDefensiveFireUnits(Unit target, List<Unit> units, ref List<Unit> df_units)
 {
     df_units.Clear();
     if ((this.sel_prop.flags & UnitFlags.FLYING) == UnitFlags.FLYING)
     {
         foreach (Unit entry in units)
         {
             if (entry.killed != 0) continue;
             if (entry == target) continue;
             if (entry == this) continue;
             /* bombers -- intercepting impossibly covered by CheckAttack() */
             if ((target.sel_prop.flags & UnitFlags.INTERCEPTOR) != UnitFlags.INTERCEPTOR)
                 if (target.IsClose(entry))
                     if ((entry.sel_prop.flags & UnitFlags.INTERCEPTOR) == UnitFlags.INTERCEPTOR)
                         if (Player.player_is_ally(entry.player, target.player))
                             if (entry.cur_ammo > 0)
                             {
                                 df_units.Add(entry);
                                 continue;
                             }
             /* air-defense */
             if ((entry.sel_prop.flags & UnitFlags.AIR_DEFENSE) == UnitFlags.AIR_DEFENSE)
                 /* FlaK will not give support when an air-to-air attack is
                  * taking place. First, in reality it would prove distastrous,
                  * second, Panzer General doesn't allow it, either.
                  */
                 if ((target.sel_prop.flags & UnitFlags.FLYING) != UnitFlags.FLYING)
                     if (target.IsClose(entry)) /* adjacent help only */
                         if (entry.CheckAttack(this, UNIT_ATTACK.UNIT_DEFENSIVE_ATTACK))
                             df_units.Add(entry);
         }
     }
     else if (this.sel_prop.rng == 0)
     {
         /* artillery for melee combat; if unit attacks ranged, there is no
            support */
         foreach (Unit entry in units)
         {
             if (entry.killed != 0) continue;
             if (entry == target) continue;
             if (entry == this) continue;
             /* HACK: An artillery with range 1 cannot support adjacent units but
                should do so. So we allow to give defensive fire on a range of 2
                like a normal artillery */
             if (((entry.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY) && entry.sel_prop.rng == 1)
                 if (target.IsClose(entry))
                     if (Player.player_is_ally(entry.player, target.player))
                         if (entry.cur_ammo > 0)
                         {
                             df_units.Add(entry);
                             continue;
                         }
             /* normal artillery */
             if ((entry.sel_prop.flags & UnitFlags.ARTILLERY) == UnitFlags.ARTILLERY)
                 if (target.IsClose(entry)) /* adjacent help only */
                     if (entry.CheckAttack(this, UNIT_ATTACK.UNIT_DEFENSIVE_ATTACK))
                         df_units.Add(entry);
         }
     }
     /* randomly remove all support but one */
     if (df_units.Count > 0)
     {
         Unit entry = df_units[Misc.RANDOM(0, df_units.Count - 1)];
         df_units.Clear();
         df_units.Add(entry);
     }
 }
예제 #23
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);
     }
 }
예제 #24
0
 /*
 ====================================================================
 Compute the rugged defense chance.
 ====================================================================
 */
 public int GetRuggedDefenseChance(Unit target)
 {
     /* PG's formula is
        5% * def_entr *
        ( (def_exp_level + 2) / (atk_exp_level + 2) ) *
        ( (def_entr_rate + 1) / (atk_entr_rate + 1) ) */
     return (int)(5.0 * target.entr *
            ((float)(target.exp_level + 2) / (this.exp_level + 2)) *
            ((float)(target.sel_prop.entr_rate + 1) / (this.sel_prop.entr_rate + 1)));
 }
예제 #25
0
 public static void unit_backup(Unit unit)
 {
     unit.backup = (Unit)unit.MemberwiseClone();
 }
예제 #26
0
 /*
 ====================================================================
 Check if units are close to each other. This means on neighbored
 hex tiles.
 ====================================================================
 */
 public bool IsClose(Unit target)
 {
     return Misc.is_close(this.x, this.y, target.x, target.y);
 }
예제 #27
0
 /// <summary>
 /// Apply suppression and damage to unit. Return the remaining 
 /// actual strength.
 /// If attacker is a bomber the suppression is counted as turn
 /// suppression.
 /// </summary>
 /// <param name="unit"></param>
 /// <param name="damage"></param>
 /// <param name="suppr"></param>
 /// <param name="attacker"></param>
 /// <returns></returns>
 public int ApplyDamage(int damage, int suppr, Unit attacker)
 {
     this.str -= damage;
     if (this.str < 0)
     {
         this.str = 0;
         return 0;
     }
     if (attacker != null && ((attacker.sel_prop.flags & UnitFlags.TURN_SUPPR) == UnitFlags.TURN_SUPPR))
     {
         this.turn_suppr += suppr;
         if (this.str - this.turn_suppr - this.suppr < 0)
         {
             this.turn_suppr = this.str - this.suppr;
             return 0;
         }
     }
     else
     {
         this.suppr += suppr;
         if (this.str - this.turn_suppr - this.suppr < 0)
         {
             this.suppr = this.str - this.turn_suppr;
             return 0;
         }
     }
     return unit_get_cur_str(this);
 }
예제 #28
0
 public FIGHT_TYPES NormalAttack(Unit target, UNIT_ATTACK type)
 {
     return this.Attack(target, type, true, false);
 }
예제 #29
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;
 }
예제 #30
0
 /*
 ====================================================================
 Locals
 ====================================================================
 */
 /*
 ====================================================================
 Get the distance of 'unit' and position of object of a special
 type.
 ====================================================================
 */
 static bool ai_check_hex_type(Unit unit, AI_FIND type, int x, int y)
 {
     switch (type)
     {
         case AI_FIND.AI_FIND_DEPOT:
             if (Engine.map.map_is_allied_depot(Engine.map.map[x, y], unit))
                 return true;
             break;
         case AI_FIND.AI_FIND_ENEMY_OBJ:
             if (!Engine.map.map[x, y].obj) return false;
             break;
         case AI_FIND.AI_FIND_ENEMY_TOWN:
             if (Engine.map.map[x, y].player != null && !Player.player_is_ally(unit.player, Engine.map.map[x, y].player))
                 return true;
             break;
         case AI_FIND.AI_FIND_OWN_OBJ:
             if (!Engine.map.map[x, y].obj) return false;
             break;
         case AI_FIND.AI_FIND_OWN_TOWN:
             if (Engine.map.map[x, y].player != null && Player.player_is_ally(unit.player, Engine.map.map[x, y].player))
                 return true;
             break;
     }
     return false;
 }