Merge pull request #5393 from pchote/palettehax

Support per-animation palettes in RenderSprites.
This commit is contained in:
Matthias Mailänder
2014-05-22 14:54:39 +02:00
43 changed files with 352 additions and 168 deletions

View File

@@ -30,40 +30,34 @@ namespace OpenRA.Traits
public class RenderSimple : RenderSprites, IAutoSelectionSize
{
RenderSimpleInfo Info;
public readonly Animation DefaultAnimation;
public RenderSimple(Actor self, Func<int> baseFacing)
: base(self)
{
anims.Add("", new Animation(self.World, GetImage(self), baseFacing));
Info = self.Info.Traits.Get<RenderSimpleInfo>();
DefaultAnimation = new Animation(self.World, GetImage(self), baseFacing);
Add("", DefaultAnimation);
}
public RenderSimple(Actor self)
: this(self, MakeFacingFunc(self))
{
anim.PlayRepeating("idle");
self.Trait<IBodyOrientation>().SetAutodetectedFacings(anim.CurrentSequence.Facings);
DefaultAnimation.PlayRepeating("idle");
self.Trait<IBodyOrientation>().SetAutodetectedFacings(DefaultAnimation.CurrentSequence.Facings);
}
public int2 SelectionSize(Actor self)
{
return anims.Values.Where(b => (b.DisableFunc == null || !b.DisableFunc())
&& b.Animation.CurrentSequence != null)
.Select(a => (a.Animation.Image.size*Info.Scale).ToInt2())
.FirstOrDefault();
}
public int2 SelectionSize(Actor self) { return AutoSelectionSize(self); }
public string NormalizeSequence(Actor self, string baseSequence)
{
return NormalizeSequence(anim, self.GetDamageState(), baseSequence);
return NormalizeSequence(DefaultAnimation, self.GetDamageState(), baseSequence);
}
public void PlayCustomAnim(Actor self, string name)
{
if (anim.HasSequence(name))
anim.PlayThen(NormalizeSequence(self, name),
() => anim.PlayRepeating(NormalizeSequence(self, "idle")));
if (DefaultAnimation.HasSequence(name))
DefaultAnimation.PlayThen(NormalizeSequence(self, name),
() => DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle")));
}
}
}

View File

@@ -10,6 +10,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.FileFormats;
using OpenRA.Primitives;
@@ -33,7 +34,42 @@ namespace OpenRA.Traits
public class RenderSprites : IRender, ITick, INotifyOwnerChanged
{
public Dictionary<string, AnimationWithOffset> anims = new Dictionary<string, AnimationWithOffset>();
class AnimationWrapper
{
public readonly AnimationWithOffset Animation;
public readonly string Palette;
public readonly bool IsPlayerPalette;
public PaletteReference PaletteReference { get; private set; }
public AnimationWrapper(AnimationWithOffset animation, string palette, bool isPlayerPalette)
{
Animation = animation;
Palette = palette;
IsPlayerPalette = isPlayerPalette;
}
public void CachePalette(WorldRenderer wr, Player owner)
{
PaletteReference = wr.Palette(IsPlayerPalette ? Palette + owner.InternalName : Palette);
}
public void OwnerChanged()
{
// Update the palette reference next time we draw
if (IsPlayerPalette)
PaletteReference = null;
}
public bool IsVisible
{
get
{
return Animation.DisableFunc == null || !Animation.DisableFunc();
}
}
}
Dictionary<string, AnimationWrapper> anims = new Dictionary<string, AnimationWrapper>();
public static Func<int> MakeFacingFunc(Actor self)
{
@@ -42,17 +78,8 @@ namespace OpenRA.Traits
return () => facing.Facing;
}
public Animation anim
{
get { return anims[""].Animation; }
protected set { anims[""] = new AnimationWithOffset(value,
anims[""].OffsetFunc, anims[""].DisableFunc, anims[""].Paused, anims[""].ZOffset); }
}
RenderSpritesInfo Info;
string cachedImage = null;
bool initializePalette = true;
protected PaletteReference palette;
public RenderSprites(Actor self)
{
@@ -78,23 +105,25 @@ namespace OpenRA.Traits
return Info.Palette ?? Info.PlayerPalette + self.Owner.InternalName;
}
protected void UpdatePalette() { initializePalette = true; }
protected void UpdatePalette()
{
foreach (var anim in anims.Values)
anim.OwnerChanged();
}
public void OnOwnerChanged(Actor self, Player oldOwner, Player newOwner) { UpdatePalette(); }
public virtual IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
{
if (initializePalette)
{
palette = wr.Palette(PaletteName(self));
initializePalette = false;
}
foreach (var a in anims.Values)
{
if (a.DisableFunc != null && a.DisableFunc())
if (!a.IsVisible)
continue;
foreach (var r in a.Render(self, wr, palette, Info.Scale))
if (a.PaletteReference == null)
a.CachePalette(wr, self.Owner);
foreach (var r in a.Animation.Render(self, wr, a.PaletteReference, Info.Scale))
yield return r;
}
}
@@ -102,7 +131,24 @@ namespace OpenRA.Traits
public virtual void Tick(Actor self)
{
foreach (var a in anims.Values)
a.Animation.Tick();
a.Animation.Animation.Tick();
}
public void Add(string key, AnimationWithOffset anim, string palette = null, bool isPlayerPalette = false)
{
// Use defaults
if (palette == null)
{
palette = Info.Palette ?? Info.PlayerPalette;
isPlayerPalette = Info.Palette == null;
}
anims.Add(key, new AnimationWrapper(anim, palette, isPlayerPalette));
}
public void Remove(string key)
{
anims.Remove(key);
}
public static string NormalizeSequence(Animation anim, DamageState state, string baseSequence)
@@ -121,5 +167,14 @@ namespace OpenRA.Traits
return baseSequence;
}
// Required by RenderSimple
protected int2 AutoSelectionSize(Actor self)
{
return anims.Values.Where(b => b.IsVisible
&& b.Animation.Animation.CurrentSequence != null)
.Select(a => (a.Animation.Animation.Image.size*Info.Scale).ToInt2())
.FirstOrDefault();
}
}
}

