#define WIN32_LEAN_AND_MEAN
#include <windows.h>
#include <Outpost2DLL.h>
#include <OP2Helper.h>

// Used below to randomize bases
#define numof(array) (sizeof(array)/sizeof(array[0]))
#define autosize(array) numof(array), array

char MapName[]		    = "on6_04.map";							// Fractures
char LevelDesc[]		= "6P, LR, 'Land Rush Test'";           // Nice name, yes?
char TechtreeName[]	    = "MULTITEK.TXT";						// Plain old Multitek
SDescBlock DescBlock	= { MultiLandRush, 6, 12, 0 };          // LR/6P/All Tech Allowed/Normal Mission

// ------------------------------------------------------------------------------------------------
BOOL APIENTRY DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved)
{
	if (fdwReason == DLL_PROCESS_ATTACH)
	{
		DisableThreadLibraryCalls(hinstDLL);
	}

    return TRUE;
}

// ------------------------------------------------------------------------------------------------
// Global Variables
short plStartX[6] = {0};    // Keep track of player's X-tile start location
short plStartY[6] = {0};    // Keep track of player's Y-tile start location

Trigger DefaultLOS;

// ------------------------------------------------------------------------------------------------
// New functions

// Setups up default land rush resources for all players
void SetupLandRushResources(int i)
{
    _Player &player = Player[i];

	switch(player.Difficulty())
	{
	case 0:		// Easy
		player.SetFoodStored(5000);
		player.SetWorkers(30);
		player.SetScientists(16);
		player.SetKids(24);
		player.MarkResearchComplete(3401);
		player.MarkResearchComplete(3303);
		player.MarkResearchComplete(3304);
		player.MarkResearchComplete(3305);

		break;
	case 1:		// Normal
		player.SetFoodStored(3400);
		player.SetWorkers(26);
		player.SetScientists(13);
		player.SetKids(21);
		player.MarkResearchComplete(3303);
		player.MarkResearchComplete(3304);
		player.MarkResearchComplete(3305);
		break;
	case 2:		// Hard
		player.SetFoodStored(1800);
		player.SetWorkers(22);
		player.SetScientists(10);
		player.SetKids(22);
		player.MarkResearchComplete(3303);
	}

} // end SetupLandRushResources

// Randomly assign start locations to the players
// Note that there's probably a better way to do this, but I don't care.
void RandomizeStartLocations()
{
    // Randomize the list of all possible start locations
    int allStarts[10] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
    RandomizeList(autosize(allStarts) );

    // Go through each active player
    for (short s = 0; s < TethysGame::NoPlayers(); s++)
    {
        // Assign them their corresponding start location from the list
        switch (allStarts[s])
        {
            case 0:
                plStartX[s] = 48 + 31;
                plStartY[s] = 43 -  1;
                break;

            case 1:
                plStartX[s] = 80 + 31;
                plStartY[s] = 68 -  1;
                break;

            case 2:
                plStartX[s] = 56 + 31;
                plStartY[s] = 97 -  1;
                break;

            case 3:
                plStartX[s] = 95  + 31;
                plStartY[s] = 120 -  1;
                break;

            case 4:
                plStartX[s] = 64  + 31;
                plStartY[s] = 167 -  1;
                break;

            case 5:
                plStartX[s] = 79  + 31;
                plStartY[s] = 202 -  1;
                break;

            case 6:
                plStartX[s] = 14  + 31;
                plStartY[s] = 205 -  1;
                break;

            case 7:
                plStartX[s] = 69  + 31;
                plStartY[s] = 234 -  1;
                break;

            case 8:
                plStartX[s] = 113 + 31;
                plStartY[s] = 152 -  1;
                break;

            case 9:
                plStartX[s] = 69 + 31;
                plStartY[s] = 14 -  1;
                break;

            // We shouldn't get to the default case, but better safe than sorry.
            default:
                plStartX[s] = 6 + 31;
                plStartY[s] = 111 -  1;
                break;
        }

    }
} // end RandomizeStartLocations

