/* LameTron - First Amiga program by Charlie/iNQ */
/* Unfinished ... Compile and works OK with vbccm68k 0.8. */

/* 2001.09.06 */

/* Most important things TO DO: */
/* Line collision detection, 2 players, menu, options */

#define WAIT_FOR_MESSAGE 1

/* Standard includes */

#include <stdio.h>

/* OS includes */

#include <exec/exec.h>
#include <dos/dos.h>
#include <graphics/gfx.h>
#include <intuition/intuition.h>

#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/graphics_protos.h>
#include <clib/intuition_protos.h>

/* definiciok */

#define NUM_PLAYERS     2L /* Ideiglenes player-szam definicio,
                               majd kell allito Options ablakba... */

#define DIR_LEFT        0L /* Iranyjelzo konstansok */
#define DIR_RIGHT       1L
#define DIR_UP          2L
#define DIR_DOWN        3L

#define WIN_WIDTH       400L /* Ablakszelesseg (Optionsba!) */
#define WIN_HEIGHT      300L /* Ablakmagassag (Optionsba!) */


/* Nem tul C-szeru az ULONG/UWORD/UBYTE, de az OS definialja, hat hasznaljuk. :) */

/* Mindenfele valtozok */

struct playerData {

       /* Keyb control (RAWKEY ertekek) */
       UBYTE leftCtrl;
       UBYTE RightCtrl;
       UBYTE UpCtrl;
       UBYTE DownCtrl;
       UBYTE BoostCtrl;

       /* Position control */
       ULONG XPos;
       ULONG YPos;

       signed char XPosD; /* Pozicio Deltak */
       signed char YPosD;

       UBYTE Boosted;
       ULONG BoostRemain;
} playerOne, playerTwo;

struct moveDelta {
        signed char XPosD;
        signed char YPosD;
} moveDeltas [4] = {
        -1, 0,  /* balra pozicio delta */
         1, 0,  /* jobbra */
         0,-1,  /* felfele */
         0, 1   /* lefele */
};

struct GfxBase          *GfxBase;
struct IntuitionBase    *IntuitionBase;

struct Screen           *Scr             = NULL;

struct Window           *MainWindow      = NULL;
UBYTE                   *MainWinTitle    = (UBYTE *)"LameTron";
UBYTE                   *MainWinScrTitle = (UBYTE *)"LameTron - First Amiga program by Charlie/iNQ (2001.09.06)";

LONG                    BackPen = 0L;
LONG                    P1Pen   = 0L;
LONG                    P2Pen   = 0L;


/* Ezek itt ilyen kafa library-nyitogatos rutinok */

int initLibs() {

        GfxBase = (struct GfxBase*)OpenLibrary("graphics.library",39L);
        if (GfxBase == NULL) {
                printf("ERROR: Cannot open graphics.library V39!\n");
                return(-1);
        }

        IntuitionBase = (struct IntuitionBase*)OpenLibrary("intuition.library",39L);
        if (IntuitionBase == NULL) {
                printf("ERROR: Cannot open intuition.library V39!\n");
                return(-1);
        }

        return(0);
}

void doneLibs() {

        if (IntuitionBase != NULL)
                CloseLibrary((struct Library*)IntuitionBase);
        if (GfxBase != NULL)
                CloseLibrary((struct Library*)GfxBase);
}


/* Itt jon a megaszuper ablaknyitogatas  */

int initWindow() {

        struct ViewPort *vPort;
        struct ColorMap *cMap;

        Scr = LockPubScreen(NULL);
        if (Scr == NULL) {
                printf("ERROR: Cannot lock screen!\n");
                return(-1);
        }

        MainWindow = OpenWindowTags(NULL,
                          WA_Left,      50L,
                          WA_Top,       50L,
                          WA_InnerWidth,  WIN_WIDTH,
                          WA_InnerHeight, WIN_HEIGHT,
                          WA_IDCMP,     /*IDCMP_MOUSEBUTTONS|*/IDCMP_RAWKEY|IDCMP_CLOSEWINDOW,
                          WA_Flags,     WFLG_DRAGBAR|WFLG_DEPTHGADGET|WFLG_CLOSEGADGET|WFLG_SMART_REFRESH|WFLG_ACTIVATE,
                          WA_Title,     MainWinTitle,
                          WA_ScreenTitle, MainWinScrTitle,
                          WA_GimmeZeroZero, TRUE,
                          TAG_DONE);

        if (MainWindow == NULL) {
                printf("ERROR: Cannot open main window!\n");
                UnlockPubScreen(NULL,Scr);
                return(-1);
        }


        BackPen = ObtainBestPenA(Scr->ViewPort.ColorMap,0x3F000000L,0x3F000000L,0x3F000000L,TAG_DONE);
        P1Pen   = ObtainBestPenA(Scr->ViewPort.ColorMap,0xFF000000L,0x3F000000L,0x3F000000L,TAG_DONE);
        P2Pen   = ObtainBestPenA(Scr->ViewPort.ColorMap,0x3F000000L,0x3F000000L,0xFF000000L,TAG_DONE);

        return(0);

}