View File

@@ -37,19 +37,19 @@ namespace OpenRA.Mods.RA.Render
left = new Animation(self.World, name, () => turret.turretFacing);
left.Play("left");
anims.Add("left", new AnimationWithOffset(left, null, () => facing.Facing > 128, 0));
Add("left", new AnimationWithOffset(left, null, () => facing.Facing > 128, 0));
right = new Animation(self.World, name, () => turret.turretFacing);
right.Play("right");
anims.Add("right", new AnimationWithOffset(right, null, () => facing.Facing <= 128, 0));
Add("right", new AnimationWithOffset(right, null, () => facing.Facing <= 128, 0));
var leftWake = new Animation(self.World, name);
leftWake.Play("wake-left");
anims.Add("wake-left", new AnimationWithOffset(leftWake, null, () => facing.Facing > 128, -87));
Add("wake-left", new AnimationWithOffset(leftWake, null, () => facing.Facing > 128, -87));
var rightWake = new Animation(self.World, name);
rightWake.Play("wake-right");
anims.Add("wake-right", new AnimationWithOffset(rightWake, null, () => facing.Facing <= 128, -87));
Add("wake-right", new AnimationWithOffset(rightWake, null, () => facing.Facing <= 128, -87));
self.Trait<IBodyOrientation>().SetAutodetectedFacings(2);
}

View File

@@ -25,7 +25,7 @@ namespace OpenRA.Mods.Cnc
var rs = self.Trait<RenderSprites>();
var roof = new Animation(self.World, rs.GetImage(self));
roof.PlayThen("fire-start", () => roof.PlayRepeating("fire-loop"));
rs.anims.Add("fire", new AnimationWithOffset(roof, null, null, 1024));
rs.Add("fire", new AnimationWithOffset(roof, null, null, 1024));
}
}
}

View File

@@ -25,7 +25,7 @@ namespace OpenRA.Mods.Cnc
var rs = self.Trait<RenderSprites>();
var roof = new Animation(self.World, rs.GetImage(self), () => self.Trait<IFacing>().Facing);
roof.Play("roof");
rs.anims.Add("roof", new AnimationWithOffset(roof, null, null, 1024));
rs.Add("roof", new AnimationWithOffset(roof, null, null, 1024));
}
}
}

View File

@@ -91,6 +91,7 @@
<Compile Include="Render\WithProductionOverlay.cs" />
<Compile Include="Render\WithDockingOverlay.cs" />
<Compile Include="Render\WithDeliveryOverlay.cs" />
<Compile Include="PaletteFromScaledPalette.cs" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.targets" />
<PropertyGroup>

View File

@@ -0,0 +1,72 @@
#region Copyright & License Information
/*
* 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,
* see COPYING.
*/
#endregion
using System;
using System.Drawing;
using OpenRA.FileSystem;
using OpenRA.Graphics;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.D2k
{
[Desc("Create a palette by applying a scale and offset to the colors in another palette.")]
class PaletteFromScaledPaletteInfo : ITraitInfo
{
[Desc("Internal palette name")]
public readonly string Name = null;
[Desc("The name of the palette to base off.")]
public readonly string BasePalette = null;
[Desc("Allow palette modifiers to change the palette.")]
public readonly bool AllowModifiers = true;
[Desc("Amount to scale the base palette colors by.")]
public readonly float Scale = 1.0f;
[Desc("Amount to offset the base palette colors by.")]
public readonly int Offset = 0;
public object Create(ActorInitializer init) { return new PaletteFromScaledPalette(this); }
}
class PaletteFromScaledPalette : IPalette
{
readonly PaletteFromScaledPaletteInfo info;
public PaletteFromScaledPalette(PaletteFromScaledPaletteInfo info) { this.info = info; }
public void InitPalette(WorldRenderer wr)
{
var remap = new ScaledPaletteRemap(info.Scale, info.Offset);
wr.AddPalette(info.Name, new Palette(wr.Palette(info.BasePalette).Palette, remap), info.AllowModifiers);
}
}
class ScaledPaletteRemap : IPaletteRemap
{
readonly float scale;
readonly int offset;
public ScaledPaletteRemap(float scale, int offset)
{
this.scale = scale;
this.offset = offset;
}
public Color GetRemappedColor(Color original, int index)
{
return Color.FromArgb(original.A,
(int)Exts.Clamp((int)(scale * original.R + offset), 0, 255),
(int)Exts.Clamp((int)(scale * original.G + offset), 0, 255),
(int)Exts.Clamp((int)(scale * original.B + offset), 0, 255));
}
}
}

View File

