introduce collection of Turrets on AttackBase, too -- turret sharing w/ recoil works again
This commit is contained in:
@@ -37,22 +37,33 @@ namespace OpenRA.Mods.RA
|
|||||||
}
|
}
|
||||||
|
|
||||||
public class Barrel { public int2 Position; public int Facing; /* relative to turret */ }
|
public class Barrel { public int2 Position; public int Facing; /* relative to turret */ }
|
||||||
|
public class Turret
|
||||||
|
{
|
||||||
|
public float Recoil = 0.0f; // remaining recoil fraction
|
||||||
|
public int2 UnitSpacePosition; // where, in the unit's local space.
|
||||||
|
public int2 ScreenSpacePosition; // screen-space hack to make things line up good.
|
||||||
|
|
||||||
|
public Turret(int[] offset)
|
||||||
|
{
|
||||||
|
ScreenSpacePosition = offset.AbsOffset().ToInt2();
|
||||||
|
UnitSpacePosition = offset.RelOffset().ToInt2();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public class Weapon
|
public class Weapon
|
||||||
{
|
{
|
||||||
public WeaponInfo Info;
|
public WeaponInfo Info;
|
||||||
public int FireDelay = 0; // time (in frames) until the weapon can fire again
|
public int FireDelay = 0; // time (in frames) until the weapon can fire again
|
||||||
public int Burst = 0; // burst counter
|
public int Burst = 0; // burst counter
|
||||||
public float Recoil = 0.0f; // remaining recoil fraction
|
|
||||||
|
|
||||||
public int[] Offset;
|
public Barrel[] Barrels; // where projectiles are spawned, in local turret space.
|
||||||
public Barrel[] Barrels;
|
public Turret Turret; // where this weapon is mounted
|
||||||
|
|
||||||
public Weapon(string weaponName, int[] offset, int[] localOffset)
|
public Weapon(string weaponName, Turret turret, int[] localOffset)
|
||||||
{
|
{
|
||||||
Info = Rules.Weapons[weaponName.ToLowerInvariant()];
|
Info = Rules.Weapons[weaponName.ToLowerInvariant()];
|
||||||
Burst = Info.Burst;
|
Burst = Info.Burst;
|
||||||
Offset = offset;
|
Turret = turret;
|
||||||
|
|
||||||
var barrels = new List<Barrel>();
|
var barrels = new List<Barrel>();
|
||||||
for (var i = 0; i < localOffset.Length / 3; i++)
|
for (var i = 0; i < localOffset.Length / 3; i++)
|
||||||
@@ -74,13 +85,26 @@ namespace OpenRA.Mods.RA
|
|||||||
public void Tick()
|
public void Tick()
|
||||||
{
|
{
|
||||||
if (FireDelay > 0) --FireDelay;
|
if (FireDelay > 0) --FireDelay;
|
||||||
Recoil = Math.Max(0f, Recoil - .2f);
|
Turret.Recoil = Math.Max(0f, Turret.Recoil - .2f);
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool IsValidAgainst(Target target)
|
public bool IsValidAgainst(Target target)
|
||||||
{
|
{
|
||||||
return Combat.WeaponValidForTarget(Info, target);
|
return Combat.WeaponValidForTarget(Info, target);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void FiredShot()
|
||||||
|
{
|
||||||
|
Turret.Recoil = 1;
|
||||||
|
|
||||||
|
if (--Burst > 0)
|
||||||
|
FireDelay = Info.BurstDelay;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
FireDelay = Info.ROF;
|
||||||
|
Burst = Info.Burst;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderCursor, IOrderVoice
|
public class AttackBase : IIssueOrder, IResolveOrder, ITick, IExplodeModifier, IOrderCursor, IOrderVoice
|
||||||
@@ -88,18 +112,23 @@ namespace OpenRA.Mods.RA
|
|||||||
public Target target;
|
public Target target;
|
||||||
|
|
||||||
public List<Weapon> Weapons = new List<Weapon>();
|
public List<Weapon> Weapons = new List<Weapon>();
|
||||||
|
public List<Turret> Turrets = new List<Turret>();
|
||||||
|
|
||||||
public AttackBase(Actor self)
|
public AttackBase(Actor self)
|
||||||
{
|
{
|
||||||
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
var info = self.Info.Traits.Get<AttackBaseInfo>();
|
||||||
|
|
||||||
|
Turrets.Add(new Turret(info.PrimaryOffset));
|
||||||
|
if (info.SecondaryOffset != null)
|
||||||
|
Turrets.Add(new Turret(info.SecondaryOffset));
|
||||||
|
|
||||||
if (info.PrimaryWeapon != null)
|
if (info.PrimaryWeapon != null)
|
||||||
Weapons.Add(new Weapon(info.PrimaryWeapon,
|
Weapons.Add(new Weapon(info.PrimaryWeapon,
|
||||||
info.PrimaryOffset, info.PrimaryLocalOffset));
|
Turrets[0], info.PrimaryLocalOffset));
|
||||||
|
|
||||||
if (info.SecondaryWeapon != null)
|
if (info.SecondaryWeapon != null)
|
||||||
Weapons.Add(new Weapon(info.SecondaryWeapon,
|
Weapons.Add(new Weapon(info.SecondaryWeapon,
|
||||||
info.SecondaryOffset ?? info.PrimaryOffset, info.SecondaryLocalOffset));
|
info.SecondaryOffset != null ? Turrets[1] : Turrets[0], info.SecondaryLocalOffset));
|
||||||
}
|
}
|
||||||
|
|
||||||
protected virtual bool CanAttack(Actor self)
|
protected virtual bool CanAttack(Actor self)
|
||||||
@@ -149,7 +178,7 @@ namespace OpenRA.Mods.RA
|
|||||||
|
|
||||||
foreach (var w in Weapons)
|
foreach (var w in Weapons)
|
||||||
if (CheckFire(self, unit, w))
|
if (CheckFire(self, unit, w))
|
||||||
w.Recoil = 1;
|
w.FiredShot();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool CheckFire(Actor self, Unit unit, Weapon w)
|
bool CheckFire(Actor self, Unit unit, Weapon w)
|
||||||
@@ -168,18 +197,10 @@ namespace OpenRA.Mods.RA
|
|||||||
var barrel = w.Barrels[w.Burst % w.Barrels.Length];
|
var barrel = w.Barrels[w.Burst % w.Barrels.Length];
|
||||||
|
|
||||||
var fireOffset = new[] {
|
var fireOffset = new[] {
|
||||||
w.Offset.ElementAtOrDefault(0) + barrel.Position.X,
|
w.Turret.UnitSpacePosition.X + barrel.Position.X,
|
||||||
w.Offset.ElementAtOrDefault(1) + barrel.Position.Y,
|
w.Turret.UnitSpacePosition.Y + barrel.Position.Y,
|
||||||
w.Offset.ElementAtOrDefault(2),
|
w.Turret.ScreenSpacePosition.X,
|
||||||
w.Offset.ElementAtOrDefault(3) };
|
w.Turret.ScreenSpacePosition.Y }; // todo: retardage.
|
||||||
|
|
||||||
if (--w.Burst > 0)
|
|
||||||
w.FireDelay = w.Info.BurstDelay;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
w.FireDelay = w.Info.ROF;
|
|
||||||
w.Burst = w.Info.Burst;
|
|
||||||
}
|
|
||||||
|
|
||||||
var destUnit = target.IsActor ? target.Actor.traits.GetOrDefault<Unit>() : null;
|
var destUnit = target.IsActor ? target.Actor.traits.GetOrDefault<Unit>() : null;
|
||||||
|
|
||||||
@@ -310,10 +331,6 @@ namespace OpenRA.Mods.RA
|
|||||||
Math.Max(0, (int)weapon.Info.Range)));
|
Math.Max(0, (int)weapon.Info.Range)));
|
||||||
}
|
}
|
||||||
|
|
||||||
/* temp hack */
|
|
||||||
public float GetPrimaryRecoil() { return Weapons.Count > 0 ? Weapons[0].Recoil : 0; }
|
|
||||||
public float GetSecondaryRecoil() { return Weapons.Count > 1 ? Weapons[1].Recoil : 0; }
|
|
||||||
|
|
||||||
public bool HasAnyValidWeapons(Target t) { return Weapons.Any(w => w.IsValidAgainst(t)); }
|
public bool HasAnyValidWeapons(Target t) { return Weapons.Any(w => w.IsValidAgainst(t)); }
|
||||||
public float GetMaximumRange() { return Weapons.Max(w => w.Info.Range); }
|
public float GetMaximumRange() { return Weapons.Max(w => w.Info.Range); }
|
||||||
|
|
||||||
|
|||||||
@@ -202,5 +202,18 @@ namespace OpenRA.Mods.RA
|
|||||||
return (Util.RotateVectorByFacing(offset.RelOffset(), quantizedFacing, .7f) + GetRecoil(self, recoil))
|
return (Util.RotateVectorByFacing(offset.RelOffset(), quantizedFacing, .7f) + GetRecoil(self, recoil))
|
||||||
+ offset.AbsOffset();
|
+ offset.AbsOffset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static float2 GetTurretPosition(Actor self, Unit unit, Turret turret)
|
||||||
|
{
|
||||||
|
if (unit == null) return turret.ScreenSpacePosition;
|
||||||
|
|
||||||
|
var ru = self.traits.GetOrDefault<RenderUnit>();
|
||||||
|
var numDirs = (ru != null) ? ru.anim.CurrentSequence.Facings : 8;
|
||||||
|
var bodyFacing = unit.Facing;
|
||||||
|
var quantizedFacing = Util.QuantizeFacing(bodyFacing, numDirs) * (256 / numDirs);
|
||||||
|
|
||||||
|
return (Util.RotateVectorByFacing(turret.UnitSpacePosition, quantizedFacing, .7f) + GetRecoil(self, turret.Recoil))
|
||||||
|
+ turret.ScreenSpacePosition;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,27 +31,24 @@ namespace OpenRA.Mods.RA.Render
|
|||||||
var turretAnim = new Animation(GetImage(self), () => turreted.turretFacing );
|
var turretAnim = new Animation(GetImage(self), () => turreted.turretFacing );
|
||||||
turretAnim.Play( "turret" );
|
turretAnim.Play( "turret" );
|
||||||
|
|
||||||
if( attackInfo.PrimaryOffset != null )
|
for( var i = 0; i < attack.Turrets.Count; i++ )
|
||||||
anims.Add("turret_1", new AnimationWithOffset(
|
|
||||||
turretAnim,
|
|
||||||
() => Combat.GetTurretPosition(self, unit, attackInfo.PrimaryOffset, attack.GetPrimaryRecoil()),
|
|
||||||
null) { ZOffset = 1 });
|
|
||||||
|
|
||||||
if (attackInfo.SecondaryOffset != null)
|
|
||||||
anims.Add("turret_2", new AnimationWithOffset(
|
|
||||||
turretAnim,
|
|
||||||
() => Combat.GetTurretPosition(self, unit, attackInfo.SecondaryOffset, attack.GetSecondaryRecoil()),
|
|
||||||
null) { ZOffset = 1 });
|
|
||||||
|
|
||||||
if( attackInfo.MuzzleFlash )
|
|
||||||
{
|
{
|
||||||
var muzzleFlash = new Animation( GetImage(self), () => self.traits.Get<Turreted>().turretFacing );
|
var turret = attack.Turrets[i];
|
||||||
muzzleFlash.PlayFetchIndex( "muzzle",
|
anims.Add( "turret_{0}".F(i),
|
||||||
() => (int)(attack.GetPrimaryRecoil() * 5.9f)); /* hack: recoil can be 1.0f, but don't overflow into next anim */
|
new AnimationWithOffset( turretAnim,
|
||||||
anims.Add( "muzzle_flash", new AnimationWithOffset(
|
() => Combat.GetTurretPosition( self, unit, turret ),
|
||||||
muzzleFlash,
|
null) { ZOffset = 1 });
|
||||||
() => Combat.GetTurretPosition(self, unit, attackInfo.PrimaryOffset, attack.GetPrimaryRecoil()),
|
|
||||||
() => attack.GetPrimaryRecoil() <= 0));
|
if (attackInfo.MuzzleFlash)
|
||||||
|
{
|
||||||
|
var muzzleFlash = new Animation(GetImage(self), () => turreted.turretFacing);
|
||||||
|
muzzleFlash.PlayFetchIndex("muzzle",
|
||||||
|
() => (int)(turret.Recoil * 5.9f)); /* hack: dumb crap */
|
||||||
|
anims.Add("muzzle_flash_{0}".F(i),
|
||||||
|
new AnimationWithOffset(muzzleFlash,
|
||||||
|
() => Combat.GetTurretPosition(self, unit, turret),
|
||||||
|
() => turret.Recoil <= 0));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user