#include "zcommon.acs"
#library "hatstuff"

#encryptstrings

#include "commonFuncs.h"
#include "hiddenhats.txt"

#define HATCOUNT 33
int HatNames[HATCOUNT] =
{
    /* 1  */ "Crown",
             "Top Hat",
             "Sombrero",
             "Fez",
    /* 5  */ "Turban",
             "Skull",
             "Bunny Ears",
             "Horns",
             "Halo",
    /* 10 */ "Mario Cap",
             "Nignog",
             "Arby's hat",
             "Bow",
             "Party Hat",
    /* 15 */ "Chef's Hat",
             "Sailor Cap",
             "Metal Pot",
             "Viking Helmet",
             "Cowboy Hat",
    /* 20 */ "Graduate Cap",
             "Pimp Hat",
             "Fedora",
             "Watermelon",
             "Bananas",
    /* 25 */ "Pirate Hat",
             "Steak",
			 "Rocket Jumper",
			 "Melee Prayer",
			 "Afro",
	/* 30 */ "Flem Mine",
			 "Golden Rocket",
			 "Cyber Helmet",
			 "Dark Cloud",
};

int HatActors[HATCOUNT] =
{
    /* 1  */ "Crown6066",
             "tophat",
             "Sombrero",
             "fez",
    /* 5  */ "Turban",
             "runescape",
             "BunnyEars",
             "demonhorns",
             "Halo",
    /* 10 */ "marioshat",
             "NIGPLZ",
             "arbyshat",
             "pinkbow",
             "partyhat",
    /* 15 */ "chefshat",
             "sailorshat",
             "metalpot",
             "vikinghat",
             "cowboyhat",
    /* 20 */ "gradhat",
             "pimphat",
             "Fedorahat",
             "WatermelonHat",
             "BananaHat",
    /* 25 */ "PirateHat",
             "SteakHat",
			 "RocketHat",
			 "ProtectFromMelee",
			 "THEAFRO",
	/* 30 */ "FELEMOIDBUMB",
			 "RocketJumperGold",
			 "CybRunnerHelmet",
			 "CloudHat",
};

//                              1     2     2     4     5     6     7     8     9    10    11    12    13    14    15    16    17    18    19    20    21    22    23,   24    25    26    27    28    29    30    31    32    33
int HatXOffsets[HATCOUNT] =  {-1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -3.0, -2.0, -3.0, -3.0,  2.0, -1.0, -1.0, -1.0, -1.0, -1.0, -3.0, -3.0, -1.0, -3.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0, -1.0};
int HatYOffsets[HATCOUNT] =  { 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    4.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0};
int HatZOffsets[HATCOUNT] =  { 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    2.0,  0,    0,    0,    0,    0,    0,   -3.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0,  0.0};
int HatTranslate[HATCOUNT] = { 0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0,    0};

int SV_PlayerHats[PLAYERMAX];    // Which one?
int SV_PlayerAlphas[PLAYERMAX];  // How does it react to translucency?
int SV_PlayerAlways[PLAYERMAX];  // Always show the hat?
int SV_ClientMenu[PLAYERMAX];    // In the menu?
int SV_PreMenuSpeed[PLAYERMAX];  // Speed before entering menu

int CL_CanBeSeen[PLAYERMAX];        // duh
int CL_ClientMenu[PLAYERMAX];       // In menu - clientside
int CL_PlayerAlphas[PLAYERMAX];     // How hats react to translucency
int CL_PlayerHats[PLAYERMAX];       // Which hat?
int CL_PlayerHatTIDs[PLAYERMAX];    // TIDs of the hats
int CL_PlayerHatScripts[PLAYERMAX]; // Currently running a hat script?
int CL_PlayerTIDS[PLAYERMAX];       // duh
int CL_ZHeightMod[PLAYERMAX];       // for Z height changes that need serverside information

int HATCVAR     = "hats_myhat";
int DISABLECVAR = "hats_disable";
int ALPHACVAR   = "hats_alphamode";
int ALWAYSCVAR  = "hats_alwaysshow";
int OWNHATCVAR  = "hats_ownhatinterpolate";
int FIRSTTIMEHATNOTIFICATION = "_hats_hasnagged";