@@ -23,6 +23,12 @@ namespace OpenRA.Mods.RA.Render
[Desc("Position relative to body")]
public readonly WVec Offset = WVec.Zero;
[Desc("Custom palette name")]
public readonly string Palette = null;
[Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithBuildingPlacedOverlay(init.self, this); }
}
@@ -40,10 +46,11 @@ namespace OpenRA.Mods.RA.Render
overlay = new Animation(self.World, rs.GetImage(self));
overlay.Play(info.Sequence);
rs.anims.Add("crane_overlay_{0}".F(info.Sequence),
rs.Add("crane_overlay_{0}".F(info.Sequence),
new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !buildComplete));
() => !buildComplete),
info.Palette, info.IsPlayerPalette);
}
public void BuildingComplete(Actor self)

View File

@@ -19,6 +19,12 @@ namespace OpenRA.Mods.RA.Render
[Desc("Sequence name to use")]
public readonly string Sequence = "crumble-overlay";
[Desc("Custom palette name")]
public readonly string Palette = null;
[Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithCrumbleOverlay(init, this); }
}
@@ -34,8 +40,9 @@ namespace OpenRA.Mods.RA.Render
{
var overlay = new Animation(init.world, rs.GetImage(init.self));
overlay.PlayThen(info.Sequence, () => buildComplete = false);
rs.anims.Add("make_overlay_{0}".F(info.Sequence),
new AnimationWithOffset(overlay, null, () => !buildComplete));
rs.Add("make_overlay_{0}".F(info.Sequence),
new AnimationWithOffset(overlay, null, () => !buildComplete),
info.Palette, info.IsPlayerPalette);
}
}

View File

@@ -24,6 +24,12 @@ namespace OpenRA.Mods.RA.Render
[Desc("Position relative to body")]
public readonly WVec Offset = WVec.Zero;
[Desc("Custom palette name")]
public readonly string Palette = null;
[Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithDeliveryOverlay(init.self, this); }
}
@@ -44,10 +50,11 @@ namespace OpenRA.Mods.RA.Render
overlay = new Animation(self.World, rs.GetImage(self));
overlay.Play(info.Sequence);
rs.anims.Add("delivery_overlay_{0}".F(info.Sequence),
rs.Add("delivery_overlay_{0}".F(info.Sequence),
new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !buildComplete));
() => !buildComplete),
info.Palette, info.IsPlayerPalette);
}
void PlayDeliveryOverlay()

View File

@@ -24,6 +24,12 @@ namespace OpenRA.Mods.RA.Render
[Desc("Position relative to body")]
public readonly WVec Offset = WVec.Zero;
[Desc("Custom palette name")]
public readonly string Palette = null;
[Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithDockingOverlay(init.self, this); }
}
@@ -44,10 +50,11 @@ namespace OpenRA.Mods.RA.Render
overlay = new Animation(self.World, rs.GetImage(self));
overlay.Play(info.Sequence);
rs.anims.Add("docking_overlay_{0}".F(info.Sequence),
rs.Add("docking_overlay_{0}".F(info.Sequence),
new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !buildComplete));
() => !buildComplete),
info.Palette, info.IsPlayerPalette);
}
void PlayDockingOverlay()

View File

@@ -26,6 +26,12 @@ namespace OpenRA.Mods.RA.Render
[Desc("Position relative to body")]
public readonly WVec Offset = WVec.Zero;
[Desc("Custom palette name")]
public readonly string Palette = null;
[Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false;
public object Create(ActorInitializer init) { return new WithProductionOverlay(init.self, this); }
}
@@ -49,10 +55,11 @@ namespace OpenRA.Mods.RA.Render
overlay = new Animation(self.World, rs.GetImage(self));
overlay.PlayRepeating(info.Sequence);
rs.anims.Add("production_overlay_{0}".F(info.Sequence),
rs.Add("production_overlay_{0}".F(info.Sequence),
new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !IsProducing || !buildComplete));
() => !IsProducing || !buildComplete),
info.Palette, info.IsPlayerPalette);
}
public void Tick(Actor self)

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.RA.Activities
if (started)
{
// Don't break the actor if someone has overriden the animation prematurely
if (rb.anim.CurrentSequence.Name != "make")
if (rb.DefaultAnimation.CurrentSequence.Name != "make")
{
complete = true;
OnComplete();

View File

@@ -24,29 +24,26 @@ namespace OpenRA.Mods.RA.Buildings
public object Create(ActorInitializer init) { return new Bib(init.self, this); }
}
public class Bib : IRender, INotifyAddedToWorld
public class Bib : INotifyAddedToWorld, INotifyRemovedFromWorld
{
readonly BibInfo info;
List<AnimationWithOffset> tiles;
readonly RenderSprites rs;
readonly BuildingInfo bi;
public Bib(Actor self, BibInfo info)
{
this.info = info;
rs = self.Trait<RenderSprites>();
bi = self.Info.Traits.Get<BuildingInfo>();
}
public void AddedToWorld(Actor self)
{
var rs = self.Trait<RenderSprites>();
var building = self.Info.Traits.Get<BuildingInfo>();
var width = building.Dimensions.X;
var bibOffset = building.Dimensions.Y - 1;
var centerOffset = FootprintUtils.CenterOffset(building);
var width = bi.Dimensions.X;
var bibOffset = bi.Dimensions.Y - 1;
var centerOffset = FootprintUtils.CenterOffset(bi);
var location = self.Location;
tiles = new List<AnimationWithOffset>();
int rows = 2;
if (info.HasMinibib)
rows = 1;
var rows = info.HasMinibib ? 1 : 2;
for (var i = 0; i < rows * width; i++)
{
@@ -63,21 +60,18 @@ namespace OpenRA.Mods.RA.Buildings
// Z-order is one set to the top of the footprint
var offset = cellOffset.ToWVec() - centerOffset;
tiles.Add(new AnimationWithOffset(anim, () => offset, null, -(offset.Y + centerOffset.Y + 512)));
var awo = new AnimationWithOffset(anim, () => offset, null, -(offset.Y + centerOffset.Y + 512));
rs.Add("bib_{0}".F(i), awo, info.Palette);
}
}
bool paletteInitialized;
PaletteReference palette;
public virtual IEnumerable<IRenderable> Render(Actor self, WorldRenderer wr)
public void RemovedFromWorld(Actor self)
{
if (!paletteInitialized)
{
palette = wr.Palette(info.Palette);
paletteInitialized = true;
}
var width = bi.Dimensions.X;
var rows = info.HasMinibib ? 1 : 2;
return tiles.SelectMany(t => t.Render(self, wr, palette, 1f));
for (var i = 0; i < rows * width; i++)
rs.Remove("bib_{0}".F(i));
}
}
}

