/*
**	A clone of a famous game.
*/
/**@name clone.c	-	The main file. */
/*
**	(c) Copyright 1998,1999 by Lutz Sammer
**
**	$Id: clone.c,v 1.76 1999/12/17 15:30:45 root Exp root $
*/

//@{

/*----------------------------------------------------------------------------
--	Includes
----------------------------------------------------------------------------*/

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#ifdef __CYGWIN__
#include <getopt.h>
#endif
#ifdef __MINGW32__
#include <SDL/SDL.h>
extern int opterr;
extern int optind;
extern int optopt;
extern char *optarg;

int getopt(int argc, char *const*argv, const char *opt);
#endif

#include "clone.h"

#include "video.h"
#include "image.h"
#include "tileset.h"
#include "map.h"
#include "minimap.h"
#include "sound_id.h"
#include "unitsound.h"
#include "icons.h"
#include "button.h"
#include "unittype.h"
#include "player.h"
#include "unit.h"
#include "missile.h"
#include "actions.h"
#include "construct.h"
#include "ai.h"
#include "ccl.h"
#include "cursor.h"
#include "upgrade.h"
#include "font.h"
#include "interface.h"
#include "sound_server.h"
#include "sound.h"
#include "network.h"

/*----------------------------------------------------------------------------
--	Variables
----------------------------------------------------------------------------*/

#ifdef DEBUG
extern unsigned AllocatedGraphicMemory;
extern unsigned CompressedGraphicMemory;
#endif

/*----------------------------------------------------------------------------
--	Speedups
----------------------------------------------------------------------------*/

global int SpeedMine=SPEED_MINE;	/// speed factor for mine gold
global int SpeedGold=SPEED_GOLD;	/// speed factor for getting gold
global int SpeedChop=SPEED_CHOP;	/// speed factor for chop
global int SpeedWood=SPEED_WOOD;	/// speed factor for getting wood
global int SpeedHaul=SPEED_HAUL;	/// speed factor for haul oil
global int SpeedOil=SPEED_OIL;		/// speed factor for getting oil
global int SpeedBuild=SPEED_BUILD;	/// speed factor for building
global int SpeedTrain=SPEED_TRAIN;	/// speed factor for training
global int SpeedUpgrade=SPEED_UPGRADE;	/// speed factor for upgrading
global int SpeedResearch=SPEED_RESEARCH;/// speed factor for researching

/*============================================================================
==	DISPLAY
============================================================================*/

// FIXME: move to video header file
global int VideoWidth;			/// window width in pixels
global int VideoHeight;			/// window height in pixels

global int FrameCounter;		/// current frame number
global int SlowFrameCounter;		/// profile, frames out of sync

// FIXME: not the correct place
global enum MustRedraw_e MustRedraw=RedrawEverything;	/// redraw flags

/*----------------------------------------------------------------------------
--	SAVE/LOAD
----------------------------------------------------------------------------*/

/**
**	Test function for the later save functions.
*/
global void SaveAll(void)
{
    FILE* file;
    time_t now;
    const char* name;

    name="save_file_of_clone.ccl";
    file=fopen(name,"wb");
    if( !file ) {
	fprintf(stderr,"Can't save to `%s'\n",name);
	return;
    }
    fprintf(file,";;; -----------------------------------------\n");
    fprintf(file,";;; Save file generated by clone version " VERSION "\n");
    time(&now);
    fprintf(file,";;;\tDate: %s",ctime(&now));
    fprintf(file,";;; -----------------------------------------\n\n\n");

    SaveUnitTypes(file);
    SaveUnits(file);
    SaveMap(file);

    fclose(file);
}

/*----------------------------------------------------------------------------
--	BUTTONS
----------------------------------------------------------------------------*/

/**
**	Defines position and size of the different buttons.
*/
global Button Buttons[MaxButtons] = {
// Menu button
    {  24,  2,168,16 },
// 9 Character portraits
    {   6,166, 46,38 },
    {  62,166, 46,38 },
    { 118,166, 46,38 },
    {   6,218, 46,38 },
    {  62,218, 46,38 },
    { 118,218, 46,38 },
    {   6,270, 46,38 },
    {  62,270, 46,38 },
    { 118,270, 46,38 },
// 9 Buttons interface
    {   6,337, 46,38 },
    {  62,337, 46,38 },
    { 118,337, 46,38 },
    {   6,384, 46,38 },
    {  62,384, 46,38 },
    { 118,384, 46,38 },
    {   6,431, 46,38 },
    {  62,431, 46,38 },
    { 118,431, 46,38 },
};

/**
**	Defines position and size of the training queue buttons.
*/
global Button Buttons2[6] = {
    {   6,216, 46,38 },
    {  62,216, 46,38 },
    { 118,216, 46,38 },
    {   6,263, 46,38 },
    {  62,263, 46,38 },
    { 118,263, 46,38 }
};

/*----------------------------------------------------------------------------
--	INIT
----------------------------------------------------------------------------*/