int HATHELP = "\
Hats! Because we know you want them.\
\n\
\nCommands:\
\n - hathelp: This.\
\n - hatmenu: Brings up a menu to choose what hat you want.\
\n\
\nCVars:\
\n - hats_myhat: The index of the hat you want.\
\n - hats_disable: Disable hats for everyone on your end.\
\n - hats_alwaysshow: I guess if you want to always have your hat visible you can?\
\n - hats_alphamode: Sets how your hat reacts to your alpha value.\
\n - hats_ownhatinterpolate: If 0, your hat is treated exactly the same as all\
\n   other hats in terms of where it's put on your head. If 1, it's placed farther\
\n   behind you on the Z axis so that your camera doesn't accidentally see it.\
\n   0: Disappears if you have less than 75% alpha.\
\n   1: Shares the same alpha value as you.\
\n   2: Sets its alpha to double your translucency. For example, if you're\
\n      at 70% alpha, your hat has 40% alpha (30% -> 60%).";


function int Hats_CanBeSeen(void)
{
    int testtid = unusedTID(34000, 44000);
    int pln = PlayerNumber();

    if (pln == -1) { return 0; }
    if (SV_PlayerAlways[pln]) { return 1; }
    
    // If this passes, we're probably in Hide 'n' Seek
    if (Spawn("TerminatorPlasmaRifle", GetActorX(0), GetActorY(0), GetActorZ(0), testtid))
    {
        Thing_Remove(testtid);

        if (CheckInventory("BlazeSphere")               // Blazer
         || CheckInventory("VanisherFist")              // Vanisher
         || CheckInventory("NoDamageRocketLauncher")    // Rocketeer
         || CheckInventory("TeleporterSuit"))           // Teleporter
        {
            return 0;
        }
    }

    return 1;
}

function int Hats_ZHeightMod(void)
{
    int testtid = unusedTID(36000, 46000);

    // GVH Hunter: taller than most, place hat higher.
	if (CheckInventory("HumanTeam") == 1 && CheckInventory("ClassID") == 2)
    {
        return 10.0;
    }

    // Zombie horde: zombies are taller, place hat higher.
    if (CheckInventory("ZombieMaker"))
    {
        return 16.0;
    }

    if (Spawn("AOWWeapon", GetActorX(0), GetActorY(0), GetActorZ(0), testtid))
    {
        Thing_Remove(testtid);

        if (CheckInventory("GuardianWeapons")) { return 12.0; }
        if (CheckInventory("MadCatWeapons")) { return 38.0; }
        if (CheckInventory("RavenWeapons")) { return 8.0; }
        if (CheckInventory("TitanWeapons")) { return 24.0; }
    }
	
	if (Spawn("Action_DropWeaponCancel", GetActorX(0), GetActorY(0), GetActorZ(0), testtid))
    {
        Thing_Remove(testtid);
		return -6.0;
    }

    return 0.0;
}



