//=====================================================================
// NemesisWINGSvX.
//      ""(§)FrÅgÊd(§)""
//               **Monarch**
//
//              555 ---===CrAzYBoNeS===--- 555
//			Boppolis_The_Dog
//
//
// Thank you Al McElrath for SLV2.
//=====================================================================
/** Utility object. Handles debugging, release info, and beta
    expiration functions.
*/
class Util extends SLInfo config (NemesisWINGSvX);


// DATA
//

var() string version;
var() string vstr;
var() string when;
var() int build;

// Expiration date.
var() int expm;
var() int expd;
var() int expy;

var() config bool bExpires;
var() string expiredMsg;

// The player who's the viewport.
var PlayerPawn player;


/** This is how the debugging system works. Each object spawns its own
    util. The default debugging level is default.defaultDL. Each util can
    have its own defaultDL as well (set via setDebugLevel()). The
    outputDL is the level of verbosity at which we actually output. Again,
    there is a default and each util can a separate output level. Console
    logging has a separate outputDL that works similarly, consoleOutputDL.
*/

enum EDebugLevel {
    DL_Default,
    DL_Error,
    DL_Normal,
    DL_Verbose
};

var() config EDebugLevel outputDL;
var() config EDebugLevel consoleOutputDL;
var() config EDebugLevel defaultDL;

/** Keeps track of when the last debug was called for each function.
*/
var float fstamp[4];
var string fname[4];

var() bool bLeftMeshesLoaded;
var() string leftWeapons[2];


// METHODS
//

function postBeginPlay() {
    if (level.netmode != NM_DedicatedServer)
        setPlayer();
}


function bool setPlayer() {
    local PlayerPawn pp;

    // Get the viewport for console logging.
    foreach allActors(class'PlayerPawn', pp) {
        if (hasViewport(pp)) {
            player = pp;
            return true;
        }
    }

    return false;
}


/** Instead of 0 to 65536, it makes it -16384 to 16384.
*/
function centerRotComp(out float comp) {
    if (comp < -32768)
        comp += 65536;
    else if (comp > 32768)
        comp -= 65536;
}


/** Useful function to keep those if statements short.
*/
function bool hasViewPort(Actor a) {
    return (a != none && a.isA('PlayerPawn') && PlayerPawn(a).player != none && ViewPort(PlayerPawn(a).player) != none);
}


function Mutator getHUDMutator (PlayerPawn P, name C, optional bool Delete)
{
    local Mutator M;
    local Mutator Last;

    if ( (P != None) && (P.myHUD != None) )
    {
        M=P.myHUD.HUDMutator;
JL003E:
        if ( M != None )
        {
            if ( M.IsA(C) )
            {
                if ( Delete )
                {
                    if ( M == P.myHUD.HUDMutator )
                    {
                        P.myHUD.HUDMutator=M.NextHUDMutator;
                    }
                    else

                    {
                        Last.NextHUDMutator=M.NextHUDMutator;
                    }
                    M.NextHUDMutator=None;
                }
                return M;
            }
            Last=M;
            M=M.NextHUDMutator;
            goto JL003E;
        }
    }
    return None;
}

/** Are we playing a legacy (non-Strangelove) gametype?
*/
function bool legacy() {
    return (!(level.game.isA('Strangewar') || level.game.isA('Strangerace')));
}

function bool UTPureOn (PlayerPawn P)
{
    if ( hasViewPort(P) )
    {
        if ( InStr(string(P.Player.Console.Class),"UTPure") >= 0 )
        {
            return True;
        }
    }
    return False;
}


function setDebugLevel(EDebugLevel l) {
    defaultDL = l;
}


function setOutputLevel(EDebugLevel l) {
    outputDL = l;
}


function setConsoleOutputLevel(EDebugLevel l) {
    consoleOutputDL = l;
}


