Even rolls? (Full Version)

All Forums >> [New Releases from Matrix Games] >> Conflict of Heroes Series



Message


Ocean1 -> Even rolls? (5/13/2012 4:36:05 AM)

A question, which I hope you'd feel ok answering if it is the case: Are the rolls and chances for kill or hit rolls the same for the AI as for the human player? The first couple of games it seemed ok, but now it just seems the AI hits me a heck of a lot more than I hit it. I am playing on the default difficulty level. Maybe it's just that I am being reckless or using bad tactics, but I thought I'd ask. I know that in some past computer war games I've played, the AI was given a slight advantage - to make it "smarter" and more of a challenge.. Either way.. it's a good game.




Joram -> RE: Even rolls? (5/13/2012 1:34:42 PM)

I'm pretty certain there are no advantages given to the AI dice. You can also always use the dice cam feature in SP.




Erik Rutins -> RE: Even rolls? (5/13/2012 3:18:02 PM)

No, the AI always uses the same dice as you.

However, as you increase in difficulty, for each level above Easy it gets 25% more CAPs and an increased chance of higher unit quality. The combination of those two can lead to better combat results, but you should see when it uses its CAPs to boost combat rolls. Also, above Normal it gets 1 extra AP per unit.

Regards,

- Erik




ericbabe -> RE: Even rolls? (5/13/2012 4:25:04 PM)

Here is the code for a unit attacking another unit, and the code for generating the results of an attack:

private void AttackPiece(GameTime gameTime, Context context, int apCost, Piece targetPiece, Random rand, int attackNo)
{
CohPiece attacker = ThisPiece;
CohPiece defender = targetPiece as CohPiece;
Player attackerPlayer = context.PlayerManager[attacker.PlayerName];
Player defenderPlayer = context.PlayerManager[defender.PlayerName];

if (attacker == null || defender == null)
return;

// attack strength
String modfDesc = "";
bool frontal;
int att;
int def;
GetAttackStats(context, targetPiece, apCost, out frontal, out att, out def, ref modfDesc, false);

// reveal attacker
attacker.Hider.Unhide();

// AI player can modify attack roll with caps now
// omitted...

// get attack roll
int roll1, roll2;
int baseRoll = MakeAttackRoll(context.GameScene.HexGame, rand, context.PlayerManager[attacker.PlayerName], out roll1, out roll2);
int modfRoll = baseRoll + att;

// zero roll bonus
context.NextRollBonus = 0;

// notify for attack
String msg = "";
if (modfRoll >= def)
{
// unhide the defender
defender.Hider.Unhide();

msg = String.Format(modfRoll != baseRoll ?
Resources.CohAttacker_AttackPiece__0__rolls__4__modified_by__2__and_hits__1__whose_defense_is__3__ :
Resources.CohAttacker_AttackPiece__0__rolls__4__and_hits__1__whose_defense_is__3__,
attacker.GetName(), defender.GetName(), modfRoll - baseRoll, def, baseRoll);
}
else
{
if (defender.Hider.Hidden)
{
if (attackNo == 0)
msg = String.Format(/*ss.Get*/(Resources.CohAttacker_AttackLocation__0__does_not_reveal_any_units___1__), attacker.GetName(), baseRoll);
}
else
{
msg = String.Format(modfRoll != baseRoll ?
Resources.CohAttacker_AttackPiece__0__rolls__4__modified_by__2__and_misses__1__whose_defense_is__3__ :
Resources.CohAttacker_AttackPiece__0__rolls__4__and_misses__1__whose_defense_is__3__,
attacker.GetName(), defender.GetName(), modfRoll - baseRoll, def, baseRoll);
}

}

// add modifiers to message
if (!defender.Hider.Hidden)
{
msg += @" (";
msg += modfDesc;
msg += @")";
}

CombatSubject.Report(msg, modfRoll >= def ? ReportColors.HitColor : ReportColors.Standard);

if (!defender.Hider.Hidden)
{
// is piece hidden damage revealed?
if (defender.GetDamage() != null &&
defender.HiddenDamage &&
(defender.GetDamage().FlankDefense != 0 ||
defender.GetDamage().FlankDefenseIsArmored != 0 ||
defender.GetDamage().FrontDefense != 0 ||
defender.GetDamage().FlankDefenseIsArmored != 0))
{
defender.HiddenDamage = false;
CombatSubject.Report(String.Format(/*ss.Get*/(Resources.CohAttacker_AttackPiece__0__damage_is_revealed___1_), defender.GetName(), defender.GetDamage().Name));

}
if (attacker.GetDamage() != null &&
attacker.HiddenDamage &&
(attacker.GetDamage().Attack != 0 ||
attacker.GetDamage().AttackVsArmor != 0 ||
attacker.GetDamage().Range != 0 ||
attacker.GetDamage().MinRange != 0))
{
attacker.HiddenDamage = false;
CombatSubject.Report(String.Format(/*ss.Get*/(Resources.CohAttacker_AttackPiece__0__damage_is_revealed___1_), attacker.GetName(), attacker.GetDamage().Name));
}
}

// roll on flying text
FlyingTextManager.AddFloatFade(gameTime, String.Format(Resources.CohAttacker_AttackPiece_Roll___0_, baseRoll),
Color.White, attacker, new Vector2(0, -30.0f * attackNo), roll1, roll2);

// get roll result
if (modfRoll >= def)
{
// hit
// give damage marker
bool instantKill = (modfRoll >= def + 4);
CohDamage damage;
instantKill |= GiveDamage(defender, out damage);

// is defender dead
bool defenderIsDead = instantKill || defender.Hp() <= 0;

// hey controller
context.GameScene.Controller.AddAttackSequence(attacker, defender, defender.MapPos,
defenderIsDead ? CohController.HitResult.Destroy : CohController.HitResult.Hit,
new Vector2(0, -30.0f * attackNo),
damage.Name);

// reveal hit piece
defender.Hider.Unhide();

// destroy if necessary
if (defenderIsDead)
{
PerformCombatKill(context, attacker, defender);
}
else
{
HeadlineSubject.Report(String.Format(/*ss.Get*/(Resources.CohAttacker_AttackPiece__0__is_damaged), defender.GetName()));
}
}
else
{
if (!defender.Hider.Hidden)
{
// miss
context.GameScene.Controller.AddAttackSequence(attacker, defender, defender.MapPos, CohController.HitResult.Miss,
new Vector2(0, -30.0f * attackNo), null);
HeadlineSubject.Report(String.Format(/*ss.Get*/(Resources.CohAttacker_AttackPiece__0__misses), attacker.GetName()));
}
}

// call event
if (PieceAttackingHandler != null)
PieceAttackingHandler(gameTime, attacker, defender, defender.MapPos);
}

