#region Copyright & License Information /* * Copyright 2007-2015 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.Collections.Generic; using System.Drawing; using System.IO; using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Graphics; using OpenRA.Primitives; using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { public class EditorActorPreview { public readonly string Tooltip; public readonly string ID; public readonly ActorInfo Info; public readonly PlayerReference Owner; public readonly WPos CenterPosition; public readonly IReadOnlyDictionary Footprint; public readonly Rectangle Bounds; public SubCell SubCell { get; private set; } readonly ActorReference actor; readonly WorldRenderer worldRenderer; IActorPreview[] previews; public EditorActorPreview(WorldRenderer worldRenderer, string id, ActorReference actor, PlayerReference owner) { ID = id; this.actor = actor; this.Owner = owner; this.worldRenderer = worldRenderer; if (!actor.InitDict.Contains()) actor.InitDict.Add(new RaceInit(owner.Race)); if (!actor.InitDict.Contains()) actor.InitDict.Add(new OwnerInit(owner.Name)); var world = worldRenderer.World; if (!world.Map.Rules.Actors.TryGetValue(actor.Type.ToLowerInvariant(), out Info)) throw new InvalidDataException("Actor {0} of unknown type {1}".F(id, actor.Type.ToLowerInvariant())); CenterPosition = PreviewPosition(world, actor.InitDict); var location = actor.InitDict.Get().Value(worldRenderer.World); var ios = Info.Traits.GetOrDefault(); var subCellInit = actor.InitDict.GetOrDefault(); var subCell = subCellInit != null ? subCellInit.Value(worldRenderer.World) : SubCell.Any; if (ios != null) Footprint = ios.OccupiedCells(Info, location, subCell); else { var footprint = new Dictionary() { { location, SubCell.FullCell } }; Footprint = new ReadOnlyDictionary(footprint); } var tooltipInfo = Info.Traits.GetOrDefault(); Tooltip = "{0} ({1})".F(tooltipInfo != null ? tooltipInfo.TooltipForPlayerStance(Stance.None) : Info.Name, ID); GeneratePreviews(); // Bounds are fixed from the initial render. // If this is a problem, then we may need to fetch the area from somewhere else var r = previews .SelectMany(p => p.Render(worldRenderer, CenterPosition)) .Select(rr => rr.PrepareRender(worldRenderer)); if (r.Any()) { Bounds = r.First().ScreenBounds(worldRenderer); foreach (var rr in r.Skip(1)) Bounds = Rectangle.Union(Bounds, rr.ScreenBounds(worldRenderer)); } } public void Tick() { foreach (var p in previews) p.Tick(); } public IEnumerable Render() { return previews.SelectMany(p => p.Render(worldRenderer, CenterPosition)); } public void ReplaceInit(T init) { var original = actor.InitDict.GetOrDefault(); if (original != null) actor.InitDict.Remove(original); actor.InitDict.Add(init); GeneratePreviews(); } public T Init() { return actor.InitDict.GetOrDefault(); } public MiniYaml Save() { Func saveInit = init => { var race = init as RaceInit; if (race != null && race.Race == Owner.Race) return false; // TODO: Other default values will need to be filtered // here after we have built a properties panel return true; }; return actor.Save(saveInit); } WPos PreviewPosition(World world, TypeDictionary init) { if (init.Contains()) return init.Get().Value(world); if (init.Contains()) { var cell = init.Get().Value(world); var offset = WVec.Zero; var subCellInit = actor.InitDict.GetOrDefault(); var subCell = subCellInit != null ? subCellInit.Value(worldRenderer.World) : SubCell.Any; var buildingInfo = Info.Traits.GetOrDefault(); if (buildingInfo != null) offset = FootprintUtils.CenterOffset(world, buildingInfo); return world.Map.CenterOfSubCell(cell, subCell) + offset; } else throw new InvalidDataException("Actor {0} must define Location or CenterPosition".F(ID)); } void GeneratePreviews() { var init = new ActorPreviewInitializer(Info, worldRenderer, actor.InitDict); previews = Info.Traits.WithInterface() .SelectMany(rpi => rpi.RenderPreview(init)) .ToArray(); } } }