/* $Filename:       WormWars/Source/init.c $
 * $VER:            WormWars 4.0 (1.11.98) $
 * $Description:    Initialization/shutdown routines for Worm Wars 4.0 $
 *
 * © Copyright 1993-1998 James R. Jacobs of Amigan Software.
 * Freely distributable.
 *
 * Release version.

#INCLUDES -------------------------------------------------------------- */

#include "init.h"				// #includes everything else

/* EXTERNAL VARIABLES -----------------------------------------------------

All of these are owned by main.c */

IMPORT	struct WormStruct		worm[4];
IMPORT	struct	Library*		SysBase;
IMPORT	struct	Process*		ProcessPtr;
IMPORT	BYTE					OldPri;
IMPORT	BYTE					mode;
IMPORT	BOOL					argument, fxable, musicable;
IMPORT	STRPTR					pathname;

// GLOBAL VARIABLES -------------------------------------------------------

		struct	ASLBase*		ASLBase			= NULL;
		struct	GadToolsBase*	GadToolsBase	= NULL;
		struct	GfxBase*		GfxBase			= NULL;
		struct	IntuitionBase*	IntuitionBase	= NULL;
		struct	MEDPlayerBase*	MEDPlayerBase	= NULL;
		struct	Library*		TimerBase		= NULL;

		struct	FileRequester*	ASLRqPtr		= NULL;

		BYTE					Controller		= GPCT_NOCONTROLLER;
		struct	InputEvent		GameEvent;
		BOOL					joy				= FALSE;

		BYTE					JoyClosed		= TRUE;
		struct	MsgPort*  		JoyPortPtr		= NULL;
		struct	IOStdReq*		JoyRqPtr		= NULL;

		BYTE					InputClosed		= TRUE;
		struct	MsgPort*  		InputPortPtr	= NULL;
		struct	IOStdReq*		InputRqPtr		= NULL;

		BOOL					menu			= FALSE;
		struct	Menu*			MenuPtr			= NULL;
        struct  VisualInfo*     VisualInfoPtr   = NULL;
		struct	Gadget*			PrevGadgetPtr	= NULL;
		struct	Gadget*			CycleGadgetPtr[4]
												= {NULL, NULL, NULL, NULL};
		struct	Gadget*			GListPtr		= NULL;
		struct	Gadget*			StringGadgetPtr[HISCORES + 1]
												= {NULL, NULL, NULL, NULL, NULL};

		struct	MMD0*			SongPtr			= NULL;

		struct	timeval*		CurrentValPtr	= NULL;
		struct	timeval*		PausedValPtr	= NULL;
		struct	timeval*		StartValPtr		= NULL;
		BYTE					TimerClosed		= TRUE;
		struct	MsgPort*		TimerPortPtr	= NULL;
		struct	timerequest*	TimerRqPtr		= NULL;

		struct	Screen*			ScreenPtr		= NULL;
		struct	Window*			MainWindowPtr	= NULL;
		struct	Window*			AboutWindowPtr	= NULL;
		APTR					OldWindowPtr	= NULL;
		ULONG					SignalMask;

// FUNCTIONS --------------------------------------------------------------