and the code for generating the attack roll:

private static int MakeAttackRoll(Application.HexGame game, Random rand, Player player, out int roll1, out int roll2)
{
if (PreferenceManager.Instance.AreUsingDiceCamera && player.IsHuman && !NetworkFacade.Game.IsActiveGame)
{
try
{
game.SuspendUpdate = true;
_DiceForm = new DiceForm
{
TopMost = true
};
_DiceForm.ShowDialog();
roll1 = 0;
roll2 = 0;
game.SuspendUpdate = false;
return _DiceForm.RollResult;
}
catch (Exception)
{
CombatSubject.Report(Resources.CohAttacker_MakeAttackRoll_Dice_Camera_failed_to_initialize_);
game.SuspendUpdate = false;
return Random2D6(rand, out roll1, out roll2);
}
}
else
return Random2D6(rand, out roll1, out roll2);
}

Here is the code to generate Random2D6:

private static int Random2D6(Random rand, out int roll1, out int roll2)
{
roll1 = rand.Next(6) + 1;
roll2 = rand.Next(6) + 1;
return roll1 + roll2;
}





ericbabe -> RE: Even rolls? (5/13/2012 4:26:08 PM)

Here is the code for our pseudorandom number generator. Note that it derives from System.Random and it is an instance of this class we pass as a parameter to Random2D6:

