Merge branch 'master' into minelayer
This commit is contained in:
@@ -50,7 +50,6 @@ namespace OpenRa.Game
|
||||
|
||||
public void Tick()
|
||||
{
|
||||
|
||||
while (currentActivity != null)
|
||||
{
|
||||
var a = currentActivity;
|
||||
@@ -93,11 +92,8 @@ namespace OpenRa.Game
|
||||
if (!Rules.Map.IsInMap(xy.X, xy.Y))
|
||||
return null;
|
||||
|
||||
// HACK: Get the first unit in the cell
|
||||
// This will need to be updated for multiple-infantry-in-a-cell
|
||||
// HACK: this doesn't work for targeting air units either
|
||||
var underCursor = Game.UnitInfluence.GetUnitsAt( xy ).FirstOrDefault()
|
||||
?? Game.BuildingInfluence.GetBuildingAt( xy );
|
||||
var loc = mi.Location + Game.viewport.Location;
|
||||
var underCursor = Game.FindUnits(loc, loc).FirstOrDefault();
|
||||
|
||||
if (underCursor != null && !underCursor.Info.Selectable)
|
||||
underCursor = null;
|
||||
@@ -107,19 +103,18 @@ namespace OpenRa.Game
|
||||
.FirstOrDefault( x => x != null );
|
||||
}
|
||||
|
||||
public RectangleF Bounds
|
||||
public RectangleF GetBounds(bool useAltitude)
|
||||
{
|
||||
get
|
||||
var size = SelectedSize;
|
||||
var loc = CenterLocation - 0.5f * size;
|
||||
|
||||
if (useAltitude)
|
||||
{
|
||||
var size = SelectedSize;
|
||||
var loc = CenterLocation - 0.5f * size;
|
||||
var unit = traits.GetOrDefault<Unit>();
|
||||
|
||||
if (unit != null)
|
||||
loc -= new float2(0, unit.Altitude);
|
||||
|
||||
return new RectangleF(loc.X, loc.Y, size.X, size.Y);
|
||||
if (unit != null) loc -= new float2(0, unit.Altitude);
|
||||
}
|
||||
|
||||
return new RectangleF(loc.X, loc.Y, size.X, size.Y);
|
||||
}
|
||||
|
||||
public bool IsDead { get { return Health <= 0; } }
|
||||
@@ -150,6 +145,8 @@ namespace OpenRa.Game
|
||||
|
||||
Game.world.AddFrameEndTask(w => w.Remove(this));
|
||||
}
|
||||
if (Health > Info.Strength)
|
||||
Health = Info.Strength;
|
||||
|
||||
var newState = GetDamageState();
|
||||
|
||||
|
||||
@@ -39,7 +39,7 @@ namespace OpenRa.Game
|
||||
|
||||
static float GetMaximumSpread(WeaponInfo weapon, WarheadInfo warhead)
|
||||
{
|
||||
return (int)(warhead.Spread * Math.Log(weapon.Damage, 2));
|
||||
return (int)(warhead.Spread * Math.Log(Math.Abs(weapon.Damage), 2));
|
||||
}
|
||||
|
||||
static float GetDamageToInflict(Actor target, int2 loc, WeaponInfo weapon, WarheadInfo warhead)
|
||||
|
||||
@@ -124,7 +124,7 @@ namespace OpenRa.Game
|
||||
{
|
||||
var mods = GetModifierKeys();
|
||||
var c = (orderGenerator is UnitOrderGenerator) ? orderGenerator.Order(dragEnd.ToInt2(),
|
||||
new MouseInput { Button = MouseButton.Right, Modifiers = mods })
|
||||
new MouseInput { Location = (Game.CellSize * dragEnd - Game.viewport.Location).ToInt2(), Button = MouseButton.Right, Modifiers = mods })
|
||||
.Where(o => o.Validate())
|
||||
.Select(o => CursorForOrderString(o.OrderString, o.Subject, o.TargetLocation))
|
||||
.FirstOrDefault(a => a != null) : null;
|
||||
|
||||
@@ -269,13 +269,19 @@ namespace OpenRa.Game
|
||||
var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y);
|
||||
|
||||
return world.Actors
|
||||
.Where(x => x.Bounds.IntersectsWith(rect));
|
||||
.Where(x => x.GetBounds(true).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);
|
||||
var min = a - new float2(r, r);
|
||||
var max = a + new float2(r, r);
|
||||
|
||||
var rect = new RectangleF(min.X, min.Y, max.X - min.X, max.Y - min.Y);
|
||||
|
||||
var inBox = world.Actors.Where(x => x.GetBounds(false).IntersectsWith(rect));
|
||||
|
||||
return inBox.Where(x => (x.CenterLocation - a).LengthSquared < r * r);
|
||||
}
|
||||
|
||||
public static IEnumerable<int2> FindTilesInCircle(int2 a, int r)
|
||||
|
||||
@@ -111,7 +111,7 @@ namespace OpenRa.Game.Graphics
|
||||
|
||||
public void DrawSelectionBox(Actor selectedUnit, Color c, bool drawHealthBar)
|
||||
{
|
||||
var bounds = selectedUnit.Bounds;
|
||||
var bounds = selectedUnit.GetBounds(true);
|
||||
|
||||
var xy = new float2(bounds.Left, bounds.Top);
|
||||
var Xy = new float2(bounds.Right, bounds.Top);
|
||||
|
||||
@@ -172,6 +172,7 @@
|
||||
<Compile Include="Traits\AttackBase.cs" />
|
||||
<Compile Include="Traits\AttackInfo.cs" />
|
||||
<Compile Include="Traits\AttackTurreted.cs" />
|
||||
<Compile Include="Traits\AutoHeal.cs" />
|
||||
<Compile Include="Traits\AutoTarget.cs" />
|
||||
<Compile Include="Traits\BelowUnits.cs" />
|
||||
<Compile Include="Traits\Building.cs" />
|
||||
|
||||
64
OpenRa.Game/Traits/AutoHeal.cs
Normal file
64
OpenRa.Game/Traits/AutoHeal.cs
Normal file
@@ -0,0 +1,64 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
|
||||
namespace OpenRa.Game.Traits
|
||||
{
|
||||
class AutoHeal : ITick
|
||||
{
|
||||
public AutoHeal(Actor self) { }
|
||||
|
||||
void AttackTarget(Actor self, Actor target)
|
||||
{
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
if (target != null)
|
||||
attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null));
|
||||
else
|
||||
self.CancelActivity();
|
||||
}
|
||||
|
||||
float GetMaximumRange(Actor self)
|
||||
{
|
||||
return new[] { self.Info.Primary, self.Info.Secondary }
|
||||
.Where(w => w != null)
|
||||
.Max(w => Rules.WeaponInfo[w].Range);
|
||||
}
|
||||
|
||||
bool NeedsNewTarget(Actor self)
|
||||
{
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var range = GetMaximumRange(self);
|
||||
|
||||
if (attack.target == null)
|
||||
return true; // he's dead.
|
||||
if ((attack.target.Location - self.Location).LengthSquared > range * range + 2)
|
||||
return true; // wandered off faster than we could follow
|
||||
if (attack.target.Health == attack.target.Info.Strength)
|
||||
return true; // fully healed
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var range = GetMaximumRange(self);
|
||||
|
||||
if (NeedsNewTarget(self))
|
||||
AttackTarget(self, ChooseTarget(self, range));
|
||||
}
|
||||
|
||||
Actor ChooseTarget(Actor self, float range)
|
||||
{
|
||||
var inRange = Game.FindUnitsInCircle(self.CenterLocation, Game.CellSize * range);
|
||||
|
||||
return inRange
|
||||
.Where(a => a.Owner == self.Owner) /* todo: one day deal with friendly players */
|
||||
.Where(a => Combat.HasAnyValidWeapons(self, a))
|
||||
.Where(a => a.Health < a.Info.Strength)
|
||||
.OrderBy(a => (a.Location - self.Location).LengthSquared)
|
||||
.FirstOrDefault();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,16 +16,23 @@ namespace OpenRa.Game.Traits
|
||||
attack.ResolveOrder(self, new Order("Attack", self, target, int2.Zero, null));
|
||||
}
|
||||
|
||||
float GetMaximumRange(Actor self)
|
||||
{
|
||||
return new[] { self.Info.Primary, self.Info.Secondary }
|
||||
.Where(w => w != null)
|
||||
.Max(w => Rules.WeaponInfo[w].Range);
|
||||
}
|
||||
|
||||
public void Tick(Actor self)
|
||||
{
|
||||
if (!self.IsIdle) return;
|
||||
|
||||
var attack = self.traits.WithInterface<AttackBase>().First();
|
||||
var range = Rules.WeaponInfo[self.Info.Primary].Range;
|
||||
var range = GetMaximumRange(self);
|
||||
|
||||
if (attack.target == null ||
|
||||
(attack.target.Location - self.Location).LengthSquared > range * range + 2)
|
||||
attack.target = ChooseTarget(self, range);
|
||||
AttackTarget(self, ChooseTarget(self, range));
|
||||
}
|
||||
|
||||
Actor ChooseTarget(Actor self, float range)
|
||||
|
||||
@@ -35,7 +35,7 @@ namespace OpenRa.Game.Traits
|
||||
{
|
||||
if (doneBuilding) roof.Tick();
|
||||
|
||||
var b = self.Bounds;
|
||||
var b = self.GetBounds(false);
|
||||
if (isOpen && !Game.UnitInfluence.GetUnitsAt(((1/24f) * self.CenterLocation).ToInt2()).Any())
|
||||
{
|
||||
isOpen = false;
|
||||
|
||||
@@ -4,11 +4,11 @@ Ground Units:
|
||||
All Infantry No idle animations
|
||||
E1 Range is wrong.
|
||||
E2 Grenades are too accurate.
|
||||
E3 AA weapon doesn't work.
|
||||
E3 Works
|
||||
E4 Flamer origin is wrong
|
||||
E6 Capture action missing, repair action missing
|
||||
E7 C4 action missing
|
||||
MEDI Heal doesn't work
|
||||
MEDI Heal targeting is wrong
|
||||
SPY Infiltrate action missing
|
||||
THF Steal action missing
|
||||
C1,C2,Einstein,Kosygin Not implemented
|
||||
@@ -33,7 +33,6 @@ ARTY Works
|
||||
Helicopters
|
||||
- Weapons don't work,
|
||||
- hover while attacking doesn't work,
|
||||
- render is broken (altitude) -- less broken, but there are Z-order issues.
|
||||
- Repair/rearm doesn't work
|
||||
TRAN Cargo doesn't work
|
||||
|
||||
|
||||
@@ -2411,7 +2411,7 @@ InfDeath=5
|
||||
|
||||
; special case to only affect infantry (do not use for regular weapons)
|
||||
[Organic]
|
||||
Spread=0
|
||||
Spread=5
|
||||
Verses=100%,0%,0%,0%,0%
|
||||
InfDeath=0
|
||||
|
||||
|
||||
@@ -7,4 +7,5 @@
|
||||
s0=Multi0,mcv,600,2841,0,Guard,None
|
||||
s1=Multi2,mcv,600,12445,0,Guard,None
|
||||
s2=Multi1,mcv,600,12505,0,Guard,None
|
||||
;s2=Multi1,e3,600,12505,0,Guard,None
|
||||
s3=Multi3,mcv,600,2910,0,Guard,None
|
||||
@@ -249,7 +249,7 @@ InitialFacing=224
|
||||
LongDesc=Anti-Air base defense.\n Strong vs Aircraft\n Weak vs Infantry, Tanks
|
||||
[FTUR]
|
||||
Description=Flame Turret
|
||||
Traits=Building, RenderBuilding, AttackTurreted, AutoTarget
|
||||
Traits=Turreted, Building, RenderBuilding, AttackTurreted, AutoTarget
|
||||
Dimensions=1,1
|
||||
Footprint=x
|
||||
SelectionPriority=3
|
||||
@@ -578,7 +578,7 @@ LongDesc=Elite commando infantry, armed with \ndual pistols and C4.\n Strong vs
|
||||
[MEDI]
|
||||
Description=Medic
|
||||
Voice=MedicVoice
|
||||
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry, AutoTarget
|
||||
Traits=Unit, Mobile, RenderInfantry, AttackBase, TakeCover, Infantry, AutoHeal
|
||||
LongDesc=Heals nearby infantry.\n Strong vs Nothing\n Weak vs Everything
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user