home *** CD-ROM | disk | FTP | other *** search
/ Amiga Plus Extra 1996 #3 / AmigaPlus_CD-ROM-EXTRA_Nr.3.bin / aminet-spiele / denk&grübel / dragon / source / dragon.c < prev    next >
C/C++ Source or Header  |  1995-03-08  |  27KB  |  953 lines

  1. /************************************************************************
  2. *                                                                        *
  3. *                                Dragon Game                                *
  4. *                                ===========                                *
  5. *                                                                        *
  6. *                        Copyright ©1995 Nick Christie                    *
  7. *                                                                        *
  8. * Distributed under the terms of the GNU Public License.                *
  9. *                                                                        *
  10. * Version 1.0    (29/08/92)                                                *
  11. * ========================                                                *
  12. * NB: The IFF ILBMs loaded as background and tiles must be of a certain    *
  13. * format: see LoadBackground() and LoadTileImages() in DragDisp.c.        *
  14. *                                                                        *
  15. *                                                                        *
  16. * Version 1.1    (2/7/94)                                                *
  17. * ======================                                                *
  18. * Converted to SAS/C 6.5.                                                *
  19. *                                                                        *
  20. *                                                                        *
  21. *************************************************************************/
  22.  
  23. /*** TODO
  24.  
  25. Some help -> describe the numbers around the screen.
  26.  
  27. Face graphic with attitude according to success.
  28.  
  29. Cheat: can work out a solution ?
  30.  
  31. Triumph graphics ?
  32.  
  33. Record of best game and # of successes ?
  34.  
  35. Make NTSC compatible.
  36.  
  37. ***/
  38.  
  39. /************************************************************************
  40. ******************************  INCLUDES  *******************************
  41. *************************************************************************/
  42.  
  43. #include "DragonDefs.h"
  44. #include "Dragon.h"
  45.  
  46. #define USAGEMSG "Usage: Dragon TILES/K BGND/K\n" \
  47.                  "Where: TILES = optional, followed by name of IFF\n" \
  48.                  "               ILBM file to get tile images from;\n" \
  49.                  "       BGND  = as above for background image.\n" \
  50.                  "Default names are DragonTiles.pic & DragonBgnd.pic.\n" \
  51.                  "See the doc for specifications of these files.\n"
  52.  
  53. /************************************************************************
  54. *************************  EXTERNAL REFERENCES  *************************
  55. *************************************************************************/
  56.  
  57. extern BOOL OpenBufRPort(void);                    /* all these from */
  58. extern void CloseBufRPort(void);                /* DragDisp.c */
  59. extern void LoadBackground(char *fname);
  60. extern void UnloadBackground(void);
  61. extern BOOL LoadTileImages(char *fname);
  62. extern void UnloadTileImages(void);
  63. extern void DrawBoard(BOARD board,struct RastPort *rp);
  64. extern void DrawOneTile(UBYTE tile,struct RastPort *rp,UWORD x,UWORD y);
  65. extern void DisplayStats(BOARD board,struct RastPort *rp);
  66. extern UWORD PossibleMoves(BOARD board);
  67. extern void SelectStats(UBYTE tile,BOARD board,struct RastPort *rp);
  68.  
  69. extern struct Library *SysBase;
  70.  
  71. /************************************************************************
  72. *****************************  PROTOTYPES  ******************************
  73. *************************************************************************/
  74.  
  75. ULONG main(ULONG cmdlen,char *cmdline);
  76.  
  77. char *ParseWBArgs(struct WBStartup *wbmsg,char **bgndptr,char **tileptr);
  78. char *ParseCLIArgs(ULONG clen,char *cline,char **bgndptr,char **tileptr);
  79.  
  80. BOOL HandleMenu(UWORD code,UWORD qual);
  81. void HandleMouse(UWORD code,UWORD qual,WORD msx,WORD msy);
  82.  
  83. BOOL WhichTileHit(WORD msx,WORD msy,UWORD *px,UWORD *py,UWORD *pz);
  84. BOOL IsInTile(UWORD scrnx,UWORD scrny,UWORD tilex,UWORD tiley,UWORD tilez);
  85. UWORD TopLevelTile(BOARD board,UWORD x,UWORD y);
  86. BOOL  CanMoveTile(BOARD board,UWORD x,UWORD y,UWORD z);
  87. void RemoveTile(BOARD board,struct RastPort *rp,UWORD x,UWORD y,UWORD z);
  88.  
  89. char *OpenAll(void);
  90. void CloseAll(char *errmsg,BOOL fromwb);
  91.  
  92. void UndoMove(BOARD board,struct RastPort *rp);
  93. void UndoAll(void);
  94.  
  95. void NewBoard(void);
  96. void ShuffleBoard(BOARD board);
  97.  
  98. ULONG Random(UWORD max);
  99. void Randomize(void);
  100.  
  101. int CXBRK(void) {return(0);}        /* Lattice: disables CTRL+C */
  102. int chkabort(void) {return(0);}
  103.  
  104. /************************************************************************
  105. *****************************  GLOBAL DATA  *****************************
  106. *************************************************************************/
  107.  
  108. /*
  109.  * Library bases
  110.  */
  111.  
  112. struct Library    *GadToolsBase = NULL;
  113. struct Library    *IFFParseBase = NULL;
  114. struct Library    *IconBase = NULL;
  115.  
  116. /*
  117.  * Pointers to the filenames for the background and tile IFF ILBMs,
  118.  * initialized to defaults.
  119.  */
  120.  
  121. char *BgndFilename = "DragonBgnd.pic";
  122. char *TilesFilename = "DragonTiles.pic";
  123.  
  124. /*
  125.  * If started okay from CLI, I allocate an RDArgs for the ReadArgs()
  126.  * call to process the command line with. This must be free'd on exit.
  127.  */
  128.  
  129. struct RDArgs *MyRDArgs = NULL;
  130.  
  131. /*
  132.  * If started okay from WB, this receives ptr to my DiskObject, to
  133.  * be released on exit. OrgCurDir receives the original current dir
  134.  * lock, which we must return to before exit.
  135.  */
  136.  
  137. struct DiskObject *MyDiskObj = NULL;
  138. BPTR OrgCurDir = NULL;
  139.  
  140. /*
  141.  * Make sure we get Topaz8 for all text
  142.  */
  143.  
  144. struct TextAttr TopazAttr = {"topaz.font",8,FS_NORMAL,
  145.                                     FPF_ROMFONT|FPF_DESIGNED};
  146.  
  147. /*
  148.  * Screen & Window data
  149.  */
  150.  
  151. struct ColorSpec ScrnClrs[] = {
  152.     {0 , 0, 0, 0}, {1 ,15,15,15}, {2 ,15,13, 9}, {3 ,14,11, 0},
  153.     {4 ,14,10, 0}, {5 ,12, 9, 0}, {6 , 9, 8, 5}, {7 , 7, 7, 7},
  154.     {8 ,14, 6, 0}, {9 ,12, 7, 1}, {10, 9, 0, 0}, {11, 5,12, 3},
  155.     {12, 5,10, 5}, {13, 3, 9, 8}, {14, 0, 9,15}, {15, 2, 8,12},
  156.     {16, 0, 0, 0}, {17,14, 4, 4}, {18, 0, 0, 0}, {19,14,14,12},
  157.     {20, 0, 0,15}, {21, 0, 2,13}, {22, 0, 4,11}, {23, 0, 6, 9},
  158.     {24, 0, 8, 7}, {25, 0,10, 5}, {26, 0,12, 3}, {27, 0,15, 0},
  159.     {28, 3,12, 0}, {29, 7, 8, 0}, {30,11, 4, 0}, {31,15, 0, 0},
  160.     {-1,0,0,0}
  161. };
  162.  
  163. struct TagItem ScreenTags[] = {
  164.     SA_Left,        0,
  165.     SA_Top,            0,
  166.     SA_Width,        SCRWIDTH,
  167.     SA_Height,        SCRHEIGHT,
  168.     SA_Depth,        SCRDEPTH,
  169.     SA_DisplayID,    0,
  170.     SA_Type,        CUSTOMSCREEN,
  171.     SA_Colors,        (ULONG) ScrnClrs,
  172.     SA_Title,        (ULONG) "Dragon V1.1",
  173.     TAG_DONE };
  174.  
  175. struct TagItem WindowTags[] = {
  176.     WA_CustomScreen, NULL,
  177.     WA_Left,        0,
  178.     WA_Top,            0,
  179.     WA_Width,        SCRWIDTH,
  180.     WA_Height,        SCRHEIGHT,
  181.     WA_IDCMP,        MAINIDCMP,
  182.     WA_Flags,        MAINWFLGS,
  183.     TAG_DONE };
  184.  
  185. struct NewMenu MyNewMenu[] = {
  186.     NM_TITLE, "Project", 0l, 0, 0, 0l,
  187.     NM_ITEM, "New Game", "N", 0, 0, 0l,
  188.     NM_ITEM, "Restart", "R", 0, 0, 0l,
  189.     NM_ITEM, "Undo Move", "U", 0, 0, 0l,
  190.     NM_ITEM, "About...", "A", 0, 0, 0l,
  191.     NM_ITEM, "Quit", "Q", 0, 0, 0l,
  192.     NM_END, 0l, 0l, 0, 0l, 0l };
  193.  
  194. struct Screen        *MyScreen = NULL;
  195. APTR                VisualInfo = NULL;
  196. struct Menu            *MainMenu = NULL;
  197. struct Window        *MainWindow = NULL;
  198. struct RastPort        *MainRPort;
  199. struct MsgPort        *MainIPort;
  200. ULONG                MainISigs;
  201.  
  202. /*
  203.  * Array that tells us what piece is where. The board is 12 tiles
  204.  * across, 6 tiles down, and 4 tiles high, but not all of those
  205.  * positions are used. Unused positions are marked as zero. The other
  206.  * numbers are ID codes for the pieces, which come as 4 instances of
  207.  * 30 types, making a total of 120 tiles. The particular arrangement
  208.  * of tiles shown here is irrelevant: it gets shuffled before use.
  209.  * Also, this array is only used to hold the starting arrangement, a
  210.  * working copy is made for playing with.
  211.  */
  212.  
  213. BOARD StartBoard =
  214.     {
  215.         {                                                /* bottom level */
  216.             { 1, 2, 3, 4, 5, 6, 7, 8, 9,10,11,12},
  217.             { 0, 0, 0,13,14,15,16,17,18, 0, 0, 0},
  218.             { 0,19,20,21,22,23,24,25,26,27,28, 0},
  219.             { 0,29,30, 1, 2, 3, 4, 5, 6, 7, 8, 0},
  220.             { 0, 0, 0, 9,10,11,12,13,14, 0, 0, 0},
  221.             {15,16,17,18,19,20,21,22,23,24,25,26}
  222.         },{                                                /* first level */
  223.             { 0, 0,27,28,29,30, 1, 2, 3, 4, 0, 0},
  224.             { 0, 0, 0, 0, 5, 6, 7, 8, 0, 0, 0, 0},
  225.             { 0, 0, 0, 9,10,11,12,13,14, 0, 0, 0},
  226.             { 0, 0, 0,15,16,17,18,19,20, 0, 0, 0},
  227.             { 0, 0, 0, 0,21,22,23,24, 0, 0, 0, 0},
  228.             { 0, 0,25,26,27,28,29,30, 1, 2, 0, 0}
  229.         },{                                                /* second level */
  230.             { 0, 0, 0, 0, 0, 3, 4, 0, 0, 0, 0, 0},
  231.             { 0, 0, 0, 0, 5, 6, 7, 8, 0, 0, 0, 0},
  232.             { 0, 0, 0, 0, 9,10,11,12, 0, 0, 0, 0},
  233.             { 0, 0, 0, 0,13,14,15,16, 0, 0, 0, 0},
  234.             { 0, 0, 0, 0,17,18,19,20, 0, 0, 0, 0},
  235.             { 0, 0, 0, 0, 0,21,22, 0, 0, 0, 0, 0}
  236.         },{                                                /* top level */
  237.             { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  238.             { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  239.             { 0, 0, 0, 0,23,24,25,26, 0, 0, 0, 0},
  240.             { 0, 0, 0, 0,27,28,29,30, 0, 0, 0, 0},
  241.             { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0},
  242.             { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
  243.         }
  244.     };
  245.  
  246. /*
  247.  * This is the array used as working copy of the board.
  248.  */
  249.  
  250. BOARD WorkBoard;
  251.  
  252. /*
  253.  * These hold the co-ordinates and type of the currently selected tile.
  254.  * Here is also the count of the number of pairs left on the board.
  255.  */
  256.  
  257. UBYTE SelectedTile;
  258. UWORD SelectX,SelectY,SelectZ;
  259.  
  260. UWORD PairsLeft;
  261.  
  262. /*
  263.  * For saving undo information.
  264.  */
  265.  
  266. struct StackMove UndoStack[NUMTILES];
  267. struct StackMove *UndoPtr;
  268.  
  269. /*
  270.  * The seed for the random number generator:
  271.  */
  272.  
  273. ULONG RandomSeed;
  274.  
  275. /*
  276.  * Messages displayed by 'about' requester and version command.
  277.  */
  278.  
  279. char VersionMsg[] = "\0$VER: Dragon 1.10 (8.2.94)";
  280.  
  281. char AboutMsg[] =    "    Dragon 1.10 (8.2.94)\n"
  282.                     "      by Nick Christie,\n"
  283.                     "      Copyright ©1995\n"
  284.                     "nick.christie@oucs.ox.ac.uk,\n"
  285.                     "    39 St Georges Drive,\n"
  286.                     "     Bransgore BH23 8EZ\n"
  287.                     "       Great Britain.";
  288.  
  289. /*
  290.  * The structure used for the 'about' requester.
  291.  */
  292.  
  293. struct EasyStruct EasyAbout = {
  294.     sizeof(struct EasyStruct), NULL, "About", AboutMsg, "Okay" };
  295.  
  296. /************************************************************************
  297. *******************************  MAIN()  ********************************
  298. *************************************************************************
  299. * Calls OpenAll() and waits for idcmp msgs. Calls CloseAll() before exit.
  300. * NB: Custom startup supplies command line + length, not argc/argv !
  301. * If WB, then cmdline ptr is actually WBStartupMsg ptr and len = 0.
  302. *
  303. *************************************************************************/
  304.  
  305. ULONG main(ULONG cmdlen,char *cmdline)
  306. {
  307. char                *errmsg;
  308. struct IntuiMessage    *imsg;
  309. ULONG                class;
  310. UWORD                code,qual;
  311. WORD                msx,msy;
  312. BOOL                done,fromwb;
  313.  
  314. errmsg = NULL;
  315. fromwb = (cmdlen == 0);
  316.  
  317. if (((struct Library *)SysBase)->lib_Version >= 36)
  318.     {
  319.     if (fromwb)
  320.         errmsg = ParseWBArgs((struct WBStartup *)cmdline,&BgndFilename,
  321.                                 &TilesFilename);
  322.     else
  323.         errmsg = ParseCLIArgs(cmdlen,cmdline,&BgndFilename,&TilesFilename);
  324.  
  325.     if (!errmsg)
  326.         {
  327.         if (!(errmsg = OpenAll()))
  328.             {
  329.             NewBoard();
  330.             done = FALSE;
  331.  
  332.             while (!done)
  333.                 {
  334.                 Wait(MainISigs);
  335.  
  336.                 while (imsg = (struct IntuiMessage *) GetMsg(MainIPort))
  337.                     {
  338.                     class = imsg->Class;
  339.                     code = imsg->Code;
  340.                     qual = imsg->Qualifier;
  341.                     msx = imsg->MouseX;
  342.                     msy = imsg->MouseY;
  343.                     ReplyMsg( (struct Message *) imsg);
  344.  
  345.                     switch(class)
  346.                         {
  347.                         case IDCMP_MOUSEBUTTONS:
  348.                             HandleMouse(code,qual,msx,msy);
  349.                             break;
  350.  
  351.                         case IDCMP_MENUPICK:
  352.                             done = HandleMenu(code,qual);
  353.                             break;
  354.                         }
  355.                     }
  356.                 }
  357.             }
  358.         }
  359.     }
  360.  
  361. CloseAll(errmsg,fromwb);
  362.  
  363. return(errmsg ? 20 : 0);
  364. }
  365.  
  366. /************************************************************************
  367. ****************************  PARSEWBARGS()  ****************************
  368. *************************************************************************
  369. * We were started from WB, so look in tooltypes for specification of
  370. * background and tile image files:
  371. *    BGND=bgndfilename
  372. *    TILES=tilesfilename
  373. * Put pointers to the correct strings at the locations supplied. If either
  374. * is missing, the default is left alone. Error msg is returned, else null.
  375. * CloseAll() is expected to release MyDiskObj and close icon library.
  376. *
  377. *************************************************************************/
  378.  
  379. char *ParseWBArgs(struct WBStartup *wbmsg,char **bgndptr,char **tileptr)
  380. {
  381. char    *name,*errmsg;
  382.  
  383. if (IconBase = OpenLibrary("icon.library",37))
  384.     {
  385.     OrgCurDir = CurrentDir(wbmsg->sm_ArgList->wa_Lock);
  386.  
  387.     if (MyDiskObj = GetDiskObject(wbmsg->sm_ArgList->wa_Name))
  388.         {
  389.         if (name = FindToolType(MyDiskObj->do_ToolTypes,"BGND"))
  390.             *bgndptr = name;
  391.         if (name = FindToolType(MyDiskObj->do_ToolTypes,"TILES"))
  392.             *tileptr = name;
  393.         errmsg = NULL;
  394.         }
  395.     else
  396.         errmsg = "Couldn't access WB tooltypes.";
  397.     }
  398. else
  399.     errmsg = "No icon library V37";
  400.  
  401. return(errmsg);
  402. }
  403.  
  404. /************************************************************************
  405. ***************************  PARSECLIARGS()  ****************************
  406. *************************************************************************
  407. * Look for specification of background and tile image files on cmd line.
  408. * Template is "Dragon [TILES=tilesfile] [BGND=bgndfile]".
  409. * If found, sets pointers supplied to correct names, else leaves them
  410. * with defaults.
  411. *
  412. *************************************************************************/
  413.  
  414. char *ParseCLIArgs(ULONG clen,char *cline,char **bgndptr,char **tileptr)
  415. {
  416. LONG    args[2];
  417. char    *errmsg;
  418.  
  419. if (*cline == '?')
  420.     errmsg = USAGEMSG;
  421. else
  422.     {
  423.     if (MyRDArgs = (struct RDArgs *)AllocDosObject(DOS_RDARGS,NULL))
  424.         {
  425.         MyRDArgs->RDA_Source.CS_Buffer = cline;
  426.         MyRDArgs->RDA_Source.CS_Length = clen;
  427.         MyRDArgs->RDA_Source.CS_CurChr = 0;
  428.         MyRDArgs->RDA_Flags |= RDAF_STDIN;
  429.         args[0] = (LONG) *tileptr;
  430.         args[1] = (LONG) *bgndptr;
  431.  
  432.         if (ReadArgs("TILES/K,BGND/K",args,MyRDArgs))
  433.             {
  434.             *tileptr = (char *)args[0];
  435.             *bgndptr = (char *)args[1];
  436.             errmsg = NULL;
  437.             }
  438.         else
  439.             errmsg = "Error in command line arguments !";
  440.         }
  441.     else
  442.         errmsg = "No memory !";
  443.     }
  444.  
  445. return(errmsg);
  446. }
  447.  
  448. /************************************************************************
  449. ****************************  HANDLEMENU()  *****************************
  450. *************************************************************************
  451. * Respond to menupick idcmp msg. Returns BOOL indicating quit if true.
  452. *
  453. *************************************************************************/
  454.  
  455. BOOL HandleMenu(UWORD code,UWORD qual)
  456. {
  457. BOOL    done = FALSE;
  458.  
  459. if ((code != MENUNULL) && (MENUNUM(code) == 0))
  460.     {
  461.     switch (ITEMNUM(code))
  462.         {
  463.         case ITEM_NEWGAME:
  464.             NewBoard();
  465.             break;
  466.  
  467.         case ITEM_RESTART:
  468.             UndoAll();
  469.             break;
  470.  
  471.         case ITEM_UNDOMOVE:
  472.             UndoMove(WorkBoard,MainRPort);
  473.             break;
  474.  
  475.         case ITEM_ABOUT:
  476.             EasyRequest(MainWindow,&EasyAbout,NULL,NULL);
  477.             break;
  478.  
  479.         case ITEM_QUIT:
  480.             done = TRUE;
  481.             break;
  482.         }
  483.     }
  484.  
  485. return(done);
  486. }
  487.  
  488. /************************************************************************
  489. ****************************  HANDLEMOUSE()  ****************************
  490. *************************************************************************
  491. * Respond to mousebuttons idcmp msg. See if it was LMB down on a tile,
  492. * and react if necessary by removing/highlighting tile(s). Also looks
  493. * for SHIFT keys: if held down, selected tile is removed momentarily and
  494. * then put back (cheating).
  495. *
  496. *************************************************************************/
  497.  
  498. void HandleMouse(UWORD code,UWORD qual,WORD msx,WORD msy)
  499. {
  500. UWORD    x,y,z;
  501. UBYTE    tile;
  502.  
  503. if (code == SELECTDOWN)
  504.     {
  505.     if (WhichTileHit(msx,msy,&x,&y,&z))
  506.         {
  507.         if (tile = WorkBoard[z][y][x])
  508.             {
  509.             if (qual & IEQ_SHIFT)
  510.                 {
  511.                 WorkBoard[z][y][x] = 0;
  512.                 DrawBoard(WorkBoard,MainRPort);
  513.                 Delay(15);
  514.                 WorkBoard[z][y][x] = tile;
  515.                 DrawBoard(WorkBoard,MainRPort);
  516.                 }
  517.             else
  518.                 {
  519.                 if (CanMoveTile(WorkBoard,x,y,z))
  520.                     {
  521.                     if ((SelectedTile == tile) && ((SelectX != x)
  522.                         || (SelectY != y) || (SelectZ != z)))
  523.                         {
  524.                         RemoveTile(WorkBoard,MainRPort,x,y,z);
  525.                         }
  526.                     else
  527.                         {
  528.                         SelectedTile = tile;
  529.                         SelectX = x;
  530.                         SelectY = y;
  531.                         SelectZ = z;
  532.                         DrawOneTile(tile,MainRPort,SELECTLEFT,SELECTTOP);
  533.                         SelectStats(tile,WorkBoard,MainRPort);
  534.                         }
  535.                     }        /* endif CanMoveTile */
  536.                 }        /* endelse not SHIFT */
  537.             }        /* endif tile != 0 */
  538.         }        /* endif tile hit */
  539.     }        /* endif SELECTDOWN */
  540. }
  541.  
  542. /************************************************************************
  543. ***************************  WHICHTILEHIT()  ****************************
  544. *************************************************************************
  545. * Determines, from mouse x/y, which tile was hit, if any, and puts the
  546. * tile's x/y/z co-ordinates into the supplied UWORDs. Returns false if
  547. * mouse x/y is outside board area or if no tile there. Accomodates for
  548. * overhanging tiles.
  549. *
  550. *************************************************************************/
  551.  
  552. BOOL WhichTileHit(WORD msx,WORD msy,UWORD *px,UWORD *py,UWORD *pz)
  553. {
  554. UWORD    mx,my,x,y,z;
  555. BOOL    found = FALSE;
  556.  
  557. if ((msx >= 0) && (msy >= 0))
  558.     {
  559.     mx = msx;
  560.     my = msy;
  561.     y = BOARDY;
  562.  
  563.     do
  564.         {
  565.         y--;
  566.         x = BOARDX;
  567.  
  568.         do
  569.             {
  570.             x--;
  571.             z = TopLevelTile(WorkBoard,x,y);
  572.             if (WorkBoard[z][y][x])
  573.                 found = IsInTile(mx,my,x,y,z);
  574.             }
  575.         while((x > 0) && !found);
  576.         }
  577.     while((y > 0) && !found);
  578.  
  579.     if (found)
  580.         {
  581.         *px = x; *py = y; *pz = z;
  582.         }
  583.     }
  584.  
  585. return(found);
  586. }
  587.  
  588. /************************************************************************
  589. *****************************  ISINTILE()  ******************************
  590. *************************************************************************
  591. * Return whether the given screen position is within the "naive"
  592. * boundaries of the given tile, specified by x/y/z coordinates.
  593. * Does not take account of "overhanging" tiles, but does take account of
  594. * x/y adjustment for given z.
  595. *
  596. *************************************************************************/
  597.  
  598. BOOL IsInTile(UWORD scrnx,UWORD scrny,UWORD tilex,UWORD tiley,UWORD tilez)
  599. {
  600. UWORD    sx,sy;
  601.  
  602. sx = BRDLEFTEDGE + (tilex * TILEXSPACE) - (tilez * LEVELXADJ);
  603. sy = BRDTOPEDGE + (tiley * TILEYSPACE) - (tilez * LEVELYADJ);
  604.  
  605. if ((scrnx >= sx) && (scrnx < sx+TILEXSPACE)
  606.     && (scrny >= sy) && (scrny < sy+TILEYSPACE)) return(TRUE);
  607. else return(FALSE);
  608. }
  609.  
  610. /************************************************************************
  611. ***************************  TOPLEVELTILE()  ****************************
  612. *************************************************************************
  613. * Determines the z coordinate of the topmost tile in the given board at
  614. * the given x,y position. Returns z=0 if no tile could be found at that
  615. * position at all, in which case this routine shouldn't have been called !
  616. *
  617. *************************************************************************/
  618.  
  619. UWORD TopLevelTile(BOARD board,UWORD x,UWORD y)
  620. {
  621. UWORD    z = BOARDZ-1;
  622.  
  623. while((z > 0) && (board[z][y][x] == 0)) --z;
  624.  
  625. return(z);
  626. }
  627.  
  628. /************************************************************************
  629. ****************************  CANMOVETILE()  ****************************
  630. *************************************************************************
  631. * Determines whether a tile can be moved or not. It can if it has no
  632. * neighbours to either the left or the right. The tile is assumed to be
  633. * the topmost, ie. caller must have already determined that it is.
  634. *
  635. *************************************************************************/
  636.  
  637. BOOL  CanMoveTile(BOARD board,UWORD x,UWORD y,UWORD z)
  638. {
  639. if ((x == 0) || (x == BOARDX-1))
  640.     return((BOOL)TRUE);
  641. else
  642.     return ((BOOL)!(board[z][y][x-1] && board[z][y][x+1]));
  643. }
  644.  
  645. /************************************************************************
  646. ****************************  REMOVETILE()  *****************************
  647. *************************************************************************
  648. * Remove a pair of tiles from the given board. It has already been
  649. * determined that the tile can be moved. One tile position is supplied,
  650. * the other is in SelectX/Y/Z. Undo information is stored & the graphics
  651. * are updated. One day this will return a BOOL meaning that all tiles
  652. * are gone & victory effects should be shown.
  653. *
  654. *************************************************************************/
  655.  
  656. void RemoveTile(BOARD board,struct RastPort *rp,UWORD x,UWORD y,UWORD z)
  657. {
  658. UBYTE tile;
  659.  
  660. tile = board[z][y][x];
  661. UndoPtr->tile = tile;
  662. UndoPtr->x1 = (UBYTE) x;
  663. UndoPtr->y1 = (UBYTE) y;
  664. UndoPtr->z1 = (UBYTE) z;
  665. UndoPtr->x2 = (UBYTE) SelectX;
  666. UndoPtr->y2 = (UBYTE) SelectY;
  667. UndoPtr->z2 = (UBYTE) SelectZ;
  668. UndoPtr++;
  669. UndoPtr->tile = 0;
  670.  
  671. board[z][y][x] = 0;
  672. board[SelectZ][SelectY][SelectX] = 0;
  673. SelectedTile = 0;
  674. PairsLeft--;
  675. DrawBoard(board,rp);
  676. }
  677.  
  678. /************************************************************************
  679. ******************************  OPENALL()  ******************************
  680. *************************************************************************
  681. * Opens libraries, screen and window. Returns error msg if fail, else
  682. * returns null.
  683. *
  684. *************************************************************************/
  685.  
  686. char *OpenAll(void)
  687. {
  688. if (!(IntuitionBase = (struct IntuitionBase *)
  689.     OpenLibrary("intuition.library",37)))
  690.         return("No Intuition V37 !");
  691.  
  692. if (!(GfxBase = (struct GfxBase *)
  693.     OpenLibrary("graphics.library",37)))
  694.         return("No Graphics !");
  695.  
  696. if (!(GadToolsBase = OpenLibrary("gadtools.library",37)))
  697.     return("No GadTools !");
  698.  
  699. if (!(IFFParseBase = OpenLibrary("iffparse.library",37)))
  700.     return("No IFFParse !");
  701.  
  702. if (!OpenBufRPort()) return("No memory !");
  703.  
  704. LoadBackground(BgndFilename);
  705.  
  706. if (!LoadTileImages(TilesFilename))
  707.     return("No tiles !");
  708.  
  709. if (!(MyScreen = OpenScreenTagList(NULL,ScreenTags)))
  710.     return("No screen !");
  711.  
  712. if (!(VisualInfo = GetVisualInfo(MyScreen,TAG_DONE)))
  713.     return("No memory !");
  714.  
  715. WindowTags[0].ti_Data = (ULONG) MyScreen;
  716.  
  717. if (!(MainWindow = OpenWindowTagList(NULL,WindowTags)))
  718.     return("No window !");
  719.  
  720. MainRPort = MainWindow->RPort;
  721. MainIPort = MainWindow->UserPort;
  722. MainISigs = 1L<<(MainIPort->mp_SigBit);
  723.  
  724. if (!(MainMenu = CreateMenus(MyNewMenu,GTMN_FrontPen,0L,TAG_DONE)))
  725.         return("No memory !");
  726.  
  727. LayoutMenus(MainMenu,VisualInfo,GTMN_TextAttr,&TopazAttr,TAG_DONE);
  728. SetMenuStrip(MainWindow,MainMenu);
  729.  
  730. return(NULL);
  731. }
  732.  
  733. /************************************************************************
  734. *****************************  CLOSEALL()  ******************************
  735. *************************************************************************
  736. * Release all resources obtained by OpenAll(), if any. At some stage will
  737. * also display supplied error msg if it's non-null.
  738. *
  739. *************************************************************************/
  740.  
  741. void CloseAll(char *errmsg,BOOL fromwb)
  742. {
  743. BPTR    out;
  744.  
  745. if (MainMenu)
  746.     {
  747.     ClearMenuStrip(MainWindow);
  748.     FreeMenus(MainMenu);
  749.     }
  750. if (MainWindow) CloseWindow(MainWindow);
  751. if (VisualInfo) FreeVisualInfo(VisualInfo);
  752. if (MyScreen) CloseScreen(MyScreen);
  753. UnloadTileImages();
  754. UnloadBackground();
  755. CloseBufRPort();
  756. if (IFFParseBase) CloseLibrary(IFFParseBase);
  757. if (GadToolsBase) CloseLibrary(GadToolsBase);
  758. if (GfxBase) CloseLibrary( (struct Library *) GfxBase);
  759. if (IntuitionBase) CloseLibrary( (struct Library *) IntuitionBase);
  760.  
  761. if (IconBase)
  762.     {
  763.     if (MyDiskObj) FreeDiskObject(MyDiskObj);
  764.     if (OrgCurDir) CurrentDir(OrgCurDir);
  765.     CloseLibrary(IconBase);
  766.     }
  767.  
  768. if (MyRDArgs)
  769.     {
  770.     FreeArgs(MyRDArgs);
  771.     FreeDosObject(DOS_RDARGS,(APTR)MyRDArgs);
  772.     }
  773.  
  774. if (errmsg)
  775.     {
  776.     if (fromwb)
  777.         out = Open("CON:0/0/300/80/Dragon Error/CLOSE/WAIT",MODE_NEWFILE);
  778.     else
  779.         out = Output();
  780.  
  781.     if (out)
  782.         {
  783.         VFPrintf(out,"%s\n",(LONG *) &errmsg);
  784.         if (fromwb)
  785.             Close(out);
  786.         }
  787.     }
  788. }
  789.  
  790. /************************************************************************
  791. *****************************  UNDOMOVE()  ******************************
  792. *************************************************************************
  793. * Use the undo stack to take back the last move. Board is redrawn & state
  794. * trackers updated.
  795. *
  796. *************************************************************************/
  797.  
  798. void UndoMove(BOARD board,struct RastPort *rp)
  799. {
  800. if (PairsLeft != NUMTILES/2)
  801.     {
  802.     UndoPtr--;
  803.     board[UndoPtr->z1][UndoPtr->y1][UndoPtr->x1] = UndoPtr->tile;
  804.     board[UndoPtr->z2][UndoPtr->y2][UndoPtr->x2] = UndoPtr->tile;
  805.  
  806.     SelectedTile = 0;
  807.     PairsLeft++;
  808.  
  809.     DrawBoard(board,rp);
  810.     }
  811. }
  812.  
  813. /************************************************************************
  814. ******************************  UNDOALL()  ******************************
  815. *************************************************************************
  816. * Reset board to starting state. Doesn't actually need undo stack to do
  817. * this, as the original board has been preserved.
  818. *
  819. *************************************************************************/
  820.  
  821. void UndoAll(void)
  822. {
  823. SelectedTile = 0;
  824. PairsLeft = NUMTILES/2;
  825. UndoPtr = UndoStack;
  826. UndoPtr->tile = 0;
  827. CopyBoard(StartBoard,WorkBoard);
  828. DrawBoard(WorkBoard,MainRPort);
  829. }
  830.  
  831. /************************************************************************
  832. *****************************  NEWBOARD()  ******************************
  833. *************************************************************************
  834. * Resets for a new board. StartBoard gets shuffled to produce WorkBoard,
  835. * which gets drawn. Counters & state trackers reset.
  836. *
  837. *************************************************************************/
  838.  
  839. void NewBoard(void)
  840. {
  841. SelectedTile = 0;
  842. PairsLeft = NUMTILES/2;
  843. UndoPtr = UndoStack;
  844. UndoPtr->tile = 0;
  845. ShuffleBoard(StartBoard);
  846. CopyBoard(StartBoard,WorkBoard);
  847. DrawBoard(WorkBoard,MainRPort);
  848. }
  849.  
  850. /************************************************************************
  851. ***************************  SHUFFLEBOARD()  ****************************
  852. *************************************************************************
  853. * Shuffle the pieces in the supplied BOARD array into a random order.
  854. * Normally, all 120 pieces are present in the array when the shuffle is
  855. * performed, as this routine spends its time swapping tiles randomly.
  856. * No tile is swapped with an array element of zero (where no tile is
  857. * present). The tile array is handled as a flat array of bytes, as we
  858. * are not concerned about the particular arrangement.
  859. *
  860. *************************************************************************/
  861.  
  862. void ShuffleBoard(BOARD board)
  863. {
  864. ULONG    r1;
  865. ULONG    r2;
  866. UWORD    i,x,y;
  867. UBYTE    t1,t2,t3,t4,*p;
  868. BOOL    reshuffle = TRUE;
  869.  
  870. while (reshuffle)
  871.     {
  872.     Randomize();
  873.  
  874.     p = (UBYTE *) board;
  875.  
  876.     for(i=0;i<8192;i++)
  877.         {
  878.         r1 = Random(BOARDX*BOARDY*BOARDZ-1);
  879.         r2 = Random(BOARDX*BOARDY*BOARDZ-1);
  880.         t1 = p[r1]; t2 = p[r2];
  881.         if (t1 && t2)
  882.             {
  883.             p[r1] = t2; p[r2] = t1;
  884.             }
  885.         }
  886.  
  887.     reshuffle = FALSE;
  888.     y = 0;
  889.  
  890.     while((y < BOARDY) && !reshuffle)
  891.         {
  892.         x = 0;
  893.  
  894.         while((x < BOARDX) && !reshuffle)
  895.             {
  896.             t1 = board[0][y][x];
  897.             t2 = board[1][y][x];
  898.             t3 = board[2][y][x];
  899.             t4 = board[3][y][x];
  900.             if (t4)
  901.                 {
  902.                 if (t1 == t2)
  903.                     {
  904.                     reshuffle = ((t2 == t3) || (t2 == t4));
  905.                     }
  906.                 else if (t3 == t4)
  907.                     {
  908.                     reshuffle = ((t1 == t3) || (t2 == t3));
  909.                     }
  910.                 }
  911.             else if (t3)
  912.                 {
  913.                 reshuffle = ((t1 == t2) && (t2 == t3));
  914.                 }
  915.             x++;
  916.             }        /* endwhile x loop */
  917.         y++;
  918.         }        /* endwhile y loop */
  919.  
  920.     }        /* endwhile reshuffle */
  921. }
  922.  
  923. /************************************************************************
  924. ******************************  RANDOM()  *******************************
  925. *************************************************************************
  926. * Utility for ShuffleBoard(), returns a pseudo-random number between 0
  927. * and max. Uses RandomSeed, which should be initialized before use by
  928. * calling Randomize().
  929. *
  930. *************************************************************************/
  931.  
  932. ULONG Random(UWORD max)
  933. {
  934. RandomSeed = ((UWORD)(RandomSeed & 0xffff) * (UWORD) 25173) + 13849L;
  935. return((ULONG) ((RandomSeed & 0xffff) % (UWORD)(max)));
  936. }
  937.  
  938. /************************************************************************
  939. *****************************  RANDOMIZE()  *****************************
  940. *************************************************************************
  941. * Initializes RandomSeed to random number from system clock.
  942. *
  943. *************************************************************************/
  944.  
  945. void Randomize(void)
  946. {
  947. struct DateStamp    ds;
  948.  
  949. DateStamp(&ds);
  950. RandomSeed = ds.ds_Minute+ds.ds_Tick;
  951. }
  952.  
  953.