Merge pull request #4828 from pchote/cursors

Cursor improvements
This commit is contained in:
Matthias Mailänder
2014-03-12 12:52:01 +01:00
26 changed files with 201 additions and 140 deletions

View File

@@ -24,6 +24,7 @@ NEW:
Fixed chat synchronization in replays.
Fixed the game sometimes crashing when deploying and activating the guard cursor at the same time.
Build time is now set when an item reaches the front of a queue, instead of immediately when queued.
The attack cursor now changes if the target is out of range.
Dune 2000:
Added the Atreides grenadier from the 1.06 patch.
Added randomized tiles for Sand and Rock terrain.
@@ -56,6 +57,7 @@ NEW:
Fixed spies staying on the minimap after infiltration.
Added maps: Blitzkrieg and Burlesca by s1w.
Both Allied and Soviet factions now build general-purpose mines instead of AT and AP mines respectively.
Added new attack-move cursor artwork.
Tiberian Dawn:
Chinook rotors now counter-rotate.
Commando can now plant C4 on bridges.
@@ -83,6 +85,7 @@ NEW:
Increased the chance of Tiberium or chemical deaths spawning a Visceroid from 2% to 10%.
Increased Obelisk of Light laser damage from 200 to 360.
Fixed Obelisk of Light charge animation and sound not playing.
Replaced or improved several mouse cursors.
Engine:
Converted Aircraft CruiseAltitude to world coordinates.
Converted Health Radius to world coordinates.

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -19,11 +19,12 @@ namespace OpenRA.Mods.RA.Air
class AttackHeli : AttackFrontal
{
public AttackHeli(Actor self, AttackHeliInfo info) : base(self, info) { }
public AttackHeli(Actor self, AttackHeliInfo info)
: base(self, info) { }
public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove)
{
return new HeliAttack( newTarget );
return new HeliAttack(newTarget);
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -19,7 +19,8 @@ namespace OpenRA.Mods.RA.Air
class AttackPlane : AttackFrontal
{
public AttackPlane(Actor self, AttackPlaneInfo info) : base(self, info) { }
public AttackPlane(Actor self, AttackPlaneInfo info)
: base(self, info) { }
public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove)
{

View File

@@ -20,6 +20,7 @@ namespace OpenRA.Mods.RA
public abstract class AttackBaseInfo : ITraitInfo
{
public readonly string Cursor = "attack";
public readonly string OutsideRangeCursor = "attackoutsiderange";
public abstract object Create(ActorInitializer init);
}
@@ -29,14 +30,20 @@ namespace OpenRA.Mods.RA
[Sync] public bool IsAttacking { get; internal set; }
readonly Actor self;
readonly AttackBaseInfo info;
protected Lazy<IFacing> facing;
Lazy<IEnumerable<Armament>> armaments;
protected IEnumerable<Armament> Armaments { get { return armaments.Value; } }
List<Pair<int, Action>> delayedActions = new List<Pair<int, Action>>();
public AttackBase(Actor self)
public AttackBase(Actor self, AttackBaseInfo info)
{
this.self = self;
this.info = info;
armaments = Lazy.New(() => self.TraitsImplementing<Armament>());
facing = Lazy.New(() => self.TraitOrDefault<IFacing>());
}
protected virtual bool CanAttack(Actor self, Target target)
@@ -60,8 +67,6 @@ namespace OpenRA.Mods.RA
public bool IsReloading() { return Armaments.Any(a => a.IsReloading); }
List<Pair<int, Action>> delayedActions = new List<Pair<int, Action>>();
public virtual void Tick(Actor self)
{
for (var i = 0; i < delayedActions.Count; i++)
@@ -88,9 +93,8 @@ namespace OpenRA.Mods.RA
if (!CanAttack(self, target))
return;
var facing = self.TraitOrDefault<IFacing>();
foreach (var a in Armaments)
a.CheckFire(self, this, facing, target);
a.CheckFire(self, this, facing.Value, target);
}
public IEnumerable<IOrderTargeter> Orders
@@ -101,7 +105,7 @@ namespace OpenRA.Mods.RA
yield break;
var negativeDamage = Armaments.First().Weapon.Warheads[0].Damage < 0;
yield return new AttackOrderTargeter("Attack", 6, negativeDamage);
yield return new AttackOrderTargeter(this, "Attack", 6, negativeDamage);
}
}
@@ -168,9 +172,11 @@ namespace OpenRA.Mods.RA
class AttackOrderTargeter : IOrderTargeter
{
readonly bool negativeDamage;
readonly AttackBase ab;
public AttackOrderTargeter(string order, int priority, bool negativeDamage)
public AttackOrderTargeter(AttackBase ab, string order, int priority, bool negativeDamage)
{
this.ab = ab;
this.OrderID = order;
this.OrderPriority = priority;
this.negativeDamage = negativeDamage;
@@ -183,12 +189,15 @@ namespace OpenRA.Mods.RA
{
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
cursor = self.Info.Traits.Get<AttackBaseInfo>().Cursor;
var a = ab.ChooseArmamentForTarget(target);
cursor = a != null && !target.IsInRange(self.CenterPosition, a.Weapon.Range)
? ab.info.OutsideRangeCursor
: ab.info.Cursor;
if (target.Type == TargetType.Actor && target.Actor == self)
return false;
if (!self.Trait<AttackBase>().HasAnyValidWeapons(target))
if (!ab.HasAnyValidWeapons(target))
return false;
if (modifiers.HasModifier(TargetModifiers.ForceAttack))
@@ -210,16 +219,23 @@ namespace OpenRA.Mods.RA
IsQueued = modifiers.HasModifier(TargetModifiers.ForceQueue);
cursor = self.Info.Traits.Get<AttackBaseInfo>().Cursor;
cursor = ab.info.Cursor;
if (negativeDamage)
return false;
if (!self.Trait<AttackBase>().HasAnyValidWeapons(Target.FromCell(location)))
if (!ab.HasAnyValidWeapons(Target.FromCell(location)))
return false;
if (modifiers.HasModifier(TargetModifiers.ForceAttack))
{
var maxRange = ab.GetMaximumRange().Range;
var targetRange = (location.CenterPosition - self.CenterPosition).HorizontalLengthSquared;
if (targetRange > maxRange * maxRange)
cursor = ab.info.OutsideRangeCursor;
return true;
}
return false;
}

View File

@@ -8,8 +8,8 @@
*/
#endregion
using OpenRA.Mods.RA.Activities;
using OpenRA.FileFormats;
using OpenRA.Mods.RA.Activities;
using OpenRA.Mods.RA.Render;
using OpenRA.Traits;
@@ -24,39 +24,41 @@ namespace OpenRA.Mods.RA
public readonly int InitialChargeDelay = 22;
[Desc("Delay for additional charges if MaxCharge is larger than 1.")]
public readonly int ChargeDelay = 3;
public override object Create(ActorInitializer init) { return new AttackCharge(init.self); }
public override object Create(ActorInitializer init) { return new AttackCharge(init.self, this); }
}
class AttackCharge : AttackOmni, ITick, INotifyAttack, ISync
{
readonly AttackChargeInfo aci;
[Sync] int charges;
[Sync] int timeToRecharge;
public AttackCharge(Actor self)
: base(self)
public AttackCharge(Actor self, AttackChargeInfo info)
: base(self, info)
{
charges = self.Info.Traits.Get<AttackChargeInfo>().MaxCharges;
aci = self.Info.Traits.Get<AttackChargeInfo>();
charges = aci.MaxCharges;
}
public override void Tick( Actor self )
public override void Tick(Actor self)
{
if( --timeToRecharge <= 0 )
charges = self.Info.Traits.Get<AttackChargeInfo>().MaxCharges;
if (--timeToRecharge <= 0)
charges = aci.MaxCharges;
base.Tick( self );
base.Tick(self);
}
public void Attacking(Actor self, Target target, Armament a, Barrel barrel)
{
--charges;
timeToRecharge = self.Info.Traits.Get<AttackChargeInfo>().ReloadTime;
timeToRecharge = aci.ReloadTime;
}
public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove)
{
return new ChargeAttack(newTarget);
}
public override void ResolveOrder(Actor self, Order order)
{
@@ -82,7 +84,7 @@ namespace OpenRA.Mods.RA
var initDelay = self.Info.Traits.Get<AttackChargeInfo>().InitialChargeDelay;
var attack = self.Trait<AttackCharge>();
if(attack.charges == 0 || !attack.CanAttack(self, target))
if (attack.charges == 0 || !attack.CanAttack(self, target))
return this;
self.Trait<RenderBuildingCharge>().PlayCharge(self);
@@ -106,7 +108,7 @@ namespace OpenRA.Mods.RA
var chargeDelay = self.Info.Traits.Get<AttackChargeInfo>().ChargeDelay;
var attack = self.Trait<AttackCharge>();
if(attack.charges == 0)
if (attack.charges == 0)
return NextActivity;
attack.DoAttack(self, target);

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -15,7 +15,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
[Desc("Unit got to face the target")]
public class AttackFrontalInfo : AttackBaseInfo
public class AttackFrontalInfo : AttackBaseInfo, Requires<IFacingInfo>
{
public readonly int FacingTolerance = 1;
@@ -27,7 +27,7 @@ namespace OpenRA.Mods.RA
readonly AttackFrontalInfo info;
public AttackFrontal(Actor self, AttackFrontalInfo info)
: base(self)
: base(self, info)
{
this.info = info;
}
@@ -37,10 +37,10 @@ namespace OpenRA.Mods.RA
if (!base.CanAttack(self, target))
return false;
var facing = self.Trait<IFacing>().Facing;
var facingToTarget = Util.GetFacing(target.CenterPosition - self.CenterPosition, facing);
var f = facing.Value.Facing;
var facingToTarget = Util.GetFacing(target.CenterPosition - self.CenterPosition, f);
if (Math.Abs(facingToTarget - facing) % 256 > info.FacingTolerance)
if (Math.Abs(facingToTarget - f) % 256 > info.FacingTolerance)
return false;
return true;

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -21,7 +21,7 @@ namespace OpenRA.Mods.RA
public class AttackLoyalty : AttackFrontal
{
public AttackLoyalty(Actor self, AttackLoyaltyInfo info)
: base( self, info ) {}
: base(self, info) { }
public override void DoAttack(Actor self, Target target)
{

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -15,7 +15,7 @@ namespace OpenRA.Mods.RA
{
class AttackOmniInfo : AttackBaseInfo
{
public override object Create(ActorInitializer init) { return new AttackOmni(init.self); }
public override object Create(ActorInitializer init) { return new AttackOmni(init.self, this); }
}
class AttackOmni : AttackBase, INotifyBuildComplete, ISync
@@ -23,30 +23,37 @@ namespace OpenRA.Mods.RA
[Sync] bool buildComplete = false;
public void BuildingComplete(Actor self) { buildComplete = true; }
public AttackOmni(Actor self) : base(self) { }
public AttackOmni(Actor self, AttackOmniInfo info)
: base(self, info) { }
protected override bool CanAttack( Actor self, Target target )
protected override bool CanAttack(Actor self, Target target)
{
var isBuilding = ( self.HasTrait<Building>() && !buildComplete );
return base.CanAttack( self, target ) && !isBuilding;
var isBuilding = self.HasTrait<Building>() && !buildComplete;
return base.CanAttack(self, target) && !isBuilding;
}
public override Activity GetAttackActivity(Actor self, Target newTarget, bool allowMove)
{
return new SetTarget( newTarget );
return new SetTarget(newTarget, this);
}
class SetTarget : Activity
{
readonly Target target;
public SetTarget( Target target ) { this.target = target; }
readonly AttackOmni ao;
public override Activity Tick( Actor self )
public SetTarget(Target target, AttackOmni ao)
{
this.target = target;
this.ao = ao;
}
public override Activity Tick(Actor self)
{
if (IsCanceled || !target.IsValidFor(self))
return NextActivity;
self.Trait<AttackOmni>().DoAttack(self, target);
ao.DoAttack(self, target);
return this;
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -16,73 +16,74 @@ using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
class AttackPopupTurretedInfo : AttackTurretedInfo
class AttackPopupTurretedInfo : AttackTurretedInfo, Requires<BuildingInfo>, Requires<RenderBuildingInfo>
{
public int CloseDelay = 125;
public int DefaultFacing = 0;
public float ClosedDamageMultiplier = 0.5f;
public override object Create(ActorInitializer init) { return new AttackPopupTurreted( init, this ); }
public override object Create(ActorInitializer init) { return new AttackPopupTurreted(init, this); }
}
class AttackPopupTurreted : AttackTurreted, INotifyBuildComplete, INotifyIdle, IDamageModifier
{
enum PopupState { Open, Rotating, Transitioning, Closed };
enum PopupState { Open, Rotating, Transitioning, Closed }
AttackPopupTurretedInfo Info;
int IdleTicks = 0;
PopupState State = PopupState.Open;
AttackPopupTurretedInfo info;
RenderBuilding rb;
int idleTicks = 0;
PopupState state = PopupState.Open;
Turreted turret;
public AttackPopupTurreted(ActorInitializer init, AttackPopupTurretedInfo info) : base(init.self)
public AttackPopupTurreted(ActorInitializer init, AttackPopupTurretedInfo info)
: base(init.self, info)
{
Info = info;
this.info = info;
buildComplete = init.Contains<SkipMakeAnimsInit>();
turret = turrets.FirstOrDefault();
rb = init.self.Trait<RenderBuilding>();
}
protected override bool CanAttack( Actor self, Target target )
protected override bool CanAttack(Actor self, Target target)
{
if (State == PopupState.Transitioning)
if (state == PopupState.Transitioning || !buildComplete)
return false;
if( self.HasTrait<Building>() && !buildComplete )
if (!base.CanAttack(self, target))
return false;
if (!base.CanAttack( self, target ))
return false;
IdleTicks = 0;
if (State == PopupState.Closed)
idleTicks = 0;
if (state == PopupState.Closed)
{
State = PopupState.Transitioning;
var rb = self.Trait<RenderBuilding>();
state = PopupState.Transitioning;
rb.PlayCustomAnimThen(self, "opening", () =>
{
State = PopupState.Open;
state = PopupState.Open;
rb.PlayCustomAnimRepeating(self, "idle");
});
return false;
}
if (!turret.FaceTarget(self,target)) return false;
if (!turret.FaceTarget(self, target))
return false;
return true;
}
public void TickIdle(Actor self)
{
if (State == PopupState.Open && IdleTicks++ > Info.CloseDelay)
if (state == PopupState.Open && idleTicks++ > info.CloseDelay)
{
turret.desiredFacing = Info.DefaultFacing;
State = PopupState.Rotating;
turret.desiredFacing = info.DefaultFacing;
state = PopupState.Rotating;
}
else if (State == PopupState.Rotating && turret.turretFacing == Info.DefaultFacing)
else if (state == PopupState.Rotating && turret.turretFacing == info.DefaultFacing)
{
State = PopupState.Transitioning;
var rb = self.Trait<RenderBuilding>();
state = PopupState.Transitioning;
rb.PlayCustomAnimThen(self, "closing", () =>
{
State = PopupState.Closed;
state = PopupState.Closed;
rb.PlayCustomAnimRepeating(self, "closed-idle");
turret.desiredFacing = null;
});
@@ -94,17 +95,17 @@ namespace OpenRA.Mods.RA
// Set true for SkipMakeAnimsInit
if (buildComplete)
{
State = PopupState.Closed;
self.Trait<RenderBuilding>()
.PlayCustomAnimRepeating(self, "closed-idle");
state = PopupState.Closed;
rb.PlayCustomAnimRepeating(self, "closed-idle");
turret.desiredFacing = null;
}
buildComplete = true;
}
public float GetDamageModifier(Actor attacker, WarheadInfo warhead)
{
return State == PopupState.Closed ? Info.ClosedDamageMultiplier : 1f;
return state == PopupState.Closed ? info.ClosedDamageMultiplier : 1f;
}
}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -19,7 +19,7 @@ namespace OpenRA.Mods.RA
{
class AttackTurretedInfo : AttackBaseInfo, Requires<TurretedInfo>
{
public override object Create(ActorInitializer init) { return new AttackTurreted(init.self); }
public override object Create(ActorInitializer init) { return new AttackTurreted(init.self, this); }
}
class AttackTurreted : AttackBase, INotifyBuildComplete, ISync
@@ -28,7 +28,8 @@ namespace OpenRA.Mods.RA
protected IEnumerable<Turreted> turrets;
[Sync] protected bool buildComplete;
public AttackTurreted(Actor self) : base(self)
public AttackTurreted(Actor self, AttackTurretedInfo info)
: base(self, info)
{
turrets = self.TraitsImplementing<Turreted>();
}
@@ -41,11 +42,13 @@ namespace OpenRA.Mods.RA
if (!target.IsValidFor(self))
return false;
bool canAttack = false;
var canAttack = false;
foreach (var t in turrets)
if (t.FaceTarget(self, target))
canAttack = true;
if (!canAttack) return false;
if (!canAttack)
return false;
return base.CanAttack(self, target);
}
@@ -88,7 +91,8 @@ namespace OpenRA.Mods.RA
if (IsCanceled || !target.IsValidFor(self))
return NextActivity;
if (self.IsDisabled()) return this;
if (self.IsDisabled())
return this;
var attack = self.Trait<AttackTurreted>();
const int RangeTolerance = 1; /* how far inside our maximum range we should try to sit */

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2013 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2014 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
@@ -35,7 +35,7 @@ namespace OpenRA.Mods.RA
[Sync] Target target;
public AttackBomber(Actor self, AttackBomberInfo info)
: base(self)
: base(self, info)
{
this.info = info;
this.camera = null;

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
mods/cnc/bits/mouse5.shp Normal file

Binary file not shown.

BIN
mods/cnc/bits/mouse6.shp Normal file

Binary file not shown.

BIN
mods/cnc/bits/mouse7.shp Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -1,7 +1,5 @@
Palettes:
cursor: cursor.pal
cursor2: racursor.pal
Cursors:
mouse2.shp: cursor
@@ -40,11 +38,6 @@ Cursors:
select:
start:12
length:6
default:
start:0
x: -16
y: -12
default-minimap:
start:86
length:1
@@ -78,12 +71,6 @@ Cursors:
c4-minimap:
start:127
length:3
guard:
start:153
length:1
guard-minimap:
start:152
length:1
# Cursors that need minimap variants
deploy:
@@ -114,66 +101,81 @@ Cursors:
start:154
length:24
mouse3.shp: cursor
default:
start:0
x: -16
y: -12
deploy-blocked:
start:1
length:1
mouse4.shp:cursor
move:
start:0
length:8
move-minimap:
start:9
start:8
length:4
move-rough:
start:0
length: 8
attackmove.shp:cursor
attackmove:
start:0
start:12
length:8
attackmove-minimap:
start:9
start:20
length:4
move-blocked:
start:8
start:24
length:1
move-blocked-minimap:
start:13
start:25
length:1
mouse3.shp: cursor2
enter-blocked:
start:212
mouse5.shp: cursor
guard:
start:0
length:8
guard-minimap:
start:8
length:8
mouse6.shp: cursor
goldwrench:
start:0
length:3
goldwrench-minimap:
start:3
length:3
goldwrench-blocked:
start:6
length:1
enter-blocked-minimap:
start:33
goldwrench-blocked-minimap:
start:7
length:1
capture:
start:164
start:8
length:3
capture-minimap:
start:167
start:11
length:3
heal:
start:160
length:4
heal-minimap:
start:194
capture-blocked:
start:14
length:1
ability-minimap:
start:214
length:8
deploy-blocked:
start:211
capture-blocked-minimap:
start:15
length:1
goldwrench:
start:170
length:24
goldwrench-blocked:
start:213
enter-blocked:
start:16
length:1
enter-blocked-minimap:
start:17
length:1
nopower.shp: cursor
powerdown-blocked:
mouse7.shp: cursor
attackoutsiderange:
start:0
length: 1
powerdown:
start:1
length: 3
length:8
attackoutsiderange-minimap:
start:8

View File

@@ -119,6 +119,16 @@ Cursors:
length: 8
x: 24
y: 24
attackoutsiderange:
start:16
length: 8
x: 24
y: 24
attackoutsiderange-minimap:
start:16
length: 8
x: 24
y: 24
attackmove:
start:16
length: 8

BIN
mods/ra/bits/attackmove.shp Normal file

Binary file not shown.

View File

@@ -70,10 +70,10 @@ Cursors:
attack-minimap:
start:203
length: 8
attackmove:
attackoutsiderange:
start:21
length: 8
attackmove-minimap:
attackoutsiderange-minimap:
start:134
length: 8
harvest:
@@ -169,4 +169,12 @@ Cursors:
length: 1
powerdown:
start:1
length: 3
length: 3
attackmove.shp: cursor
attackmove:
start:0
length: 4
attackmove-minimap:
start:4
length: 4

View File

@@ -72,6 +72,12 @@ Cursors:
attack-minimap:
start: 63
length: 5
attackoutsiderange:
start: 58
length: 5
attackoutsiderange-minimap:
start: 63
length: 5
attackmove: #TODO
start: 58
length: 5