void cleanexit(void)
{
	
if (TimerRqPtr && (!CheckIO(TimerRqPtr)))
					{	AbortIO(TimerRqPtr);
						WaitIO(TimerRqPtr);								}
if (menu)				ClearMenuStrip();
if (mode == FX)			kill8();
						destroy8();
if (mode == MUSIC)		StopPlayer();
if (SongPtr)			UnLoadModule(SongPtr);
if (mode == MUSIC)		FreePlayer();
if (MEDPlayerBase)		CloseLibrary(MEDPlayerBase);
if (joy)			{	AbortIO(JoyRqPtr);
						WaitIO(JoyRqPtr);								}
if (Controller != GPCT_NOCONTROLLER)
					{	Forbid();
						Controller				= GPCT_NOCONTROLLER;
						JoyRqPtr->io_Command	= GPD_SETCTYPE;
						JoyRqPtr->io_Length		= 1;
						JoyRqPtr->io_Data		= (APTR) &Controller;
						DoIO(JoyRqPtr);
						Permit();										}
if (!JoyClosed)			CloseDevice(JoyRqPtr);
if (JoyRqPtr)			DeleteIORequest(JoyRqPtr);
if (JoyPortPtr)			DeleteMsgPort(JoyPortPtr);
if (ASLRqPtr)			FreeAslRequest(ASLRqPtr);
if (OldWindowPtr)		ProcessPtr->pr_WindowPtr = OldWindowPtr;
if (MainWindowPtr)	{	clearkybd();
						CloseWindow(MainWindowPtr);						}
if (GListPtr)			FreeGadgets(GListPtr);
if (MenuPtr)			FreeMenus(MenuPtr);
if (VisualInfoPtr)		FreeVisualInfo(VisualInfoPtr);
if (ScreenPtr)			CloseScreen(ScreenPtr);
if (!TimerClosed)		CloseDevice(TimerRqPtr);
if (TimerRqPtr)			DeleteIORequest(TimerRqPtr);
if (TimerPortPtr)		DeleteMsgPort(TimerPortPtr);
if (PausedValPtr)		FreeMem(PausedValPtr, sizeof(struct timeval));
if (CurrentValPtr)		FreeMem(CurrentValPtr, sizeof(struct timeval));
if (StartValPtr)		FreeMem(StartValPtr, sizeof(struct timeval));
if (!InputClosed)		CloseDevice(InputRqPtr);
if (InputRqPtr)			DeleteIORequest(InputRqPtr);
if (InputPortPtr)		DeleteMsgPort(InputPortPtr);
if (ASLBase)			CloseLibrary(ASLBase);
if (GadToolsBase)		CloseLibrary(GadToolsBase);
if (GfxBase)			CloseLibrary(GfxBase);
if (IntuitionBase)	{	OpenWorkBench();
						CloseLibrary(IntuitionBase);					}
						SetTaskPri((struct Task *) ProcessPtr, OldPri);

// End of program.
}

void setup(void)
{
BOOL success = FALSE;
BYTE counter, player, result, which;
TEXT errormessage[SAYLIMIT + 1];
UWORD Pens[10] = {BLACK, WHITE, WHITE, WHITE, DARKGREY, PURPLE, BLACK, BLACK, ORANGE, (UWORD) ~0};
struct ColorSpec Colours[21] =
{   /* colour   red     green   blue    description */
    {   0,      0x0,    0x0,    0x0},   //        BLACK
    {   1,      0xF,    0xF,    0xF},   //        WHITE
    {   2,      0x2,    0x2,    0x2},   //    DARKGREY
    {   3,      0x6,    0x6,    0x6},   // medium grey
    {   4,      0xA,    0xA,    0xA},   //   LIGHTGREY
    {   5,      0xE,    0x8,    0x3},   //        ORANGE
    {   6,      0xA,    0x2,    0xA},   //        PURPLE
    {   7,      0x8,    0x4,    0x2},   //        brown
    {   8,      0x3,    0x9,    0x3},   //    DARKGREEN
    {   9,      0x4,    0xE,    0x4},   //  light GREEN
    {   10,     0xF,    0x1,    0x1},   //    DARKRED
    {   11,     0xF,    0x4,    0x4},   //  light RED
    {   12,     0x3,    0x3,    0xF},   //    DARKBLUE
    {   13,     0x6,    0x6,    0xF},   //  light BLUE
    {   14,     0xA,    0x8,    0x3},   //    DARKYELLOW
    {   15,     0xC,    0xC,    0x2},   //  light YELLOW
    {   16,     0x0,    0x0,    0x0},   // pointer: transparent
    {   17,     0xE,    0x4,    0x4},   // pointer: fill
    {   18,     0x3,    0x3,    0x3},   // pointer: shadow
    {   19,     0xC,    0xC,    0xC},   // pointer: shine
    {   -1,     NULL,   NULL,   NULL
}   };

if (!(IntuitionBase = (struct IntuitionBase *) OpenLibrary("intuition.library", 37L)))
{	printf("Worm Wars: You need Kickstart R2.04+!\n(Can't open intuition.library V37+!)\n");
	exit(EXIT_FAILURE);
}
if (SysBase->lib_Version < 36L)
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Need exec.library V36+!\0", 24);
	exit(EXIT_FAILURE);
}
if (!(GfxBase = (struct GfxBase *) OpenLibrary("graphics.library", 0L)))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open graphics.library!\0", 24);
	exit(EXIT_FAILURE);
}
if (!(GadToolsBase = (struct GadToolsBase *) OpenLibrary("gadtools.library", 37L)))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open GadTools.library V37+!\0", 24);
	exit(EXIT_FAILURE);
}
if (!(ASLBase = (struct ASLBase *) OpenLibrary("asl.library", 0L)))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open ASL.library!\0", 24);
	exit(EXIT_FAILURE);
}
	
