combat actually works

This commit is contained in:
Chris Forbes
2009-10-21 21:34:34 +13:00
parent 659c3669e7
commit 4382a10568
9 changed files with 81 additions and 30 deletions

View File

@@ -86,5 +86,8 @@ namespace OpenRa
public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); } public static float2 Max(float2 a, float2 b) { return new float2(Math.Max(a.X, b.X), Math.Max(a.Y, b.Y)); }
public static float2 Min(float2 a, float2 b) { return new float2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); } public static float2 Min(float2 a, float2 b) { return new float2(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y)); }
public float LengthSquared { get { return X * X + Y * Y; } }
public float Length { get { return (float)Math.Sqrt(LengthSquared); } }
} }
} }

View File

@@ -78,5 +78,26 @@ namespace OpenRa.Game
return new RectangleF(loc.X, loc.Y, size.X, size.Y); return new RectangleF(loc.X, loc.Y, size.X, size.Y);
} }
} }
public void InflictDamage(Actor attacker, Bullet inflictor, int damage)
{
/* todo: auto-retaliate, etc */
/* todo: death sequence for infantry based on inflictor */
/* todo: start smoking if < conditionYellow and took damage, and not already smoking
if (Health <= 0) return; /* overkill! */
Health -= damage;
if (Health <= 0)
{
Health = 0;
if (attacker.Owner != null)
attacker.Owner.Kills++;
Game.world.AddFrameEndTask(w => w.Remove(this));
/* todo: explosion */
}
}
} }
} }

View File

@@ -59,6 +59,12 @@ namespace OpenRa.Game
{ {
Game.world.AddFrameEndTask(w => w.Remove(this)); Game.world.AddFrameEndTask(w => w.Remove(this));
Game.world.AddFrameEndTask(w => w.Add(new Explosion(Dest))); Game.world.AddFrameEndTask(w => w.Add(new Explosion(Dest)));
var maxSpread = GetMaximumSpread();
var hitActors = Game.FindUnitsInCircle(Dest, GetMaximumSpread());
foreach (var victim in hitActors)
victim.InflictDamage(FiredBy, this, (int)GetDamageToInflict(victim));
} }
} }
@@ -70,5 +76,20 @@ namespace OpenRa.Game
Dest.ToFloat2(), Dest.ToFloat2(),
(float)t / TotalTime()) - 0.5f * anim.Image.size); (float)t / TotalTime()) - 0.5f * anim.Image.size);
} }
float GetMaximumSpread()
{
return (int)(Warhead.Spread * Math.Log(Weapon.Damage, 2));
}
float GetDamageToInflict(Actor target)
{
/* todo: some things can't be damaged AT ALL by certain weapons! */
var distance = (target.CenterLocation - Dest).Length;
var rawDamage = Weapon.Damage * (float)Math.Exp(-distance / Warhead.Spread);
var multiplier = Warhead.EffectivenessAgainst(target.unitInfo.Armor);
return rawDamage * multiplier;
}
} }
} }

View File

@@ -144,6 +144,12 @@ namespace OpenRa.Game
.Where(x => x.Bounds.IntersectsWith(rect)); .Where(x => x.Bounds.IntersectsWith(rect));
} }
public static IEnumerable<Actor> FindUnitsInCircle(float2 a, float r)
{
return FindUnits(a - new float2(r, r), a + new float2(r, r))
.Where(x => (x.CenterLocation - a).LengthSquared < r * r);
}
public static IEnumerable<Actor> SelectUnitsInBox(float2 a, float2 b) public static IEnumerable<Actor> SelectUnitsInBox(float2 a, float2 b)
{ {
return FindUnits(a, b).Where(x => x.Owner == LocalPlayer && x.traits.Contains<Traits.Mobile>()); return FindUnits(a, b).Where(x => x.Owner == LocalPlayer && x.traits.Contains<Traits.Mobile>());

View File

@@ -22,34 +22,34 @@ namespace OpenRa.Game.GameRules
if( fieldType == typeof( int ) ) if( fieldType == typeof( int ) )
return int.Parse( x ); return int.Parse( x );
else if( fieldType == typeof( float ) ) else if (fieldType == typeof(float))
return float.Parse( x ); return float.Parse(x.Replace("%","")) * (x.Contains( '%' ) ? 0.01f : 1f);
else if( fieldType == typeof( string ) ) else if (fieldType == typeof(string))
return x;//.ToLowerInvariant(); return x;//.ToLowerInvariant();
else if( fieldType.IsEnum ) else if (fieldType.IsEnum)
return Enum.Parse( fieldType, x ); return Enum.Parse(fieldType, x);
else if( fieldType == typeof( bool ) ) else if (fieldType == typeof(bool))
return ParseYesNo( x ); return ParseYesNo(x);
else if( fieldType.IsArray ) else if (fieldType.IsArray)
{ {
var parts = x.Split( new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries ); var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
var ret = Array.CreateInstance( fieldType.GetElementType(), parts.Length ); var ret = Array.CreateInstance(fieldType.GetElementType(), parts.Length);
for( int i = 0 ; i < parts.Length ; i++ ) for (int i = 0; i < parts.Length; i++)
ret.SetValue( GetValue( fieldType.GetElementType(), parts[ i ].Trim() ), i ); ret.SetValue(GetValue(fieldType.GetElementType(), parts[i].Trim()), i);
return ret; return ret;
} }
else if( fieldType == typeof( int2 ) ) else if (fieldType == typeof(int2))
{ {
var parts = x.Split( new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries ); var parts = x.Split(new char[] { ',' }, StringSplitOptions.RemoveEmptyEntries);
return new int2( int.Parse( parts[ 0 ] ), int.Parse( parts[ 1 ] ) ); return new int2(int.Parse(parts[0]), int.Parse(parts[1]));
} }
else else
throw new InvalidOperationException( "FieldLoader: don't know how to load field of type " + fieldType.ToString() ); throw new InvalidOperationException("FieldLoader: don't know how to load field of type " + fieldType.ToString());
} }
static bool ParseYesNo( string p ) static bool ParseYesNo( string p )

