Merge Mods.TS into Mods.Cnc

This commit is contained in:
reaperrr
2017-02-02 21:14:03 +01:00
parent db04234062
commit 709e2a26e1
23 changed files with 36 additions and 142 deletions

View File

@@ -0,0 +1,70 @@
#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 OpenRA.Activities;
using OpenRA.Mods.Cnc.Traits.Render;
using OpenRA.Mods.Common.Activities;
namespace OpenRA.Mods.Cnc.Activities
{
public class VoxelHarvesterDockSequence : HarvesterDockSequence
{
readonly WithVoxelUnloadBody body;
readonly WithDockingOverlay spriteOverlay;
public VoxelHarvesterDockSequence(Actor self, Actor refinery, int dockAngle, bool isDragRequired, WVec dragOffset, int dragLength)
: base(self, refinery, dockAngle, isDragRequired, dragOffset, dragLength)
{
body = self.Trait<WithVoxelUnloadBody>();
spriteOverlay = refinery.TraitOrDefault<WithDockingOverlay>();
}
public override Activity OnStateDock(Actor self)
{
body.Docked = true;
if (spriteOverlay != null && !spriteOverlay.Visible)
{
spriteOverlay.Visible = true;
spriteOverlay.WithOffset.Animation.PlayThen(spriteOverlay.Info.Sequence, () => {
dockingState = DockingState.Loop;
spriteOverlay.Visible = false;
});
}
else
dockingState = DockingState.Loop;
return this;
}
public override Activity OnStateUndock(Actor self)
{
dockingState = DockingState.Wait;
if (spriteOverlay != null && !spriteOverlay.Visible)
{
spriteOverlay.Visible = true;
spriteOverlay.WithOffset.Animation.PlayBackwardsThen(spriteOverlay.Info.Sequence, () => {
dockingState = DockingState.Complete;
body.Docked = false;
spriteOverlay.Visible = false;
});
}
else
{
dockingState = DockingState.Complete;
body.Docked = false;
}
return this;
}
}
}

View File

@@ -0,0 +1,78 @@
#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;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Effects;
using OpenRA.Graphics;
using OpenRA.Scripting;
namespace OpenRA.Mods.Cnc.Effects
{
public class AnimatedBeacon : IEffect, IEffectAboveShroud
{
readonly Player owner;
readonly WPos position;
readonly string beaconPalette;
readonly bool isPlayerPalette;
readonly Animation beacon;
readonly int duration;
int delay;
int tick;
public AnimatedBeacon(Player owner, WPos position, int duration, string beaconPalette, bool isPlayerPalette, string beaconImage, string beaconSequence, int delay = 0)
{
this.owner = owner;
this.position = position;
this.beaconPalette = beaconPalette;
this.isPlayerPalette = isPlayerPalette;
this.duration = duration;
this.delay = delay;
if (!string.IsNullOrEmpty(beaconSequence))
{
beacon = new Animation(owner.World, beaconImage);
beacon.PlayRepeating(beaconSequence);
}
}
void IEffect.Tick(World world)
{
if (delay-- > 0)
return;
if (beacon != null)
beacon.Tick();
if (duration > 0 && duration <= tick++)
owner.World.AddFrameEndTask(w => w.Remove(this));
}
IEnumerable<IRenderable> IEffect.Render(WorldRenderer r) { return SpriteRenderable.None; }
IEnumerable<IRenderable> IEffectAboveShroud.RenderAboveShroud(WorldRenderer r)
{
if (delay > 0)
return SpriteRenderable.None;
if (beacon == null)
return SpriteRenderable.None;
if (!owner.IsAlliedWith(owner.World.RenderPlayer))
return SpriteRenderable.None;
var palette = r.Palette(isPlayerPalette ? beaconPalette + owner.InternalName : beaconPalette);
return beacon.Render(position, palette);
}
}
}

View File

@@ -74,6 +74,22 @@
<Compile Include="Traits\SupportPowers\IonCannonPower.cs" />
<Compile Include="ImportTiberianDawnLegacyMapCommand.cs" />
<Compile Include="Projectiles\IonCannon.cs" />
<Compile Include="Activities\VoxelHarvesterDockSequence.cs" />
<Compile Include="SpriteLoaders\TmpTSLoader.cs" />
<Compile Include="Traits\Buildings\TiberianSunRefinery.cs" />
<Compile Include="Traits\Render\WithDockingOverlay.cs" />
<Compile Include="Traits\Render\WithPermanentInjury.cs" />
<Compile Include="Traits\Render\WithVoxelWalkerBody.cs" />
<Compile Include="Traits\Render\WithVoxelUnloadBody.cs" />
<Compile Include="Traits\SupportPowers\AttackOrderPower.cs" />
<Compile Include="UtilityCommands\LegacyTilesetImporter.cs" />
<Compile Include="Traits\World\TSShroudPalette.cs" />
<Compile Include="UtilityCommands\ImportTSMapCommand.cs" />
<Compile Include="Player\PlaceSimpleBeacon.cs" />
<Compile Include="Effects\AnimatedBeacon.cs" />
<Compile Include="UtilityCommands\LegacyRulesImporter.cs" />
<Compile Include="UtilityCommands\LegacySequenceImporter.cs" />
<Compile Include="Widgets\Logic\PreReleaseWarningPrompt.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\OpenRA.Game\OpenRA.Game.csproj">

View File

@@ -0,0 +1,81 @@
#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 OpenRA.Mods.Cnc.Effects;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits
{
[Desc("A beacon that consists of a single sprite that can be animated.")]
public class PlaceSimpleBeaconInfo : ITraitInfo
{
public readonly int Duration = 30 * 25;
public readonly string NotificationType = "Sounds";
public readonly string Notification = "Beacon";
public readonly bool IsPlayerPalette = false;
[PaletteReference("IsPlayerPalette")] public readonly string Palette = "effect";
public readonly string BeaconImage = "beacon";
[SequenceReference("BeaconImage")] public readonly string BeaconSequence = "idle";
public object Create(ActorInitializer init) { return new PlaceSimpleBeacon(init.Self, this); }
}
public class PlaceSimpleBeacon : IResolveOrder
{
readonly PlaceSimpleBeaconInfo info;
readonly RadarPings radarPings;
AnimatedBeacon playerBeacon;
RadarPing playerRadarPing;
public PlaceSimpleBeacon(Actor self, PlaceSimpleBeaconInfo info)
{
radarPings = self.World.WorldActor.TraitOrDefault<RadarPings>();
this.info = info;
}
public void ResolveOrder(Actor self, Order order)
{
if (order.OrderString != "PlaceBeacon")
return;
var pos = self.World.Map.CenterOfCell(order.TargetLocation);
self.World.AddFrameEndTask(w =>
{
if (playerBeacon != null)
self.World.Remove(playerBeacon);
playerBeacon = new AnimatedBeacon(self.Owner, pos, info.Duration, info.Palette, info.IsPlayerPalette, info.BeaconImage, info.BeaconSequence);
self.World.Add(playerBeacon);
if (self.Owner.IsAlliedWith(self.World.RenderPlayer))
Game.Sound.PlayNotification(self.World.Map.Rules, null, info.NotificationType, info.Notification,
self.World.RenderPlayer != null ? self.World.RenderPlayer.Faction.InternalName : null);
if (radarPings != null)
{
if (playerRadarPing != null)
radarPings.Remove(playerRadarPing);
playerRadarPing = radarPings.Add(
() => self.Owner.IsAlliedWith(self.World.RenderPlayer),
pos,
self.Owner.Color.RGB,
info.Duration);
}
});
}
}
}

View File