/**
**	Initialise.
**
**		Load all graphics, sounds.
*/
global void CloneInit(void)
{
    DebugLevel3("Terrain %d\n",TheMap.Terrain);

    // FIXME: must use palette from tileset!!
    // FIXME: this must be extendable!!

    switch( TheMap.Terrain ) {
	case TilesetSummer:
	    LoadRGB(GlobalPalette, CLONE_LIB_PATH "/summer.rgb");
	    break;
	case TilesetWinter:
	    LoadRGB(GlobalPalette, CLONE_LIB_PATH "/winter.rgb");
	    break;
	case TilesetWasteland:
	    LoadRGB(GlobalPalette, CLONE_LIB_PATH "/wasteland.rgb");
	    break;
	case TilesetSwamp:
	    LoadRGB(GlobalPalette, CLONE_LIB_PATH "/swamp.rgb");
	    break;
	default:
	    DebugLevel2("Unknown Terrain %d\n",TheMap.Terrain);
	    LoadRGB(GlobalPalette, CLONE_LIB_PATH "/summer.rgb");
	    break;
    }
    // GlobalPalette=(typeof(GlobalPalette))PalettePNG);

    VideoCreatePalette(GlobalPalette);

    //
    //	Graphic part
    //
    LoadIcons();
    LoadImages();
    LoadCursors();
    LoadFonts();
    LoadTileset();
    InitUnitButtons();
    LoadUnitSprites();
    LoadMissileSprites();
    LoadConstructions();
    LoadDecorations();

    IfDebug(
	DebugLevel0("Graphics uses %d bytes (%d KB, %d MB)\n"
		,AllocatedGraphicMemory
		,AllocatedGraphicMemory/1024
		,AllocatedGraphicMemory/1024/1024);
	DebugLevel0("Compressed graphics uses %d bytes (%d KB, %d MB)\n"
		,CompressedGraphicMemory
		,CompressedGraphicMemory/1024
		,CompressedGraphicMemory/1024/1024);
    );

    // FIXME: johns: did this belong into LoadMap!
    CreateMinimap();			// create minimap for pud
    InitMapFogOfWar();			// build tables for fog of war
    PreprocessMap();			// Adjust map for use
    MapColorCycle();			// Setup color cycle

    //
    //	Sound part
    //
    //FIXME: check if everything is really loaded
    LoadUnitSounds();
    MapUnitSounds();

#ifdef WITH_SOUND
    IfDebug(
	DebugLevel0("Sounds uses %d bytes (%d KB, %d MB)\n"
		,AllocatedSoundMemory
		,AllocatedSoundMemory/1024
		,AllocatedSoundMemory/1024/1024);
	DebugLevel0("Compressed sounds uses %d bytes (%d KB, %d MB)\n"
		,CompressedSoundMemory
		,CompressedSoundMemory/1024
		,CompressedSoundMemory/1024/1024);
    );
#endif

    //
    //	Network part
    //
    InitNetwork();

    //
    //  Init units' groups
    //
    InitGroups();

    //
    //	Init players?
    //
    DebugPlayers();
    PlayersInitAi();

    //
    //  Upgrades
    //
    UpgradesInit();

    //
    //  Dependencies
    //
    InitDeps();

    //
    //  Buttons (botpanel)
    //
    InitButtons();

    DebugLevel3("Center map for %d at %d,%d\n"
	    ,ThisPlayer-Players
	    ,ThisPlayer->X,ThisPlayer->Y);
    MapCenter(ThisPlayer->X,ThisPlayer->Y);
}

/*----------------------------------------------------------------------------
--	Random
----------------------------------------------------------------------------*/

/**
**	Syncron rand.
*/
global int SyncRand(void)
{
    static unsigned rnd = 0x87654321;
    int val;

    val=rnd>>16;

    rnd=rnd*(0x12345678 * 4 + 1) + 1;

    return val;
}

/*============================================================================
==	MAIN
============================================================================*/

global char* TitleScreen;		/// Titlescreen show by startup
global int FlagRevealMap;		/// Flag must reveal the map

	///	Filename for the map to load
local const char* MapName;