/** Pass an actor reference and debug string (usually function name).
*/
function debug(string s, optional EDebugLevel dl, optional float wait, optional string tag) {
    local Actor a;
    local string msg;
    local string ostr;

    if (dl == DL_Default)
        dl = defaultDL;

    // No waiting if verbose.
    if (wait > 0.0 && outputDL != DL_Verbose && !waitover(getFuncName(s), wait))
        return;

    if (dl <= outputDL) {
        a = self.owner;

        if (tag == "")
            tag = "DEBUG";

        if (level.netmode != NM_Standalone)
            tag = tag @ theTime();
        else
            tag = tag @ level.timeseconds;

        msg = tag @ "in ";

        if (a != none)
            msg = msg $ sname(a) $ "(" $ sname(a.owner) $ ")." $ s;
        else
            msg = msg $ "unknown()." $ s;

        log(msg);

        if (dl <= consoleOutputDL && level.netmode != NM_DedicatedServer) {
            if (player != none || (player == none && setPlayer())) {
                // This could be done better. FIX.
                if (wait > 0.0 && (outputDL == DL_Verbose && consoleOutputDL != DL_Verbose) && !waitover(getFuncName(s), wait))
                    return;

                player.player.console.message(player.playerReplicationInfo, msg, 'debug');
            }
        }
    }
}


function err(string s) {
    debug(s, DL_Error, 0.0, "ERROR!");
}


function string theTime() {
    local int ms;
    local string mss;

    ms = level.millisecond;
    if (ms < 100)
        mss = "0" $ ms;
    else
        mss = string(ms);

    return (level.hour $ ":" $ level.minute $ ":" $ level.second $ "." $ mss);
}


/** Only print debugs for this func every w seconds.
*/
function bool waitover(string func, float w) {
    local int i;
    local float t;

    t = level.timeseconds;

    for (i = 0; i < arrayCount(fstamp); i++) {
        if (fname[i] == func) {
            if (t - fstamp[i] > w) {
                fstamp[i] = t;
                return true;
            } else {
                return false;
            }
        }
    }

    // Didn't find the func name, insert it.
    for (i = 0; i < arrayCount(fstamp); i++) {
        if (fname[i] == "") {
            fname[i] = func;
            fstamp[i] = t;
            // Don't debug initially.
            return false;
        }
    }

    // Need to increase the fstamp and fname arrays...
    err("wait(" $ func $ ", " $ sf(w) $ "): no tags slots");
    return false;
}


function string getFuncName(string s) {
    local int i;

    i = instr(s, "(");
    return left(s, i);
}


function string sv(vector v, optional bool bSize) {
    local string size;

    if (bSize)
        size = " vsize=" $ chopf(vsize(v));

    return "(x=" $ chopf(v.x) $ " y=" $ chopf(v.y) $ " z=" $ chopf(v.z) $ size $ ")";
}


function string sr(rotator r) {
    return "(p=" $ r.pitch $ " y=" $ r.yaw $ " r=" $ r.roll $ ")";
}


/** Cuts off trailing 0's.
*/
function string sf(float f) {
    local string s;

    s = string(f);

    while (right(s, 1) == "0") {
        s = left(s, len(s) - 1);
    }

    if (right(s, 1) == ".") {
        s = s $ "0";
    }

    return s;
}


/** Chops off anything after the tenths place.
*/
function string chopf(float f, optional float nochop) {
    local string s;
    local int i;

    if (abs(f) < nochop)
        return string(f);

    s = string(f);
    i = instr(s, ".");
    s = left(s, i + 2);

    return s;
}


function string sname(Actor a) {
    if (a != none) {
        if (a.isA('Pawn')) {
            return Pawn(a).playerReplicationInfo.playername;
        } else {
            return noMap(a);
        }
    } else {
        return "none";
    }
}


function string noMap(Actor a) {
    local int index;

    index = instr(a, ".");
    if (index == -1) {
        return string(a);
    } else {
        return right(a, len(a) - index - 1);
    }
}


/** Parses the damage string and sets it in the GameInfo.
*/
function setDamageString(string s, Actor k, Actor o) {
    debug("setDamageString(" $ s $ ", " $ sname(k) $ ", " $ sname(o) $ ")");

    level.game.specialDamageString = parseKillString(s, k, o);
}


