home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Frozen Fish 1: Amiga
/
FrozenFish-Apr94.iso
/
bbs
/
alib
/
d1xx
/
d122
/
iff2pcs.lha
/
Iff2Pcs
/
Source
/
pzuser.c
< prev
next >
Wrap
C/C++ Source or Header
|
1987-12-31
|
19KB
|
696 lines
#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);
}
}