void doneWindow() {

        ReleasePen(Scr->ViewPort.ColorMap,BackPen);
        ReleasePen(Scr->ViewPort.ColorMap,P1Pen);
        ReleasePen(Scr->ViewPort.ColorMap,P2Pen);

        if (Scr != NULL) {
                UnlockPubScreen(NULL,Scr);
        }

        if (MainWindow != NULL) {

                struct Message *Msg;

                /* Kiuritjuk az ablak msgQueue-jet */
                Forbid();
                while (Msg = GetMsg(MainWindow->UserPort)) ReplyMsg(Msg);
                Permit();

                CloseWindow(MainWindow);
        }
}


/* Beallitja a player default pozicio ertekeit, es a default deltat (felfele) */

void initPlayer(struct playerData *plData) {
        plData->XPos = WIN_WIDTH / 2;
        plData->YPos = WIN_HEIGHT / 2;

        plData->XPosD = moveDeltas[DIR_UP].XPosD;
        plData->YPosD = moveDeltas[DIR_UP].YPosD;
}

/* Beallitja a player delta ertekeit */

void setPlayer(struct playerData *plData, ULONG direction) {

        plData->XPosD = moveDeltas[direction].XPosD;
        plData->YPosD = moveDeltas[direction].YPosD;

        /* Debug code rulez*/
        /* printf("XD: %d YD: %d\n",plData->XPosD,plData->YPosD); */
}

/* Allitja a plData strukturaban levo ertekeket az msgHandlerben
   beallitottak szerint, valamint figyeli, hogy nem masztunk-e falnak
   (ha igen akkor 1-et ad vissza) */

int updatePlayer(struct playerData *plData) {

        plData->XPos += plData->XPosD;
        plData->YPos += plData->YPosD;

        if (((plData->XPos == WIN_WIDTH) || (plData->XPos == 0L)) ||
            ((plData->YPos == WIN_HEIGHT) || (plData->YPos == 0L))) {
                initPlayer(plData);
                return(1);
        }

        return(0);
}


/* Jol lekezeljuk a messagekat (0-t ad vissza, amig nem kell kilepni a progibol)
   Ezenkivul beallitja a megfelelo strukturakat az updateScreen-nek az updatePlayer fuggvennyel */

int msgHandler() {

        struct IntuiMessage *iMsg = NULL;

        ULONG   msgClass;
        UWORD   msgCode;
        APTR    msgAddress;

#if WAIT_FOR_MESSAGE
        WaitPort(MainWindow->UserPort); 
#endif

        /* Gyere uzenet, cicc-cicc... */
        iMsg = (struct IntuiMessage*)GetMsg(MainWindow->UserPort);
        if (iMsg != NULL) {

                msgClass = iMsg->Class;
                msgCode = iMsg->Code;
                msgAddress = iMsg->IAddress;

                ReplyMsg((struct Message*)iMsg); /* Valaszolunk messagere ugyesen */

                switch (msgClass) {

                        case IDCMP_RAWKEY: {
                                switch (msgCode) {

                                        /* Beallitjuk a mozgasdeltakat, ha gomblenyomas volt */
                                        case 0x4C: {
                                                /*printf("fel\n");*/
                                                setPlayer(&playerOne,DIR_UP);
                                                break;
                                        }
                                        case 0x4D: {
                                                /*printf("le\n");*/
                                                setPlayer(&playerOne,DIR_DOWN);
                                                break;
                                        }
                                        case 0x4E: {
                                                /*printf("jobbra\n");*/
                                                setPlayer(&playerOne,DIR_RIGHT);
                                                break;
                                        }
                                        case 0x4F: {
                                                /*printf("balra\n");*/
                                                setPlayer(&playerOne,DIR_LEFT);
                                                break;
                                        }

                                        /* Ha megcsapkodtak az ESC-et, abbafejezzuk */
                                        case 0x45: {
                                                /*printf("ESC\n");*/
                                                return(1);
                                        }

                                }
                                break;
                        }

                        /* Ha megbizergaltak az ablakbecsuko gadgetet, akkor kilepunk */
                        case IDCMP_CLOSEWINDOW: {
                                /*printf("closegadget\n");*/
                                return(1);
                        }
                }
        }

        /* Atmeneti ganyolas, hogy ne zabaljuk meg a 100% cpu idot... kesobb majd
           multithreading meg msgportra varas Wait()-tel kell bele */
        Delay(1); /* Tiszta Pascal feeling hehe... :) */

        return(0);
}


/* Ez a rutin vegzi az ablakunk frissiteset, meg a mindenfele kirajzolast */

void updateScreen() {

        struct RastPort *rastp = MainWindow->RPort;

        SetAPen(rastp,P1Pen);
        WritePixel(rastp,playerOne.XPos,playerOne.YPos);

}


/* Letorli az ablakunkat... */
void clearScreen() {

        struct RastPort *rastp = MainWindow->RPort;

        SetAPen(rastp,BackPen);
        RectFill(rastp,0,0,WIN_WIDTH,WIN_HEIGHT);
}


/* Van kafa foprogramunk */

int main() {

        if (initLibs() != 0) {
           doneLibs();
           return(-1);
        }

        if (initWindow() != 0) {
           return(-1);
        }

        initPlayer(&playerOne);
        clearScreen();

        /* Addig maszik a ciklus korbe, amig a juuuzer nem kezdi el birizgalni a
           becsukogadgetet vagy az ESC-et */
        while (msgHandler() == 0) {
           if (updatePlayer(&playerOne) != 0) {
                clearScreen();
           }
           updateScreen();
        }

        doneWindow();
        doneLibs();

        return(0);
}