// Create player objects
void SetupPlayerLandRush(short s)
{
        // Center view on start location
        Player[s].CenterViewOn(plStartX[s], plStartY[s]);

        Unit Unit1;

        // High Resources setup
        if (Player[s].Difficulty() == 0)
        {
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s],   plStartY[s]  ), s, mapCommandCenter,    6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+1, plStartY[s]  ), s, mapStructureFactory, 6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+2, plStartY[s]  ), s, mapCommonOreSmelter, 6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+3, plStartY[s]  ), s, mapTokamak,          6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+4, plStartY[s]  ), s, mapAgridome,         6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s],   plStartY[s]+1), s, mapStandardLab,      6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+1, plStartY[s]+1), s, mapVehicleFactory,   6);
                Unit1.DoSetLights(1);

            TethysGame::CreateUnit(Unit1, mapCargoTruck, LOCATION(plStartX[s],   plStartY[s]+2), s, mapNone, 6);
                Unit1.DoSetLights(1);
                Unit1.SetTruckCargo(truckCommonMetal, 1000);
            TethysGame::CreateUnit(Unit1, mapCargoTruck, LOCATION(plStartX[s]+1, plStartY[s]+2), s, mapNone, 6);
                Unit1.DoSetLights(1);
                Unit1.SetTruckCargo(truckCommonMetal, 1000);
            TethysGame::CreateUnit(Unit1, mapCargoTruck, LOCATION(plStartX[s]+2, plStartY[s]+2), s, mapNone, 6);
                Unit1.DoSetLights(1);
                Unit1.SetTruckCargo(truckCommonMetal, 1000);
            TethysGame::CreateUnit(Unit1, mapCargoTruck, LOCATION(plStartX[s]+3, plStartY[s]+2), s, mapNone, 6);
                Unit1.DoSetLights(1);
                Unit1.SetTruckCargo(truckFood, 1000);

            TethysGame::CreateUnit(Unit1, mapRoboMiner,    LOCATION(plStartX[s]+2, plStartY[s]+1), s, mapNone, 6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapRoboSurveyor, LOCATION(plStartX[s]+3, plStartY[s]+1), s, mapNone, 6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapEarthworker,  LOCATION(plStartX[s]+4, plStartY[s]+1), s, mapNone, 6);
                Unit1.DoSetLights(1);

            // Sloppy Initial Vehicles Code
            map_id Weapon1 = mapMicrowave;
            if (Player[s].IsEden() )
            {
                Weapon1 = mapLaser;
            }

            switch (TethysGame::InitialUnits() )
            {
                case 12:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+4, plStartY[s]+2), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 11:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s],   plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 10:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+1, plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case  9:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+2, plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 8:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+3, plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 7:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+4, plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 6:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s],   plStartY[s]+4), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 5:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+1, plStartY[s]+4), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 4:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+2, plStartY[s]+4), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 3:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+3, plStartY[s]+4), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 2:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+4, plStartY[s]+4), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 1:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s],   plStartY[s]+5), s, Weapon1, 6);
                        Unit1.DoSetLights(1);

                case 0:
                default:
                    break;
            } // Ugh, I'm ashamed that I actually wrote that...  Too tired to code.

        } // end huge if statement

        // Med/Low Res Setup
        else
        {
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s],   plStartY[s]  ), s, mapCommandCenter,    6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+1, plStartY[s]  ), s, mapStructureFactory, 6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+2, plStartY[s]  ), s, mapCommonOreSmelter, 6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+3, plStartY[s]  ), s, mapTokamak,          6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapConVec, LOCATION(plStartX[s]+4, plStartY[s]  ), s, mapAgridome,         6);
                Unit1.DoSetLights(1);

            TethysGame::CreateUnit(Unit1, mapCargoTruck, LOCATION(plStartX[s],   plStartY[s]+1), s, mapNone, 6);
                Unit1.DoSetLights(1);
                Unit1.SetTruckCargo(truckCommonMetal, 1000);
            TethysGame::CreateUnit(Unit1, mapCargoTruck, LOCATION(plStartX[s]+1, plStartY[s]+1), s, mapNone, 6);
                Unit1.DoSetLights(1);
                Unit1.SetTruckCargo(truckCommonMetal, 1000);
            TethysGame::CreateUnit(Unit1, mapCargoTruck, LOCATION(plStartX[s]+2, plStartY[s]+1), s, mapNone, 6);
                Unit1.DoSetLights(1);
                Unit1.SetTruckCargo(truckFood, 1000);

            TethysGame::CreateUnit(Unit1, mapRoboMiner,    LOCATION(plStartX[s]+3, plStartY[s]+1), s, mapNone, 6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapRoboSurveyor, LOCATION(plStartX[s]+4, plStartY[s]+1), s, mapNone, 6);
                Unit1.DoSetLights(1);
            TethysGame::CreateUnit(Unit1, mapEarthworker,  LOCATION(plStartX[s],   plStartY[s]+2), s, mapNone, 6);
                Unit1.DoSetLights(1);

            // Sloppy Initial Vehicles Code
            map_id Weapon1 = mapMicrowave;
            if (Player[s].IsEden() )
            {
                Weapon1 = mapLaser;
            }

            switch (TethysGame::InitialUnits() )
            {
                case 12:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+1, plStartY[s]+2), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 11:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+2, plStartY[s]+2), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 10:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+3, plStartY[s]+2), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case  9:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+4, plStartY[s]+2), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 8:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s],   plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 7:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+1, plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 6:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+2, plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 5:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+3, plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 4:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+4, plStartY[s]+3), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 3:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s],   plStartY[s]+4), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 2:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+1, plStartY[s]+4), s, Weapon1, 6);
                        Unit1.DoSetLights(1);
                case 1:
                    TethysGame::CreateUnit(Unit1, mapLynx, LOCATION(plStartX[s]+2, plStartY[s]+4), s, Weapon1, 6);
                        Unit1.DoSetLights(1);

                case 0:
                default:
                    break;
            } // Ugh, I'm ashamed that I actually wrote that...  Too tired to code.

        } // end huge else


} // end SetupPlayerLandRush