if (!(InputPortPtr = (struct MsgPort *) CreateMsgPort()))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open input.device!\0", 24);
	exit(EXIT_FAILURE);
}
if (!(InputRqPtr = (struct IOStdReq *) CreateIORequest(InputPortPtr, sizeof(struct IOStdReq))))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create input I/O request!\0", 24);
	exit(EXIT_FAILURE);
}
if (InputClosed = OpenDevice("input.device", 0, InputRqPtr, 0))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open input.device!\0", 24);
	exit(EXIT_FAILURE);
}
	
if (!(StartValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
{	DisplayAlert(AT_Recovery, ALERTTIMERVALUE, 24);
	exit(EXIT_FAILURE);
}
if (!(CurrentValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
{	DisplayAlert(AT_Recovery, ALERTTIMERVALUE, 24);
	exit(EXIT_FAILURE);
}
if (!(PausedValPtr = (struct timeval *) AllocMem(sizeof(struct timeval), MEMF_PUBLIC | MEMF_CLEAR)))
{	DisplayAlert(AT_Recovery, ALERTTIMERVALUE, 24);
	exit(EXIT_FAILURE);
}
if (!(TimerPortPtr = (struct MsgPort *) CreateMsgPort()))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't allocate timer message port!\0", 24);
	exit(EXIT_FAILURE);
}
if (!(TimerRqPtr = (struct timerequest *) CreateIORequest(TimerPortPtr, sizeof(struct timerequest))))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create timer I/O request!\0", 24);
	exit(EXIT_FAILURE);
}
if (TimerClosed = OpenDevice(TIMERNAME, UNIT_VBLANK, TimerRqPtr, 0))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open timer.device!\0", 24);
	exit(EXIT_FAILURE);
}
TimerBase = (struct Library *) TimerRqPtr->tr_node.io_Device;

/* PREPARE DISPLAY -----------------------------------------------

screen */

if (!(ScreenPtr = (struct Screen *) OpenScreenTags(NULL,
	SA_Width,			640,
	SA_Height,			256,
	SA_Depth,			4,
	SA_DisplayID,		HIRES_KEY | PAL_MONITOR_ID,
	SA_Title,			TITLEBAR,
    SA_Colors,			Colours,
    SA_Font,            NULL,
	SA_Pens,			Pens,
	TAG_DONE)))
	{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open screen!\0", 24);
		exit(EXIT_FAILURE);
	}

// GadTools

if (!(CycleGadget.ng_VisualInfo = StringGadget.ng_VisualInfo = VisualInfoPtr = (APTR) GetVisualInfo(ScreenPtr, TAG_DONE)))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't get GadTools visual info!\0", 24);
	exit(EXIT_FAILURE);
}
if (!(MenuPtr = (struct Menu *) CreateMenus(NewMenu, TAG_DONE)))
{	DisplayAlert(AT_Recovery, ALERTMENUCREATE, 24);
	exit(EXIT_FAILURE);
}
if (!(LayoutMenus(MenuPtr, VisualInfoPtr, TAG_DONE)))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't lay out menus!\0", 24);
	exit(EXIT_FAILURE);
}
if (!(PrevGadgetPtr = (struct Gadget *) CreateContext(&GListPtr)))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create GadTools context!\0", 24);
	exit(EXIT_FAILURE);
}
for (player = 0; player <= 3; player++)
{	CycleGadget.ng_TopEdge = 184 + (player * (FONTX + 8));
	CycleGadget.ng_GadgetText = GadgetText[player];
	CycleGadgetPtr[player] = PrevGadgetPtr = (struct Gadget *) CreateGadget(CYCLE_KIND, PrevGadgetPtr, &CycleGadget, GTCY_Labels, GadgetOptions[player], GT_Underscore, '_', GTCY_Active, worm[player].control, TAG_DONE);
}
if (!PrevGadgetPtr)
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create cycle gadgets!\0", 24);
	exit(EXIT_FAILURE);
}

