home *** CD-ROM | disk | FTP | other *** search
- #include "pz.h"
-
- /* Ali Ozer
- ** Main user interface/action loop for IFF2PCS
- ** AND a whole lot more...
- ** This file shouldn't be this long, but unfortunately, it is...
- ** It is also a bit messy (too many extern references, ack!)
- ** Nov 1987
- */
-
- /* We assume several things:
- ** puzph = puzpw
- ** picx = integer multiple of (puzpw)
- ** picy = integer multiple of (puzph)
- */
- extern int puzpn, puzdepth; /* These are the parameters for a piece */
- extern int picx, picy; /* Where the picture is */
- extern int picw, pich; /* The size of the picture */
- extern int textcolor;
- extern int bordercolor;
- extern int normcolor;
- extern int nonzerocolor;
- struct BitMap bgbm, rotbm; /* Background bitmap, rotation bitmap */
-
- extern struct PopUp_Menu pzmenu;
-
- unsigned long starttime; /* In seconds */
-
- int minmousex, maxmousex, minmousey, maxmousey;
-
- int puzph, puzpw;
- int picxbase, picybase; /* Simply picx-puzpw/2 and picy-puzph/2 */
-
- extern struct BitMap picbm;
-
- struct BitMap *wbm;
- struct RastPort *wrp;
-
- struct Window *picwin;
- struct Screen *picscr;
-
- int winoffset; /* Offset of the puzzle area within the window */
-
- int numpieces, numx, numy;
-
- int toppiece, bottompiece;
-
- /* Number of pieces will be (picw / puzpw) * (pich / puzph)
- */
-
- struct piecestr {
- int xloc, yloc; /* Pixel location on screen */
- int next, prev; /* Next piece, in top to bottom sorted order */
- int rotation; /* 0 normal, 1 ninety cw, 2 upsidedown, 3 90ccw */
- int ingrid; /* True if piece is in the puzzle somewhere... */
- } *pieces; /* Bottompiece -> Prev -> Prev -> ... -> -1 */
-
- ubyte *gridinfo; /* Whether a grid piece is occupied or not... */
-
- DrawGrid ()
- {
- long x = picx-1;
- long y = picy-1;
- int cnt;
-
- SetAPen (wrp, (long)bordercolor);
- for (cnt = 0; cnt <= numy; cnt++) {
- Move (wrp, x, y); Draw (wrp, x + picw + 1, y);
- Move (wrp, x, y+1); Draw (wrp, x + picw + 1, y+1);
- y += puzph;
- };
-
- y = picy-1;
- for (cnt = 0; cnt <= numx; cnt++) {
- Move (wrp, x, y); Draw (wrp, x, y + pich + 1);
- Move (wrp, x+1, y); Draw (wrp, x+1, y + pich + 1);
- x += puzpw;
- };
- }
-
-
- static ubyte tmp[8]; /* Temp for rotates... */
-
- Rotate (plane, nbytes) /* n is the side of the square in bytes... */
- ubyte *plane;
- int nbytes;
- {
- int cnt, side, n, nbytec = nbytes << 3;
- ubyte *s1, *s2, *s3, *s4;
-
- for (n = nbytes; n > 1; n -= 2) {
- s1 = plane;
- s2 = plane + n - 1;
- s4 = s1 + nbytec * (n - 1);
- s3 = s4 + n - 1;
- for (side = 0; side < n-1; side++) {
- for (cnt = 0; cnt < 8; cnt++) tmp[cnt] = s1[cnt * nbytes];
- flip (s4, nbytes, s1, nbytes);
- flip (s3, nbytes, s4, nbytes);
- flip (s2, nbytes, s3, nbytes);
- flip (&tmp[0], 1, s2, nbytes);
- s1++; s3--; s2 += nbytec; s4 -= nbytec;
- };
- plane += (nbytec + 1);
- }
- }
-
-
- /* Border modes */
- #define NOBORDER 0
- #define BORDER 1
- #define HLBORDER 2 /* Highlighted border */
- #define ERASE 3
- #define JUSTBORDER 4
-
-
- /* Come in with x = -1 to use the pieces default position...
- */
- DrawPiece (pnum, x, y, border)
- int border, x, y, pnum;
- {
- long cnt;
- int rot;
- int bmx = (pnum % numx) * puzpw;
- int bmy = (pnum / numx) * puzph;
-
- if (x == -1) {
- x = pieces[pnum].xloc;
- y = pieces[pnum].yloc;
- };
-
- if (border == ERASE || border == JUSTBORDER) {
- SetAPen (wrp, 0L);
- RectFill (wrp, (long)x, (long)y, (long)(x+puzpw-1), (long)(y+puzph-1));
- } else {
- if (pieces[pnum].rotation) {
- SavePuzBM (&picbm, bmx, bmy, &rotbm);
- for (rot = 0; rot < pieces[pnum].rotation; rot++)
- for (cnt = 0; cnt < rotbm.Depth; cnt++)
- Rotate (rotbm.Planes[cnt], puzph >> 3);
- CopyFromBMToBM (&rotbm, 0, 0, wbm, x, y, puzpw, puzph);
- } else CopyFromBMToBM (&picbm, bmx, bmy, wbm, x, y, puzpw, puzph);
- };
-
- if (border != ERASE) {
- if (border != NOBORDER) {
- if (border == HLBORDER) SetAPen (wrp, (long)textcolor);
- else SetAPen (wrp, (long)bordercolor);
- Move (wrp, (long)x, (long)y);
- Draw (wrp, (long)x+puzpw-1, (long)y);
- Draw (wrp, (long)x+puzpw-1, (long)y+puzph-1);
- Draw (wrp, (long)x, (long)y+puzph-1);
- Draw (wrp, (long)x, (long)y);
- }
- }
- }
-
-
- int RndInt();
- int Min ();
- int Max ();
- unsigned long TimeInSecs ();
-
- int PuzzleSolved ()
- {
- int width = (picw >> 3);
- int planecnt, bytecnt, rowcnt;
- unsigned char *curplane;
-
- for (planecnt = 0; planecnt < wbm->Depth; planecnt++) {
- curplane = (unsigned char *)(wbm->Planes[planecnt]) + winoffset;
- for (rowcnt = 0; rowcnt < pich; rowcnt++) {
- for (bytecnt = 0; bytecnt < width; bytecnt++) {
- if (*(curplane+bytecnt)) return (false);
- }
- curplane += wbm->BytesPerRow;
- }
- }
- return (true);
- }
-
-
- CheckPuzzle ()
- {
- int solved;
- unsigned long timedif = TimeInSecs() - starttime;
- static char *solvestr = "Time: 0:00:00 *** Puzzle is SOLVED ***";
-
- XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
- if (timedif >= 360000) solvestr[5] = '0' + (timedif / 360000) % 10;
- if (timedif >= 36000) solvestr[6] = '0' + (timedif / 36000) % 10;
- solvestr[7] = '0' + (timedif / 3600) % 10;
- solvestr[9] = '0' + (timedif / 600) % 6;
- solvestr[10] = '0' + (timedif / 60) % 10;
- solvestr[12] = '0' + (timedif / 10) % 6;
- solvestr[13] = '0' + (timedif % 10);
-
- SetWindowTitles (picwin, NULL, "Checking...");
- if (solved = PuzzleSolved()) {
- solvestr[14] = ' ';
- XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
- } else solvestr[14] = '\0';
- SetWindowTitles (picwin, NULL, solvestr);
- Wait (1L << picwin->UserPort->mp_SigBit);
- if (solved == false) XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
- SetWindowTitles (picwin, NULL, PROGNAME);
- }
-
-
-
- void MakePuzzle ()
- {
- int cnt, miny, maxy, minx, maxx;
-
- /* Puzzle piece size. Puzpn is the power of two size of each piece.
- ** For now, pieces have to be square, so we set puzph = puzpw.
- */
-
- /* Minimum and maximum locations for puzzle pieces */
- miny = picy + pich + 4;
- maxy = picwin->Height - puzph - 4;
- minx = 2;
- maxx = picwin->Width - puzpw - 2;
-
- minmousex = 0;
- maxmousex = picscr->Width - puzpw - 1;
- minmousey = picscr->BarHeight + 1;
- maxmousey = picscr->Height - puzph - 1;
-
- if (((pieces = (struct piecestr *)
- AllocMem ((long)(numpieces * sizeof(struct piecestr)), 0L)) == NULL) ||
- ((gridinfo = (ubyte *)
- AllocMem ((long)(((numx * numy) >> 3) + 1), MEMF_CLEAR)) == NULL)) {
- FreeBMs ();
- Panic ("No memory for bitmaps");
- };
-
- DrawGrid ();
-
- for (cnt = 0; cnt < numpieces; cnt++) {
- /* piecexnum = cnt % numx AND pieceynum = cnt / numx */
- pieces[cnt].ingrid = false;
- pieces[cnt].rotation = RndInt (0, 3);
- pieces[cnt].next = cnt + 1;
- pieces[cnt].prev = cnt - 1;
- pieces[cnt].xloc = RndInt (minx, maxx);
- pieces[cnt].yloc = RndInt (miny, maxy);
- };
-
- pieces[numpieces-1].next = -1;
- bottompiece = numpieces - 1;
- toppiece = 0;
-
- /* Shuffle some so that we don't always get the same order... */
- for (cnt = 0; cnt < (numpieces>>3); cnt++)
- PutPieceAtTop (RndInt(0, numpieces-1));
-
- DrawAllPieces ();
- }
-
-
-
- PutPieceAtTop (piece)
- int piece;
- {
- if (pieces[piece].next != -1)
- pieces[pieces[piece].next].prev = pieces[piece].prev;
- else
- bottompiece = pieces[piece].prev;
- if (pieces[piece].prev != -1)
- pieces[pieces[piece].prev].next = pieces[piece].next;
- else
- toppiece = pieces[piece].next;
- pieces[piece].next = toppiece;
- pieces[toppiece].prev = piece;
- toppiece = piece;
- pieces[piece].prev = -1;
- }
-
-
- SeeIfInGrid (piece, newx, newy)
- int piece, newx, newy;
- {
- if ((newx <= picx + picw) && (newx >= picx - puzpw) &&
- (newy <= picy + pich) && (newy >= picy - puzph)) {
- if (newx < picxbase) newx = picxbase;
- else if (newx >= picxbase + picw) newx = picxbase + picw - 1;
- if (newy < picybase) newy = picybase;
- else if (newy >= picybase + pich) newy = picybase + pich - 1;
- newx = ((newx - picxbase) / puzpw) * puzpw + picx;
- newy = ((newy - picybase) / puzph) * puzph + picy;
- if (GridBoxOccupied (newx, newy, -1) == false) {
- GridBoxOccupied (newx, newy, true);
- pieces[piece].ingrid = true;
- pieces[piece].xloc = newx;
- pieces[piece].yloc = newy;
- } else SeeIfInGrid (piece, pieces[piece].xloc, pieces[piece].yloc);
- } else {
- pieces[piece].ingrid = false;
- pieces[piece].xloc = newx;
- pieces[piece].yloc = newy;
- }
- }
-
-
- /* Draws pieces that overlap the specified area in any way. Then grows the
- ** specified area by the bounding box of the new piece. A rather inefficient
- ** way of fixing up the picture after a change... The argument notpiece
- ** specifies a piece (if any) that does not need to be redrawn. Set to -1 if
- ** no such piece.
- */
- /*
- ReDrawThePiecesAt (x1, x2, y1, y2, notpiece)
- int x1, x2, y1, y2, notpiece;
- {
- int cnt = bottompiece;
- cnt = bottompiece;
- while (cnt != -1) {
- if ((pieces[cnt].xloc <= x2) && (pieces[cnt].xloc+puzpw-1 >= x1) &&
- (pieces[cnt].yloc <= y2) && (pieces[cnt].yloc+puzph-1 >= y1) &&
- (cnt != notpiece)) {
- DrawPiece (cnt, -1, -1, BORDER);
- x1 = Min (x1, pieces[cnt].xloc);
- x2 = Max (x2, pieces[cnt].xloc+puzpw-1);
- y1 = Min (y1, pieces[cnt].yloc);
- y2 = Max (y2, pieces[cnt].yloc+puzph-1);
- };
- cnt = pieces[cnt].prev;
- }
- }
- */
-
-
- ReDrawThePiecesAt (x1, x2, y1, y2, notpiece)
- int x1, x2, y1, y2, notpiece;
- {
- int cnt = bottompiece, i, tmpprev;
- for (i = 0; i < numpieces; i++) {
- tmpprev = pieces[cnt].prev;
- if ((pieces[cnt].xloc <= x2) && (pieces[cnt].xloc+puzpw-1 >= x1) &&
- (pieces[cnt].yloc <= y2) && (pieces[cnt].yloc+puzph-1 >= y1) &&
- (cnt != notpiece)) {
- DrawPiece (cnt, -1, -1, BORDER);
- PutPieceAtTop (cnt);
- };
- cnt = tmpprev;
- }
- }
-
-
- ErasePiece (piece)
- int piece;
- {
- if (pieces[piece].ingrid == true) {
- DrawPiece (piece, -1, -1, JUSTBORDER);
- GridBoxOccupied (pieces[piece].xloc, pieces[piece].yloc, false);
- pieces[piece].ingrid = false;
- } else {
- DrawPiece (piece, -1, -1, ERASE);
- ReDrawThePiecesAt (pieces[piece].xloc, pieces[piece].xloc + puzph - 1,
- pieces[piece].yloc, pieces[piece].yloc + puzpw - 1,
- piece);
- }
- }
-
-
- DrawAllPieces ()
- {
- int cnt = bottompiece;
- while (cnt != -1) {
- DrawPiece (cnt, -1, -1, BORDER);
- cnt = pieces[cnt].prev;
- };
- }
-
-
- FreeBMs ()
- {
- FreeBM (&bgbm);
- FreeBM (&rotbm);
- if (gridinfo != NULL) FreeMem (gridinfo, (long)(((numx * numy) >> 3) + 1));
- if (pieces != NULL) FreeMem (pieces, (long)(numpieces * sizeof(struct piecestr)));
- }
-
-
- /* Come in with x, y to test and possibly set the mode of the grid at location
- ** x, y. If mode is true or false, then the new mode is set. If mode is -1, then
- ** the old mode is returned...
- */
- int GridBoxOccupied (x, y, mode)
- int x, y, mode;
- {
- int index;
- ubyte bit;
-
- x = (x - picx) / puzpw;
- y = (y - picy) / puzph;
- index = (y * numx + x) >> 3;
- bit = (1 << ((y * numx + x) & 7));
- if (mode == true) gridinfo[index] |= bit;
- else if (mode == false) gridinfo[index] &= ~bit;
- else if ((gridinfo[index] & bit) != 0) return (true);
- else return (false);
- }
-
-
- /* SavePuzBM will save the indicated section of bm in tmpbm; RestorePuzBM
- ** will bring that section back into the indicated section in bm.
- */
- SavePuzBM (bm, x, y, tmpbm)
- struct BitMap *bm, *tmpbm;
- int x, y;
- {
- CopyFromBMToBM (bm, x, y, tmpbm, 0, 0, puzpw, puzph);
- }
-
-
- RestorePuzBM (bm, x, y, tmpbm)
- struct BitMap *bm, *tmpbm;
- int x, y;
- {
- CopyFromBMToBM (tmpbm, 0, 0, bm, x, y, puzpw, puzph);
- }
-
-
- int PuzzlePieceAt (x, y)
- int x, y;
- {
- int i = toppiece;
-
- while (i != -1) {
- if ((pieces[i].xloc-1 <= x) &&
- (pieces[i].xloc+puzpw >= x) &&
- (pieces[i].yloc-1 <= y) &&
- (pieces[i].yloc+puzph >= y)) return(i);
- i = pieces[i].next;
- }
- return(-1); /* Not on any piece... */
- }
-
-
- RotatePiece (piece)
- int piece;
- {
- if (++(pieces[piece].rotation) > 3) pieces[piece].rotation = 0;
- }
-
-
- GetAndHandleEvents (win)
- struct Window *win;
- {
- struct IntuiMessage *msg;
- int mousemoved, selected;
- ULONG class;
- USHORT code;
- int x, y, lastx, lasty, deltax, deltay, restorex, restorey, selectedpiece;
-
- picwin = win;
- picscr = win->WScreen;
-
- wbm = &(picscr->BitMap);
- wrp = win->RPort;
-
- CopyFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
-
- SetDrMd (wrp, JAM1);
-
- if ((puzpn = GetDifficulty(win)) == 0) Panic (NULL);
-
- SetAPen (wrp, 0L);
- RectFill (wrp, 0L, (long)picy, (long)(win->Width-1), (long)(win->Height-1));
-
- puzph = puzpw = (1 << puzpn);
-
- picxbase = picx - (puzpw >> 1);
- picybase = picy - (puzph >> 1);
-
- pich = (pich >> puzpn) << puzpn;
- picw = (picw >> puzpn) << puzpn;
-
- numx = (picw / puzpw);
- numy = (pich / puzph);
-
- numpieces = numx * numy;
-
- winoffset = picy * wbm->BytesPerRow + (picx >> 3); /* Offset in plane, in bytes */
-
- if (InitBM (&bgbm, puzph, puzpw, puzdepth) == false ||
- InitBM (&rotbm, puzph, puzpw, puzdepth) == false) {
- FreeBMs ();
- Panic ("Out of memory!");
- };
-
- MakePuzzle ();
-
- selectedpiece = -1;
-
- starttime = TimeInSecs ();
-
- while (1) {
-
- mousemoved = false;
-
- while (msg = (struct IntuiMessage *) GetMsg (win->UserPort)) {
-
- class = msg->Class;
- code = msg->Code;
- x = msg->MouseX;
- y = msg->MouseY;
-
- ReplyMsg (msg);
-
- switch (class) {
-
- case MENUPICK:
- switch (ITEMNUM(code)) {
- case 0: /* Show */ break;
- case 1: /* New */ break;
- case 2: /* Quit */
- FreeBMs ();
- return; /* For now, MENUUP signifies EXIT */
- break;
- };
- break;
-
- case MOUSEMOVE:
- mousemoved = true;
- break;
-
- case MOUSEBUTTONS:
- switch (code) {
- case SELECTDOWN:
- lastx = x;
- lasty = y;
- if ((selectedpiece = PuzzlePieceAt (x, y)) != -1) {
- ReportMouse (TRUE, win); /* Start telling us about mouse loc */
- lastx = pieces[selectedpiece].xloc;
- deltax = lastx - x;
- lasty = pieces[selectedpiece].yloc;
- deltay = lasty - y;
- ErasePiece (selectedpiece);
- SavePuzBM (wbm, lastx, lasty, &bgbm); /* Save background */
- DrawPiece (selectedpiece, -1, -1, HLBORDER);
- SavePuzBM (wbm, lastx, lasty, &rotbm); /* Piece picked up */
- mousemoved = true;
- };
- break;
- case SELECTUP:
- if (selectedpiece != -1) {
- ReportMouse (FALSE, win);
- RestorePuzBM (wbm, lastx, lasty, &bgbm);
- PutPieceAtTop (selectedpiece);
- SeeIfInGrid (selectedpiece, x+deltax, y+deltay);
- DrawPiece (selectedpiece, -1, -1,
- (pieces[selectedpiece].ingrid == true ? NOBORDER : BORDER));
- selectedpiece = -1;
- mousemoved = false;
- };
- break;
- case MENUDOWN:
- if (selectedpiece != -1) {
- RotatePiece (selectedpiece);
- DrawPiece (selectedpiece, lastx, lasty, HLBORDER);
- SavePuzBM (wbm, lastx, lasty, &rotbm); /* Piece picked up */
- } else
- switch (PopUp (&pzmenu, win)) {
- case CHECKCMD:
- CheckPuzzle ();
- break;
- case SHOWCMD:
- XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
- XORFromBMToBM (wbm, picx, picy, &picbm, 0, 0, picw, pich);
- XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
- Wait (1L << win->UserPort->mp_SigBit);
- XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
- XORFromBMToBM (wbm, picx, picy, &picbm, 0, 0, picw, pich);
- XORFromBMToBM (&picbm, 0, 0, wbm, picx, picy, picw, pich);
- break;
- case NEWCMD:
- /* SetWindowTitles (picwin, NULL, "Option not available yet");
- ** Wait (1L << picwin->UserPort->mp_SigBit);
- ** SetWindowTitles (picwin, NULL, PROGNAME);
- */ break;
- case HELPCMD:
- if (DoAboutBox (bordercolor, textcolor) == false) {
- SetWindowTitles (picwin, NULL, COPYRIGHT);
- Wait (1L << picwin->UserPort->mp_SigBit);
- SetWindowTitles (picwin, NULL, PROGNAME);
- };
- break;
- case QUITCMD:
- FreeBMs ();
- return;
- break;
- default:
- break;
- };
- break;
- case MENUUP:
- break;
- default:
- break;
- };
- break;
-
- default:
- break;
- }
-
- }
-
- if ((mousemoved == true) && (selectedpiece != -1)) {
- restorex = lastx;
- restorey = lasty;
- lastx = x + deltax;
- lasty = y + deltay;
- if (lastx < minmousex) lastx = minmousex;
- else if (lastx > maxmousex) lastx = maxmousex;
- if (lasty < minmousey) lasty = minmousey;
- else if (lasty > maxmousey) lasty = maxmousey;
- deltax = lastx - x;
- deltay = lasty - y;
- WaitBOVP (&(picscr->ViewPort));
- RestorePuzBM (wbm, restorex, restorey, &bgbm);
- SavePuzBM (wbm, lastx, lasty, &bgbm);
- CopyFromBMToBM (&rotbm, 0, 0, wbm, lastx, lasty, puzpw, puzph);
- Delay (2L);
- };
-
- Wait (1L << win->UserPort->mp_SigBit);
-
- }
-
- }
-
-
- /* Gadgets to get the difficulty from the user...
- */
-
- #define GADWIDTH 120
- #define GADHEIGHT 12
- #define GADX 400
- #define GADY 300
- #define NUMGADS 4
-
- static struct Gadget pzgad[NUMGADS];
-
- static struct Gadget samplegad = {
- NULL, GADX, 0, GADWIDTH, GADHEIGHT,
- GADGHBOX, RELVERIFY, BOOLGADGET, NULL, NULL, NULL, 0L, NULL, 0, NULL};
-
- static char *gadtext[NUMGADS] = {
- "Real easy", "Not so easy", "Difficult", "Quit"};
-
- int GetDifficulty ()
- {
- int cnt;
- struct IntuiMessage *msg;
-
- SetAPen (wrp, (long)nonzerocolor);
-
- Move (wrp, (long)GADX-8, (long)GADY-8);
- Text (wrp, "Select difficulty level:", 24L);
-
- for (cnt = 0; cnt < NUMGADS; cnt++) {
- pzgad[cnt] = samplegad; /* Structure copy */
- pzgad[cnt].TopEdge = GADY+cnt*(GADHEIGHT+2)+(cnt == NUMGADS-1 ? 8 : 0);
- if (cnt != NUMGADS-1) {
- pzgad[cnt].GadgetID = DIFF_EASY - cnt;
- pzgad[cnt].NextGadget = &pzgad[cnt+1];
- };
- Move (wrp, (long)pzgad[cnt].LeftEdge+10, (long)pzgad[cnt].TopEdge+8);
- Text (wrp, gadtext[cnt], (long)strlen(gadtext[cnt]));
- }
-
- AddGList (picwin, pzgad, -1L, -1L, NULL);
- /*RefreshGList (picwin->FirstGadget, picwin, NULL, -1L);*/
-
- cnt = -1;
- while (true) {
- while (msg = (struct IntuiMessage *)GetMsg(picwin->UserPort)) {
- if (msg->Class == GADGETUP && msg->IAddress != NULL)
- cnt = ((struct Gadget *)(msg->IAddress))->GadgetID;
- ReplyMsg (msg);
- if (cnt != -1) {
- RemoveGList (picwin, pzgad, -1L);
- return (cnt);
- }
- }
- Wait (1L << picwin->UserPort->mp_SigBit);
- }
- }
-
-
-
-