/** Handles pronouns and such that parseKillMessage() doesn't. pkm()
    still handles %k, %o, and %w, though. This has to be called first.

    If we are passing this to pkm(), bNames should be false. Note
    pkm() silently fails if you don't use %k.
*/
function string parseKillString(string s, Actor killer, Actor other, optional bool bNames) {

    if (killer != none && killer.isA('Pawn') && Pawn(killer).bIsFemale) {
        replace(s, "%kpa", "her");
        replace(s, "%kop", "her");
	replace(s, "%kkh", "she");
    } else {
        replace(s, "%kpa", "his");
        replace(s, "%kop", "him");
	replace(s, "%kkh", "he");
    }

    if (other != none && other.isA('Pawn') && Pawn(other).bIsFemale) {
        replace(s, "%opa", "her");
        replace(s, "%oop", "her");
	replace(s, "%okh", "she");
    } else {
        replace(s, "%opa", "his");
        replace(s, "%oop", "him");
	replace(s, "%okh", "he");
    }

    if (bNames) {
        replace(s, "%ks", sname(killer) $ poss(sname(killer)));
	replace(s, "%k", sname(killer));
    } else {
        // Leave the %k in for pkw()!
        replace(s, "%ks", "%k" $ poss(sname(killer)));
    }

    // We can always do %o.
    replace(s, "%os", sname(other) $ poss(sname(other)));
    replace(s, "%o", sname(other));

    debug("u.parseKillString(): returning: " $ s, DL_Verbose);
    return s;
}


/** Takes a proper name and makes it possessive. E.g. Drewbacca
    becomes Drewbacca's and yrns becomes yrns'.

    Update: Only returns what we'd tack on the end.
*/
function string poss(string name) {
    if (right(name, 1) == "s")
        return "'";
    else
        return "'s";
}


/** Replace in with out in str.
*/
function replace(out string str, string in, string out) {
    local int i;

    i = instr(str, in);
    if (i != -1) {
        str = left(str, i) $ out $ right(str, len(str) - (i + len(in)));
    }
}


static function string getVersionString() {
    //return default.vstr $ " build: " $ default.build $ " compiled: " $ default.when;
    return default.vstr $ "." $ default.build $ " built on " $ default.when;
}


// Beta expiration check.
static function bool expiredBeta(LevelInfo level) {
    if (default.bExpires && !(level.year < default.expy || (level.year == default.expy && level.month < default.expm || (level.month == default.expm && level.day < default.expd)))) {
        log(default.expiredMsg);
        return true;
    }

    return false;
}


/** Preloads the left meshes for the necessary weapons. Called from
    SLWeapon.postBeginPlay().
*/
function loadLeftMeshes() {
    local int i;
    local Class<SLWeapon> c;
    local SkeletalMesh m;

    if (!bLeftMeshesLoaded) {
        for (i = 0; i < arrayCount(leftWeapons); i++) {
            if (leftWeapons[i] != "") {
                c = Class<SLWeapon>(dynamicLoadObject(leftWeapons[i], Class'Class'));
                if (c != none) {
                    debug("loadLeftMeshes(): loading: " $ c.default.leftMesh);
                    m = SkeletalMesh(dynamicLoadObject(c.default.leftMesh, Class'SkeletalMesh'));
                }
            }
        }

        default.bLeftMeshesLoaded = true;
    }
}



// end

defaultproperties
{
     version="200"
     vstr="RELEASE-2.00"
     when="Wed Aug 29 01:35:40 2001"
     Build=52
     expm=8
     expd=17
     expy=2001
     expiredMsg="This Strangelove BETA version has expired. Visit http://www.planetunreal.com/0fus/ for a release version."
     outputDL=DL_Error
     consoleOutputDL=DL_Error
     defaultDL=DL_Normal
     leftWeapons(0)="SLV2.Sidearm"
     leftWeapons(1)="SLV2.Konglauncher"
}