View File

@@ -13,7 +13,7 @@ using OpenRA.Traits;
namespace OpenRA.Mods.Cnc
{
class DeadBuildingStateInfo : ITraitInfo, Requires<HealthInfo>, Requires<RenderSpritesInfo>
class DeadBuildingStateInfo : ITraitInfo, Requires<HealthInfo>, Requires<RenderSimpleInfo>
{
public readonly int LingerTime = 20;
@@ -23,23 +23,23 @@ namespace OpenRA.Mods.Cnc
class DeadBuildingState : INotifyKilled
{
DeadBuildingStateInfo info;
RenderSprites rs;
RenderSimple rs;
public DeadBuildingState(Actor self, DeadBuildingStateInfo info)
{
this.info = info;
rs = self.Trait<RenderSprites>();
self.Trait<Health>().RemoveOnDeath = !rs.anim.HasSequence("dead");
rs = self.Trait<RenderSimple>();
self.Trait<Health>().RemoveOnDeath = !rs.DefaultAnimation.HasSequence("dead");
}
public void Killed(Actor self, AttackInfo e)
{
if (!rs.anim.HasSequence("dead")) return;
if (!rs.DefaultAnimation.HasSequence("dead")) return;
if (rs.anim.GetSequence("dead").Length > 1)
rs.anim.Play("dead");
if (rs.DefaultAnimation.GetSequence("dead").Length > 1)
rs.DefaultAnimation.Play("dead");
else
rs.anim.PlayRepeating("dead");
rs.DefaultAnimation.PlayRepeating("dead");
self.World.AddFrameEndTask(
w => w.Add(

View File

@@ -34,7 +34,7 @@ namespace OpenRA.Mods.RA
var anim = new Animation(self.World, "fire", () => 0);
anim.IsDecoration = true;
anim.PlayRepeating(Info.Anim);
self.Trait<RenderSprites>().anims.Add("fire", anim);
self.Trait<RenderSprites>().Add("fire", anim);
}
public void Tick(Actor self)

View File

@@ -49,8 +49,8 @@ namespace OpenRA.Mods.RA.Render
this.info = info;
// Work around a bogus crash
anim.PlayRepeating(NormalizeSequence(self, "idle"));
self.Trait<IBodyOrientation>().SetAutodetectedFacings(anim.CurrentSequence.Facings);
DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle"));
self.Trait<IBodyOrientation>().SetAutodetectedFacings(DefaultAnimation.CurrentSequence.Facings);
// Can't call Complete() directly from ctor because other traits haven't been inited yet
if (self.Info.Traits.Get<RenderBuildingInfo>().HasMakeAnimation && !init.Contains<SkipMakeAnimsInit>())
@@ -61,45 +61,45 @@ namespace OpenRA.Mods.RA.Render
void Complete(Actor self)
{
anim.PlayRepeating(NormalizeSequence(self, "idle"));
DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle"));
foreach (var x in self.TraitsImplementing<INotifyBuildComplete>())
x.BuildingComplete(self);
if (info.PauseOnLowPower)
{
var disabled = self.TraitsImplementing<IDisable>();
anim.Paused = () => disabled.Any(d => d.Disabled)
&& anim.CurrentSequence.Name == NormalizeSequence(self, "idle");
DefaultAnimation.Paused = () => disabled.Any(d => d.Disabled)
&& DefaultAnimation.CurrentSequence.Name == NormalizeSequence(self, "idle");
}
}
public void PlayCustomAnimThen(Actor self, string name, Action a)
{
anim.PlayThen(NormalizeSequence(self, name),
() => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); });
DefaultAnimation.PlayThen(NormalizeSequence(self, name),
() => { DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle")); a(); });
}
public void PlayCustomAnimRepeating(Actor self, string name)
{
anim.PlayThen(NormalizeSequence(self, name),
DefaultAnimation.PlayThen(NormalizeSequence(self, name),
() => PlayCustomAnimRepeating(self, name));
}
public void PlayCustomAnimBackwards(Actor self, string name, Action a)
{
anim.PlayBackwardsThen(NormalizeSequence(self, name),
() => { anim.PlayRepeating(NormalizeSequence(self, "idle")); a(); });
DefaultAnimation.PlayBackwardsThen(NormalizeSequence(self, name),
() => { DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle")); a(); });
}
public void CancelCustomAnim(Actor self)
{
anim.PlayRepeating(NormalizeSequence(self, "idle"));
DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle"));
}
public virtual void DamageStateChanged(Actor self, AttackInfo e)
{
if (anim.CurrentSequence != null)
anim.ReplaceAnim(NormalizeSequence(self, "idle"));
if (DefaultAnimation.CurrentSequence != null)
DefaultAnimation.ReplaceAnim(NormalizeSequence(self, "idle"));
}
}
}

View File

@@ -35,8 +35,8 @@ namespace OpenRA.Mods.RA.Render
public void PlayCharge(Actor self)
{
Sound.Play(info.ChargeAudio, self.CenterPosition);
anim.PlayThen(NormalizeSequence(self, info.ChargeSequence),
() => anim.PlayRepeating(NormalizeSequence(self, "idle")));
DefaultAnimation.PlayThen(NormalizeSequence(self, info.ChargeSequence),
() => DefaultAnimation.PlayRepeating(NormalizeSequence(self, "idle")));
}
}
}

View File

@@ -30,9 +30,9 @@ namespace OpenRA.Mods.RA.Render
public void BuildingComplete(Actor self)
{
var animation = (self.GetDamageState() >= DamageState.Heavy) ? "damaged-idle" : "idle";
anim.PlayFetchIndex(animation,
DefaultAnimation.PlayFetchIndex(animation,
() => playerResources.OreCapacity != 0
? ((10 * anim.CurrentSequence.Length - 1) * playerResources.Ore) / (10 * playerResources.OreCapacity)
? ((10 * DefaultAnimation.CurrentSequence.Length - 1) * playerResources.Ore) / (10 * playerResources.OreCapacity)
: 0);
}

View File

@@ -34,13 +34,13 @@ namespace OpenRA.Mods.RA.Render
: base(init, info, MakeTurretFacingFunc(init.self))
{
t = init.self.TraitsImplementing<Turreted>().FirstOrDefault();
t.QuantizedFacings = anim.CurrentSequence.Facings;
t.QuantizedFacings = DefaultAnimation.CurrentSequence.Facings;
}
public override void DamageStateChanged(Actor self, AttackInfo e)
{
base.DamageStateChanged(self, e);
t.QuantizedFacings = anim.CurrentSequence.Facings;
t.QuantizedFacings = DefaultAnimation.CurrentSequence.Facings;
}
}
}

View File

@@ -35,12 +35,12 @@ namespace OpenRA.Mods.RA.Render
public void BuildingComplete(Actor self)
{
anim.PlayFetchIndex(info.Sequence, () => adjacent);
DefaultAnimation.PlayFetchIndex(info.Sequence, () => adjacent);
}
public override void DamageStateChanged(Actor self, AttackInfo e)
{
anim.PlayFetchIndex(NormalizeSequence(anim, e.DamageState, info.Sequence), () => adjacent);
DefaultAnimation.PlayFetchIndex(NormalizeSequence(DefaultAnimation, e.DamageState, info.Sequence), () => adjacent);
}
public override void Tick(Actor self)

View File

@@ -51,7 +51,7 @@ namespace OpenRA.Mods.RA.Render
// Additional 512 units move from center -> top of cell
var offset = FootprintUtils.CenterOffset(bi).Y + 512;
anims.Add("roof", new AnimationWithOffset(roof, null,
Add("roof", new AnimationWithOffset(roof, null,
() => !buildComplete, offset));
}
@@ -91,7 +91,7 @@ namespace OpenRA.Mods.RA.Render
roof.PlayThen(NormalizeSequence(self, "build-top"), () => { isOpen = true; openExit = exit; });
}
public void Selling(Actor self) { anims.Remove("roof"); }
public void Selling(Actor self) { Remove("roof"); }
public void Sold(Actor self) { }
}
}

View File

@@ -40,7 +40,7 @@ namespace OpenRA.Mods.RA.Render
if (disguise.AsSprite != intendedSprite)
{
intendedSprite = disguise.AsSprite;
anim.ChangeImage(intendedSprite ?? GetImage(self), info.StandAnimations.Random(Game.CosmeticRandom));
DefaultAnimation.ChangeImage(intendedSprite ?? GetImage(self), info.StandAnimations.Random(Game.CosmeticRandom));
UpdatePalette();
}

View File

@@ -22,7 +22,7 @@ namespace OpenRA.Mods.RA.Render
public RenderFlare(Actor self)
: base(self, () => 0)
{
anim.PlayThen("open", () => anim.PlayRepeating("idle"));
DefaultAnimation.PlayThen("open", () => DefaultAnimation.PlayRepeating("idle"));
}
}
}