script 171 open clientside
{
    int pukestr;
    int curhat, prvhat;
    curhat = -1;

    if (!GetCVar(HATCVAR))
    {
        ConsoleCommand(StrParam(s:"set ", s:HATCVAR, s:" 0"));
        ConsoleCommand(StrParam(s:"archivecvar ", s:HATCVAR));
    }

    if (!GetCVar(DISABLECVAR))
    {
        ConsoleCommand(StrParam(s:"set ", s:DISABLECVAR, s:" 0"));
        ConsoleCommand(StrParam(s:"archivecvar ", s:DISABLECVAR));
    }

    if (!GetCVar(ALWAYSCVAR))
    {
        ConsoleCommand(StrParam(s:"set ", s:ALWAYSCVAR, s:" 0"));
        ConsoleCommand(StrParam(s:"archivecvar ", s:ALWAYSCVAR));
    }

    if (!GetCVar(ALPHACVAR))
    {
        ConsoleCommand(StrParam(s:"set ", s:ALPHACVAR, s:" 0"));
        ConsoleCommand(StrParam(s:"archivecvar ", s:ALPHACVAR));
    }

    if (!GetCVar(OWNHATCVAR))
    {
        ConsoleCommand(StrParam(s:"set ", s:OWNHATCVAR, s:" 0"));
        ConsoleCommand(StrParam(s:"archivecvar ", s:OWNHATCVAR));
    }

    if (GetCVar(FIRSTTIMEHATNOTIFICATION) != 1)
    {
        ConsoleCommand(StrParam(s:"set ", s:FIRSTTIMEHATNOTIFICATION, s:" 1"));
        ConsoleCommand(StrParam(s:"archivecvar ", s:FIRSTTIMEHATNOTIFICATION));
		setfont("bigfont");
		hudmessage(s:"Welcome to hats!\nTo open the hat menu, type in 'hatmenu' in the console.\nFor more help type in 'hathelp' in the console.\n- Dominating doom fashion since 1993."; 
		HUDMSG_FADEOUT | HUDMSG_LOG, 0, CR_White, 0.5, 0.4, 6.5, 1.0, 1.0);
    }

    while (1)
    {
        prvhat = curhat;
        curhat = GetCVar(HATCVAR);
		
		setactivator( CL_PlayerTIDs[ConsolePlayerNumber()] );
		if (PlayerIsSpectator(ConsolePlayerNumber()) || (curhat == 27 && !Hats_Unlockable(1)))
		{
//			log(d:playernumber());
			curhat = 0;
		}
		if (PlayerIsSpectator(ConsolePlayerNumber()) || (curhat == 28 && Hats_Unlockable(2) != 1))
		{
			curhat = 0;
		}
		if (PlayerIsSpectator(ConsolePlayerNumber()) || (curhat == 29 && Hats_Unlockable(3) != 1))
		{
			curhat = 0;
		}
		if (PlayerIsSpectator(ConsolePlayerNumber()) || (curhat == 30 && Hats_Unlockable(4) != 1))
		{
			curhat = 0;
		}
		if (PlayerIsSpectator(ConsolePlayerNumber()) || (curhat == 31 && Hats_Unlockable(5) != 1))
		{
			curhat = 0;
		}
		if (PlayerIsSpectator(ConsolePlayerNumber()) || (curhat == 32 && Hats_Unlockable(6) != 1))
		{
			curhat = 0;
		}
		if (PlayerIsSpectator(ConsolePlayerNumber()) || (curhat == 33 && Hats_Unlockable(7) != 1))
		{
			curhat = 0;
		}
		setactivator(-1);
		
        if (Timer() % 35 == 0  || prvhat != curhat)
        {
            pukestr = StrParam(s:"puke -172 ", d:curhat, s:" ", d:GetCVar(ALPHACVAR), s:" ", d:GetCVar(ALWAYSCVAR));
            ConsoleCommand(pukestr);
        }
        Delay(1);
    }
}

script 172 (int myhat, int alpha, int always) net
{
    int pln = PlayerNumber();
    if (pln == -1) { terminate; }

    SV_PlayerHats[pln] = myhat;
    SV_PlayerAlphas[pln] = alpha;
    SV_PlayerAlways[pln] = always;
}

script 173 enter
{
    int pln = PlayerNumber();
    int tid;
    int prvhat, hat;
    int prvsee, cursee;
    int prvheight, curheight;
    int bothat = random(0, HATCOUNT);
    int alphamode;
    int time = 0;
    while (1)
    {
        if (!isDead(0)) { tid = defaultTID(-1); }

        alphamode = SV_PlayerAlphas[pln];
        prvhat = hat;
        if (!PlayerIsBot(pln)) { hat = SV_PlayerHats[pln]; }
        else { hat = bothat; SV_PlayerHats[pln] = hat; }

        prvsee = cursee;
        cursee = Hats_CanBeSeen();

        prvheight = curheight;
        curheight = Hats_ZHeightMod();

        if (hat != prvhat || prvsee != cursee || prvheight != curheight || time % 18 == 0)
        {
            ACS_ExecuteAlways(174, 0, 0, tid, hat);
            ACS_ExecuteAlways(174, 0, 1, alphamode, cursee);
            ACS_ExecuteAlways(174, 0, 2, curheight, 0);
            time %= 18;
        }

        time++;
        Delay(1);
    }
}

