home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Atari FTP
/
ATARI_FTP_0693.zip
/
ATARI_FTP_0693
/
Games
/
shfflsrc.zoo
/
shuffle.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-03-16
|
15KB
|
535 lines
/*
This is Shuffle, a puzzle game for the Atari ST
Copyright (C) 1991 by Robert Fischer
This program costs no money; you may redistribute it and/or modify it
under the terms of the Lynxware General License as published by Robert
Fischer; either version 1, or (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
Lynxware General License for more details.
You should have received a copy of the Lynxware General License
along with this program; if not, write to the author.
To contact the author, call or write:
Robert Fischer
80 Killdeer Road
Hamden, CT 06517
(203) 288-9599
E-mail: fischer-robert@cs.yale.edu
*/
/* NOTE: Shuffle requires LynxLib to compile */
long _stksize = 4000L;
#define THE_RESOURCE "SHUFFLE.RSC"
#include <stdio.h>
#include <e_osbind.h>
#include <picture.h>
#include <gemdefs.h>
#include <aesbind.h>
#include <vdibind.h>
#include <mygem.h>
#include <nobdefs.h>
#include "shuffle.h"
/* ---------------------------------------------------------------- */
/* Types & constants */
typedef struct {
int hand; /* the VDI handle */
xy size; /* Width and height of device */
} vdi_hand;
/* ---------------------------------------------------------------- */
/* Global Variables */
vdi_hand screen; /* VDI virtual workstation handle */
int intin[128];
int intout[128];
int ptsin[128];
int ptsout[128];
int contrl[12];
/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
/* ---------------------------------------------------------------- */
fix_sizebox() /* Fixes up the size box */
{
OBJECT *d;
int i;
rsrc_gaddr(0, SIZEBOX, &d);
/* Change each thing from one char high to 1 char - 1 pixel */
for (i = ACRO1; i < ACRO64; i++)
d[i].ob_height -= 1;
for (i = DOWN1; i < DOWN50; i++)
d[i].ob_height -= 1;
}
/* ---------------------------------------------------------------- */
BOOLEAN gem_puzsize(pic, x, y) /* Asks the user for the puzzle size */
/* Returns in x & y the number of pieces for that axis */
pic_rec *pic;
int *x, *y;
{
OBJECT *d;
static index_to_across[] = {1, 2, 4, 5, 8, 10, 16, 20, 32, 40, 64, -1};
static index_to_down[] = {1, 2, 4, 5, 8, 10, 20, 25, 40, 50, -1};
register int *i;
int index;
int b; /* Button used to exit */
rsrc_gaddr(0, SIZEBOX, &d);
form_center(d, &b, &b, &b, &b);
/* Set selected thing and clear all others */
for (i = index_to_down, index = DOWN1; *i != -1; i++, index++) {
if (*i == *y) {
d[index].ob_state |= SELECTED;
} else {
d[index].ob_state &= ~SELECTED;
}
}
for (i = index_to_across, index = ACRO1; *i != -1; i++, index++) {
if (*i == *x) {
d[index].ob_state |= SELECTED;
} else {
d[index].ob_state &= ~SELECTED;
}
}
draw_box(d);
do {
b = form_do(d, 0);
d[b].ob_state &= ~SELECTED;
objc_draw(d, b, 1, 0, 0, 0, 0);
/* See if he wanted to see the picture */
if (b == PICLOOK) {
graf_mouse(M_OFF);
switch_pic(pic);
wait_mouse(LEFT_BUTTON);
switch_norm(pic);
graf_mouse(M_ON);
wait_mouse(0);
}
} while (b == PICLOOK);
undraw_box(d);
/* Scan for selected one */
if (b == SBOK) {
for (index = ACRO1; (d[index].ob_state & SELECTED) == 0; index++);
*x = index_to_across[index - ACRO1];
for (index = DOWN1; (d[index].ob_state & SELECTED) == 0; index++);
*y = index_to_down[index - DOWN1];
return TRUE;
}
return FALSE;
}
/* ---------------------------------------------------------------- */
/* End of GEM stuff */
/* ---------------------------------------------------------------- */
static FDB f_screen = {0L, ACRO1 + 0, 0, 0, TRUE, 0, 0, 0, 0}; /* for bit blitting */
blit_block(ioblock, ifdb, ofdb)
xyxyxyxy ioblock;
FDB *ifdb, *ofdb;
{
vro_cpyfm(screen.hand, OPAQUE, &ioblock, ifdb, ofdb);
}
/* ---------------------------------------------------------------- */
find_block(pos, squaresize)
/* Finds the puzzle square that the mouse is in */
register xyxy *pos; /* Mouse position, also output */
xy squaresize; /* Size of each square */
{
pos->x -= (pos->x % squaresize.x);
pos->y -= (pos->y % squaresize.y);
pos->x1 = pos->x + squaresize.x - 1;
pos->y1 = pos->y + squaresize.y - 1;
}
/* ---------------------------------------------------------------- */
wait_mouse(state) /* Awaits for the mouse buttons to enter the desired state */
WORD state;
{
int i, mstate;
if (state == 0)
evnt_button(1, LEFT_BUTTON | RIGHT_BUTTON, 0, &i, &i, &i, &i);
else
evnt_button(1, state, 1, &i, &i, &i, &i);
}
/* ---------------------------------------------------------------- */
graf_waitm(state) /* Same as wait_mouse, only uses graf_mouse */
WORD state;
{
int i, mstate;
do {
graf_mkstate(&i, &i, &mstate, &i);
} while (mstate != state);
}
/* ---------------------------------------------------------------- */
BOOLEAN c_cmpmem(a, b, numlongs)
register LONG *a, *b;
register int numlongs;
{
for (; numlongs > 0; numlongs --) {
if (*a++ != *b++) return FALSE;
}
return TRUE;
}
/* ---------------------------------------------------------------- */
/* Generate a positive random number */
unsigned int rnd(low, high)
/* Generates a number between low & high, including low & excluding high */
unsigned int low, high;
{
return ((unsigned int)Random()) % (high - low) + low;
}
/* ---------------------------------------------------------------- */
#ifdef NODEF
func *old_etv_term;
char *old_screen;
err_handler()
{
SCREENPT = old_screen;
ETV_TERM = old_etv_term;
}
install_err()
{
LONG usp;
usp = Super(0);
old_screen = V_BASE_AD;
old_etv_term = ETV_TERM;
ETV_TERM = &err_handler;
Super(usp);
}
dinstall_err()
{
LONG usp;
usp = Super(0);
ETV_TERM = old_etv_term;
Super(usp);
}
#endif
/* ----------------------------------------------------------- */
int g_getkey() /* Gets a key from GEM AES */
/* Returns -1 if no key is available */
{
int i, key, event;
event = evnt_multi(MU_KEYBD | MU_TIMER,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
&i, 0, 0, &i, &i, &i, &i, &key, &i);
if (event == MU_TIMER) return -1;
return key & 0xFF;
}
/* ---------------------------------------------------------------- */
BOOLEAN puzzle_pic(pic, squaresize) /* Puzzles on a picture */
/* Returns TRUE if you should puzzle this picture again, but with */
/* a different size */
pic_rec *pic; /* Picture to puzzle on */
xy squaresize; /* Size of puzzle squares to use */
{
xyxy ipos, opos; /* Block position */
WORD mstate; /* Mouse button state */
WORD kstate; /* Keyboard shift state */
int c;
pic_rec *messed_pic; /* Picture which will be destroyed */
LONG usp;
char stringg[80];
LONG time;
char s[2];
/* For blitting */
FDB temp_fdb; /* FDB of temporary storage area */
WORD *temp; /* Pointer to temporary storage area */
xy lastxy;
xyxyxyxy pline;
int ystart, yend, xstart, xend, xincr, yincr;
xy opos_offset; /* opos.x - ipos.x, opos.y - ipos.y */
/* Copy the original picture */
messed_pic = malloc(sizeof(pic_rec));
messed_pic->p_start = (char *)(((LONG)(messed_pic->p) + 255) & 0xFFFFFF00L);
memcpy(messed_pic->p_start, pic->p_start, SCR_SIZE);
messed_pic->rez = pic->rez;
for (c = 0; c < 16; c++) messed_pic->pal[c] = pic->pal[c];
graf_mouse(M_OFF); /* Put GEM into new picture */
switch_pic(messed_pic);
/* Set up the temporary blit buffer */
temp_fdb.fd_w = squaresize.x;
temp_fdb.fd_h = squaresize.y;
temp_fdb.fd_wdwidth = (temp_fdb.fd_w + 15) >> 4;
temp_fdb.fd_stand = TRUE;
temp_fdb.fd_nplanes = (1 << (2 - Getrez()));
temp_fdb.fd_r1 = 0;
temp_fdb.fd_r2 = 0;
temp_fdb.fd_r3 = 0;
temp = (WORD *)malloc(temp_fdb.fd_wdwidth * temp_fdb.fd_h
* 2 * temp_fdb.fd_nplanes);
temp_fdb.fd_addr = (LONG)temp;
/* Shuffle the picture */
lastxy.x = squaresize.x - 1;
lastxy.y = squaresize.y - 1;
for (ipos.y = 0; ipos.y < screen.size.y; ipos.y += squaresize.y)
for (ipos.x = 0; ipos.x < screen.size.x; ipos.x += squaresize.x) {
ipos.x1 = ipos.x + lastxy.x;
ipos.y1 = ipos.y + lastxy.y;
opos.x = rnd(0, screen.size.x);
opos.y = rnd(0, screen.size.y);
find_block(&opos, squaresize);
temp_fdb.fd_addr = (LONG)temp;
blit_block(opos, 0,0,lastxy, &f_screen, &temp_fdb);
blit_block(ipos, opos, &f_screen, &f_screen);
blit_block(0,0, lastxy, ipos, &temp_fdb, &f_screen);
}
graf_mouse(M_ON);
/* Read clock */
usp = Super(0);
time = HZ_200; /* Time when user started */
Super(usp);
do {
/* Search for the RETURN key being pressed */
c = g_getkey();
switch(c) {
case '\r' :
case ' ' :
graf_mouse(M_OFF);
switch_norm(messed_pic);
graf_mouse(M_ON);
free(temp);
free(messed_pic);
return (c == ' ');
}
/* Get a mouse button */
graf_mkstate(&ipos.x, &ipos.y, &mstate, &kstate);
if (mstate != 0) { /* Process the button event */
if (mstate & LEFT_BUTTON) { /* User wants to move a block */
if (kstate & (R_SHIFT | L_SHIFT)) {
/* Let the user select a block */
ipos.x -= (ipos.x % squaresize.x);
ipos.y -= (ipos.y % squaresize.y);
graf_rubbox(ipos.x, ipos.y, 0, 0, &ipos.x1, &ipos.y1);
/* Get size of user-selected box */
ipos.x1 += ipos.x + squaresize.x - 1;
ipos.x1 -= ((ipos.x1 % squaresize.x) + 1);
ipos.y1 += ipos.y + squaresize.y - 1;
ipos.y1 -= ((ipos.y1 % squaresize.y) + 1);
graf_waitm(0);
/* Draw a box around area */
pline.x = pline.x3 = ipos.x;
pline.y = pline.y1 = ipos.y;
pline.x1 = pline.x2 = ipos.x1;
pline.y3 = pline.y2 = ipos.y1;
vswr_mode(screen.hand, 3);
vsm_type(screen.hand, 1);
graf_mouse(M_OFF);
v_pline(screen.hand, 4, &pline);
graf_mouse(M_ON);
graf_waitm(LEFT_BUTTON);
/* Undraw the box */
graf_mouse(M_OFF);
v_pline(screen.hand, 4, &pline);
graf_mouse(M_ON);
graf_mkstate(XY_PTR(lastxy), &mstate, &kstate);
/* Quit if user decided to quit */
if (IBETWEEN(lastxy.x, ipos.x, ipos.x1) &&
IBETWEEN(lastxy.y, ipos.y, ipos.y1)) ; else
goto quit_drag;
/* Let user drag it */
graf_dragbox(ipos.x1 - ipos.x, ipos.y1 - ipos.y,
ipos.x, ipos.y, 0, 0, screen.size, XY_PTR(opos));
} else {
find_block(&ipos, squaresize);
graf_dragbox(squaresize, ipos.x, ipos.y, 0,0,screen.size,
&opos.x, &opos.y);
graf_mkstate(&opos.x, &opos.y, &mstate, &kstate);
}
opos.x -= (opos.x % squaresize.x);
opos.y -= (opos.y % squaresize.y);
/* Figure out which order to copy blocks in */
if (ipos.x > opos.x) {
xstart = ipos.x;
xend = xstart + (ipos.x1 - ipos.x) + 1;
xincr = squaresize.x;
} else {
xstart = ipos.x + (ipos.x1 - ipos.x) + 1 - squaresize.x;
xend = ipos.x - squaresize.x;
xincr = -squaresize.x;
}
if (ipos.y > opos.y) {
ystart = ipos.y;
yend = ystart + (ipos.y1 - ipos.y) + 1;
yincr = squaresize.y;
} else {
ystart = ipos.y + (ipos.y1 - ipos.y) + 1 - squaresize.y;
yend = ipos.y - squaresize.y;
yincr = -squaresize.y;
}
/* Blit each piece, one at a time */
graf_mouse(M_OFF);
vs_clip(screen.hand, FALSE, &pline);
lastxy.x = squaresize.x - 1;
lastxy.y = squaresize.y - 1;
opos_offset.x = opos.x - ipos.x;
opos_offset.y = opos.y - ipos.y;
for (ipos.y = ystart; ipos.y != yend; ipos.y += yincr)
for (ipos.x = xstart; ipos.x != xend; ipos.x += xincr) {
temp_fdb.fd_addr = (LONG)temp;
ipos.x1 = ipos.x + lastxy.x;
ipos.y1 = ipos.y + lastxy.y;
opos.x = ipos.x + opos_offset.x;
opos.y = ipos.y + opos_offset.y;
opos.x1 = ipos.x1 + opos_offset.x;
opos.y1 = ipos.y1 + opos_offset.y;
blit_block(ipos, 0,0,lastxy, &f_screen, &temp_fdb);
blit_block(opos, ipos, &f_screen, &f_screen);
blit_block(0,0,lastxy, opos, &temp_fdb, &f_screen);
}
/* Test to see if it's correct */
if (c_cmpmem(pic->p_start, messed_pic->p_start, SCR_SIZE/4)) {
usp = Super(0);
time = HZ_200 - time;
fitoa((int)((time/200)%60), 2, 10, s);
Super(usp);
sprintf(stringg,
"[0][You finished!|Your time was|%d:%s][ Great! ]",
(int)(time/12000), s);
form_alert(1, stringg);
usp = Super(0);
time = HZ_200;
Super(usp);
}
graf_mouse(M_ON);
} else if (mstate & RIGHT_BUTTON) {
graf_mouse(M_OFF);
Setscreen(-1, pic->p_start, -1);
graf_waitm(0);
graf_waitm(RIGHT_BUTTON);
graf_waitm(0);
Setscreen(-1, messed_pic->p_start, -1);
graf_mouse(M_ON);
}
}
quit_drag: ;
} while (TRUE);
}
/* ---------------------------------------------------------------- */
do_puzzler()
{
static xy numsquares = {10, 10}; /* # squares in puzzle */
fle_name path; /* For file selector */
leaf_name name;
fle_name fname; /* Actual pathname selected */
pic_rec *pic;
int i;
BOOLEAN b;
OBJECT *d;
pic = malloc(sizeof(*pic));
get_curdir(path);
strcat(path, "*.*");
name[0] = '\0';
while (TRUE) {
if (fsel_exinput(path, name, &i, "Select file to puzzle on") == 0) break;
if (i == 0) break; /* User pressed Cancel */
strcpy(fname, path);
trim_leaf(fname);
strcat(fname, name);
/* Load the picture */
rsrc_gaddr(0, LOADING, &d);
form_center(d, &i, &i, &i, &i);
draw_box(d);
b = load_pic(pic, fname);
if (b) {
/* Convert to current resolution */
change_res(pic, Getrez());
}
undraw_box(d);
if (b) {
/* Ask squaresize from user & puzzle on it */
while (gem_puzsize(pic,
XY_PTR(numsquares)) &&
puzzle_pic(pic,
screen.size.x/numsquares.x,
screen.size.y/numsquares.y)) ;
} else {
gem_err("Error loading picture!");
}
}
free(pic);
}
/* ---------------------------------------------------------------- */
main()
{
static int work_in[] = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2};
int work_out[60];
int i;
OBJECT *d;
appl_init();
if (rsrc_load(THE_RESOURCE)) {
/* Display introductory dialog box */
rsrc_gaddr(0, TITLE, &d);
form_center(d, &i, &i, &i, &i);
draw_box(d);
form_do(d, 0);
undraw_box(d);
/* Fix up the size box */
fix_sizebox();
screen.hand = graf_handle(&i, &i, &i, &i);
v_opnvwk(work_in, &screen.hand, work_out);
screen.size.x = work_out[0] + 1;
screen.size.y = work_out[1] + 1;
vs_clip(screen.hand, FALSE, work_out);
do_puzzler();
v_clsvwk(screen.hand);
}
appl_exit();
}