View File

@@ -40,15 +40,15 @@ namespace OpenRA.Mods.RA.Render
var desiredState = harv.Fullness * (info.ImagesByFullness.Length - 1) / 100;
var desiredImage = info.ImagesByFullness[desiredState];
if (anim.Name != desiredImage)
anim.ChangeImage(desiredImage, "idle");
if (DefaultAnimation.Name != desiredImage)
DefaultAnimation.ChangeImage(desiredImage, "idle");
base.Tick(self);
}
public void Harvested(Actor self, ResourceType resource)
{
if (anim.CurrentSequence.Name != "harvest")
if (DefaultAnimation.CurrentSequence.Name != "harvest")
PlayCustomAnim(self, "harvest");
}
}

View File

@@ -59,20 +59,20 @@ namespace OpenRA.Mods.RA.Render
: base(self, MakeFacingFunc(self))
{
this.info = info;
anim.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
State = AnimationState.Waiting;
move = self.Trait<IMove>();
self.Trait<IBodyOrientation>().SetAutodetectedFacings(anim.CurrentSequence.Facings);
self.Trait<IBodyOrientation>().SetAutodetectedFacings(DefaultAnimation.CurrentSequence.Facings);
}
public void Attacking(Actor self, Target target)
{
State = AnimationState.Attacking;
if (anim.HasSequence(NormalizeInfantrySequence(self, "shoot")))
anim.PlayThen(NormalizeInfantrySequence(self, "shoot"), () => State = AnimationState.Idle);
else if (anim.HasSequence(NormalizeInfantrySequence(self, "heal")))
anim.PlayThen(NormalizeInfantrySequence(self, "heal"), () => State = AnimationState.Idle);
if (DefaultAnimation.HasSequence(NormalizeInfantrySequence(self, "shoot")))
DefaultAnimation.PlayThen(NormalizeInfantrySequence(self, "shoot"), () => State = AnimationState.Idle);
else if (DefaultAnimation.HasSequence(NormalizeInfantrySequence(self, "heal")))
DefaultAnimation.PlayThen(NormalizeInfantrySequence(self, "heal"), () => State = AnimationState.Idle);
}
public void Attacking(Actor self, Target target, Armament a, Barrel barrel)
@@ -87,12 +87,12 @@ namespace OpenRA.Mods.RA.Render
if ((State == AnimationState.Moving || dirty) && !move.IsMoving)
{
State = AnimationState.Waiting;
anim.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
}
else if ((State != AnimationState.Moving || dirty) && move.IsMoving)
{
State = AnimationState.Moving;
anim.PlayRepeating(NormalizeInfantrySequence(self, "run"));
DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, "run"));
}
dirty = false;
@@ -102,7 +102,7 @@ namespace OpenRA.Mods.RA.Render
{
if (State != AnimationState.Idle && State != AnimationState.IdleAnimating)
{
anim.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
DefaultAnimation.PlayFetchIndex(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)), () => 0);
State = AnimationState.Idle;
if (info.IdleAnimations.Length > 0)
@@ -113,12 +113,12 @@ namespace OpenRA.Mods.RA.Render
}
else if (AllowIdleAnimation(self) && idleDelay > 0 && --idleDelay == 0)
{
if (anim.HasSequence(idleSequence))
if (DefaultAnimation.HasSequence(idleSequence))
{
State = AnimationState.IdleAnimating;
anim.PlayThen(idleSequence, () =>
DefaultAnimation.PlayThen(idleSequence, () =>
{
anim.PlayRepeating(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)));
DefaultAnimation.PlayRepeating(NormalizeInfantrySequence(self, info.StandAnimations.Random(Game.CosmeticRandom)));
State = AnimationState.Waiting;
});
}