@@ -0,0 +1,197 @@
#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.Drawing;
using System.IO;
using OpenRA.Graphics;
namespace OpenRA.Mods.Cnc.SpriteLoaders
{
public class TmpTSLoader : ISpriteLoader
{
class TmpTSDepthFrame : ISpriteFrame
{
readonly TmpTSFrame parent;
public Size Size { get { return parent.Size; } }
public Size FrameSize { get { return Size; } }
public float2 Offset { get { return parent.Offset; } }
public byte[] Data { get { return parent.DepthData; } }
public bool DisableExportPadding { get { return false; } }
public TmpTSDepthFrame(TmpTSFrame parent)
{
this.parent = parent;
}
}
class TmpTSFrame : ISpriteFrame
{
public Size Size { get; private set; }
public Size FrameSize { get { return Size; } }
public float2 Offset { get; private set; }
public byte[] Data { get; set; }
public byte[] DepthData { get; set; }
public bool DisableExportPadding { get { return false; } }
public TmpTSFrame(Stream s, Size size, int u, int v)
{
if (s.Position != 0)
{
Size = size;
// Skip unnecessary header data
s.Position += 20;
// Extra data is specified relative to the top-left of the template
var extraX = s.ReadInt32() - (u - v) * size.Width / 2;
var extraY = s.ReadInt32() - (u + v) * size.Height / 2;
var extraWidth = s.ReadInt32();
var extraHeight = s.ReadInt32();
var flags = s.ReadUInt32();
var bounds = new Rectangle(0, 0, size.Width, size.Height);
if ((flags & 0x01) != 0)
{
var extraBounds = new Rectangle(extraX, extraY, extraWidth, extraHeight);
bounds = Rectangle.Union(bounds, extraBounds);
Offset = new float2(bounds.X + 0.5f * (bounds.Width - size.Width), bounds.Y + 0.5f * (bounds.Height - size.Height));
Size = new Size(bounds.Width, bounds.Height);
}
// Skip unnecessary header data
s.Position += 12;
Data = new byte[bounds.Width * bounds.Height];
DepthData = new byte[bounds.Width * bounds.Height];
UnpackTileData(s, Data, size, bounds);
UnpackTileData(s, DepthData, size, bounds);
if ((flags & 0x01) == 0)
return;
// Load extra data (cliff faces, etc)
for (var j = 0; j < extraHeight; j++)
{
var start = (j + extraY - bounds.Y) * bounds.Width + extraX - bounds.X;
for (var i = 0; i < extraWidth; i++)
{
var extra = s.ReadUInt8();
if (extra != 0)
Data[start + i] = extra;
}
}
// Extra data depth
for (var j = 0; j < extraHeight; j++)
{
var start = (j + extraY - bounds.Y) * bounds.Width + extraX - bounds.X;
for (var i = 0; i < extraWidth; i++)
{
var extra = s.ReadUInt8();
// XCC source indicates that there are only 32 valid values
if (extra < 32)
DepthData[start + i] = extra;
}
}
}
else
Data = new byte[0];
}
}
static void UnpackTileData(Stream s, byte[] data, Size size, Rectangle frameBounds)
{
var width = 4;
for (var j = 0; j < size.Height; j++)
{
var start = (j - frameBounds.Y) * frameBounds.Width + (size.Width - width) / 2 - frameBounds.X;
for (var i = 0; i < width; i++)
data[start + i] = s.ReadUInt8();
width += (j < size.Height / 2 - 1 ? 1 : -1) * 4;
}
}
bool IsTmpTS(Stream s)
{
var start = s.Position;
s.Position += 8;
var sx = s.ReadUInt32();
var sy = s.ReadUInt32();
// Find the first non-empty frame
var offset = s.ReadUInt32();
while (offset == 0)
offset = s.ReadUInt32();
if (offset > s.Length - 52)
{
s.Position = start;
return false;
}
s.Position = offset + 12;
var test = s.ReadUInt32();
s.Position = start;
return test == sx * sy / 2 + 52;
}
ISpriteFrame[] ParseFrames(Stream s)
{
var start = s.Position;
var templateWidth = s.ReadUInt32();
var templateHeight = s.ReadUInt32();
var tileWidth = s.ReadInt32();
var tileHeight = s.ReadInt32();
var size = new Size(tileWidth, tileHeight);
var offsets = new uint[templateWidth * templateHeight];
for (var i = 0; i < offsets.Length; i++)
offsets[i] = s.ReadUInt32();
// Depth information are stored as a second set of frames (like split shadows)
var stride = offsets.Length;
var tiles = new ISpriteFrame[stride * 2];
for (var j = 0; j < templateHeight; j++)
{
for (var i = 0; i < templateWidth; i++)
{
var k = j * templateWidth + i;
s.Position = offsets[k];
var frame = new TmpTSFrame(s, size, i, j);
tiles[k] = frame;
tiles[k + stride] = new TmpTSDepthFrame(frame);
}
}
s.Position = start;
return tiles;
}
public bool TryParseSprite(Stream s, out ISpriteFrame[] frames)
{
if (!IsTmpTS(s))
{
frames = null;
return false;
}
frames = ParseFrames(s);
return true;
}
}
}

View File

@@ -0,0 +1,32 @@
#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 OpenRA.Activities;
using OpenRA.Mods.Cnc.Activities;
using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Cnc.Traits
{
public class TiberianSunRefineryInfo : RefineryInfo
{
public override object Create(ActorInitializer init) { return new TiberianSunRefinery(init.Self, this); }
}
public class TiberianSunRefinery : Refinery
{
public TiberianSunRefinery(Actor self, RefineryInfo info) : base(self, info) { }
public override Activity DockSequence(Actor harv, Actor self)
{
return new VoxelHarvesterDockSequence(harv, self, DeliveryAngle, IsDragRequired, DragOffset, DragLength);
}
}
}

View File

@@ -0,0 +1,61 @@
#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 OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits.Render
{
[Desc("Rendered on the refinery when a voxel harvester is docking and undocking.")]
public class WithDockingOverlayInfo : ITraitInfo, Requires<RenderSpritesInfo>, Requires<BodyOrientationInfo>
{
[Desc("Sequence name to use")]
[SequenceReference] public readonly string Sequence = "unload-overlay";
[Desc("Position relative to body")]
public readonly WVec Offset = WVec.Zero;
[Desc("Custom palette name")]
[PaletteReference("IsPlayerPalette")] 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); }
}
public class WithDockingOverlay
{
public readonly WithDockingOverlayInfo Info;
public readonly AnimationWithOffset WithOffset;
public bool Visible;
public WithDockingOverlay(Actor self, WithDockingOverlayInfo info)
{
Info = info;
var rs = self.Trait<RenderSprites>();
var body = self.Trait<BodyOrientation>();
var overlay = new Animation(self.World, rs.GetImage(self));
overlay.Play(info.Sequence);
WithOffset = new AnimationWithOffset(overlay,
() => body.LocalToWorld(info.Offset.Rotate(body.QuantizeOrientation(self, self.Orientation))),
() => !Visible);
rs.Add(WithOffset, info.Palette, info.IsPlayerPalette);
}
}
}

View File

@@ -0,0 +1,47 @@
#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 OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits.Render
{
[Desc("Change the sprite after a certain amount of damage is taken, even when the hitpoints are regenerated.")]
public class WithPermanentInjuryInfo : ITraitInfo
{
public readonly DamageState TriggeringDamageStage = DamageState.Critical;
public readonly string InjuredSequencePrefix = "crippled-";
public object Create(ActorInitializer init) { return new WithPermanentInjury(init, this); }
}
public class WithPermanentInjury : INotifyDamage, IRenderInfantrySequenceModifier
{
readonly WithPermanentInjuryInfo info;
bool isInjured;
bool IRenderInfantrySequenceModifier.IsModifyingSequence { get { return isInjured; } }
string IRenderInfantrySequenceModifier.SequencePrefix { get { return info.InjuredSequencePrefix; } }
public WithPermanentInjury(ActorInitializer init, WithPermanentInjuryInfo info)
{
this.info = info;
}
void INotifyDamage.Damaged(Actor self, AttackInfo e)
{
if (e.DamageState == info.TriggeringDamageStage)
isInjured = true;
}
}
}

View File

@@ -0,0 +1,78 @@
#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;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Mods.Common.Traits.Render;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits.Render
{
public class WithVoxelUnloadBodyInfo : ITraitInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>
{
[Desc("Voxel sequence name to use when docked to a refinery.")]
public readonly string UnloadSequence = "unload";
[Desc("Voxel sequence name to use when undocked from a refinery.")]
public readonly string IdleSequence = "idle";
[Desc("Defines if the Voxel should have a shadow.")]
public readonly bool ShowShadow = true;
public object Create(ActorInitializer init) { return new WithVoxelUnloadBody(init.Self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var voxel = VoxelProvider.GetVoxel(image, IdleSequence);
yield return new VoxelAnimation(voxel, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(orientation(), facings) },
() => false, () => 0, ShowShadow);
}
}
public class WithVoxelUnloadBody : IAutoSelectionSize
{
public bool Docked;
readonly int2 size;
public WithVoxelUnloadBody(Actor self, WithVoxelUnloadBodyInfo info)
{
var body = self.Trait<BodyOrientation>();
var rv = self.Trait<RenderVoxels>();
var idleVoxel = VoxelProvider.GetVoxel(rv.Image, info.IdleSequence);
rv.Add(new VoxelAnimation(idleVoxel, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(self, self.Orientation) },
() => Docked,
() => 0, info.ShowShadow));
// Selection size
var rvi = self.Info.TraitInfo<RenderVoxelsInfo>();
var s = (int)(rvi.Scale * idleVoxel.Size.Aggregate(Math.Max));
size = new int2(s, s);
var unloadVoxel = VoxelProvider.GetVoxel(rv.Image, info.UnloadSequence);
rv.Add(new VoxelAnimation(unloadVoxel, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(self, self.Orientation) },
() => !Docked,
() => 0, info.ShowShadow));
}
public int2 SelectionSize(Actor self) { return size; }
}
}