script 174 (int which, int a1, int a2) clientside
{
    int pln = PlayerNumber();
    int testtid = unusedTID(38000, 48000);

    switch (which)
    {
      case 0:
        CL_PlayerTIDs[pln] = a1;
        CL_PlayerHats[pln] = a2;

        Thing_ChangeTID(0, a1);

        // AOW does some weird stuff on join, making you look like you're dead for half a second
        if (Spawn("AOWWeapon", GetActorX(0), GetActorY(0), GetActorZ(0), testtid))
        {
            Thing_Remove(testtid);
            ACS_ExecuteWithResult(175, pln, Timer()+18);
        }
        else
        {
            ACS_ExecuteWithResult(175, pln, 0);
        }
        break;

      case 1:
        CL_PlayerAlphas[pln] = a1;
        CL_CanBeSeen[pln] = a2;
        break;
      
      case 2:
        CL_ZHeightMod[pln] = a1;
        break;
    }
}

script 175 (int pln, int countdeath) clientside
{
    if (CL_PlayerHatScripts[pln]) { terminate; }
    CL_PlayerHatScripts[pln] = 1;

    SetActivator(-1);
    int hattid = -1;
    int curhat, oldhat;
    int mytid;
    int i, x, y, z, a, vx, vy, vz;
    int reloop;
    int nx, ny, nz;
    int height;

    curhat = CL_PlayerHats[pln];

    while (PlayerInGame(pln))
    {
        mytid = CL_PlayerTIDs[pln];
        oldhat = curhat;
        curhat = middle(0, CL_PlayerHats[pln], HATCOUNT)-1;

        if (curhat == -1 || GetCVar(DISABLECVAR) || !CL_CanBeSeen[pln])
        {
            if (hattid > 0 && ThingCount(0, hattid) > 0)
            {
                Thing_Remove(hattid);
                hattid = -1;
            }

            Delay(1);
            continue;
        }
		
        if (isDead(mytid) && Timer() >= countdeath)
        {
            if (hattid > 0 && ThingCount(0, hattid) > 0)
            {
                GiveActorInventory(hattid, "Hat_FallOffHead", 1);
                Thing_ChangeTID(hattid, 0);
                hattid = -1;
            }

            Delay(1);
            continue;
        }
        
        x = GetActorX(mytid);
        y = GetActorY(mytid);
        z = GetActorZ(mytid);
        a = GetActorAngle(mytid);
        vx = GetActorVelX(mytid);
        vy = GetActorVelY(mytid);
        vz = GetActorVelZ(mytid);

        if (ThingCount(0, hattid) <= 0 || oldhat != curhat)
        {
            if (ThingCount(0, hattid) > 0 && hattid != 0) { Thing_Remove(hattid); }

            hattid = unusedTID(12000, 15000);
            while (1)
            {
                reloop = 0;

                for (i = 0; i < PLAYERMAX; i++)
                {
                    if (CL_PlayerTIDs[i] == hattid || CL_PlayerHatTIDs[i] == hattid || ThingCount(0, hattid) > 0)
                    {
                        hattid++;
                        reloop = 1;
                        break;
                    }
                }
                
                if (!reloop) { break; }
            }

            Spawn(HatActors[curhat], x,y,z, hattid, a);
        }

        if (HatTranslate[curhat])
        {
            SetActivator(mytid);
            Thing_SetTranslation(hattid, -1);
            SetActivator(-1);
        }
		
		else if(curhat == 29 || curhat == 31)
		{//FLEMOID HAT AND cyberrunner helmet
            SetActivator(mytid);
            Thing_SetTranslation(hattid, -1);
            SetActivator(-1);
		}

        CL_PlayerHatTIDs[pln] = hattid;
        height += HatZOffsets[curhat];

        switch (CL_PlayerAlphas[pln])
        {
          default: // Disappear if alpha is less than 0.75
            if (GetActorProperty(mytid, APROP_Alpha) < 0.75) { SetActorProperty(hattid, APROP_Alpha, 0); }
            else { SetActorProperty(hattid, APROP_Alpha, 1.0); }
            break;

          case 1: // Match player's alpha
            SetActorProperty(hattid, APROP_Alpha, GetActorProperty(mytid, APROP_Alpha));
            break;

          case 2: // Double player's alpha, with the base being 1.0
            i = -1.0 + (2 * GetActorProperty(mytid, APROP_Alpha));
            SetActorProperty(hattid, APROP_Alpha, i);
            break;
        }

        nx = x + FixedMul(HatXOffsets[curhat], cos(a)) + FixedMul(HatYOffsets[curhat], sin(a));
        ny = y + FixedMul(HatXOffsets[curhat], sin(a)) - FixedMul(HatYOffsets[curhat], cos(a));
        nz = z + HatZOffsets[curhat];
        nz += cond(isDead(mytid), 8.0, GetActorViewHeight(mytid)+7.0);
        nz += CL_ZHeightMod[pln];

        if (pln != ConsolePlayerNumber() || !GetCVar(OWNHATCVAR))
        {
            nx -= vx; ny -= vy; nz -= vz;
        }
        else
        {
            switch (GetCVar(OWNHATCVAR))
            {
              case 1:
                nx -= vx; ny -= vy; nz -= 2*vz;
                break;

              default:
                nx -= vx; ny -= vy; nz -= vz;
                break;
            }
        }

        SetActorAngle(hattid, a);
		if(curhat == 30) //golden rocket
		{
			SetActorPosition(hattid, nx, ny, nz+6.0, 0);
		}
        else
		{
			SetActorPosition(hattid, nx, ny, nz, 0);
		}
        SetActorVelocity(hattid, vx, vy, vz, 0, 0);
        
        Delay(1);
    }

    CL_PlayerHatScripts[pln] = 0;
}