View File

@@ -32,7 +32,7 @@ namespace OpenRA.Mods.RA.Render
{
var prefix = sc != null && sc.Panicking ? "panic-" : "";
if (anim.HasSequence(prefix + baseSequence))
if (DefaultAnimation.HasSequence(prefix + baseSequence))
return prefix + baseSequence;
else
return baseSequence;

View File

@@ -51,20 +51,20 @@ namespace OpenRA.Mods.RA.Render
void Open()
{
if (open || !anim.HasSequence(info.OpenAnim))
if (open || !DefaultAnimation.HasSequence(info.OpenAnim))
return;
open = true;
PlayCustomAnimation(self, info.OpenAnim, () =>
{
if (anim.HasSequence(info.UnloadAnim))
if (DefaultAnimation.HasSequence(info.UnloadAnim))
PlayCustomAnimRepeating(self, info.UnloadAnim);
});
}
void Close()
{
if (!open || !anim.HasSequence(info.OpenAnim))
if (!open || !DefaultAnimation.HasSequence(info.OpenAnim))
return;
open = false;

View File

@@ -25,19 +25,19 @@ namespace OpenRA.Mods.RA.Render
public void PlayCustomAnimation(Actor self, string newAnim, Action after)
{
anim.PlayThen(newAnim, () => { anim.Play("idle"); if (after != null) after(); });
DefaultAnimation.PlayThen(newAnim, () => { DefaultAnimation.Play("idle"); if (after != null) after(); });
}
public void PlayCustomAnimRepeating(Actor self, string name)
{
anim.PlayThen(name,
DefaultAnimation.PlayThen(name,
() => { PlayCustomAnimRepeating(self, name); });
}
public void PlayCustomAnimBackwards(Actor self, string name, Action after)
{
anim.PlayBackwardsThen(name,
() => { anim.PlayRepeating("idle"); if (after != null) after(); });
DefaultAnimation.PlayBackwardsThen(name,
() => { DefaultAnimation.PlayRepeating("idle"); if (after != null) after(); });
}
}
}

View File

@@ -38,8 +38,8 @@ namespace OpenRA.Mods.RA.Render
public override void Tick(Actor self)
{
var sequence = (armament.IsReloading ? "empty-" : "") + (attack.IsAttacking ? "aim" : "idle");
if (sequence != anim.CurrentSequence.Name)
anim.ReplaceAnim(sequence);
if (sequence != DefaultAnimation.CurrentSequence.Name)
DefaultAnimation.ReplaceAnim(sequence);
base.Tick(self);
}

View File

@@ -35,7 +35,7 @@ namespace OpenRA.Mods.RA.Render
var images = info.XmasImages.Any() && DateTime.Today.Month == 12 ? info.XmasImages : info.Images;
anim = new Animation(self.World, images.Random(Game.CosmeticRandom));
anim.Play("idle");
rs.anims.Add("", anim);
rs.Add("", anim);
}
public void OnLanded()