View File

@@ -7,8 +7,6 @@ using IjwFramework.Types;
namespace OpenRa.Game.GameRules namespace OpenRa.Game.GameRules
{ {
public class UnitInfo
{
public enum ArmorType public enum ArmorType
{ {
none = 0, none = 0,
@@ -18,6 +16,8 @@ namespace OpenRa.Game.GameRules
concrete = 4, concrete = 4,
} }
public class UnitInfo
{
public readonly string Name; public readonly string Name;
public readonly string Description = ""; public readonly string Description = "";

View File

@@ -10,11 +10,13 @@ namespace OpenRa.Game.GameRules
class WarheadInfo class WarheadInfo
{ {
public readonly int Spread = 1; public readonly int Spread = 1;
public readonly string Verses = "100%,100%,100%,100%,100%"; public readonly float[] Verses = { 1, 1, 1, 1, 1 };
public readonly bool Wall = false; public readonly bool Wall = false;
public readonly bool Wood = false; public readonly bool Wood = false;
public readonly bool Ore = false; public readonly bool Ore = false;
public readonly int Explosion = 0; public readonly int Explosion = 0;
public readonly int InfDeath = 0; public readonly int InfDeath = 0;
public float EffectivenessAgainst(ArmorType at) { return Verses[ (int)at ]; }
} }
} }

View File

@@ -57,7 +57,7 @@ namespace OpenRa.Game
Game.world.Add( new Actor( "mcv", new int2( 5, 5 ), Game.players[ 3 ]) ); Game.world.Add( new Actor( "mcv", new int2( 5, 5 ), Game.players[ 3 ]) );
Game.world.Add( new Actor( "mcv", new int2( 7, 5 ), Game.players[ 2 ] ) ); Game.world.Add( new Actor( "mcv", new int2( 7, 5 ), Game.players[ 2 ] ) );
Game.world.Add( new Actor( "mcv", new int2( 9, 5 ), Game.players[ 0 ] ) ); Game.world.Add( new Actor( "mcv", new int2( 9, 5 ), Game.players[ 0 ] ) );
var jeep = new Actor( "jeep", new int2( 9, 7 ), Game.players[ 1 ] ); var jeep = new Actor( "jeep", new int2( 9, 15 ), Game.players[ 1 ] );
Game.world.Add( jeep ); Game.world.Add( jeep );
var tank = new Actor( "3tnk", new int2( 12, 7 ), Game.players[ 1 ] ); var tank = new Actor( "3tnk", new int2( 12, 7 ), Game.players[ 1 ] );
Game.world.Add( tank ); Game.world.Add( tank );
@@ -77,10 +77,7 @@ namespace OpenRa.Game
while (Created && Visible) while (Created && Visible)
{ {
Game.Tick(); Game.Tick();
// rude hack
Game.viewport.cursor = Game.controller.ChooseCursor(); Game.viewport.cursor = Game.controller.ChooseCursor();
Application.DoEvents(); Application.DoEvents();
} }
} }

View File

@@ -4,6 +4,7 @@ namespace OpenRa.Game
class Player class Player
{ {
public int Palette; public int Palette;
public int Kills;
public string PlayerName; public string PlayerName;
public TechTree.TechTree TechTree = new OpenRa.TechTree.TechTree(); public TechTree.TechTree TechTree = new OpenRa.TechTree.TechTree();