// Create mining beacons
void SetupMiningBeacons()
{
    // Place mining beacons here
} // end SetupMiningBeacons

// ------------------------------------------------------------------------------------------------
// InitProc
int InitProc()
{
	// Morale/Daylight/Disaster Settings
	TethysGame::ForceMoraleOK(-1);              // Temporarily set morale to Fair (50) if MS is off
	if (TethysGame::UsesMorale() == 1)
	{
	    TethysGame::ForceMoraleGood(-1);        // Lock morale at 75 for all players if Morale Steady on
	}

	TethysGame::SetDaylightEverywhere(1);       // Turn on perma-day if Day/Night off
	if (TethysGame::UsesDayNight() == 1)
	{
	    TethysGame::SetDaylightEverywhere(0);   // But turn it off if Day/Night is on
        TethysGame::SetDaylightMoves(1);        // Also make the daylight move
	}

	if (TethysGame::CanHaveDisasters() == 1)
	{
        // Do something here if you want
	}

	// Setup LR Resources
	for (int i = 0; i < TethysGame::NoPlayers(); i++)
    {
        SetupLandRushResources(i);
    }

    // Determine player start locations
    RandomizeStartLocations();

    // Setup player units
    for (int i = 0; i < TethysGame::NoPlayers(); i++)
    {
        SetupPlayerLandRush(i);
    }

    // Create the (disabled) victory condition
    DefaultLOS   = CreateOnePlayerLeftTrigger(0, 1, "None");
    CreateVictoryCondition(1, 1, DefaultLOS, "Eliminate your opponents.");

	return 1; // return 1 if OK; 0 on failure
} // end InitProc

// ------------------------------------------------------------------------------------------------
// Trigger Callback Functions
SCRIPT_API void PlayersReady()
{
    // If Morale is supposed to be unsteady, disable steady morale
    if (TethysGame::UsesMorale() )
    {
        TethysGame::FreeMoraleLevel(-1);
    }

    // Enable our victory condition
    DefaultLOS.Enable();

    // Play "new mission objective" notification
    TethysGame::AddMessage(-1, -1, "New objective.", 0, sndSavant30);
} // end PlayersReady


// ------------------------------------------------------------------------------------------------
// AIProc
void AIProc()
{
    // Don't enter this loop if we're already ready
    if (DefaultLOS.IsEnabled() == false)
    {
        // Keep track of how many players are ready
        short numReady = 0;

        // Check each active player for active CC/no units left
        for (short i = 0; i < TethysGame::NoPlayers(); i++)
        {
            // Create a vehicle enumerator so we can check if the player has at least one unit
            Unit tempUnit;
            PlayerVehicleEnum countUnits(i);

            // If player has a CC or has no units left, mark him/her as ready
            if ( (Player[i].hasActiveCommand() ) || !(countUnits.GetNext(tempUnit) ) )
            {
                // Add this player to the "total ready" count
                numReady++;
            } // end if player ready

        } // end for all players

        // Now check if all players are ready
        if (numReady == TethysGame::NoPlayers() )
        {
            // Create a time trigger that will fire in 1 tick
            CreateTimeTrigger(1, 1, 1, "PlayersReady");
        } // end if all ready

    } // end if trigger not already enabled

} // end AIProc

// ------------------------------------------------------------------------------------------------
// Nothing below this line is relevant to this example
void __cdecl GetSaveRegions(struct BufferDesc &bufDesc)
{
	bufDesc.bufferStart = 0;	// Pointer to a buffer that needs to be saved
	bufDesc.length = 0;			// sizeof(buffer)
}

int StatusProc()
{
	return 0; // must return 0
}

SCRIPT_API void None()
{
}

