Files
OpenRA/OpenRA.Mods.Cnc/Traits/Render/WithCargo.cs
Paul Chote 86bfe28ade Add ScreenBounds method to IRender interface.
This method is expected to return Rectangles that cover
the region where Renderables returned by Render may exist.
2017-12-11 19:45:07 +01:00

121 lines
3.7 KiB
C#

#region Copyright & License Information
/*
* Copyright 2007-2017 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, either version 3 of
* the License, or (at your option) any later version. For more
* information, see COPYING.
*/
#endregion
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Primitives;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits.Render
{
[Desc("Renders the cargo loaded into the unit.")]
public class WithCargoInfo : ITraitInfo, Requires<CargoInfo>, Requires<BodyOrientationInfo>
{
[Desc("Cargo position relative to turret or body in (forward, right, up) triples. The default offset should be in the middle of the list.")]
public readonly WVec[] LocalOffset = { WVec.Zero };
[Desc("Passenger CargoType to display.")]
public readonly HashSet<string> DisplayTypes = new HashSet<string>();
public object Create(ActorInitializer init) { return new WithCargo(init.Self, this); }
}
public class WithCargo : ITick, IRender, INotifyPassengerEntered, INotifyPassengerExited
{
readonly WithCargoInfo info;
readonly Cargo cargo;
readonly BodyOrientation body;
readonly IFacing facing;
Dictionary<Actor, IActorPreview[]> previews = new Dictionary<Actor, IActorPreview[]>();
public WithCargo(Actor self, WithCargoInfo info)
{
this.info = info;
cargo = self.Trait<Cargo>();
body = self.Trait<BodyOrientation>();
facing = self.TraitOrDefault<IFacing>();
}
void ITick.Tick(Actor self)
{
foreach (var actorPreviews in previews.Values)
if (actorPreviews != null)
foreach (var preview in actorPreviews)
preview.Tick();
}
IEnumerable<IRenderable> IRender.Render(Actor self, WorldRenderer wr)
{
var bodyOrientation = body.QuantizeOrientation(self, self.Orientation);
var pos = self.CenterPosition;
var i = 0;
// Generate missing previews
var missing = previews
.Where(kv => kv.Value == null)
.Select(kv => kv.Key)
.ToList();
foreach (var p in missing)
{
var passengerInits = new TypeDictionary()
{
new OwnerInit(p.Owner),
new DynamicFacingInit(() => body.QuantizeFacing(facing.Facing)),
};
foreach (var api in p.TraitsImplementing<IActorPreviewInitModifier>())
api.ModifyActorPreviewInit(p, passengerInits);
var init = new ActorPreviewInitializer(p.Info, wr, passengerInits);
previews[p] = p.Info.TraitInfos<IRenderActorPreviewInfo>()
.SelectMany(rpi => rpi.RenderPreview(init))
.ToArray();
}
foreach (var p in previews.Values.SelectMany(p => p))
{
var index = cargo.PassengerCount > 1 ? i++ % info.LocalOffset.Length : info.LocalOffset.Length / 2;
var localOffset = info.LocalOffset[index];
foreach (var pp in p.Render(wr, pos + body.LocalToWorld(localOffset.Rotate(bodyOrientation))))
yield return pp.WithZOffset(1);
}
}
IEnumerable<Rectangle> IRender.ScreenBounds(Actor self, WorldRenderer wr)
{
var pos = self.CenterPosition;
foreach (var p in previews.Values.SelectMany(p => p))
foreach (var b in p.ScreenBounds(wr, pos))
yield return b;
}
void INotifyPassengerEntered.OnPassengerEntered(Actor self, Actor passenger)
{
if (info.DisplayTypes.Contains(passenger.Trait<Passenger>().Info.CargoType))
previews.Add(passenger, null);
}
void INotifyPassengerExited.OnPassengerExited(Actor self, Actor passenger)
{
previews.Remove(passenger);
}
}
}