// main window

if (!(MainWindowPtr = (struct Window *) OpenWindowTags(NULL,
	WA_Top,				11,
	WA_Width,			SCREENXPIXEL,
	WA_Height,			SCREENYPIXEL,
    WA_IDCMP,           IDCMP_RAWKEY | IDCMP_MOUSEBUTTONS | IDCMP_CLOSEWINDOW | IDCMP_ACTIVEWINDOW | IDCMP_MENUPICK | IDCMP_MENUVERIFY | CYCLEIDCMP | STRINGIDCMP | IDCMP_REFRESHWINDOW | IDCMP_INTUITICKS,
	WA_Gadgets,			GListPtr,
	WA_CustomScreen,	ScreenPtr,
	WA_Borderless,		TRUE,
	WA_Activate,		TRUE,
	WA_SmartRefresh,	TRUE,
	WA_RptQueue,		16,
	TAG_DONE)))
	{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't open main window!\0", 24);
		exit(EXIT_FAILURE);
	}
SignalMask = 1L << MainWindowPtr->UserPort->mp_SigBit;

// redirection of AmigaDOS system requesters
	
OldWindowPtr = ProcessPtr->pr_WindowPtr;
ProcessPtr->pr_WindowPtr = (APTR) MainWindowPtr;

if (!(ASLRqPtr = AllocAslRequestTags(ASL_FileRequest, ASL_Pattern, PATTERN, ASL_Window, MainWindowPtr, TAG_DONE)))
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create ASL request!\0", 24);
	exit(EXIT_FAILURE);
}

/* String gadgets: first the window is opened with the cycle gadgets.
It is necessary not to display the string gadgets yet, so the
gadgets are then created and added to the gadget list. You will note
there is no command given to render them as yet. When the attributes
are modified at highscore time, the applicable gadget is refreshed
then. */

for (which = 0; which <= HISCORES; which++)
{	StringGadget.ng_TopEdge = 104 + (which * HISCOREDISTANCE);
	StringGadgetPtr[which] = PrevGadgetPtr = (struct Gadget *) CreateGadget(STRING_KIND, PrevGadgetPtr, &StringGadget, GTST_MaxChars, NAMELENGTH, STRINGA_ReplaceMode, TRUE, GA_Disabled, TRUE, TAG_DONE);
}
if (!PrevGadgetPtr)
{	DisplayAlert(AT_Recovery, "\0\20\20Worm Wars: Can't create string gadgets!\0", 24);
	exit(EXIT_FAILURE);
}