/**
**	Main, called from guile main.
**
**	@param	argc	Number of arguments.
**	@param	argv	Vector of arguments.
*/
global int main1(int argc __attribute__ ((unused)),char** argv __attribute__ ((unused)))
{
    InitVideo();			// setup video display
#ifdef WITH_SOUND
    if( InitSound() ) {			// setup sound card
	SoundOff=1;
	SoundFildes=-1;
    }
#endif
    //
    //	Show title screen.
    //
    if( TitleScreen ) {
	DisplayPicture(TitleScreen);
    }
    Invalidate();

    //
    //  Units Memory Management
    //
    InitUnitsMemory();
    UpdateStats();
    InitUnitTypes();

    //
    //	Load the map.
    //
    LoadMap(MapName,&TheMap);
    if( FlagRevealMap ) {
	RevealMap();
    }

    CloneInit();
    if (SoundFildes!=-1) {
	// must be done after sounds are loaded
	InitSoundClient();
    }

    SetStatusLine("Clone V" VERSION ", (c) 1998,1999 by ALE.");
    SetMessage("Do it! Do it now!");
    // FIXME: Add this again:
    if( ThisPlayer->Race==PlayerRaceHuman ) {
	DefaultReverseText=0;
    //	PlaySound(SoundBasicHumanVoicesSelected1);
    }
    if( ThisPlayer->Race==PlayerRaceOrc ) {
	DefaultReverseText=1;
    //	PlaySound(SoundBasicOrcVoicesSelected1);
    }

    printf("Clone V" VERSION ", (c) 1998,1999 by ALE\nwritten by Lutz Sammer, Fabrice Rossi, Vladi Shabanski, Patrice Fortier,\nJon Gabrielson and others.\nCompile options ");
#ifdef USE_CCL
    printf("CCL ");
#endif
#ifdef GUILE_GTK
    printf("GTK ");
#endif
#ifdef USE_THREAD
    printf("THREAD ");
#endif
#ifdef DEBUG
    printf("DEBUG ");
#endif
#ifdef USE_ZLIB
    printf("ZLIB ");
#endif
#ifdef USE_BZ2LIB
    printf("BZ2LIB ");
#endif
#ifdef USE_GLIB
    printf("GLIB ");
#endif
#ifdef USE_SDL
    printf("SDL ");
#endif
#ifdef USE_X11
    printf("X11 ");
#endif
    printf("\n\nDISCLAIMER:\n\
This software is provided as-is.  The author can not be held liable for any\n\
damage that might arise from the use of this software.\n\
Use it at your own risk.\n");

    CloneMainLoop();

    return 0;
}

/**
**	Exit clone.
**
**	Called from 'q'.
*/
global volatile void Exit(int err)
{
    IfDebug(
	extern unsigned PfCounterFail;
	extern unsigned PfCounterOk;
	extern unsigned PfCounterDepth;
	extern unsigned PfCounterNotReachable;
    );

    NetworkQuit();
    DebugLevel0("Frames %d, Slow frames %d = %d%%\n"
	,FrameCounter,SlowFrameCounter
	,(SlowFrameCounter*100)/FrameCounter);
    IfDebug(
	UnitCacheStatistic();
	DebugLevel0("Path: Error: %u(%u) OK: %u Depth: %u\n"
		,PfCounterFail,PfCounterNotReachable
		,PfCounterOk,PfCounterDepth);
    );
    DebugLevel0("Thanks for playing clone.\n");
    exit(err);
}

/**
**	Display the usage.
*/
local void Usage(void)
{
    printf("Clone V" VERSION ", (c) 1998,1999 by ALE\nwritten by Lutz Sammer, Fabrice Rossi, Vladi Shabanski, Patrice Fortier,\nJon Gabrielson and others.\n\n\
Usage: clone [OPTIONS] [map.pud|map.pud.gz|map.cm|map.cm.gz]\n\
\t-c file.ccl\tccl start file\n\
\t-f factor\tComputer units cost factor\n\
\t-h\t\tHelp shows this page\n\
\t-p players\tNumber of players\n\
\t-s sleep\tNumber of frames for the AI to sleep before they starts\n\
\t-f factor\tComputer units built time factor\n\
\t-F\tFullscreen videomode\n\
\t-W\tWindowed videomode\n\
");
}

/**
**	The main program: initialise, parse options and arguments.
**
**	@param	argc	Number of arguments.
**	@param	argv	Vector of arguments.
*/
#ifdef __MINGW32__
global int mymain(int argc,char** argv)
#else
global int main(int argc,char** argv)
#endif
{
    //
    //	Setup some defaults.
    //
    TitleScreen=strdup("graphic/title.png");
    MapName=CLONE_LIB_PATH"/default.pud";	// .gz automatic appended
#ifdef USE_CCL
    CclStartFile=CLONE_LIB_PATH"/ccl/clone.ccl";
#endif

    // FIXME: Parse options before ccl oder after?

    //
    //	Parse commandline
    //
    for( ;; ) {
	switch( getopt(argc,argv,"c:f:hp:s:t:FW?") ) {
#ifdef USE_CCL
	    case 'c':
		CclStartFile=optarg;
		continue;
#endif
	    case 'f':
		AiCostFactor=atoi(optarg);
		continue;
	    case 'p':
		NetPlayers=atoi(optarg);
		continue;
	    case 's':
		AiSleep=atoi(optarg);
		continue;
	    case 't':
		AiTimeFactor=atoi(optarg);
		continue;

	    case 'F':
		VideoFullScreen=1;
		continue;
	    case 'W':
		VideoFullScreen=0;
		continue;

	    case -1:
		break;
	    case '?':
	    case 'h':
	    default:
		Usage();
		exit(-1);
	}
	break;
    }

    if( argc-optind>1 ) {
	fprintf(stderr,"too many files\n");
	Usage();
	exit(-1);
    }

    if( argc-optind ) {
	MapName=argv[optind];
	--argc;
    }

#ifdef USE_CCL
    CclInit();				// load configurations!
#endif

    main1(argc,argv);			// CclInit may not return!

    return 0;
}

//@}