View File

@@ -0,0 +1,108 @@
#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;
using System.Collections.Generic;
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
{
public class WithVoxelWalkerBodyInfo : ITraitInfo, IRenderActorPreviewVoxelsInfo, Requires<RenderVoxelsInfo>, Requires<IMoveInfo>, Requires<IFacingInfo>
{
public readonly string Sequence = "idle";
[Desc("The speed of the walker's legs.")]
public readonly int TickRate = 5;
[Desc("Defines if the Voxel should have a shadow.")]
public readonly bool ShowShadow = true;
public object Create(ActorInitializer init) { return new WithVoxelWalkerBody(init.Self, this); }
public IEnumerable<VoxelAnimation> RenderPreviewVoxels(
ActorPreviewInitializer init, RenderVoxelsInfo rv, string image, Func<WRot> orientation, int facings, PaletteReference p)
{
var voxel = VoxelProvider.GetVoxel(image, Sequence);
var body = init.Actor.TraitInfo<BodyOrientationInfo>();
var frame = init.Contains<BodyAnimationFrameInit>() ? init.Get<BodyAnimationFrameInit, uint>() : 0;
yield return new VoxelAnimation(voxel, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(orientation(), facings) },
() => false, () => frame, ShowShadow);
}
}
public class WithVoxelWalkerBody : IAutoSelectionSize, ITick, IActorPreviewInitModifier
{
WithVoxelWalkerBodyInfo info;
IMove movement;
IFacing facing;
int oldFacing;
int2 size;
uint tick, frame, frames;
public WithVoxelWalkerBody(Actor self, WithVoxelWalkerBodyInfo info)
{
this.info = info;
movement = self.Trait<IMove>();
facing = self.Trait<IFacing>();
var body = self.Trait<BodyOrientation>();
var rv = self.Trait<RenderVoxels>();
var voxel = VoxelProvider.GetVoxel(rv.Image, info.Sequence);
frames = voxel.Frames;
rv.Add(new VoxelAnimation(voxel, () => WVec.Zero,
() => new[] { body.QuantizeOrientation(self, self.Orientation) },
() => false, () => frame, info.ShowShadow));
// Selection size
var rvi = self.Info.TraitInfo<RenderVoxelsInfo>();
var s = (int)(rvi.Scale * voxel.Size.Aggregate(Math.Max));
size = new int2(s, s);
}
public int2 SelectionSize(Actor self) { return size; }
public void Tick(Actor self)
{
if (movement.IsMoving || facing.Facing != oldFacing)
tick++;
oldFacing = facing.Facing;
if (tick < info.TickRate)
return;
tick = 0;
if (++frame == frames)
frame = 0;
}
void IActorPreviewInitModifier.ModifyActorPreviewInit(Actor self, TypeDictionary inits)
{
inits.Add(new BodyAnimationFrameInit(frame));
}
}
public class BodyAnimationFrameInit : IActorInit<uint>
{
[FieldFromYamlKey] readonly uint value = 0;
public BodyAnimationFrameInit() { }
public BodyAnimationFrameInit(uint init) { value = init; }
public uint Value(World world) { return value; }
}
}

View File

@@ -0,0 +1,148 @@
#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.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits
{
class AttackOrderPowerInfo : SupportPowerInfo, Requires<AttackBaseInfo>
{
public override object Create(ActorInitializer init) { return new AttackOrderPower(init.Self, this); }
}
class AttackOrderPower : SupportPower, INotifyCreated, INotifyBurstComplete
{
readonly AttackOrderPowerInfo info;
AttackBase attack;
public AttackOrderPower(Actor self, AttackOrderPowerInfo info)
: base(self, info)
{
this.info = info;
}
public override void SelectTarget(Actor self, string order, SupportPowerManager manager)
{
Game.Sound.PlayToPlayer(SoundType.UI, manager.Self.Owner, Info.SelectTargetSound);
self.World.OrderGenerator = new SelectAttackPowerTarget(self, order, manager, info.Cursor, MouseButton.Left, attack);
}
public override void Activate(Actor self, Order order, SupportPowerManager manager)
{
base.Activate(self, order, manager);
attack.AttackTarget(Target.FromCell(self.World, order.TargetLocation), false, false, true);
}
void INotifyCreated.Created(Actor self)
{
attack = self.Trait<AttackBase>();
}
void INotifyBurstComplete.FiredBurst(Actor self, Target target, Armament a)
{
self.World.IssueOrder(new Order("Stop", self, false));
}
}
public class SelectAttackPowerTarget : IOrderGenerator
{
readonly SupportPowerManager manager;
readonly SupportPowerInstance instance;
readonly string order;
readonly string cursor;
readonly string cursorBlocked;
readonly MouseButton expectedButton;
readonly AttackBase attack;
public SelectAttackPowerTarget(Actor self, string order, SupportPowerManager manager, string cursor, MouseButton button, AttackBase attack)
{
// Clear selection if using Left-Click Orders
if (Game.Settings.Game.UseClassicMouseStyle)
manager.Self.World.Selection.Clear();
instance = manager.GetPowersForActor(self).FirstOrDefault();
this.manager = manager;
this.order = order;
this.cursor = cursor;
expectedButton = button;
this.attack = attack;
cursorBlocked = cursor + "-blocked";
}
Actor GetFiringActor(World world, CPos cell)
{
var pos = world.Map.CenterOfCell(cell);
var range = attack.GetMaximumRange().LengthSquared;
return instance.Instances.Where(i => !i.Self.IsDisabled()).MinByOrDefault(a => (a.Self.CenterPosition - pos).HorizontalLengthSquared).Self;
}
bool IsValidTarget(World world, CPos cell)
{
var pos = world.Map.CenterOfCell(cell);
var range = attack.GetMaximumRange().LengthSquared;
return world.Map.Contains(cell) && instance.Instances.Any(a => !a.Self.IsDisabled() && (a.Self.CenterPosition - pos).HorizontalLengthSquared < range);
}
IEnumerable<Order> IOrderGenerator.Order(World world, CPos cell, int2 worldPixel, MouseInput mi)
{
world.CancelInputMode();
if (mi.Button == expectedButton && IsValidTarget(world, cell))
yield return new Order(order, manager.Self, false)
{
TargetActor = GetFiringActor(world, cell),
TargetLocation = cell,
SuppressVisualFeedback = true
};
}
void IOrderGenerator.Tick(World world)
{
// Cancel the OG if we can't use the power
if (!manager.Powers.ContainsKey(order))
world.CancelInputMode();
}
IEnumerable<IRenderable> IOrderGenerator.Render(WorldRenderer wr, World world) { yield break; }
IEnumerable<IRenderable> IOrderGenerator.RenderAboveShroud(WorldRenderer wr, World world)
{
foreach (var a in instance.Instances.Where(i => !i.Self.IsDisabled()))
{
yield return new RangeCircleRenderable(
a.Self.CenterPosition,
attack.GetMinimumRange(),
0,
Color.Red,
Color.FromArgb(96, Color.Black));
yield return new RangeCircleRenderable(
a.Self.CenterPosition,
attack.GetMaximumRange(),
0,
Color.Red,
Color.FromArgb(96, Color.Black));
}
}
string IOrderGenerator.GetCursor(World world, CPos cell, int2 worldPixel, MouseInput mi)
{
return IsValidTarget(world, cell) ? cursor : cursorBlocked;
}
}
}

View File

@@ -0,0 +1,51 @@
#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;
using System.Collections.Generic;
using System.Linq;
using OpenRA.Graphics;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.Traits
{
[Desc("Adds the hard-coded shroud palette to the game")]
class TSShroudPaletteInfo : ITraitInfo
{
[FieldLoader.Require, PaletteDefinition]
[Desc("Internal palette name")]
public readonly string Name = "shroud";
public object Create(ActorInitializer init) { return new TSShroudPalette(this); }
}
class TSShroudPalette : ILoadsPalettes, IProvidesAssetBrowserPalettes
{
readonly TSShroudPaletteInfo info;
public TSShroudPalette(TSShroudPaletteInfo info) { this.info = info; }
public void LoadPalettes(WorldRenderer wr)
{
Func<int, uint> makeColor = i =>
{
if (i < 128)
return (uint)(int2.Lerp(255, 0, i, 127) << 24);
return 0;
};
wr.AddPalette(info.Name, new ImmutablePalette(Enumerable.Range(0, Palette.Size).Select(i => makeColor(i))));
}
public IEnumerable<string> PaletteNames { get { yield return info.Name; } }
}
}

View File