if (!(JoyPortPtr = (struct MsgPort *) CreateMsgPort()))
{	say("Can't create joystick message port!", BLUE);
	anykey(TRUE);
} else if (!(JoyRqPtr = (struct IOStdReq *) CreateIORequest(JoyPortPtr, sizeof(struct IOStdReq))))
{	say("Can't create joystick I/O request!", BLUE);
	anykey(TRUE);
} else if (JoyClosed = OpenDevice("gameport.device", 1, JoyRqPtr, 0))
{	say("Can't open gameport.device!", BLUE);
	anykey(TRUE);
} else
{	Forbid();
	JoyRqPtr->io_Command		= GPD_ASKCTYPE;
	JoyRqPtr->io_Length			= 1;
	JoyRqPtr->io_Flags			= IOF_QUICK;
	JoyRqPtr->io_Data			= (APTR) &Controller;
	DoIO(JoyRqPtr);
	if (Controller == GPCT_NOCONTROLLER)
	{	Controller				= GPCT_ABSJOYSTICK;
		JoyRqPtr->io_Command	= GPD_SETCTYPE;
		JoyRqPtr->io_Length 	= 1;
		JoyRqPtr->io_Data		= (APTR) &Controller;
		DoIO(JoyRqPtr);
		success = TRUE;
	}
	Permit();
	if (success)
	{	JoyRqPtr->io_Command	= GPD_SETTRIGGER;
		JoyRqPtr->io_Data		= (APTR) &Trigger;
		JoyRqPtr->io_Length		= sizeof(struct GamePortTrigger);
		DoIO(JoyRqPtr);
		sendreadrequest();
		joy = TRUE;
	} else
	/* Note that say(), anykey() calls must be outside the
	Forbid()/Permit() pair. */
	{	say("Gameport already in use!", BLUE);
		anykey(TRUE);
}	}

if (!(MEDPlayerBase = (struct MEDPlayerBase *) OpenLibrary("medplayer.library", 0L)))
{	say("Can't open MEDPlayer.library!", RED);
	anykey(TRUE);
} else if (GetPlayer(0))
{	say("Can't allocate channels for music!", RED);
	anykey(TRUE);
} else
{	say("Loading music...", WHITE);
	if (SongPtr = (struct MMD0 *) LoadModule(MEDMODULE))
	{	PlayModule(SongPtr);
		musicable = TRUE;
		mode = MUSIC;
		draw(MUSICICON, ICONY, MUSIC);
	} else
	{	FreePlayer();
		say("Can't load music!", RED);
		anykey(TRUE);
}	}

fxable = TRUE;
presetup();
say("Loading sound effects...", WHITE);
for (counter = 0; counter <= SAMPLES; counter++)
{	if (result = loadsample(samp[counter].fname, counter))
	{	fxable = FALSE;
		strcpy(errormessage, samp[counter].fname);
		strcat(errormessage, ": ");
		strcat(errormessage, sfxerror[result]);
		say(errormessage, RED);
		anykey(TRUE);
		break;
}	}
if (fxable && (!musicable))
	initsound();

if (argument && !loadfields(pathname))
{	strcpy(errormessage, "Can't open ");
	strcat(errormessage, pathname);
	strcat(errormessage, "!");
	say(errormessage, RED);
	anykey(TRUE);
	argument = FALSE;
	pathname = DEFAULTSET;
}
if (!argument && !loadfields(DEFAULTSET))
{	strcpy(errormessage, "Can't open ");
	strcat(errormessage, DEFAULTSET);
	strcat(errormessage, "!");
	say(errormessage, RED);
	anykey(TRUE);
	newfields();
}
}

void initsound(void)
{	BYTE result;

	if (result = getaudio())
	{	say(sfxerror[result], RED);
		anykey(TRUE);
		mode = FALSE;
		blitmode(BLACK);
		draw(MUSICICON, ICONY, ANYTHING);
		blitmode(NORMAL);
	} else
	{	mode = FX;
		draw(MUSICICON, ICONY, FX);
}	}

// Must have blank line at EOF.