script 176 (int pln) disconnect clientside
{
    Thing_Remove(CL_PlayerHatTIDs[pln]);
    CL_PlayerTIDs[pln] = 0;
    CL_PlayerHats[pln] = 0;
    CL_PlayerHatTIDs[pln] = 0;
}

script 177 (void) net clientside
{
    int i;

    for (i = 0; i < PLAYERMAX; i++)
    {
        if (!PlayerInGame(i)) { continue; }

        Log(d:i, s:" (", n:i+1, s:"\c-) - (TID: ", d:CL_PlayerTIDs[i], s:") (Hat: ", d:CL_PlayerHats[i], s:") (Hat TID: ", d:CL_PlayerHatTIDs[i], s:")");
    }
}

script 178 (int pln, int onOff) clientside
{
    if (ConsolePlayerNumber() != pln) { terminate; }

    if (PlayerIsSpectator(pln))
    {
        Print(s:"Spectators suck at menus.");
        terminate;
    }

    SetHudSize(640, 480, 1);

    CL_ClientMenu[pln] = onOff;
    int curhat = GetCVar(HATCVAR);
    int useexit;

    while (CL_ClientMenu[pln])
    {
        curhat += keyPressed(BT_MOVERIGHT);
        curhat -= keyPressed(BT_MOVELEFT);
        curhat = mod(curhat, HATCOUNT+1);
        
        SetFont("BIGFONT");
        HudMessage(s:"SELECT A HAT";
                HUDMSG_FADEOUT, 1785, CR_GOLD, 320.4, 240.0, 1.0, 0.5);

        if (curhat == 0)
        {
            HudMessage(s:"None";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.4, 280.0, 1.0, 0.5);
        }
		else if (curhat == 27)
		{
			if(Hats_Unlockable(1) == 0)
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_Red, 320.4, 280.0, 1.0, 0.5);			
			}
			else
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_White, 320.4, 280.0, 1.0, 0.5);
			}
		}
		else if (curhat == 28)
		{
			if(Hats_Unlockable(2) == 0)
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_Red, 320.4, 280.0, 1.0, 0.5);			
			}
			else
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_White, 320.4, 280.0, 1.0, 0.5);
			}
		}
		else if (curhat == 29)
		{
			if(Hats_Unlockable(3) == 0)
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_Red, 320.4, 280.0, 1.0, 0.5);			
			}
			else
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_White, 320.4, 280.0, 1.0, 0.5);
			}
		}
		else if (curhat == 30)
		{
			if(Hats_Unlockable(4) == 0)
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_Red, 320.4, 280.0, 1.0, 0.5);			
			}
			else
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_White, 320.4, 280.0, 1.0, 0.5);
			}
		}
		else if (curhat == 31)
		{
			if(Hats_Unlockable(5) == 0)
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_Red, 320.4, 280.0, 1.0, 0.5);			
			}
			else
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_White, 320.4, 280.0, 1.0, 0.5);
			}
		}
		else if (curhat == 32)
		{
			if(Hats_Unlockable(6) == 0)
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_Red, 320.4, 280.0, 1.0, 0.5);			
			}
			else
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_White, 320.4, 280.0, 1.0, 0.5);
			}
		}
		else if (curhat == 33)
		{
			if(Hats_Unlockable(7) == 0)
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_Red, 320.4, 280.0, 1.0, 0.5);			
			}
			else
			{
				HudMessage(s:HatNames[curhat-1];
				HUDMSG_FADEOUT, 1780, CR_White, 320.4, 280.0, 1.0, 0.5);
			}
		}
        else
        {
            HudMessage(s:HatNames[curhat-1];
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.4, 280.0, 1.0, 0.5);
        }

        HudMessage(s:"<-";
                HUDMSG_FADEOUT, 1781, CR_GREEN, 240.2, 280.0, 1.0, 0.5);

        HudMessage(s:"->";
                HUDMSG_FADEOUT, 1782, CR_GREEN, 400.1, 280.0, 1.0, 0.5);

        SetFont("SMALLFONT");
        HudMessage(s:"hats_myhat ", d:curhat;
                HUDMSG_FADEOUT, 1783, CR_WHITE, 320.0, 310.0, 1.0, 0.5);

        HudMessage(s:"\cf", k:"+use", s:"\c- selects; \cf", k:"+jump", s:"\c- exits";
                HUDMSG_FADEOUT, 1784, CR_WHITE, 320.0, 330.0, 1.0, 0.5);

        if (keyPressed(BT_USE))
        {
            useexit = 1;
            ConsoleCommand("puke -179");
            break;
        }

        if (keyPressed(BT_JUMP))
        {
            ConsoleCommand("puke -179");
            break;
        }

        Delay(1);
    }

    if (onOff)
    {
        HudMessage(s:""; HUDMSG_PLAIN, 1780, 0,0,0,0);
        HudMessage(s:""; HUDMSG_PLAIN, 1781, 0,0,0,0);
        HudMessage(s:""; HUDMSG_PLAIN, 1782, 0,0,0,0);
        HudMessage(s:""; HUDMSG_PLAIN, 1783, 0,0,0,0);
        HudMessage(s:""; HUDMSG_PLAIN, 1784, 0,0,0,0);
        HudMessage(s:""; HUDMSG_PLAIN, 1785, 0,0,0,0);

        if (useexit)
        {
            FadeRange(255, 255, 255, 0.5, 255, 255, 255, 0.0, 0.25);
            LocalAmbientSound("misc/p_pkup", 96);

            SetFont("SMALLFONT");

            if (curhat == 0)
            {
                HudMessage(s:"Your hat has been \cadisabled\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);
            }
			else if (curhat == 27)
			{
				if(Hats_Unlockable(1) == 0)
				{
					HudMessage(s:"You cannot set your hat to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_RED, 320.0, 280.0, 2.0, 0.5);
				}
				else
				{
					HudMessage(s:"Your hat has been set to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);		
				}
			}
			else if (curhat == 28)
			{
				if(Hats_Unlockable(2) == 0)
				{
					HudMessage(s:"You cannot set your hat to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_RED, 320.0, 280.0, 2.0, 0.5);
				}
				else
				{
					HudMessage(s:"Your hat has been set to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);		
				}
			}
			else if (curhat == 29)
			{
				if(Hats_Unlockable(3) == 0)
				{
					HudMessage(s:"You cannot set your hat to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_RED, 320.0, 280.0, 2.0, 0.5);
				}
				else
				{
					HudMessage(s:"Your hat has been set to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);		
				}
			}
			else if (curhat == 30)
			{
				if(Hats_Unlockable(4) == 0)
				{
					HudMessage(s:"You cannot set your hat to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_RED, 320.0, 280.0, 2.0, 0.5);
				}
				else
				{
					HudMessage(s:"Your hat has been set to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);		
				}
			}
			else if (curhat == 31)
			{
				if(Hats_Unlockable(5) == 0)
				{
					HudMessage(s:"You cannot set your hat to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_RED, 320.0, 280.0, 2.0, 0.5);
				}
				else
				{
					HudMessage(s:"Your hat has been set to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);		
				}
			}
			else if (curhat == 32)
			{
				if(Hats_Unlockable(6) == 0)
				{
					HudMessage(s:"You cannot set your hat to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_RED, 320.0, 280.0, 2.0, 0.5);
				}
				else
				{
					HudMessage(s:"Your hat has been set to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);		
				}
			}
			else if (curhat == 33)
			{
				if(Hats_Unlockable(7) == 0)
				{
					HudMessage(s:"You cannot set your hat to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_RED, 320.0, 280.0, 2.0, 0.5);
				}
				else
				{
					HudMessage(s:"Your hat has been set to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);		
				}
			}
            else
            {
					HudMessage(s:"Your hat has been set to \cf", s:HatNames[curhat-1], s:"\c- (", d:curhat, s:").";
                    HUDMSG_FADEOUT, 1780, CR_WHITE, 320.0, 280.0, 1.0, 0.5);
            }

            ConsoleCommand(StrParam(s:"set ", s:HATCVAR, s:" ", d:curhat));
        }
    }
}

script 179 (void) net
{
    int pln = PlayerNumber();
    if (pln == -1) { terminate; }

    SV_ClientMenu[pln] = !SV_ClientMenu[pln];

    if (SV_ClientMenu[pln])  // enter
    {
        GiveInventory("HatMenuFreeze", 1);
        ACS_ExecuteAlways(178, 0, pln, 1);
    }
    else  // exit
    {
        TakeInventory("HatMenuFreeze", 1);
        ACS_ExecuteAlways(178, 0, pln, 0);
    }
}

script 180 (void) net clientside
{
    int i, hat;
    int hatnumlen = 0;
    Log(s:"-----\n");
    Log(s:HATHELP);
    Log(s:"\nHat list:");

    i = HATCOUNT;

    while (i)
    {
        i /= 10;
        hatnumlen++;
    }

    for (i = 0; i <= HATCOUNT; i++)
    {
        hat = cond(i == 0, "None", HatNames[i-1]);
        Log(s:" ", s:padStringL(StrParam(d:i), " ", hatnumlen), s:": ", s:hat);
    }
    Log(s:"\n-----");
}

script 181 (int fadestart, int alpha, int fadetime) clientside
{
    if (CheckInventory("IAmAHat")) { SetActorState(0, "HatDeath"); }
    alpha = itof(alpha) / 100;
    int i;
    int start   = GetActorProperty(0, APROP_Alpha);
    int fademod = alpha - start;

    Delay(fadestart);

    for (i = 0; i < fadetime-1; i++)
    {
        SetActorProperty(0, APROP_Alpha, start + ((fademod/fadetime) * i));
        Delay(1);
    }

    SetActorProperty(0, APROP_Alpha, alpha);

    if (alpha == 0 && CheckInventory("IAmAHat")) { Thing_Remove(0); }
}