View File

@@ -39,7 +39,7 @@ namespace OpenRA.Mods.RA.Render
anim = new Animation(self.World, rs.GetImage(self), RenderSimple.MakeFacingFunc(self));
anim.Play(info.Sequence);
rs.anims.Add("harvest_{0}".F(info.Sequence), new AnimationWithOffset(anim,
rs.Add("harvest_{0}".F(info.Sequence), new AnimationWithOffset(anim,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !visible,
() => false,

View File

@@ -24,6 +24,12 @@ namespace OpenRA.Mods.RA.Render
[Desc("Position relative to body")]
public readonly WVec Offset = WVec.Zero;
[Desc("Custom palette name")]
public readonly string Palette = null;
[Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false;
public readonly bool PauseOnLowPower = false;
public object Create(ActorInitializer init) { return new WithIdleOverlay(init.self, this); }
@@ -43,12 +49,13 @@ namespace OpenRA.Mods.RA.Render
buildComplete = !self.HasTrait<Building>(); // always render instantly for units
overlay = new Animation(self.World, rs.GetImage(self));
overlay.PlayRepeating(info.Sequence);
rs.anims.Add("idle_overlay_{0}".F(info.Sequence),
rs.Add("idle_overlay_{0}".F(info.Sequence),
new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !buildComplete,
() => info.PauseOnLowPower && disabled.Any(d => d.Disabled),
p => WithTurret.ZOffsetFromCenter(self, p, 1)));
p => WithTurret.ZOffsetFromCenter(self, p, 1)),
info.Palette, info.IsPlayerPalette);
}
public void BuildingComplete(Actor self)

View File

@@ -25,6 +25,12 @@ namespace OpenRA.Mods.RA.Render
[Desc("Position relative to body")]
public readonly WVec Offset = WVec.Zero;
[Desc("Custom palette name")]
public readonly string Palette = null;
[Desc("Custom palette is a player palette BaseName")]
public readonly bool IsPlayerPalette = false;
public readonly bool PauseOnLowPower = false;
public object Create(ActorInitializer init) { return new WithRepairOverlay(init.self, this); }
@@ -44,12 +50,13 @@ namespace OpenRA.Mods.RA.Render
buildComplete = !self.HasTrait<Building>(); // always render instantly for units
overlay = new Animation(self.World, rs.GetImage(self));
overlay.Play(info.Sequence);
rs.anims.Add("repair_{0}".F(info.Sequence),
rs.Add("repair_{0}".F(info.Sequence),
new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !buildComplete,
() => info.PauseOnLowPower && disabled.Any(d => d.Disabled),
p => WithTurret.ZOffsetFromCenter(self, p, 1)));
p => WithTurret.ZOffsetFromCenter(self, p, 1)),
info.Palette, info.IsPlayerPalette);
}
public void BuildingComplete(Actor self)

View File

@@ -42,7 +42,7 @@ namespace OpenRA.Mods.RA.Render
? ((10 * anim.CurrentSequence.Length - 1) * playerResources.Ore) / (10 * playerResources.OreCapacity)
: 0);
rs.anims.Add("resources_{0}".F(info.Sequence), new AnimationWithOffset(
rs.Add("resources_{0}".F(info.Sequence), new AnimationWithOffset(
anim, null, () => !buildComplete, 1024));
}
@@ -62,7 +62,7 @@ namespace OpenRA.Mods.RA.Render
playerResources = newOwner.PlayerActor.Trait<PlayerResources>();
}
public void Selling(Actor self) { rs.anims.Remove("resources_{0}".F(info.Sequence)); }
public void Selling(Actor self) { rs.Remove("resources_{0}".F(info.Sequence)); }
public void Sold(Actor self) { }
}
}

View File

@@ -45,7 +45,7 @@ namespace OpenRA.Mods.RA.Render
rotorAnim = new Animation(self.World, rs.GetImage(self));
rotorAnim.PlayRepeating(info.Sequence);
rs.anims.Add(info.Id, new AnimationWithOffset(rotorAnim,
rs.Add(info.Id, new AnimationWithOffset(rotorAnim,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
null, () => false, p => WithTurret.ZOffsetFromCenter(self, p, 1)));
}

View File

@@ -28,7 +28,7 @@ namespace OpenRA.Mods.RA.Render
var rs = self.Trait<RenderSprites>();
anim = new Animation(self.World, "smoke_m");
rs.anims.Add("smoke", new AnimationWithOffset(anim, null, () => !isSmoking));
rs.Add("smoke", new AnimationWithOffset(anim, null, () => !isSmoking));
}
public void Damaged(Actor self, AttackInfo e)

View File

