
/* SNAKE by Michael Warner January 1993. Public Domain. */

#include <mw/rawkeys.h>

#define XSIZE 40
#define YSIZE 40

#define CLEAR 0
#define SNAKE 3
#define BRICK 1
#define FROG  2

extern APTR IntuitionBase,DOSBase,GfxBase;

struct Window *win;
struct RastPort *rp;
BOOL stretch;

void open_window(void)
{
  struct Screen *scr;

  scr = LockPubScreen(NULL);
  stretch = scr->Height<400;
  UnlockPubScreen(NULL,scr);

  win = OpenWindowTags(NULL,
    WA_Width,stretch?491:251, WA_Height,255,
    WA_IDCMP, CLOSEWINDOW|RAWKEY,
    WA_ScreenTitle,"Snake by Michael Warner 1993 (Public Domain)",
    WA_Flags,ACTIVATE|WINDOWCLOSE|WINDOWDRAG|RMBTRAP|WINDOWDEPTH|SMART_REFRESH|NOCAREREFRESH,
    TAG_DONE);
  if (!win) exit(10);
  rp = win->RPort;
}

void close_window(void)
{
  CloseWindow(win);
}

void notify(char *str)
{
  struct EasyStruct es;

  es.es_StructSize = sizeof(struct EasyStruct);
  es.es_Flags = 0;
  es.es_Title = "Snake Info";
  es.es_TextFormat = str;
  es.es_GadgetFormat = "OK";
  EasyRequestArgs(NULL,&es,NULL,NULL);
}

UBYTE grid[XSIZE][YSIZE];
UBYTE snx[1500],sny[1500],frx[5],fry[5];
int dir,length,head,tail,grow,frogtime[5];
UBYTE key;

void set_point(int x, int y, int item)
{
  grid[x][y]=item;

  SetAPen(rp,item);
  if (stretch) RectFill(rp,5+x*12,12+y*6,5+x*12+11,12+y*6+5);
  else RectFill(rp,5+x*6,12+y*6,5+x*6+5,12+y*6+5);
}

void clear_grid(void)
{
  int x,y;

  for (x=0;x<XSIZE;x++) for (y=0;y<YSIZE;y++)
    if (grid[x][y]) set_point(x,y,CLEAR);
}

void draw_score(void)
{
  static char str[20];

  sprintf(str,"Length: %d",length);
  SetWindowTitles(win,str,(APTR)-1);
}

void pause(void)
{
  struct IntuiMessage *msg;

  FOREVER {
    msg=WaitPort(win->UserPort);
    if (msg->Class==RAWKEY && msg->Code&0x80) 
      ReplyMsg(GetMsg(win->UserPort));
    else return;
  }
}

void create_frog(int n)
{
  int x,y;

  do { x = RangeRand(XSIZE); y = RangeRand(YSIZE); } 
  while (grid[x][y]);
  frx[n]=x; fry[n]=y; 
  set_point(x,y,FROG);
  frogtime[n] = 20 + RangeRand(50);
}

void check_frogs(void)
{
  int n,x,y;

  for (n=0;n<5;n++) {
    if (!frogtime[n]--) {
      x=frx[n]; y=fry[n];
      create_frog(n);
      set_point(x,y,RangeRand(10)?CLEAR:BRICK); 
    }
  }
}

void replace_frog(int x, int y)
{
  int n;

  for (n=0;n<5;n++) {
    if (frx[n]==x && fry[n]==y) create_frog(n);
  }
  set_point(x,y,CLEAR);
}

void setup_game(void)
{
  int i;

  clear_grid();
  length=1; draw_score();
  head=tail=0; snx[0]=XSIZE/2; sny[0]=YSIZE/2;
  set_point(snx[0],sny[0],SNAKE);
  key = KEY_RIGHT;
  for (i=0;i<5;i++) create_frog(i);
  draw_score();
}

BOOL play_one_game(void)
{
  int i,item;
  struct IntuiMessage *msg;
  ULONG class; USHORT code;
  int x,y,nx,ny;

  FOREVER {
    for (i=0;i<6;i++) WaitTOF();
    while (msg=GetMsg(win->UserPort)) {
      class = msg->Class; code = msg->Code;
      ReplyMsg(msg);
      switch (class) {
        case CLOSEWINDOW: return(TRUE);
        case RAWKEY:
          if (!(code&0x80)) switch (code) {
            case KEY_ESC: return(TRUE);
            case KEY_P: pause(); break;
	    case KEY_UP: case KEY_DOWN:case KEY_LEFT: case KEY_RIGHT:           
              key = code;
          }
      }
    }

    x=snx[head]; y=sny[head];
    switch (key) {
      case KEY_UP: nx=x; ny=y-1; break;
      case KEY_DOWN: nx=x; ny=y+1; break;
      case KEY_LEFT: nx=x-1; ny=y; break;
      case KEY_RIGHT: nx=x+1; ny=y; break;
    }
    if (nx<0||ny<0||nx>=XSIZE||ny>=YSIZE) return(FALSE);
    item = grid[nx][ny];
    switch (item) {
      case FROG: grow+=2+RangeRand(10); replace_frog(nx,ny);
      case CLEAR: 
        head = (head+1)%1500; snx[head]=nx; sny[head]=ny; 
        set_point(nx,ny,SNAKE);
        if (grow) { grow--; length++; draw_score(); }
        else {
          set_point(snx[tail],sny[tail],CLEAR); tail = (tail+1)%1500; 
        }
        break;
      case SNAKE: case BRICK: return(FALSE);
    }
    check_frogs();
  }
}       

void play_game(void)
{
  char str[80];

  FOREVER {
    setup_game(); WaitPort(win->UserPort);
    if (play_one_game()) return;
    sprintf(str,"You were %d long",length);
    notify(str);
  }
}

void randomise(void)
{
  extern ULONG __far RangeSeed;
  int clk[2];

  timer(clk); RangeSeed = clk[0]+clk[1];
}

void main(void)
{
  randomise();
  open_window();
  SetTaskPri(FindTask(0),10);
  play_game();
  close_window();
  SetTaskPri(FindTask(0),0);
}


