// Normalize rotational values by & 65535?  Test with commandlet.

//-----------------------------------------------------------
// Generic Emitter stuff.
//-----------------------------------------------------------
class XS_Emitter extends Emitter
    abstract;

/** Sets r's values to Value. */
// static final operator(100) range = (out range r, float Value)
// {
//     r.Min = Value;
//     r.Max = Value;
// 
//     return r;
// }

/** Adds Value to r's values. */
static final operator(20) range += (out range r, float Value)
{
    r.Min += Value;
    r.Max += Value;

    return r;
}

/** Adds Value to r's values. */
static final operator(20) range + (range r, float Value)
{
    r += Value;

    return r;
}

/** Adds Value to rv's values. */
static final operator(20) rangevector += (out rangevector rv, float Value)
{
    rv.X += Value;
    rv.Y += Value;
    rv.Z += Value;

    return rv;
}

/** Adds Value to rv's values. */
static final operator(20) rangevector + (rangevector rv, float Value)
{
    rv += Value;

    return rv;
}

/** Adds v to rv's values. */
static final operator(20) rangevector += (out rangevector rv, vector v)
{
    rv.X += v.X;
    rv.Y += v.Y;
    rv.Z += v.Z;

    return rv;
}

/** Adds v to rv's values. */
static final operator(20) rangevector + (rangevector rv, vector v)
{
    rv += v;

    return rv;
}

/** Multiplies r's values by Multiplier. */
static final operator(16) range *= (out range r, float Multiplier)
{
    r.Min *= Multiplier;
    r.Max *= Multiplier;

    return r;
}

/** Multiplies r's values by Multiplier. */
static final operator(16) range * (range r, float Multiplier)
{
    r *= Multiplier;

    return r;
}

/** Multiplies rv's values by Multiplier. */
static final operator(16) rangevector *= (out rangevector rv, float Multiplier)
{
    rv.X *= Multiplier;
    rv.Y *= Multiplier;
    rv.Z *= Multiplier;

    return rv;
}

/** Multiplies rv's values by Multiplier. */
static final operator(16) rangevector * (rangevector rv, float Multiplier)
{
    rv *= Multiplier;

    return rv;
}

/** Constructs a range from Min and Max. */
static final function range ran(float Min, float Max)
{
    local range r;

    r.Min = Min;
    r.Max = Max;

    return r;
}

/** Returns a value in r proportional to RelativeValue, where 0 <= RelativeValue <= 1. */
static final function float Relate(float RelativeValue, range r)
{
    return r.Min + (r.Max - r.Min) * RelativeValue;
}

/** Concatenates v to a string in X,Y,Z format without fractions. */
static final operator(40) string $ (coerce string s, vector v)
{
    local string NewString;
    local string X;
    local string Y;
    local string Z;

    X = string(Round(v.X));
    X = Left(X, Len(X) - 3);
    Y = string(Round(v.Y));
    Y = Left(Y, Len(Y) - 3);
    Z = string(Round(v.Z));
    Z = Left(Z, Len(Z) - 3);

    NewString = s $ X $ "," $ Y $ "," $ Z;

    return NewString;
}

/** Concatenates rv to a string in X,Y,Z-X,Y,Z format without fractions. */
static final operator(40) string $ (coerce string s, rangevector rv)
{
    local string NewString;
    local vector Min;
    local vector Max;

    Min.X = rv.X.Min;
    Min.Y = rv.Y.Min;
    Min.Z = rv.Z.Min;
    Max.X = rv.X.Max;
    Max.Y = rv.Y.Max;
    Max.Z = rv.Z.Max;

    NewString = s $ Min $ "-" $ Max;

    return NewString;
}

/** Concatenates r to a string in Pitch,Yaw,Roll format. */
static final operator(40) string $ (coerce string s, rotator r)
{
    local string NewString;

    NewString = s $ r.Pitch $ "," $ r.Yaw $ "," $ r.Roll;

    return NewString;
}

/** Degrees postoperator.

    Example:

        r.Pitch = 45 degrees;

    is equivalent to:

        r.Pitch = 8192; */
static final postoperator float degrees(float Value)
{
    return Value / 360 * 65536;
}

/** Unreal Rotational Units postoperator.

    Example:

        r.Pitch = 8192 URU;

    is equivalent to:

        r.Pitch = 45 degrees; */
static final postoperator float URU(float Value)
{
    return Value * 65536 / 360;
}

/** Normalize r into the 0 to 65535 range.
    The native Normalize() function seems to sometimes, but not always,
    normalize into the -32768 to 32767 range.*/
static final function rotator Normalize2(rotator r)
{
    while(r.Pitch < 0)
    {
        r.Pitch += 65536;
    }

    while(r.Yaw < 0)
    {
        r.Yaw += 65536;
    }
    
    while(r.Roll < 0)
    {
        r.Roll += 65536;
    }

    return r;
}

/** Return true if f is between Min and Max. */
static final function bool IsBetween(float f, float Min, float Max)
{
    local bool bBetween;

    if(f >= Min
    && f <= Max)
    {
        bBetween = true;
    }

    return bBetween;
}


/** Ensure r points upwards. */
static final function rotator UpEnd(rotator r)
{
    r = Normalize2(r);

    // Not upright?
    if(vector(r) dot vect(0,0,1) < 0)
    {
        UpEndPlane(r.Pitch);
        UpEndPlane(r.Roll);
    }
    
    return r;
}

/** Ensures r is in a rotator's upper hemisphere. */
static final function int UpEndPlane(int r)
{
    // Twist clockwise or counterclockwise?
    if(IsBetween(r, 16384, 32768))
    {
        // Twist counterclockwise to 90 degrees.
        r = 16384;
    }
    else if(IsBetween(r, 32768, 49152))
    {
        // Twist clockwise to 270 degrees.
        r = 49152;
    }
    
    return r;
}

/** Resizes all 3D aspects of all particle emitters. */
simulated function Resize(float Size)
{
    local int i;

    for(i = 0; i < Emitters.length; i++)
    {
        Emitters[i].StartSizeRange.X *= Size;
        Emitters[i].StartVelocityRange.X *= Size;
        Emitters[i].StartLocationRange.X *= Size;
        Emitters[i].Acceleration *= Size;
    }
}

/** Zeroes v's Z component. */
static final postoperator vector in2D(vector v)
{
    local vector v2D;

    v2D = v;
    v2D.Z = 0;

    return v2D;
}

/** Checks if o == none.

    Example:

        // MyDoodad must be empty.
        if(!MyDoodad)
*/
static final preoperator bool ! (object o)
{
    return o == none;
}

/** Checks if o != none.

    Example:

        // my doodad must be an instance of something.
        if(MyDoodad?)
*/
static final postoperator bool ? (object o)
{
    return o != none;
}

/*
// Check if Bob is bGrabable, without knowing whether bGrabbable is a member of 
// Bob's class.
if (bool(Bob.GetPropertyText("bGrabable")))
{
     // do stuff
}
*/

/** Increases i by one, and wraps around to Beginning if exceeding End. */
static function Cycle(out byte i, byte Beginning, byte End)
{
    i++;

    if(i > End)
    {
        i = Beginning;
    }
}

/** Normalize rotational value (-32768 <= Value < 32768). */
function int NormalRotValue(int Value)
{
    while(Value < -32768)
    {
        Value += 65536;
    }

    while(32768 < Value)
    {
        Value -= 65536;
    }

    return Value;
}

defaultproperties
{
}