@@ -57,7 +57,7 @@ namespace OpenRA.Mods.RA.Render
anim = new Animation(self.World, rs.GetImage(self), () => t.turretFacing);
anim.Play(info.Sequence);
rs.anims.Add("turret_{0}".F(info.Turret), new AnimationWithOffset(
rs.Add("turret_{0}".F(info.Turret), new AnimationWithOffset(
anim, () => TurretOffset(self), null, () => false, p => ZOffsetFromCenter(self, p, 1)));
// Restrict turret facings to match the sprite
@@ -82,7 +82,7 @@ namespace OpenRA.Mods.RA.Render
return;
var sequence = ab.IsAttacking ? info.AimSequence : info.Sequence;
rs.anims["turret_{0}".F(info.Turret)].Animation.ReplaceAnim(sequence);
anim.ReplaceAnim(sequence);
}
static public int ZOffsetFromCenter(Actor self, WPos pos, int offset)

View File

@@ -87,7 +87,7 @@ namespace OpenRA.Mods.RA
{
var prefix = tc != null && tc.IsProne ? "prone-" : "";
if (anim.HasSequence(prefix + baseSequence))
if (DefaultAnimation.HasSequence(prefix + baseSequence))
return prefix + baseSequence;
else
return baseSequence;

View File

@@ -79,7 +79,7 @@ namespace OpenRA.Mods.RA
var anim = new Animation(init.world, rs.GetImage(self), () => (int)facing);
anim.PlayRepeating(info.Anim);
rs.anims.Add(info.Anim, new AnimationWithOffset(anim, () => pos, null));
rs.Add(info.Anim, new AnimationWithOffset(anim, () => pos, null));
}
public void Tick(Actor self)

View File

@@ -74,6 +74,7 @@ CONCRETEB:
ProvidesCustomPrerequisite:
Prerequisite: Conyard
WithBuildingPlacedOverlay:
Palette: d2k
^POWER:
Inherits: ^Building
@@ -380,6 +381,7 @@ CONCRETEB:
Produces: Starport
ActorType: frigate
WithDeliveryOverlay:
Palette: starportlights
ProductionBar:
PrimaryBuilding:
RequiresPower:
@@ -579,6 +581,7 @@ WALL:
ProvidesCustomPrerequisite:
Prerequisite: Repair
WithRepairOverlay:
Palette: repairlights
^HIGHTECH:
Inherits: ^Building

View File

@@ -66,6 +66,16 @@ World:
G: 0
B: 0
A: 180
PaletteFromScaledPalette@starportlights:
Name: starportlights
BasePalette: d2k
AllowModifiers: false
Offset: -64
PaletteFromScaledPalette@repairlights:
Name: repairlights
BasePalette: d2k
AllowModifiers: false
Offset: -128
PaletteFromR8@shroud:
Name: shroud
Filename: DATA.R8

View File

@@ -219,21 +219,23 @@ repaira:
Start: 2571
Offset: -48,48
ZOffset: -1c511
damaged-idle: DATA
Start: 2572
Offset: -48,48
ZOffset: -1c511
active: DATA
Start: 4746
Length: 14
Offset: -48,48
ZOffset: -1c511
BlendMode: Additive
damaged-active: DATA
Start: 4746
Length: 14
Tick: 60
Offset: -48,48
ZOffset: -1c511
damaged-idle: DATA
Start: 2572
Offset: -48,48
ZOffset: -1c511
BlendMode: Additive
icon: DATA
Start: 4096
Offset: -30,-24
@@ -252,21 +254,23 @@ repairh:
Start: 2731
Offset: -48,48
ZOffset: -1c511
damaged-idle: DATA
Start: 2732
Offset: -48,48
ZOffset: -1c511
active: DATA
Start: 4746
Length: 14
Offset: -48,48
ZOffset: -1c511
BlendMode: Additive
damaged-active: DATA
Start: 4746
Length: 14
Tick: 60
Offset: -48,48
ZOffset: -1c511
damaged-idle: DATA
Start: 2732
Offset: -48,48
ZOffset: -1c511
BlendMode: Additive
icon: DATA
Start: 4097
Offset: -30,-24
@@ -285,21 +289,23 @@ repairo:
Start: 2891
Offset: -48,48
ZOffset: -1c511
damaged-idle: DATA
Start: 2892
Offset: -48,48
ZOffset: -1c511
active: DATA
Start: 4746
Length: 14
Offset: -48,48
ZOffset: -1c511
BlendMode: Additive
damaged-active: DATA
Start: 4746
Length: 14
Tick: 60
Offset: -48,48
ZOffset: -1c511
damaged-idle: DATA
Start: 2892
Offset: -48,48
ZOffset: -1c511
BlendMode: Additive
icon: DATA
Start: 4098
Offset: -30,-24
@@ -318,14 +324,14 @@ starporta:
Length: 23
ZOffset: -1c511
Offset: -48,64
BlendMode: Alpha
BlendMode: Additive
Tick: 200
damaged-active: DATA
Start: 4723
Length: 23
ZOffset: -1c511
Offset: -48,64
BlendMode: Alpha
BlendMode: Additive
Tick: 200
make: DATA
Start: 4347
@@ -820,14 +826,14 @@ starporth:
Length: 23
ZOffset: -1c511
Offset: -48,64
BlendMode: Alpha
BlendMode: Additive
Tick: 200
damaged-active: DATA
Start: 4723
Length: 23
ZOffset: -1c511
Offset: -48,64
BlendMode: Alpha
BlendMode: Additive
Tick: 200
make: DATA
Start: 4347
@@ -1231,14 +1237,14 @@ starporto:
Length: 23
ZOffset: -1c511
Offset: -48,64
BlendMode: Alpha
BlendMode: Additive
Tick: 200
damaged-active: DATA
Start: 4723
Length: 23
ZOffset: -1c511
Offset: -48,64
BlendMode: Alpha
BlendMode: Additive
Tick: 200
make: DATA
Start: 4347
@@ -1624,14 +1630,14 @@ starportc: # TODO: unused
Length: 23
ZOffset: -1c511
Offset: -48,64
BlendMode: Alpha
BlendMode: Additive
Tick: 200
damaged-active: DATA
Start: 4723
Length: 23
ZOffset: -1c511
Offset: -48,64
BlendMode: Alpha
BlendMode: Additive
Tick: 200
make: DATA
Start: 4347