@@ -0,0 +1,569 @@
#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;
using System.Collections.Generic;
using System.Drawing;
using System.IO;
using System.Linq;
using OpenRA.FileSystem;
using OpenRA.Mods.Common;
using OpenRA.Mods.Common.FileFormats;
using OpenRA.Mods.Common.Traits;
using OpenRA.Traits;
namespace OpenRA.Mods.Cnc.UtilityCommands
{
class ImportTSMapCommand : IUtilityCommand
{
string IUtilityCommand.Name { get { return "--import-ts-map"; } }
bool IUtilityCommand.ValidateArguments(string[] args) { return args.Length >= 2; }
static readonly Dictionary<byte, string> OverlayToActor = new Dictionary<byte, string>()
{
{ 0x01, "gasand" },
{ 0x03, "gawall" },
{ 0x18, "bridge1" },
{ 0x19, "bridge2" },
{ 0x1A, "nawall" },
{ 0x27, "tracks01" },
{ 0x28, "tracks02" },
{ 0x29, "tracks03" },
{ 0x2A, "tracks04" },
{ 0x2B, "tracks05" },
{ 0x2C, "tracks06" },
{ 0x2D, "tracks07" },
{ 0x2E, "tracks08" },
{ 0x2F, "tracks09" },
{ 0x30, "tracks10" },
{ 0x31, "tracks11" },
{ 0x32, "tracks12" },
{ 0x33, "tracks13" },
{ 0x34, "tracks14" },
{ 0x35, "tracks15" },
{ 0x36, "tracks16" },
{ 0x37, "tracktunnel01" },
{ 0x38, "tracktunnel02" },
{ 0x39, "tracktunnel03" },
{ 0x3A, "tracktunnel04" },
{ 0x3B, "railbrdg1" },
{ 0x3C, "railbrdg2" },
{ 0x3D, "crat01" },
{ 0x3E, "crat02" },
{ 0x3F, "crat03" },
{ 0x40, "crat04" },
{ 0x41, "crat0A" },
{ 0x42, "crat0B" },
{ 0x43, "crat0C" },
{ 0x44, "drum01" },
{ 0x45, "drum02" },
{ 0x46, "palet01" },
{ 0x47, "palet02" },
{ 0x48, "palet03" },
{ 0x49, "palet04" },
{ 0x4A, "lobrdg_b" }, // lobrdg01
{ 0x4B, "lobrdg_b" }, // lobrdg02
{ 0x4C, "lobrdg_b" }, // lobrdg03
{ 0x4D, "lobrdg_b" }, // lobrdg04
{ 0x4E, "lobrdg_b" }, // lobrdg05
{ 0x4F, "lobrdg_b" }, // lobrdg06
{ 0x50, "lobrdg_b" }, // lobrdg07
{ 0x51, "lobrdg_b" }, // lobrdg08
{ 0x52, "lobrdg_b" }, // lobrdg09
{ 0x53, "lobrdg_a" }, // lobrdg10
{ 0x54, "lobrdg_a" }, // lobrdg11
{ 0x55, "lobrdg_a" }, // lobrdg12
{ 0x56, "lobrdg_a" }, // lobrdg13
{ 0x57, "lobrdg_a" }, // lobrdg14
{ 0x58, "lobrdg_a" }, // lobrdg15
{ 0x59, "lobrdg_a" }, // lobrdg16
{ 0x5A, "lobrdg_a" }, // lobrdg17
{ 0x5B, "lobrdg_a" }, // lobrdg18
{ 0x5C, "lobrdg_r_se" }, // lobrdg19
{ 0x5D, "lobrdg_r_se" }, // lobrdg20
{ 0x5E, "lobrdg_r_nw" }, // lobrdg21
{ 0x5F, "lobrdg_r_nw" }, // lobrdg22
{ 0x60, "lobrdg_r_ne" }, // lobrdg23
{ 0x61, "lobrdg_r_ne" }, // lobrdg24
{ 0x62, "lobrdg_r_sw" }, // lobrdg25
{ 0x63, "lobrdg_r_sw" }, // lobrdg26
{ 0x64, "lobrdg_b_d" }, // lobrdg27
{ 0x65, "lobrdg_a_d" }, // lobrdg28
{ 0x7A, "lobrdg_r_se" }, // lobrdg1
{ 0x7B, "lobrdg_r_nw" }, // lobrdg2
{ 0x7C, "lobrdg_r_ne" }, // lobrdg3
{ 0x7D, "lobrdg_r_sw" }, // lobrdg4
{ 0xA7, "veinhole" },
{ 0xA8, "srock01" },
{ 0xA9, "srock02" },
{ 0xAA, "srock03" },
{ 0xAB, "srock04" },
{ 0xAC, "srock05" },
{ 0xAD, "trock01" },
{ 0xAE, "trock02" },
{ 0xAF, "trock03" },
{ 0xB0, "trock04" },
{ 0xB1, "trock05" },
{ 0xBB, "veinholedummy" },
{ 0xBC, "crate" }
};
static readonly Dictionary<byte, Size> OverlayShapes = new Dictionary<byte, Size>()
{
{ 0x4A, new Size(1, 3) },
{ 0x4B, new Size(1, 3) },
{ 0x4C, new Size(1, 3) },
{ 0x4D, new Size(1, 3) },
{ 0x4E, new Size(1, 3) },
{ 0x4F, new Size(1, 3) },
{ 0x50, new Size(1, 3) },
{ 0x51, new Size(1, 3) },
{ 0x52, new Size(1, 3) },
{ 0x53, new Size(3, 1) },
{ 0x54, new Size(3, 1) },
{ 0x55, new Size(3, 1) },
{ 0x56, new Size(3, 1) },
{ 0x57, new Size(3, 1) },
{ 0x58, new Size(3, 1) },
{ 0x59, new Size(3, 1) },
{ 0x5A, new Size(3, 1) },
{ 0x5B, new Size(3, 1) },
{ 0x5C, new Size(1, 3) },
{ 0x5D, new Size(1, 3) },
{ 0x5E, new Size(1, 3) },
{ 0x5F, new Size(1, 3) },
{ 0x60, new Size(3, 1) },
{ 0x61, new Size(3, 1) },
{ 0x62, new Size(3, 1) },
{ 0x63, new Size(3, 1) },
{ 0x64, new Size(1, 3) },
{ 0x65, new Size(3, 1) },
{ 0x7A, new Size(1, 3) },
{ 0x7B, new Size(1, 3) },
{ 0x7C, new Size(3, 1) },
{ 0x7D, new Size(3, 1) },
};
static readonly Dictionary<byte, DamageState> OverlayToHealth = new Dictionary<byte, DamageState>()
{
// 1,3 bridge tiles
{ 0x4A, DamageState.Undamaged },
{ 0x4B, DamageState.Undamaged },
{ 0x4C, DamageState.Undamaged },
{ 0x4D, DamageState.Undamaged },
{ 0x4E, DamageState.Heavy },
{ 0x4F, DamageState.Heavy },
{ 0x50, DamageState.Heavy },
{ 0x51, DamageState.Critical },
{ 0x52, DamageState.Critical },
// 3,1 bridge tiles
{ 0x53, DamageState.Undamaged },
{ 0x54, DamageState.Undamaged },
{ 0x55, DamageState.Undamaged },
{ 0x56, DamageState.Undamaged },
{ 0x57, DamageState.Heavy },
{ 0x58, DamageState.Heavy },
{ 0x59, DamageState.Heavy },
{ 0x5A, DamageState.Critical },
{ 0x5B, DamageState.Critical },
// Ramps
{ 0x5C, DamageState.Undamaged },
{ 0x5D, DamageState.Heavy },
{ 0x5E, DamageState.Undamaged },
{ 0x5F, DamageState.Heavy },
{ 0x60, DamageState.Undamaged },
{ 0x61, DamageState.Heavy },
{ 0x62, DamageState.Undamaged },
{ 0x63, DamageState.Heavy },
// Ramp duplicates
{ 0x7A, DamageState.Undamaged },
{ 0x7B, DamageState.Undamaged },
{ 0x7C, DamageState.Undamaged },
{ 0x7D, DamageState.Undamaged },
// actually dead, placeholders for resurrection
{ 0x64, DamageState.Undamaged },
{ 0x65, DamageState.Undamaged },
};
static readonly Dictionary<byte, byte[]> ResourceFromOverlay = new Dictionary<byte, byte[]>()
{
// "tib" - Regular Tiberium
{ 0x01, new byte[] { 0x66, 0x67, 0x68, 0x69, 0x6A, 0x6B, 0x6C, 0x6D, 0x6E, 0x6F,
0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79 } },
// "btib" - Blue Tiberium
{ 0x02, new byte[] { 0x1B, 0x1C, 0x1D, 0x1E, 0x1F, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26,
// Should be "tib2"
0x7F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88,
0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92,
// Should be "tib3"
0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C,
0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6 } },
// Veins
{ 0x03, new byte[] { 0x7E } }
};
static readonly Dictionary<string, string> DeployableActors = new Dictionary<string, string>()
{
{ "gadpsa", "lpst" },
{ "gatick", "ttnk" }
};
[Desc("FILENAME", "Convert a Tiberian Sun map to the OpenRA format.")]
void IUtilityCommand.Run(Utility utility, string[] args)
{
// HACK: The engine code assumes that Game.modData is set.
Game.ModData = utility.ModData;
var filename = args[1];
var file = new IniFile(File.Open(args[1], FileMode.Open));
var basic = file.GetSection("Basic");
var mapSection = file.GetSection("Map");
var tileset = mapSection.GetValue("Theater", "");
var iniSize = mapSection.GetValue("Size", "0, 0, 0, 0").Split(',').Select(int.Parse).ToArray();
var iniBounds = mapSection.GetValue("LocalSize", "0, 0, 0, 0").Split(',').Select(int.Parse).ToArray();
var size = new Size(iniSize[2], 2 * iniSize[3]);
var map = new Map(Game.ModData, utility.ModData.DefaultTileSets[tileset], size.Width, size.Height)
{
Title = basic.GetValue("Name", Path.GetFileNameWithoutExtension(filename)),
Author = "Westwood Studios",
Bounds = new Rectangle(iniBounds[0], iniBounds[1], iniBounds[2], 2 * iniBounds[3] + 2 * iniBounds[1]),
RequiresMod = utility.ModData.Manifest.Id
};
var fullSize = new int2(iniSize[2], iniSize[3]);
ReadTiles(map, file, fullSize);
ReadActors(map, file, "Structures", fullSize);
ReadActors(map, file, "Units", fullSize);
ReadActors(map, file, "Infantry", fullSize);
ReadTerrainActors(map, file, fullSize);
ReadWaypoints(map, file, fullSize);
ReadOverlay(map, file, fullSize);
ReadLighting(map, file);
var spawnCount = map.ActorDefinitions.Count(n => n.Value.Value == "mpspawn");
var mapPlayers = new MapPlayers(map.Rules, spawnCount);
map.PlayerDefinitions = mapPlayers.ToMiniYaml();
var dest = Path.GetFileNameWithoutExtension(args[1]) + ".oramap";
map.Save(ZipFile.Create(dest, new Folder(".")));
Console.WriteLine(dest + " saved.");
}
static void UnpackLZO(byte[] src, byte[] dest)
{
var srcOffset = 0U;
var destOffset = 0U;
while (destOffset < dest.Length && srcOffset < src.Length)
{
var srcLength = BitConverter.ToUInt16(src, (int)srcOffset);
var destLength = (uint)BitConverter.ToUInt16(src, (int)srcOffset + 2);
srcOffset += 4;
LZOCompression.DecodeInto(src, srcOffset, srcLength, dest, destOffset, ref destLength);
srcOffset += srcLength;
destOffset += destLength;
}
}
static void UnpackLCW(byte[] src, byte[] dest, byte[] temp)
{
var srcOffset = 0;
var destOffset = 0;
while (destOffset < dest.Length)
{
var srcLength = BitConverter.ToUInt16(src, srcOffset);
var destLength = BitConverter.ToUInt16(src, srcOffset + 2);
srcOffset += 4;
LCWCompression.DecodeInto(src, temp, srcOffset);
Array.Copy(temp, 0, dest, destOffset, destLength);
srcOffset += srcLength;
destOffset += destLength;
}
}
static void ReadTiles(Map map, IniFile file, int2 fullSize)
{
var tileset = Game.ModData.DefaultTileSets[map.Tileset];
var mapSection = file.GetSection("IsoMapPack5");
var data = Convert.FromBase64String(mapSection.Aggregate(string.Empty, (a, b) => a + b.Value));
int cells = (fullSize.X * 2 - 1) * fullSize.Y;
int lzoPackSize = cells * 11 + 4; // last 4 bytes contains a lzo pack header saying no more data is left
var isoMapPack = new byte[lzoPackSize];
UnpackLZO(data, isoMapPack);
var mf = new MemoryStream(isoMapPack);
for (var i = 0; i < cells; i++)
{
var rx = mf.ReadUInt16();
var ry = mf.ReadUInt16();
var tilenum = mf.ReadUInt16();
/*var zero1 = */mf.ReadInt16();
var subtile = mf.ReadUInt8();
var z = mf.ReadUInt8();
/*var zero2 = */mf.ReadUInt8();
int dx = rx - ry + fullSize.X - 1;
int dy = rx + ry - fullSize.X - 1;
var mapCell = new MPos(dx / 2, dy);
var cell = mapCell.ToCPos(map);
if (map.Tiles.Contains(cell))
{
if (!tileset.Templates.ContainsKey(tilenum))
tilenum = subtile = 0;
map.Tiles[cell] = new TerrainTile(tilenum, subtile);
map.Height[cell] = z;
}
}
}
static void ReadOverlay(Map map, IniFile file, int2 fullSize)
{
var overlaySection = file.GetSection("OverlayPack");
var overlayCompressed = Convert.FromBase64String(overlaySection.Aggregate(string.Empty, (a, b) => a + b.Value));
var overlayPack = new byte[1 << 18];
var temp = new byte[1 << 18];
UnpackLCW(overlayCompressed, overlayPack, temp);
var overlayDataSection = file.GetSection("OverlayDataPack");
var overlayDataCompressed = Convert.FromBase64String(overlayDataSection.Aggregate(string.Empty, (a, b) => a + b.Value));
var overlayDataPack = new byte[1 << 18];
UnpackLCW(overlayDataCompressed, overlayDataPack, temp);
var overlayIndex = new CellLayer<int>(map);
overlayIndex.Clear(0xFF);
for (var y = 0; y < fullSize.Y; y++)
{
for (var x = fullSize.X * 2 - 2; x >= 0; x--)
{
var dx = (ushort)x;
var dy = (ushort)(y * 2 + x % 2);
var uv = new MPos(dx / 2, dy);
var rx = (ushort)((dx + dy) / 2 + 1);
var ry = (ushort)(dy - rx + fullSize.X + 1);
if (!map.Resources.Contains(uv))
continue;
overlayIndex[uv] = rx + 512 * ry;
}
}
foreach (var cell in map.AllCells)
{
var overlayType = overlayPack[overlayIndex[cell]];
if (overlayType == 0xFF)
continue;
string actorType;
if (OverlayToActor.TryGetValue(overlayType, out actorType))
{
var shape = new Size(1, 1);
if (OverlayShapes.TryGetValue(overlayType, out shape))
{
// Only import the top-left cell of multi-celled overlays
var aboveType = overlayPack[overlayIndex[cell - new CVec(1, 0)]];
if (shape.Width > 1 && aboveType != 0xFF)
{
string a;
if (OverlayToActor.TryGetValue(aboveType, out a) && a == actorType)
continue;
}
var leftType = overlayPack[overlayIndex[cell - new CVec(0, 1)]];
if (shape.Height > 1 && leftType != 0xFF)
{
string a;
if (OverlayToActor.TryGetValue(leftType, out a) && a == actorType)
continue;
}
}
var ar = new ActorReference(actorType)
{
new LocationInit(cell),
new OwnerInit("Neutral")
};
DamageState damageState;
if (OverlayToHealth.TryGetValue(overlayType, out damageState))
{
var health = 100;
if (damageState == DamageState.Critical)
health = 25;
else if (damageState == DamageState.Heavy)
health = 50;
else if (damageState == DamageState.Medium)
health = 75;
if (health != 100)
ar.Add(new HealthInit(health));
}
map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save()));
continue;
}
var resourceType = ResourceFromOverlay
.Where(kv => kv.Value.Contains(overlayType))
.Select(kv => kv.Key)
.FirstOrDefault();
if (resourceType != 0)
{
map.Resources[cell] = new ResourceTile(resourceType, overlayDataPack[overlayIndex[cell]]);
continue;
}
Console.WriteLine("{0} unknown overlay {1}", cell, overlayType);
}
}
static void ReadWaypoints(Map map, IniFile file, int2 fullSize)
{
var waypointsSection = file.GetSection("Waypoints", true);
foreach (var kv in waypointsSection)
{
var pos = int.Parse(kv.Value);
var ry = pos / 1000;
var rx = pos - ry * 1000;
var dx = rx - ry + fullSize.X - 1;
var dy = rx + ry - fullSize.X - 1;
var cell = new MPos(dx / 2, dy).ToCPos(map);
int wpindex;
var ar = new ActorReference((!int.TryParse(kv.Key, out wpindex) || wpindex > 7) ? "waypoint" : "mpspawn");
ar.Add(new LocationInit(cell));
ar.Add(new OwnerInit("Neutral"));
map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save()));
}
}
static void ReadTerrainActors(Map map, IniFile file, int2 fullSize)
{
var terrainSection = file.GetSection("Terrain", true);
foreach (var kv in terrainSection)
{
var pos = int.Parse(kv.Key);
var ry = pos / 1000;
var rx = pos - ry * 1000;
var dx = rx - ry + fullSize.X - 1;
var dy = rx + ry - fullSize.X - 1;
var cell = new MPos(dx / 2, dy).ToCPos(map);
var name = kv.Value.ToLowerInvariant();
var ar = new ActorReference(name);
ar.Add(new LocationInit(cell));
ar.Add(new OwnerInit("Neutral"));
if (!map.Rules.Actors.ContainsKey(name))
Console.WriteLine("Ignoring unknown actor type: `{0}`".F(name));
else
map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save()));
}
}
static void ReadActors(Map map, IniFile file, string type, int2 fullSize)
{
var structuresSection = file.GetSection(type, true);
foreach (var kv in structuresSection)
{
var isDeployed = false;
var entries = kv.Value.Split(',');
var name = entries[1].ToLowerInvariant();
if (DeployableActors.ContainsKey(name))
{
name = DeployableActors[name];
isDeployed = true;
}
var health = short.Parse(entries[2]);
var rx = int.Parse(entries[3]);
var ry = int.Parse(entries[4]);
var facing = (byte)(byte.Parse(entries[5]) + 96);
var dx = rx - ry + fullSize.X - 1;
var dy = rx + ry - fullSize.X - 1;
var cell = new MPos(dx / 2, dy).ToCPos(map);
var ar = new ActorReference(name)
{
new LocationInit(cell),
new OwnerInit("Neutral"),
new HealthInit(100 * health / 256),
new FacingInit(facing),
};
if (isDeployed)
ar.Add(new DeployStateInit(DeployState.Deployed));
if (!map.Rules.Actors.ContainsKey(name))
Console.WriteLine("Ignoring unknown actor type: `{0}`".F(name));
else
map.ActorDefinitions.Add(new MiniYamlNode("Actor" + map.ActorDefinitions.Count, ar.Save()));
}
}
static void ReadLighting(Map map, IniFile file)
{
var lightingTypes = new[] { "Red", "Green", "Blue", "Ambient" };
var lightingSection = file.GetSection("Lighting");
var lightingNodes = new List<MiniYamlNode>();
foreach (var kv in lightingSection)
{
if (lightingTypes.Contains(kv.Key))
{
var val = FieldLoader.GetValue<float>(kv.Key, kv.Value);
if (val != 1.0f)
lightingNodes.Add(new MiniYamlNode(kv.Key, FieldSaver.FormatValue(val)));
}
else
Console.WriteLine("Ignoring unknown lighting type: `{0}`".F(kv.Key));
}
if (lightingNodes.Any())
{
map.RuleDefinitions.Nodes.Add(new MiniYamlNode("World", new MiniYaml("", new List<MiniYamlNode>()
{
new MiniYamlNode("GlobalLightingPaletteEffect", new MiniYaml("", lightingNodes))
})));
}
}
}
}