namespace HexGame.WCS.RandomNumbers
{
public class MersenneTwister : System.Random
{
// number generated since last reseed
private int NumberGenerated;

/* Period parameters */
private const int N = 624;
private const int M = 397;
private const uint MATRIX_A = 0x9908b0df; /* constant vector a */
private const uint UPPER_MASK = 0x80000000; /* most significant w-r bits */
private const uint LOWER_MASK = 0x7fffffff; /* least significant r bits */

/* Tempering parameters */
private const uint TEMPERING_MASK_B = 0x9d2c5680;
private const uint TEMPERING_MASK_C = 0xefc60000;

private static uint TEMPERING_SHIFT_U(uint y) { return (y >> 11); }
private static uint TEMPERING_SHIFT_S(uint y) { return (y << 7); }
private static uint TEMPERING_SHIFT_T(uint y) { return (y << 15); }
private static uint TEMPERING_SHIFT_L(uint y) { return (y >> 18); }

private uint[] mt = new uint[N]; /* the array for the state vector */

private short mti;

private static uint[] mag01 = { 0x0, MATRIX_A };

/* initializing the array with a NONZERO seed */
public MersenneTwister(uint seed)
{
/* setting initial seeds to mt[N] using */
/* the generator Line 25 of Table 1 in */
/* [KNUTH 1981, The Art of Computer Programming */
/* Vol. 2 (2nd Ed.), pp102] */
mt[0] = seed & 0xffffffffU;
for (mti = 1; mti < N; ++mti)
{
mt[mti] = (69069 * mt[mti - 1]) & 0xffffffffU;
}

// reset number generated
NumberGenerated = 0;
}
public MersenneTwister()
: this(4357) /* a default initial seed is used */
{
}

public String GetCurrentState()
{
return string.Format(@"{0}.{1}", mt[0].ToString(), NumberGenerated);
}

protected uint GenerateUInt()
{
uint y;

/* mag01[x] = x * MATRIX_A for x=0,1 */
if (mti >= N) /* generate N words at one time */
{
short kk = 0;

for (; kk < N - M; ++kk)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1];
}

for (; kk < N - 1; ++kk)
{
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1];
}

y = (mt[N - 1] & UPPER_MASK) | (mt[0] & LOWER_MASK);
mt[N - 1] = mt[M - 1] ^ (y >> 1) ^ mag01[y & 0x1];

mti = 0;
}

y = mt[mti++];
y ^= TEMPERING_SHIFT_U(y);
y ^= TEMPERING_SHIFT_S(y) & TEMPERING_MASK_B;
y ^= TEMPERING_SHIFT_T(y) & TEMPERING_MASK_C;
y ^= TEMPERING_SHIFT_L(y);

// remember we generated another one
NumberGenerated++;

return y;
}

public virtual uint NextUInt()
{
return this.GenerateUInt();
}

public virtual uint NextUInt(uint maxValue)
{
return (uint)(this.GenerateUInt() / ((double)uint.MaxValue / maxValue));
}

public virtual uint NextUInt(uint minValue, uint maxValue) /* throws ArgumentOutOfRangeException */
{
if (minValue >= maxValue)
{
throw new ArgumentOutOfRangeException();
}

return (uint)(this.GenerateUInt() / ((double)uint.MaxValue / (maxValue - minValue)) + minValue);
}

public override int Next()
{
return this.Next(int.MaxValue);
}

public override int Next(int maxValue) /* throws ArgumentOutOfRangeException */
{
if (maxValue <= 1)
{
if (maxValue < 0)
{
throw new ArgumentOutOfRangeException();
}

return 0;
}

return (int)(this.NextDouble() * maxValue);
}

public override int Next(int minValue, int maxValue)
{
if (maxValue < minValue)
{
throw new ArgumentOutOfRangeException();
}
else if (maxValue == minValue)
{
return minValue;
}
else
{
return this.Next(maxValue - minValue) + minValue;
}
}

public override void NextBytes(byte[] buffer) /* throws ArgumentNullException*/
{
int bufLen = buffer.Length;

if (buffer == null)
{
throw new ArgumentNullException();
}

for (int idx = 0; idx < bufLen; ++idx)
{
buffer[idx] = (byte)this.Next(256);
}
}

public override double NextDouble()
{
return (double)this.GenerateUInt() / ((ulong)uint.MaxValue + 1);
}
}
}




Page: [1]

Valid CSS!




Forum Software © ASPPlayground.NET Advanced Edition 2.4.5 ANSI
4.203125