This override allows quantization to be disabled, and is used by the TS mod as the voxel based actors can be rotated to any orientation/facing. To prevent a divide by zero error for these actors, we need to return early from QuantizeFacing just like we do in QuantizeOrientation. However, when QuantizedFacings is not explicitly set to zero, we still want to catch errors when artwork sequences have zero facings. The new check would cause such errors to be hidden. To prevent this add some exceptions with a detailed error message.
128 lines
4.0 KiB
C#
128 lines
4.0 KiB
C#
#region Copyright & License Information
|
|
/*
|
|
* Copyright (c) The OpenRA Developers and Contributors
|
|
* 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 OpenRA.Mods.Common.Traits.Render;
|
|
using OpenRA.Traits;
|
|
|
|
namespace OpenRA.Mods.Common.Traits
|
|
{
|
|
public class BodyOrientationInfo : TraitInfo
|
|
{
|
|
[Desc("Number of facings for gameplay calculations. -1 indicates auto-detection from another trait. 0 disables quantization.")]
|
|
public readonly int QuantizedFacings = -1;
|
|
|
|
[Desc("Camera pitch for rotation calculations.")]
|
|
public readonly WAngle CameraPitch = WAngle.FromDegrees(40);
|
|
|
|
[Desc("Fudge the coordinate system angles to simulate non-top-down perspective in mods with square cells.")]
|
|
public readonly bool UseClassicPerspectiveFudge = true;
|
|
|
|
public WVec LocalToWorld(in WVec vec)
|
|
{
|
|
// Rotate by 90 degrees
|
|
if (!UseClassicPerspectiveFudge)
|
|
return new WVec(vec.Y, -vec.X, vec.Z);
|
|
|
|
// The 2d perspective of older games with square cells doesn't correspond to an orthonormal 3D
|
|
// coordinate system, so fudge the y axis to make things look good
|
|
return new WVec(vec.Y, -CameraPitch.Sin() * vec.X / 1024, vec.Z);
|
|
}
|
|
|
|
public WRot QuantizeOrientation(in WRot orientation, int facings)
|
|
{
|
|
// Quantization disabled
|
|
if (facings == 0)
|
|
return orientation;
|
|
|
|
// Map yaw to the closest facing
|
|
var facing = QuantizeFacing(orientation.Yaw, facings);
|
|
|
|
// Roll and pitch are always zero if yaw is quantized
|
|
return WRot.FromYaw(facing);
|
|
}
|
|
|
|
public virtual WAngle QuantizeFacing(WAngle facing, int facings)
|
|
{
|
|
// Quantization disabled
|
|
if (facings == 0)
|
|
return facing;
|
|
|
|
return Util.QuantizeFacing(facing, facings);
|
|
}
|
|
|
|
public override object Create(ActorInitializer init) { return new BodyOrientation(init, this); }
|
|
}
|
|
|
|
public class BodyOrientation : ISync
|
|
{
|
|
readonly BodyOrientationInfo info;
|
|
readonly Lazy<int> quantizedFacings;
|
|
|
|
[Sync]
|
|
public int QuantizedFacings => quantizedFacings.Value;
|
|
|
|
public BodyOrientation(ActorInitializer init, BodyOrientationInfo info)
|
|
{
|
|
this.info = info;
|
|
var self = init.Self;
|
|
var faction = init.GetValue<FactionInit, string>(self.Owner.Faction.InternalName);
|
|
|
|
quantizedFacings = Exts.Lazy(() =>
|
|
{
|
|
// Override value is set
|
|
if (info.QuantizedFacings >= 0)
|
|
return info.QuantizedFacings;
|
|
|
|
var qboi = self.Info.TraitInfoOrDefault<IQuantizeBodyOrientationInfo>();
|
|
|
|
// If a sprite actor has neither custom QuantizedFacings nor a trait implementing IQuantizeBodyOrientationInfo, throw
|
|
if (qboi == null)
|
|
{
|
|
if (self.Info.HasTraitInfo<WithSpriteBodyInfo>())
|
|
throw new InvalidOperationException("Actor '" + self.Info.Name + "' has a sprite body but no facing quantization."
|
|
+ " Either add the QuantizeFacingsFromSequence trait or set custom QuantizedFacings on BodyOrientation.");
|
|
else
|
|
throw new InvalidOperationException("Actor type '" + self.Info.Name + "' does not define a quantized body orientation.");
|
|
}
|
|
|
|
var facings = qboi.QuantizedBodyFacings(self.Info, self.World.Map.Sequences, faction);
|
|
if (facings == 0)
|
|
throw new InvalidOperationException($"Actor {self.Info.Name} defines a quantized body orientation from {qboi.GetType().Name} with zero facings.");
|
|
|
|
return facings;
|
|
});
|
|
}
|
|
|
|
public WAngle CameraPitch => info.CameraPitch;
|
|
|
|
public WVec LocalToWorld(in WVec vec)
|
|
{
|
|
return info.LocalToWorld(vec);
|
|
}
|
|
|
|
public WRot QuantizeOrientation(in WRot orientation)
|
|
{
|
|
return info.QuantizeOrientation(orientation, quantizedFacings.Value);
|
|
}
|
|
|
|
public WAngle QuantizeFacing(WAngle facing)
|
|
{
|
|
return info.QuantizeFacing(facing, quantizedFacings.Value);
|
|
}
|
|
|
|
public WAngle QuantizeFacing(WAngle facing, int facings)
|
|
{
|
|
return info.QuantizeFacing(facing, facings);
|
|
}
|
|
}
|
|
}
|