View File

@@ -0,0 +1,217 @@
#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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.Mods.Common.FileFormats;
using OpenRA.Mods.Common.Traits;
namespace OpenRA.Mods.Cnc.UtilityCommands
{
class LegacyRulesImporter : IUtilityCommand
{
bool IUtilityCommand.ValidateArguments(string[] args)
{
return args.Length >= 3;
}
string IUtilityCommand.Name { get { return "--rules-import"; } }
IniFile rulesIni;
IniFile artIni;
[Desc("RULES.INI", "ART.INI", "Convert ART.INI and RULES.INI to the OpenRA rules definition format.")]
void IUtilityCommand.Run(Utility utility, string[] args)
{
// HACK: The engine code assumes that Game.modData is set.
Game.ModData = utility.ModData;
rulesIni = new IniFile(File.Open(args[1], FileMode.Open));
artIni = new IniFile(File.Open(args[2], FileMode.Open));
var buildings = rulesIni.GetSection("BuildingTypes").Select(b => b.Value).Distinct();
Console.WriteLine("# Buildings");
Console.WriteLine();
ImportStructures(buildings);
var terrainObjects = rulesIni.GetSection("TerrainTypes").Select(b => b.Value).Distinct();
Console.WriteLine("# Terrain Objects");
Console.WriteLine();
ImportStructures(terrainObjects, true);
}
void ImportStructures(IEnumerable<string> structures, bool useTerrainPalette = false)
{
foreach (var building in structures)
{
var rulesSection = rulesIni.GetSection(building, allowFail: true);
if (rulesSection == null)
continue;
Console.WriteLine(rulesSection.Name + ":");
var name = rulesSection.GetValue("Name", string.Empty);
if (!string.IsNullOrEmpty(name))
{
Console.WriteLine("\tTooltip:");
Console.WriteLine("\t\tName: " + name);
}
var prerequisite = rulesSection.GetValue("Prerequisite", string.Empty);
if (!string.IsNullOrEmpty(prerequisite))
{
Console.WriteLine("\tBuildable:");
Console.WriteLine("\t\tPrerequisites: " + prerequisite.ToLowerInvariant());
}
var cost = rulesSection.GetValue("Cost", string.Empty);
if (!string.IsNullOrEmpty(cost))
{
Console.WriteLine("\tValued:");
Console.WriteLine("\t\tCost: " + cost);
}
var armor = rulesSection.GetValue("Armor", string.Empty);
if (!string.IsNullOrEmpty(armor))
{
Console.WriteLine("\tArmor:");
Console.WriteLine("\t\tType: " + armor);
}
var sight = rulesSection.GetValue("Sight", string.Empty);
if (!string.IsNullOrEmpty(sight))
{
Console.WriteLine("\tRevealsShroud:");
Console.WriteLine("\t\tRange: " + sight + "c0");
}
var strength = rulesSection.GetValue("Strength", string.Empty);
if (!string.IsNullOrEmpty(strength))
{
Console.WriteLine("\tHealth:");
Console.WriteLine("\t\tHP: " + strength);
}
var power = rulesSection.GetValue("Power", string.Empty);
if (!string.IsNullOrEmpty(power))
{
Console.WriteLine("\tPower:");
Console.WriteLine("\t\tAmount: " + power);
}
var captureable = rulesSection.GetValue("Capturable", string.Empty);
if (!string.IsNullOrEmpty(captureable) && captureable == "true")
Console.WriteLine("\tCapturable:");
var crewed = rulesSection.GetValue("Crewed", string.Empty);
if (!string.IsNullOrEmpty(crewed) && crewed == "yes")
Console.WriteLine("\tEmitInfantryOnSell:");
var deploysInto = rulesSection.GetValue("DeploysInto", string.Empty);
if (!string.IsNullOrEmpty(deploysInto))
{
Console.WriteLine("\tTransforms:");
Console.WriteLine("\t\tIntoActor: " + deploysInto);
}
var undeploysInto = rulesSection.GetValue("UndeploysInto", string.Empty);
if (!string.IsNullOrEmpty(undeploysInto))
{
Console.WriteLine("\tTransforms:");
Console.WriteLine("\t\tIntoActor: " + undeploysInto);
}
if (artIni.Sections.Any(s => s.Name == building.ToLowerInvariant()))
{
var artSection = artIni.GetSection(building);
var foundation = artSection.GetValue("Foundation", string.Empty);
if (!string.IsNullOrEmpty(foundation))
{
var dimensions = foundation.Split('x');
if (dimensions.First() == "0" || dimensions.Last() == "0")
Console.WriteLine("\tImmobile:\n \t\tOccupiesSpace: False");
else
{
Console.WriteLine("\tBuilding:");
var adjacent = rulesSection.GetValue("Adjacent", string.Empty);
if (!string.IsNullOrEmpty(adjacent))
Console.WriteLine("\t\tAdjacent: " + adjacent);
Console.WriteLine("\t\tDimensions: " + dimensions.First() + "," + dimensions.Last());
Console.Write("\t\tFootprint:");
var width = 0;
int.TryParse(dimensions.First(), out width);
var height = 0;
int.TryParse(dimensions.Last(), out height);
for (var y = 0; y < height; y++)
{
Console.Write(" ");
for (var x = 0; x < width; x++)
Console.Write("x");
}
Console.WriteLine();
}
}
var buildup = artSection.GetValue("Buildup", string.Empty);
if (!string.IsNullOrEmpty(buildup) && buildup != "none")
Console.WriteLine("\tWithMakeAnimation:");
var terrainPalette = artSection.GetValue("TerrainPalette", string.Empty);
if (!string.IsNullOrEmpty(terrainPalette))
bool.TryParse(terrainPalette, out useTerrainPalette);
var remapable = artSection.GetValue("Remapable", string.Empty);
if (!string.IsNullOrEmpty(remapable) && remapable == "yes")
useTerrainPalette = false;
}
var isAnimated = rulesSection.GetValue("IsAnimated", string.Empty);
if (!string.IsNullOrEmpty(isAnimated) && isAnimated == "yes")
useTerrainPalette = false;
var invisibleInGame = rulesSection.GetValue("InvisibleInGame", string.Empty);
if (!string.IsNullOrEmpty(invisibleInGame) && invisibleInGame == "yes")
Console.WriteLine("\tRenderSpritesEditorOnly:");
else
Console.WriteLine("\tRenderSprites:");
if (useTerrainPalette)
{
if (Game.ModData.DefaultRules.Actors.ContainsKey("world"))
{
var terrainPaletteDefintion = Game.ModData.DefaultRules.Actors["world"].TraitInfos<PaletteFromCurrentTilesetInfo>();
if (terrainPaletteDefintion.Any())
Console.WriteLine("\t\tPalette: " + terrainPaletteDefintion.Last().Name);
}
}
var image = rulesSection.GetValue("Image", string.Empty);
if (!string.IsNullOrEmpty(image) && image != "none")
Console.WriteLine("\t\tImage: " + image.ToLowerInvariant());
Console.WriteLine("\tWithSpriteBody:");
Console.WriteLine("\tAutoSelectionSize:");
Console.WriteLine("\tBodyOrientation:\n\t\tUseClassicPerspectiveFudge: False\n\t\tQuantizedFacings: 1");
Console.WriteLine("\tFrozenUnderFog:");
Console.WriteLine();
}
}
}
}

View File

@@ -0,0 +1,277 @@
#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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using OpenRA.Mods.Common.FileFormats;
namespace OpenRA.Mods.Cnc.UtilityCommands
{
class ImportLegacySequenceCommand : IUtilityCommand
{
bool IUtilityCommand.ValidateArguments(string[] args)
{
return args.Length >= 2;
}
string IUtilityCommand.Name { get { return "--sequence-import"; } }
IniFile file;
MapGrid grid;
[Desc("FILENAME", "Convert ART.INI to the OpenRA sequence definition format.")]
void IUtilityCommand.Run(Utility utility, string[] args)
{
// HACK: The engine code assumes that Game.modData is set.
Game.ModData = utility.ModData;
grid = Game.ModData.Manifest.Get<MapGrid>();
file = new IniFile(File.Open(args[1], FileMode.Open));
foreach (var section in file.Sections)
{
var sequence = section.GetValue("Sequence", string.Empty);
if (!string.IsNullOrEmpty(sequence))
ImportInfantrySequences(section, sequence);
var foundation = section.GetValue("Foundation", string.Empty);
if (!string.IsNullOrEmpty(foundation))
ImportBuildingSequences(section);
}
}
void ImportBuildingSequences(IniSection section)
{
Console.WriteLine(section.Name + ":");
Console.WriteLine("\tDefaults:");
var foundation = section.GetValue("Foundation", string.Empty);
if (!string.IsNullOrEmpty(foundation))
{
var size = foundation.Split('x');
if (size.Length == 2)
{
var x = int.Parse(size[0]);
var y = int.Parse(size[1]);
var xOffset = (x - y) * grid.TileSize.Width / 4;
var yOffset = (x + y) * grid.TileSize.Height / 4;
Console.WriteLine("\t\tOffset: {0},{1}", -xOffset, -yOffset);
}
}
var theater = section.GetValue("Theater", string.Empty);
if (!string.IsNullOrEmpty(theater) && theater == "yes")
Console.WriteLine("\t\tUseTilesetExtension: true");
else
{
var toOverlay = section.GetValue("ToOverlay", string.Empty);
if (!string.IsNullOrEmpty(toOverlay))
{
var overlaySection = file.GetSection(toOverlay);
var overlayTheater = overlaySection.GetValue("Theater", string.Empty);
if (!string.IsNullOrEmpty(overlayTheater) && overlayTheater == "yes")
Console.WriteLine("\t\tUseTilesetExtension: true");
}
}
var newTheater = section.GetValue("NewTheater", string.Empty);
if (!string.IsNullOrEmpty(newTheater) && newTheater == "yes")
Console.WriteLine("\t\tUseTilesetCode: true");
var cameo = section.GetValue("Cameo", string.Empty);
if (!string.IsNullOrEmpty(cameo))
{
Console.WriteLine("\ticon: " + cameo.ToLowerInvariant());
Console.WriteLine("\t\tOffset: 0,0");
Console.WriteLine("\t\tUseTilesetExtension: false");
Console.WriteLine("\t\tUseTilesetCode: false");
}
Console.WriteLine("\tidle: ");
var buildup = section.GetValue("Buildup", string.Empty);
if (!string.IsNullOrEmpty(buildup) && buildup != "none")
{
Console.WriteLine("\tmake: " + buildup.ToLowerInvariant());
}
var bibShape = section.GetValue("BibShape", string.Empty);
if (!string.IsNullOrEmpty(bibShape))
{
Console.WriteLine("\tbib: " + bibShape.ToLowerInvariant());
Console.WriteLine("\t\tLength: 1");
Console.WriteLine("\t\tZOffset: -1024");
}
Console.WriteLine();
}
void ImportInfantrySequences(IniSection section, string sequence)
{
Console.WriteLine(section.Name + ":");
var image = section.GetValue("Image", string.Empty);
if (!string.IsNullOrEmpty(image))
{
Console.WriteLine("\tDefaults: " + image.ToLowerInvariant());
Console.WriteLine("\t\tTick: 80");
}
var cameo = section.GetValue("Cameo", string.Empty);
if (!string.IsNullOrEmpty(cameo))
{
Console.WriteLine("\ticon: " + cameo.ToLowerInvariant());
Console.WriteLine("\t\tOffset: 0,0");
Console.WriteLine("\t\tUseTilesetExtension: false");
Console.WriteLine("\t\tUseTilesetCode: false");
}
if (file.Sections.Any(s => s.Name == sequence.ToLowerInvariant()))
{
var sequenceSection = file.GetSection(sequence);
var guard = sequenceSection.GetValue("Guard", string.Empty);
if (!string.IsNullOrEmpty(guard))
{
Console.WriteLine("\tstand:");
ConvertStartLengthFacings(guard);
}
var walk = sequenceSection.GetValue("Walk", string.Empty);
if (!string.IsNullOrEmpty(walk))
{
Console.WriteLine("\trun:");
ConvertStartLengthFacings(walk);
}
var prone = sequenceSection.GetValue("Prone", string.Empty);
if (!string.IsNullOrEmpty(prone))
{
Console.WriteLine("\tprone-stand:");
ConvertStartLengthFacings(prone);
}
var crawl = sequenceSection.GetValue("Crawl", string.Empty);
if (!string.IsNullOrEmpty(crawl))
{
Console.WriteLine("\tprone-run:");
ConvertStartLengthFacings(crawl);
}
var fireProne = sequenceSection.GetValue("FireProne", string.Empty);
if (!string.IsNullOrEmpty(fireProne))
{
Console.WriteLine("\tprone-shoot:");
ConvertStartLengthFacings(fireProne);
}
var fireUp = sequenceSection.GetValue("FireUp", string.Empty);
if (!string.IsNullOrEmpty(fireUp))
{
Console.WriteLine("\tshoot:");
ConvertStartLengthFacings(fireUp);
}
var idle1 = sequenceSection.GetValue("Idle1", string.Empty);
if (!string.IsNullOrEmpty(idle1))
{
Console.WriteLine("\tidle1:");
ConvertStartLengthFacings(idle1);
}
var idle2 = sequenceSection.GetValue("Idle2", string.Empty);
if (!string.IsNullOrEmpty(idle2))
{
Console.WriteLine("\tidle2:");
ConvertStartLengthFacings(idle2);
}
var die1 = sequenceSection.GetValue("Die1", string.Empty);
if (!string.IsNullOrEmpty(die1))
{
Console.WriteLine("\tdie1:");
ConvertStartLengthFacings(die1);
}
var die2 = sequenceSection.GetValue("Die2", string.Empty);
if (!string.IsNullOrEmpty(die2))
{
Console.WriteLine("\tdie2:");
ConvertStartLengthFacings(die2);
}
var die3 = sequenceSection.GetValue("Die3", string.Empty);
if (!string.IsNullOrEmpty(die3))
{
Console.WriteLine("\tdie3:");
ConvertStartLengthFacings(die3);
}
var die4 = sequenceSection.GetValue("Die4", string.Empty);
if (!string.IsNullOrEmpty(die4))
{
Console.WriteLine("\tdie4:");
ConvertStartLengthFacings(die4);
}
var die5 = sequenceSection.GetValue("Die5", string.Empty);
if (!string.IsNullOrEmpty(die5))
{
Console.WriteLine("\tdie5:");
ConvertStartLengthFacings(die5);
}
var cheer = sequenceSection.GetValue("Cheer", string.Empty);
if (!string.IsNullOrEmpty(cheer))
{
Console.WriteLine("\tcheer:");
ConvertStartLengthFacings(cheer);
}
var panic = sequenceSection.GetValue("Panic", string.Empty);
if (!string.IsNullOrEmpty(panic))
{
Console.WriteLine("\tpanic-stand:");
ConvertStartLengthFacings(panic);
Console.WriteLine("\tpanic-run:");
ConvertStartLengthFacings(panic);
}
}
Console.WriteLine();
}
void ConvertStartLengthFacings(string input)
{
var splitting = input.Split(',');
if (splitting.Length >= 3)
{
Console.WriteLine("\t\tStart: " + splitting[0]);
Console.WriteLine("\t\tLength: " + splitting[1]);
if (splitting.Length == 4)
Console.WriteLine("\t\tFacings: 1");
else
Console.WriteLine("\t\tFacings: 8");
int length, stride;
int.TryParse(splitting[2], out stride);
int.TryParse(splitting[1], out length);
if (stride != 0 && stride != length)
Console.WriteLine("\t\tStride: " + stride);
}
}
}
}

View File

@@ -0,0 +1,194 @@
#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;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using OpenRA.Mods.Common.FileFormats;
namespace OpenRA.Mods.Cnc.UtilityCommands
{
class ImportLegacyTilesetCommand : IUtilityCommand
{
string IUtilityCommand.Name { get { return "--tileset-import"; } }
bool IUtilityCommand.ValidateArguments(string[] args)
{
return args.Length >= 3;
}
[Desc("FILENAME", "TEMPLATEEXTENSION", "[TILESETNAME]", "Convert a legacy tileset to the OpenRA format.")]
void IUtilityCommand.Run(Utility utility, string[] args)
{
// HACK: The engine code assumes that Game.modData is set.
var modData = Game.ModData = utility.ModData;
var file = new IniFile(File.Open(args[1], FileMode.Open));
var extension = args[2];
var tileSize = utility.ModData.Manifest.Get<MapGrid>().TileSize;
var templateIndex = 0;
var terrainTypes = new string[]
{
"Clear",
"Clear", // Note: sometimes "Ice"
"Ice",
"Ice",
"Ice",
"Road", // TS defines this as "Tunnel", but we don't need this
"Rail",
"Impassable", // TS defines this as "Rock", but also uses it for buildings
"Impassable",
"Water",
"Water", // TS defines this as "Beach", but uses it for water...?
"Road",
"DirtRoad", // TS defines this as "Road", but we may want different speeds
"Clear",
"Rough",
"Cliff" // TS defines this as "Rock"
};
var metadata = new StringBuilder();
metadata.AppendLine("General:");
var name = args.Length > 3 ? args[3] : Path.GetFileNameWithoutExtension(args[2]);
metadata.AppendLine("\tName: {0}".F(name));
metadata.AppendLine("\tId: {0}".F(name.ToUpperInvariant()));
metadata.AppendLine("\tPalette: iso{0}.pal".F(extension));
metadata.AppendLine("\tHeightDebugColors: 00000080, 00004480, 00008880, 0000CC80, 0000FF80, 4400CC80," +
" 88008880, CC004480, FF110080, FF550080, FF990080, FFDD0080, DDFF0080, 99FF0080, 55FF0080, 11FF0080");
// Loop over template sets
var data = new StringBuilder();
data.AppendLine("Templates:");
var definedCategories = new HashSet<string>();
var usedCategories = new HashSet<string>();
try
{
for (var tilesetGroupIndex = 0;; tilesetGroupIndex++)
{
var section = file.GetSection("TileSet{0:D4}".F(tilesetGroupIndex));
var sectionCount = int.Parse(section.GetValue("TilesInSet", "1"));
var sectionFilename = section.GetValue("FileName", "").ToLowerInvariant();
var sectionCategory = section.GetValue("SetName", "");
if (!string.IsNullOrEmpty(sectionCategory) && sectionFilename != "blank")
definedCategories.Add(sectionCategory);
// Loop over templates
for (var i = 1; i <= sectionCount; i++, templateIndex++)
{
var templateFilename = "{0}{1:D2}.{2}".F(sectionFilename, i, extension);
if (!modData.DefaultFileSystem.Exists(templateFilename))
continue;
using (var s = modData.DefaultFileSystem.Open(templateFilename))
{
data.AppendLine("\tTemplate@{0}:".F(templateIndex));
data.AppendLine("\t\tCategory: {0}".F(sectionCategory));
usedCategories.Add(sectionCategory);
data.AppendLine("\t\tId: {0}".F(templateIndex));
var images = new List<string>();
images.Add("{0}{1:D2}.{2}".F(sectionFilename, i, extension));
for (var v = 'a'; v <= 'z'; v++)
{
var variant = "{0}{1:D2}{2}.{3}".F(sectionFilename, i, v, extension);
if (modData.DefaultFileSystem.Exists(variant))
images.Add(variant);
}
data.AppendLine("\t\tImages: {0}".F(images.JoinWith(", ")));
var templateWidth = s.ReadUInt32();
var templateHeight = s.ReadUInt32();
/* var tileWidth = */s.ReadInt32();
/* var tileHeight = */s.ReadInt32();
var offsets = new uint[templateWidth * templateHeight];
for (var j = 0; j < offsets.Length; j++)
offsets[j] = s.ReadUInt32();
data.AppendLine("\t\tSize: {0}, {1}".F(templateWidth, templateHeight));
data.AppendLine("\t\tTiles:");
for (var j = 0; j < offsets.Length; j++)
{
if (offsets[j] == 0)
continue;
s.Position = offsets[j] + 40;
var height = s.ReadUInt8();
var terrainType = s.ReadUInt8();
var rampType = s.ReadUInt8();
if (terrainType >= terrainTypes.Length)
throw new InvalidDataException("Unknown terrain type {0} in {1}".F(terrainType, templateFilename));
data.AppendLine("\t\t\t{0}: {1}".F(j, terrainTypes[terrainType]));
if (height != 0)
data.AppendLine("\t\t\t\tHeight: {0}".F(height));
if (rampType != 0)
data.AppendLine("\t\t\t\tRampType: {0}".F(rampType));
data.AppendLine("\t\t\t\tLeftColor: {0:X2}{1:X2}{2:X2}".F(s.ReadUInt8(), s.ReadUInt8(), s.ReadUInt8()));
data.AppendLine("\t\t\t\tRightColor: {0:X2}{1:X2}{2:X2}".F(s.ReadUInt8(), s.ReadUInt8(), s.ReadUInt8()));
data.AppendLine("\t\t\t\tZOffset: {0}".F(-tileSize.Height / 2.0f));
data.AppendLine("\t\t\t\tZRamp: 0");
}
}
}
}
}
catch (InvalidOperationException)
{
// GetSection will throw when we run out of sections to import
}
var unusedCategories = definedCategories.Except(usedCategories);
metadata.Append("\tEditorTemplateOrder: " + usedCategories.JoinWith(", ") + " # " + unusedCategories.JoinWith(", "));
metadata.AppendLine();
metadata.AppendLine("\tSheetSize: 2048");
metadata.AppendLine("\tEnableDepth: true");
metadata.AppendLine();
metadata.AppendLine("Terrain:");
terrainTypes = terrainTypes.Distinct().ToArray();
foreach (var terrainType in terrainTypes)
{
metadata.AppendLine("\tTerrainType@{0}:".F(terrainType));
metadata.AppendLine("\t\tType: {0}".F(terrainType));
if (terrainType == "Water")
{
metadata.AppendLine("\t\tTargetTypes: Water");
metadata.AppendLine("\t\tIsWater: True");
}
else
metadata.AppendLine("\t\tTargetTypes: Ground");
// TODO guess Color from Low/HighRadarColor
metadata.AppendLine("\t\tColor: 000000");
}
metadata.AppendLine();
Console.Write(metadata.ToString());
Console.Write(data.ToString());
}
}
}

View File

@@ -0,0 +1,37 @@
#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 OpenRA.Mods.Common.Widgets;
using OpenRA.Widgets;
namespace OpenRA.Mods.Cnc.Widgets.Logic
{
public class PreReleaseWarningPrompt : ChromeLogic
{
static bool promptAccepted;
[ObjectCreator.UseCtor]
public PreReleaseWarningPrompt(Widget widget, World world, ModData modData)
{
if (!promptAccepted && modData.Manifest.Metadata.Version != "{DEV_VERSION}")
widget.Get<ButtonWidget>("CONTINUE_BUTTON").OnClick = () => ShowMainMenu(world);
else
ShowMainMenu(world);
}
void ShowMainMenu(World world)
{
promptAccepted = true;
Ui.ResetAll();
Game.LoadWidget(world, "MAINMENU", Ui.Root, new WidgetArgs());
}
}
}