delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp-workers/2000/06/07/14:46:23

X-Apparently-From: <amitvikas AT yahoo DOT com>
Message-ID: <393E94DB.2CC9D7F0@yahoo.com>
Date: Thu, 08 Jun 2000 00:00:57 +0530
From: Vikas <amitvikas AT yahoo DOT com>
Organization: programmingParadise.com
X-Mailer: Mozilla 4.7 [en] (Win98; I)
X-Accept-Language: en
MIME-Version: 1.0
To: djgpp-workers AT delorie DOT com
Subject: SNAKE Source code
Reply-To: djgpp-workers AT delorie DOT com

Hiey ! everybody.
    This is my first mail to mailing list. I was reading it
from past 2 weeks only. I have been using DJGPP from past
year but I subscibed to mailing list only 2 weeks before.
So do not mind anything I write :-)

   The mail contains a source file of a simple game.

           ---: SNAKE :---

   This is one of my best programs I have written. I thought when
this file was doing no good execpt taking 30K on my HDD, this
would not matter on other HDD's too. :-)
   You require ZLIB and Allegro to compile it. Snake has
*NO GRAPHICS*. I have only used "key[]" from Allegro. ZLIB was
used to save files like recorded games, ini's etc.
   Now the serious text. *There are bugs* as it is the birthright
of every program. Some (most) of which I am not able to debug.
The following is the most irritating of all:
      --> If you keep on pressing certain key the program says
      "going...   going   goNE!". It goes competly silent
                  "Not responding".
      --> Executing snake.exe sometimes damages the DPMI host
      reagdless of whether it is CWSDPMI or Windows. After
      damage snake.exe does not execute normally and starts
      to do strange things. Even a new DOS box does not solve
      the problem and finnaly you have to shut down win.com
      *I am not sure but this problem occured after compiling
      with " -pg" profiling*.

    While editing in RHIDE I always face problem in TAB's . If you
edit it in "edit.com" it is more easy to indent source file but
it is too hard to do the same in RHIDE. Sometimes tab is 8
spaces and sometimes it is 3 and changes the size if you
change line number of file.

    *I AM READY TO HELP FOR ANY COMPILATION PROBLEMS*

TATA.
Vikas Yadav
http://www.programmingparadise.com/


////////////////////////////////////////////////////////////////
// Snake By Vikas Yadav, Chennai, India
// 05-Mar-2000 Timestamp:050320002334
//
// File: main.cpp
//
// Date Started  : 16-Feb-2000
// Date Completed: 04-Mar-2000 (v1.00)
// Date ReStarted: 15-Apr-2000
//
// Version 1.00
//
//**********************DISCLAIMER*****************************
//  This computer program like all other FREEWARE is
// absolutely out of any kind of warranty. I will not be held
// responsible for the consequenses through the use or misuse
// of this program in any way. You use this in your and solely
// at your own risk.
//*************************************************************
//     You are free to use, modify, distribute it in any way,
// but strictly for personal use on a NOT-FOR-PROFIT basis.
//     This is my second most successfull program after
// FTPServer2. This program is written for DJGPP version 2,
// so you should not have compiler problems. If you are not
// known to this terrific FREE compiler which had compiled
// [id's Quake], jump to http://www.delorie.com/ or get it from
// ftp://ftp.simtel.net/pub/simtelnet/gnu/djgpp/. The editing
// was done using RHIDE, another freeware and a part of DJGPP.
// 150420001340
//     There is a new member. ALLEGRO. This is a
// GAME PROGRAMMING LIBRARY. I have used its "Keyboard" KIT.
// Read on the source to know more! I may use the "Sound"
// also. ALLEGRO is so big that it takes some to know about
// it.
//     Completed version 1 in less that 45Hrs in total,
// I had seen this *stupid* game on my dad's cellular phone.
// This game is far more better in performance and features.
//
// Command line syntax:
// ====================
// snake.exe [/play:<file>|/record:<file>] [/auto|/auto2] [/delay:<N>]
// Eg:
//    snake /record:rc1 /delay:20 /auto
//    snake /play:rc1
//
//
//   /record:<filename>      To record the game as played.
//                           Only possible during Human or
//                           FAP play.
//   /play:<filename>        To play the recorded game.
//                           Only possible during Human or
//                           FAP play.
//   /delay:<Number>         Specify delay time in milliseconds.
//                           More is slow, Less is FAST!
//   /auto2                  Play with FAP and yourself.
//   /auto                   Watch FAP play by itself.
//   /2player                Play with you friend.
//                           Human vs. Human
//
// Here are most of them:
// 1) Choose your speed yourself. Through command line or
//    in-game. The point-per-food changes like wise.
// 2) Choose FAP(Follish Auto Pilot) mode and see computer
//    play. This is a very fine demostration of Artificial
//    Intelligence with *much work yet to be done*.
// 3) Save and load games in-game.
// 4) Record and Play the entire game. Possible only through
//    command line. Currently no in-game alternative.
// 5) Pause and Resume play.
// 6) Keep track of Highscores.
// 7) Save diskspace. Except scores.dat (highscore file) all
//    other generated files i.e. Recorded game and Saved game
//    files use in-build GZIP compression. Easiest compression
//    for standalone apps with compression equal or more
//    that existing ZIP format.
// 8) Constantly updated game statistics during game play.
// 9) Completly CUI based game. No graphics used. Actually
//    I did not find is nessasary at all. In CUI itself I
//    tried to create a collourfull scene.
// 10)Stack allocation prefered except class String, so no
//    runtime memory hazard.
// 11)Single file game. No other source file. Requires
//    ZLIBrary which is included.
// 16-Mar-2000:-
// 12)INI file supported. Reads settings from
//    INI file is found, else starts using the default
//    settings.
// 13)Play with FAP i.e. Computer vs. Human. This is
//    the most important feature. I could not add
//    Human vs. Human because I could find better
//    keyboard routines. Using keyboard port access?
//
// Author:
//
//    =======================================
//    = Vikas Yadav                         =
//    = Flat B-1, Ashok Kirthi,             =
//    = 152, L. B. Road,                    =
//    = Chennai 600041                      =
//    = INDIA                               =
//    = vkas AT programmingparadise DOT com        =
//    = http://www.programmingparadise.com/ =
//    =======================================
//
////////////////////////////////////////////////////////////////

// Command line parser
#include "command.h"

#include <bios.h>
#include <math.h>
#include "sys/nearptr.h"
#include <keys.h>

// The compression library.
#include <zlib.h>

//
// 150420001325
// Yippee! Say hello to
//          ---------------
//          + * ALLEGRO * +
//          ---------------
// I just found what I was desperatly waiting for.
// Guess what? Keyboard.
// ALLEGRO will give me a keyboard access that
// <conio.h> or <bios.h> cannot!
// I will tell you. Sit back.
// When you are using keyboard routines from
// <bios.h> or <conio.h> you get limited keyboard
// access. They use keyboard buffer which does not
// store current keyboard status but instead buffer
// it. So you cannot get events like
// (WM_KEYDOWN || WM_KEYUP). You only get WM_KEYPRESS.
// This was the problem which was kepping me from
// writing [Human vs. Human] version of SNAKE. I
// could only get one keypress at a time which is not
// the case when two humans are playing on the same
// keybpoard. Humans like me and my friend will bang
// the keyboard using hand, head and legs.
// All at ONCE! You CANNOT TRAP ALL THE KEYS JUST BY
// USING BIOS. In ALLEGRO you can. I will not be
// using any, not even one keyboard function to read
// it. just access a special keyaboard array which
// gets updated as-and-when the key is presses and
// unpressed. Isn't it GREAT!.
//
#include <allegro.h>

// Super-fast mem access
//  defines K_Up

/*
 * Stores the position of the the entire snake
 * -1,-1 if not valid i.e. snake is'nt that lengthy
 * snake[0] - Head
 * snake[length-1] - Tail.
 */
struct pos {
 unsigned char x,y;
} snake1[500], snake2[500];
pos* snake;
int *total;

struct Settings
{
char foodchar,
     foodcolor,
     borderchar,
     bordercolor,
     stailchar,
     sheadchar,
     ftailchar,
     fheadchar,
     sheadcolor,
     stailcolor,
     ftailcolor,
     fheadcolor;

} current;

/*
 * The struct save the game on the disk.
 * If stores uncompresses will consume
 * above 4K. This is also why I used zlib.
 */
struct savegame
{
  pos snake[500];
  int waittime,
      length,
      points,
      total;
  char file[13];
  unsigned char mt,
  fx,
  fy,
  max_x,
  max_y,
  min_x,
  min_y,
  record,
  play,
  auto1,
  pause;/* Rubbish field. */
  Settings st;
} sg;

/* You should understand that */
unsigned char min_x=1,
    min_y=2,
    max_x=79,
    max_y=48,
    hit;
/* Snake length */
unsigned char exit1=0;

// Used by FAP
int tried=0;

int gp1,gp2;

gzFile recording=NULL;
gzFile playing=NULL;

char file[13];
/* delay(waittime) */
int waittime=50;
int auto1=0;
int errors=0;
unsigned char up=1;
unsigned char right=3;
unsigned char down=2;
unsigned char active=0,
              player2=0;
int food1=0,food2=0;
int *food;
unsigned char left=4;
int points;
int highscore;
int total1,total2;
int length1,length2;
int *length;
/* move direction */
unsigned char mt1=3;
unsigned char mt2=3;
unsigned char* mt;
unsigned char pause=0;

/* Settings with defaults */
char foodchar='@',
     borderchar='$',
     stailchar='#',
     sheadchar='O',
     ftailchar='#',
     fheadchar='O',
     sheadcolor=7,
     stailcolor=7,
     ftailcolor=7,
     fheadcolor=7,
     foodcolor=7,
     bordercolor=7;



/*
 * Future version will have compatiblity
 * for many compilers including TC.
 * Currenlty CANNOT be compiled with TC/VC/??.
 *
 * #ifdef __DJGPP__
 * # include "djfast.h"
 * #else
 * # include "fast.h"
 * #endif
 */

void dropfood(char def=' ');
char getxy(int,int);

/*
 * What is Super-Fast mem access
 * TODO: This and getxy() is somewhat buggy in
 * calculation.
 */
int putxy(int x,int y,char val,char attr=7)
{
 char *target;
 __djgpp_nearptr_enable();
 int scr = (int)(__djgpp_conventional_base + 0xb8000);
 target = (char*)scr + (y * 80 * 2) + (x * 2);
 *target = val;
 *(target+1) = attr;
 __djgpp_nearptr_disable();
}
/*
 * Rather storing wht entire screen in vars I used
 * simpler trick. The snake should actually SEE the screen
 * and decide whether it is hit or not!
 */
__inline char getxy(int x,int y)
{
 unsigned char rt;
 unsigned char *target;
 __djgpp_nearptr_enable();
 int scr = (int)(__djgpp_conventional_base + 0xb8000);
 target = (unsigned char*)scr + (y * 80 * 2) + (x * 2);
 rt=(char)*target;
 __djgpp_nearptr_disable();
 return rt;
}
/* Relax! */
__inline void putsxy(int x1,int y1,char* buf,char attr=7)
{
 int i=0;
 int x=x1;
 int y=y1;
 while(buf[i])
  putxy(x++,y,buf[i++],attr);
}

/* Yahoo! I just won. */
int Yahoo()
{
 clrscr();
 printf("******************************\n"
        "     H I G H   S C O R E      \n"
        "******************************\n"
        "            %8.8lu            \n"
        "==============================\n",(*total));
}
/* Only if hungry. */
void eatfood()
{
 (*length)++;
 (*total)+=points;
 dropfood();
}
/* Tried a Quake-like ending. */
int rndmsg()
{
 char bufmsg[][50]={ "Opps! You bit your tongue.",
                "Watch out pal! That was my head.",
                "I was blind. You killed me?",
                "Damm! Don't be so hungry.",
                "Ouch! This isn't a game any more.",
                "I hate amateures and you know that.",
                "May his soul rest in peace.",
                "Slipped?...    ...Dead.",
                "I am blind. You are blind.",
                "This isn't funny. You just cracked my skull.",
                "Your head or a bowl. What's the difference?",
                "Empty head in a foolish workshop." };
 char buf[256];
 int ln=random() % 12;
 printf("%s",bufmsg[ln]);
}
/*
 * This is called to exit the app from anywhere and
 * at anytime.
 */
int ExitApp(unsigned char force=0)
{
 clrscr();
 if( (*total) > highscore)
 {
 /*
  * There is a very strong reson that I did not use
  * compression on high score file(scores.dat).
  * Currently scores.dat is 4 bytes only. The gzip
  * header itself 12 bytes. Ho Ho.
  */
  FILE* fp=fopen("scores.dat","wb+");
  fwrite(total,sizeof(int),1,fp);
  fclose(fp);
  Yahoo();
  _setcursortype(_NORMALCURSOR);
  goto ex;
 }
 exit1=1;
 if(!auto1 || !force)
  goto ex;
 return 0;
ex:
 if(recording)
  gzclose(recording);
 if(playing)
  gzclose(playing);
  _setcursortype(_NORMALCURSOR);
 if(hit)
   rndmsg();
 gzFile* st;
 st=(gzFile*)gzopen("snake.ini","wb");
 if(!st)
   goto st2;
 gzwrite(st,&current,sizeof(current));
 gzclose(st);
st2:
 exit(0);
}
/* Nothing could be simpler than this.  */
int drawsnake()
{
 if(hit)
 {
  if(!active && !player2)
    ExitApp();
  return 0;
 }
 if(active || player2)
 {
  putxy(snake1[0].x,snake1[0].y,sheadchar,sheadcolor);
  for(int i=1; i< length1; i++)
  {
    putxy(snake1[i].x,snake1[i].y,stailchar,stailcolor);
  }
  putxy(snake2[0].x,snake2[0].y,fheadchar,fheadcolor);
  for(int i=1; i<length2; i++)
  {
   putxy(snake2[i].x,snake2[i].y,ftailchar,ftailcolor);
  }
  goto ex;
 }
 putxy(snake[0].x,snake[0].y,sheadchar,sheadcolor);
 for(int i=1; i< (*length); i++)
 {
  putxy(snake[i].x,snake[i].y,stailchar);
 }
ex:;
}
/*  Inaugarate the game. */
int drawdefsnake(int sn=0)
{
 int x1,y1;
 x1=40;
 y1=12;
 if(sn == 1)
  goto ds1;
 else if(sn ==2)
  goto ds2;
 if(active || player2)
 {
ds1:
  for(int i=0; i< length1; i++)
  {
   if(getxy(x1,y1) != foodchar)
   {
    snake1[i].x = x1;
    snake1[i].y = y1;
    x1--;
   }
   else
   {
    y1--;
    snake1[i].x = x1;
    snake1[i].y = y1;
    continue;
   }
  }
  if(sn)
   goto ex;
ds2:
  y1++;
  x1=40;
  for(int i=0; i< length2; i++)
  {
   if(getxy(x1,y1) != foodchar)
   {
    snake2[i].x = x1;
    snake2[i].y = y1;
    x1--;
   }
   else
   {
    y1--;
    snake1[i].x = x1;
    snake1[i].y = y1;
    continue;
   }
  }
  goto ex;
 }
 for(int i=0; i< (*length); i++)
 {
  snake[i].x = x1--;
  snake[i].y = y1;
 }
ex:
 drawsnake();
}
///////////////////////////////////////////
// Move tactics.
//
int moveright(int try1=0)
{
 if(pause)
  return 0;
 static int excuse=1;
 int i;
 if(!auto1)
  goto lp1;
 if( (snake[0].x + 1) == snake[1].x &&
      snake[0].y == snake[1].y       )
 {
  hit=1;
  return 0;
 }
lp1:
 if( (snake[0].x + 1) == max_x)
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
 if( getxy(snake[0].x+1,snake[0].y) == stailchar )
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
 if( getxy((snake[0].x + 1),snake[0].y) == foodchar && !try1)
  eatfood();
 if(try1)
  return 1;
 putxy(snake[ (*length)-1].x,
       snake[ (*length)-1].y,
       ' ');
 for(i=( (*length)-1); i>0; i--)
 {
  snake[i].x = snake[i-1].x;
  snake[i].y = snake[i-1].y;
 }
 snake[0].x++;
 *mt=right;
}
int moveleft(int try1=0)
{
 if(pause)
  return 0;
 static int excuse=1;
 int i;
 if(!auto1)
  goto lp1;
 if( (snake[0].x - 1) == snake[1].x &&
      snake[0].y == snake[1].y       )
 {
  hit=1;
  return 0;
 }
lp1:
 if( (snake[0].x - 1) < min_x)
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
 if( getxy(snake[0].x-1,snake[0].y) == stailchar )
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
 if( getxy((snake[0].x - 1),snake[0].y) == foodchar && !try1)
  eatfood();
 if(try1)
  return 1;
 putxy(snake[ (*length)-1].x,
       snake[(*length)-1].y,
       ' ');
 for(i=( (*length)-1); i>0; i--)
 {
  snake[i].x = snake[i-1].x;
  snake[i].y = snake[i-1].y;
 }
 snake[0].x--;
 *mt=left;
}
int movedown(int try1=0)
{
 if(pause)
  return 0;
 static int excuse=1;
 int i;
 if(!auto1)
  goto lp1;
 if( (snake[0].y + 1) == snake[1].y &&
      snake[0].x == snake[1].x       )
 {
  hit=1;
  return 0;
 }
lp1:
 if( (snake[0].y + 1) == max_y)
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
 if( getxy(snake[0].x,snake[0].y+1) == stailchar )
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
 if(getxy(snake[0].x,snake[0].y + 1) == foodchar && !try1)
  eatfood();
 if(try1)
  return 1;
 putxy(snake[ (*length)-1].x,
       snake[(*length)-1].y,
       ' ');
 for(i=((*length)-1); i>0; i--)
 {
  snake[i].x = snake[i-1].x;
  snake[i].y = snake[i-1].y;
 }
 snake[0].y++;
 *mt=down;
}
int moveup(int try1=0)
{
 if(pause)
  return 0;
 int i;
 static int excuse=1;
 if(!auto1)
  goto lp1;
 if( (snake[0].y - 1) == snake[1].y &&
      snake[0].x == snake[1].x       )
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
lp1:
 if( (snake[0].y - 1) < min_y)
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
 if( getxy(snake[0].x,snake[0].y-1) == stailchar )
 {
  if(!excuse--)
  {
   hit=1;
   excuse=1;
  }
  return 0;
 }
 if(getxy(snake[0].x,snake[0].y - 1) == foodchar && !try1)
  eatfood();
 if(try1)
  return 1;
 putxy(snake[(*length)-1].x,
       snake[(*length)-1].y,
       ' ');
 for(i=((*length)-1); i>0; i--)
 {
  snake[i].x = snake[i-1].x;
  snake[i].y = snake[i-1].y;
 }
 snake[0].y--;
 *mt=up;
 }
///////////////////////////////////////////
// called when snake is ideal.
// Keyboard buf is empty,.
int movesnake()
{
 if(pause)
  return 0;
 switch(*mt)
 {
  case 1:
   moveup();
   break;
  case 2:
   movedown();
   break;
  case 3:
   moveright();
   break;
  case 4:
   moveleft();
   break;
 }
 drawsnake();
}
/* Dinner is rEADy .... */
void dropfood(char fd)
{
 int x,y;
st2:
 if(playing)
 {
  if(fd != foodchar)
   gzread(playing,&fd,sizeof(fd));
  if(fd != foodchar)
   return;
  int l=sizeof(x);
  gzread(playing,&x,sizeof(x));
  gzread(playing,&y,sizeof(y));
  goto st4;
 }
 x=random() % max_x;
 y=random() % max_y;
 if(x <= min_x)
  x = min_x;
 else if(x >= max_x)
  x = max_x - 1;
 if(y <= min_y)
  y = min_y;
 else if(y >= max_y)
  y = max_y;
 if(getxy(x,y) != ' ')
 {
  errors++;
  goto st2;
 }
st4:
 gotoxy(x+1,y+1);
 textattr(16);
 putxy(x,y,foodchar,foodcolor);
 textattr(7);
 (*food)++;
 sg.fx=x;
 sg.fy=y;
 char buf[100];
 if(!active || player2)
 {
  sprintf(buf," %6.6lu %6.6lu %2.2lu%%",*total,highscore,( (*total)
*100)/highscore);
  putsxy(0,0,buf);
 }
 else
 {
  int mx=max_x+1;
  putsxy(mx, 0, "-PLAYER 1-");
          // 1          8
  putsxy(mx, 2, "Games :   ");
  putsxy(mx, 3, "Played:   ");
          // 4     3
  putsxy(mx, 5, "TotalScore");
  putsxy(mx, 6, "          ");
          // 7     3
  putsxy(mx, 8, "Food Count");
  putsxy(mx, 9, "          ");
          //10          8
  putsxy(mx,11, "Length:   ");
          //12

  putsxy(mx,20, "-PLAYER 2-");
          //21          8
  putsxy(mx,22, "Games :   ");
  putsxy(mx,23, "Played:   ");
          //24     3
  putsxy(mx,25, "TotalScore");
  putsxy(mx,26, "          ");
          //27     3
  putsxy(mx,28, "Food Count");
  putsxy(mx,29, "          ");
          //30          8
  putsxy(mx,31, "Length:   ");
          //32

  sprintf(buf,"%lu",gp1);
  putsxy(mx+8,3,buf);
  sprintf(buf,"%lu",gp2);
  putsxy(mx+8,23,buf);

  sprintf(buf,"%lu",total1);
  putsxy(mx+3,6,buf);
  sprintf(buf,"%lu",total2);
  putsxy(mx+3,26,buf);

  sprintf(buf,"%lu",length1);
  putsxy(mx+8,11,buf);
  sprintf(buf,"%lu",length2);
  putsxy(mx+8,31,buf);

  sprintf(buf,"%lu",food1);
  putsxy(mx+3,9,buf);
  sprintf(buf,"%lu",food2);
  putsxy(mx+3,29,buf);

 }
 if(recording)
 {
  /************* RECORDING AND PLAYING ***************
   * We need to record the food location.
   * The record file is completly DUMB.
   * There is no header/footer info in it.
   * Data is stored as recived. Key pressed is recorded
   * likewise. To identify food in this jungle a foodchar
   * is placed before food details. The loop checks this
   * only when there is a hit and we need new food to be
   * dropped. In djgpp sizeof(int) == 4. So an average
   * size of 1 minute uncomressed game recorded would be
   * more than 10K. After compression is is not even
   * more than 2K.
   * No key pressed == nothing recorded.
   */
  fd=foodchar;
  gzwrite(recording,&fd,sizeof(fd));
  gzwrite(recording,&x,sizeof(x));
  gzwrite(recording,&y,sizeof(y));
 }
}
void drawborder()
{
 int ix = min_x - 1;
 int iy = min_y - 1;
 //Top row
 for(; ix<=max_x; ix++)
  putxy(ix,iy,borderchar,bordercolor)  ;
 ix = min_x - 1;
 iy = max_y;
 //Bottom
 for(; ix<max_x; ix++)
  putxy(ix,iy,borderchar,bordercolor);
 if(recording)
 {

   gotoxy(max_x-12,max_y);
   textattr(140);
   cprintf("\n *");
   textattr(143);
   cprintf(" Recording ");
   textattr(7);
 }
 if(playing)
 {

   gotoxy(max_x-12,max_y);
   textattr(140);
   cprintf("\n >>");
   textattr(143);
   cprintf(" Playing ");
   textattr(7);
 }
 ix = min_x - 1;
 iy = min_y - 1;
 //left row
 for(; iy<=max_y; iy++)
  putxy(ix,iy,borderchar,116);
 ix = max_x;
 iy = min_y - 1;
 //right row
 for(; iy<=max_y; iy++)
  putxy(ix,iy,borderchar,116);
}
void loadgame()
{
 if(active || auto1)
  return;
 gzFile fp=gzopen("game.sav","rb");
 int l=sizeof(sg);
 gzread(fp,&sg,l);
 gzclose(fp);
 fheadchar = sg.st.fheadchar;
 fheadcolor = sg.st.fheadcolor;
 ftailchar = sg.st.ftailchar;
 ftailcolor= sg.st.ftailcolor;
 sheadchar = sg.st.sheadchar;
 sheadcolor = sg.st.sheadcolor;
 stailchar = sg.st.stailchar;
 stailcolor = sg.st.stailcolor;
 borderchar = sg.st.borderchar;
 bordercolor = sg.st.bordercolor;
 foodchar = sg.st.foodchar;
 foodcolor = sg.st.foodcolor;
 memcpy(&snake,&sg.snake,500 * 8);
 points=sg.points;
 *total=sg.total;
 max_x=sg.max_x;
 auto1 = sg.auto1;
 min_x=sg.min_x;
 max_y=sg.max_y;
 strcpy(file,sg.file);
 min_y=sg.min_y;
 waittime=sg.waittime;
 pause=sg.pause;
 mt1=sg.mt;
 length1=sg.length;
 if(sg.play)
  {
   if(!(playing=gzopen(file,"rb")))
   {
     printf("snake.exe: Could not open file for playing.");
     ExitApp();
   }
  }
 else if(sg.record)
  {
   if(!(recording=gzopen(file,"wb")))
   {
     printf("snake.exe: Could not open file recording.");
     ExitApp();
   }
  }
}
void savegame()
{
 if(active || auto1)
  return;
 memcpy(&sg.snake,&snake,500 * 8);
 sg.points=points;
 sg.total=total1;
 sg.max_x=max_x;
 sg.auto1 = auto1;
 sg.min_x=min_x;
 sg.max_y=max_y;
 sg.min_y=min_y;
 sg.waittime=waittime;
 sg.mt=mt1;
 strcpy(sg.file,file);
 sg.pause=pause;
 sg.play = (int)playing;
 sg.record= (int) recording;
 sg.length=length1;
 sg.st.fheadchar = fheadchar;
 sg.st.fheadcolor = fheadcolor;
 sg.st.ftailchar = ftailchar;
 sg.st.ftailcolor = ftailcolor;
 sg.st.sheadchar = sheadchar;
 sg.st.sheadcolor = sheadcolor;
 sg.st.stailchar = stailchar;
 sg.st.stailcolor = stailcolor;
 sg.st.borderchar = borderchar;
 sg.st.bordercolor = bordercolor;
 sg.st.foodchar = foodchar;
 sg.st.foodcolor = foodcolor;
 gzFile fp=gzopen("game.sav","wb");
 if(!fp)
  return;
 gzwrite(fp,&sg,sizeof(sg));
 gzclose(fp);
}
int getbestkey()
{
 if(sg.fx < snake[0].x)
 { //@#
  if(!moveleft(1))
  {
   if( sg.fy < snake[0].y )
   {//@
    // #
    if(!moveup(1))
    {
     if(!moveright(1))
     {
                    if(!movedown(1))
      {
       return 'p';
      }
      return K_Down;
     }
     else
      return K_Right;
    }
    else
     return K_Up;
   }
   else if( sg.fy > snake[0].y )
   {// #
    //@
    if(!movedown(1))
    {
     if(!moveright(1))
     {
      if(!moveup(1))
      {
       return 'p';
      }
      return K_Up;
     }
     else
      return K_Right;
    }
    else
     return K_Down;
   }
   else
   {//@#
    if(!movedown(1))
    {
     if(!moveleft(1))
     {
      if(!moveup(1))
      {
       return 'p';
      }
      return K_Up;
     }
     else
      return K_Left;
    }
    else
     return K_Down;
   }

  }
  else
   return K_Left;

 }
 else if(sg.fx > snake[0].x)
 {// # @
  if(!moveright(1))
  {
   if( sg.fy < snake[0].y )
   {// @
    //#
    if(!moveup(1))
    {
                    if(!movedown(1))
     {
                        if(!moveleft(1))
      {
       return 'p';
      }
                        return K_Left;
     }
     else
                        return K_Down;
    }
    else
     return K_Up;
   }
   else if( sg.fy > snake[0].y )
   {//#
    // @
    if(!movedown(1))
    {
     if(!moveleft(1))
     {
      if(!moveup(1))
      {
       return 'p';
      }
      return K_Up;
     }
     else
      return K_Left;
    }
    else
     return K_Down;
   }
   else
   {//#@
                if(!moveup(1))
    {
                    if(!movedown(1))
     {
                        if(!moveleft(1))
      {
       return 'p';
      }
                        return K_Left;
     }
     else
                        return K_Down;
    }
    else
                    return K_Up;
   }
  }
  else
   return K_Right;
 }
 else
 {//@
         //#
  //@
  if( sg.fy < snake[0].y )
  {//@
          //#
   if(!moveup(1))
   {
                if(!movedown(1))
    {
                    if(!moveleft(1))
     {
                        if(!moveright(1))
       return 'p';
      else
                            return K_Right;
     }
     else
                        return K_Left;
    }
    else
                    return K_Down;
   }
   else
    return K_Up;
  }
  else if( sg.fy > snake[0].y )
  {//#
          //@

   if(!movedown(1))
   {
    if(!moveleft(1))
    {
     if(!moveright(1))
     {
                        return 'p';
                    }
     else
      return K_Right;
    }
    else
     return K_Left;
   }
   else
    return K_Down;
  }
 }
}
void ToggleSnake(unsigned char force=0)
{
 if(player2)
  goto ts2;
 if(force)
    active=2 - ( (force + 1) % 2);
 if(active == 1)
 {
  snake=(pos*)&snake2;
  total=&total2;
  length=&length2;
  mt=&mt2;
  active=2;
  auto1=1;
  food=&food2;
 }
 else if(active == 2)
 {
  snake=(pos*)&snake1;
  total=&total1;
  length=&length1;
  mt=&mt1;
  active=1;
  auto1=0;
  food=&food1;
 }
 goto ex;
ts2:
 if(force)
    player2 = 2 - ( (force + 1) % 2);
 if(player2 == 1)
 {
  snake=(pos*)&snake2;
  total=&total2;
  length=&length2;
  mt=&mt2;
  player2=2;
  food=&food2;
 }
 else if(player2 == 2)
 {
  snake=(pos*)&snake1;
  total=&total1;
  length=&length1;
  mt=&mt1;
  player2=1;
  food=&food1;
 }
ex:;
}

void resetsnake(int sn)
{
 int i;
 hit=0;
 if(sn==1)
 {
  gp1++;
  for(i=0; i<length1; i++)
   putxy(snake1[i].x,snake1[i].y,' ');
  length1=30;
  drawdefsnake(1);
  mt1=up;
 }
 else if(sn==2)
 {
  gp2++;
  for(i=0; i<length2; i++)
   putxy(snake2[i].x,snake2[i].y,' ');
  length2=30;
  drawdefsnake(2);
  mt2=up;
 }

}
void RunSetup();
void Do2Player()
{
  food1 = food2 = total1 = total2 = active = auto1 = 0;
  length1 = length2 = 30;
  allegro_init();
  install_keyboard();
  player2 = 1;
  srandom( time(NULL) );
  max_x -= 10;
  min_y = 1;
  min_x = 1;
  for (int i=0; i<500; i++)
   snake1[i].x = snake[i].y = -1;
  for (int i=0; i<500; i++)
   snake2[i].x = snake[i].y = -1;
  clrscr();
  points = 1000 - waittime;
  drawborder();
  drawdefsnake();
  dropfood();
  textattr(7);
  snake = (pos*)snake1;
rr:
  if(key[KEY_A])
   moveleft();
  else if(key[KEY_W])
   moveup();
  else if(key[KEY_D])
   moveright();
  else if(key[KEY_Z])
   movedown();
  else
   movesnake();
  if(hit)
   resetsnake(1);
  ToggleSnake();
  if(key[KEY_LEFT])
   moveleft();
  else if(key[KEY_UP])
   moveup();
  else if(key[KEY_RIGHT])
   moveright();
  else if(key[KEY_DOWN])
   movedown();
  else
   movesnake();
  if(hit)
   resetsnake(2);
  ToggleSnake();
  if(key[KEY_MINUS] || key[KEY_MINUS_PAD])
  {
      waittime+=20;
      points = 1000 - waittime;
  }
  else if(key[KEY_PLUS_PAD] || key[KEY_EQUALS])
  {
      waittime-=20;
      points = 1000 - waittime;
  }
  else if(key['q'] || key[KEY_ESC])
      ExitApp(1);
  delay(waittime);
  goto rr;

}

int main(int argc, char* argv[])
{
  unsigned char ck=0;
  int ky;
  int moves=0;
  char buf[100];
  Command c(argc,argv);
  gzFile* st;
  st=(gzFile*)gzopen("snake.ini","rb");
  if(!st)
  {
   current.fheadchar = fheadchar;
   current.fheadcolor = fheadcolor;
   current.ftailchar = ftailchar;
   current.ftailcolor = ftailcolor;
   current.sheadchar = sheadchar;
   current.sheadcolor = sheadcolor;
   current.stailchar = stailchar;
   current.stailcolor = stailcolor;
   current.borderchar = borderchar;
   current.bordercolor = bordercolor;
   current.foodchar = foodchar;
   current.foodcolor = foodcolor;
   goto st2;
  }
  gzread(st,&current,sizeof(current));
  gzclose(st);
st2:
  if(c.IsGiven("setup"))
  {
   RunSetup();
  };
  tried=0;
  food=&food1;
  total=&total1;
  length=&length1;
  gp1=1;
  gp2=1;
  int px=(max_x - min_x)/2 + min_x - 8;
  FILE*fp=fopen("scores.dat","rb+");
  if(!fp)
  {
   highscore=1;
   goto lp0;
  }
  fread(&highscore,sizeof(int),1,fp);
  fclose(fp);
  textmode(C4350);
  snake=(pos*)&snake1;
  mt=&mt1;
lp0:
  _setcursortype(_NOCURSOR);
  exit1=0;
  if(!auto1)
  {
    *food=0;
    errors=0;
  }
  pause=0;
  *total=0;
  *length=30;
  waittime=c.GetNumber("delay",100);
  if(c.IsGiven("2player"))
  {
   Do2Player();
   ExitApp();
  }
  if(!(active=c.IsGiven("auto2")))
       auto1=c.IsGiven("auto");
  else
  {
   length1 = length2 = 30;
   max_x -= 10;
   min_y = 1;
   min_x = 1;
   goto skip_rp;
  }
  if(c.IsGiven("play"))
  {
   strcpy(file,c.GetString("play",buf));
   if(!(playing=gzopen(file,"rb")))
   {
    printf("%s: Could not open file for playing.",argv[0]);
    ExitApp();
   }
  }
  else if(c.IsGiven("record"))
  {
   strcpy(file,c.GetString("record",buf));
   if(!(recording=gzopen(file,"wb")))
   {
    printf("%s: Could not open file recording.",argv[0]);
    ExitApp();
   }
  }
skip_rp:
  srandom( time(NULL) );
  for (int i=0; i<500; i++)
   snake1[i].x = snake[i].y = -1;
  for (int i=0; i<500; i++)
   snake2[i].x = snake[i].y = -1;
  drawdefsnake();
  dropfood();
lp01:
  clrscr();
  points = 1000 - waittime;
  textattr(7);
  drawborder();
  putxy(sg.fx,sg.fy,foodchar);
  if(!active)
  {
   sprintf(buf," %3.3lu %3.3lu %5.5lu %1.1lu%%
",++tried,errors,*food,(errors*100)/ *food);
   putsxy(30,0,buf);
  }
lp1:
  if(exit1 && auto1)
  {
        ExitApp();
        goto lp0;
  }
  while( !(ky=kbhit()) && !pause && !auto1)
  {
    delay(waittime);
    if(playing)
    {
     gzread(playing,&ky,sizeof(ky));
     if((char)ky == 'F')
     {
      gzread(playing,&mt,sizeof(mt));
      movesnake();
      continue;
     }
     else if((char)ky == foodchar)
     {
      gzseek(playing,-4,SEEK_CUR);
      dropfood();
      continue;
     }
     else
      goto dm;
    }
    if(recording)
    {
     ky='F';
     gzwrite(recording,&ky,sizeof(ky));
     gzwrite(recording,&mt,sizeof(mt));
    }
    movesnake();
    if(hit)
      resetsnake(1);
    if(active)
     ToggleSnake();

  }
  if(!active)
   goto na;
  if(ky && pause)
   goto gk;
  if(ky && ck<=1)
  {
   ck++;
   ToggleSnake(1);
  }
  if(ck>1)
  {
   getkey();
   ToggleSnake(2);
  }
na:
  if(auto1)
  {
   if(pause && !active)
   {
     ExitApp();
     goto lp0;
   }
   drawsnake();
do2:
   if(!active)
   {
    if(!kbhit())
     ky=getbestkey();
    else
     goto gk;
   }
   else
    ky=getbestkey();
   if(ky == 'p')
   {
    resetsnake(2);
    goto do2;
   }
   ck=0;
   hit=0;

  }
  else if(playing)
  {
   drawsnake();
   gzread(playing,&ky,sizeof(ky));
   if(ky == foodchar)
     ExitApp();
  }
  else if(!pause)
  {
gk:
   while(bioskey(1))
    ky=getkey();
  }
dm:
  if(!active)
  {
   sprintf(buf," %2.2lu %2.2lu ",++moves,*length);
   putsxy(22,0,buf);
  }

  if(recording)
   gzwrite(recording,&ky,sizeof(ky));

  switch(ky)
  {
    case K_Up:
      moveup();
      break;
    case K_Down:
      movedown();
      break;
    case K_Right:
      moveright();
      break;
    case K_Left:
      moveleft();
      break;
    case 'p':
    case 'P':
      if(pause = !pause)
      {
       gotoxy(max_x-12,max_y);
       textattr(140);
       cprintf("\n ||");
       textattr(143);
       cprintf(" Paused ");
       textattr(7);
      }
      else
      {
nopause:
       drawborder();
      }
       break;
    case 'l':
    case 'L':
      loadgame();
      goto lp01;
      break;
    case 's':
    case 'S':
      savegame();
      break;
    case K_Plus:
      waittime-=20;
      points = 1000 - waittime;
      break;
    case K_Dash:
      waittime+=20;
      points = 1000 - waittime;
      break;
    case 'a':
    case 'A':
      auto1=!auto1;
      break;
    case 'q':
    case 'Q':
      ExitApp(1);
      break;
  }
  ky=0;
  if(active != 2)
    delay(waittime);
  if(active && !pause)
   ToggleSnake();
  goto lp1;
}

void RunSetup()
{
 printf("TODO:");
 printf("If you have the guts, try writing\n"
        "the code for a nice setup menu that\n"
        "would modify the contents of the\n"
        "snake.ini . Open the file to know\n"
        "more about it.\n\n"
        "Bye till then.");
 exit(0);
}

@@@@@-----=======(((((((((********))))))))======------@@@@@
@@@@@-----            END OF MAIN.CPP           ------@@@@@
@@@@@-----=======(((((((((********))))))))======------@@@@@
@@@@@-----          START OF COMMAND.H          ------@@@@@
@@@@@-----=======(((((((((********))))))))======------@@@@@

////////////////////////////////////////////////////////////////////////

// Uility Library by Vikas Yadav, Chennai, INDIA
// File: command.h
// Class Command
// Created: 27-Oct-1999
// Purpose: To help resolving the Command line given to a program
// Revision 3
// 2:200420001308:First change for WinMain(...) donw.
// 3:140520001020:Added GetLastString().
//
#ifndef _STRING_
#include "cstring.h"
#endif

class Command
{
public:
    String s1;
    char* laststring;
 // This is main(int argc,char* argv[]) Version.
    Command(int argc,char* argv[])
    {
        int c;
 s1="";
        laststring=NULL;
 for(c=0; c<argc; c++)
        {
            s1+=(char*)" ";
            s1+=argv[c];
        }
    }
 // This is WinMain(... ,LPSTR lpszCmdLine) Version.
    Command(char* cmdline)
    {
  s1 = cmdline;
    }
    BOOL IsGiven(char* param)
    {
        String s="/";
        s+=param;
        return s1.indexOf(s.str1) != -1;
    }
    int GetNumber(char*param,int defval=0,char sep=':')
    {
        int p;
        if( (p=s1.indexOf(param)) == -1)
            return defval;
        String s2=s1.right(s1.length() - p - strlen(param));
        return atoi(s2.str1);
    }
    char* GetString(char*param,char *dest,char* defval=0,char sep=':')
    {
        int p;
        if( (p=s1.indexOf(param)) == -1)
            return defval;
        String s2=s1.right(s1.length() - p - strlen(param));
        p=s2.indexOf(' ');
        strcpy(dest,s2.left(p));
        return dest;
    }
    char* GetLastString()
    {
        if(!laststring)
         laststring = s1.right(s1.length() - s1.lastIndexOf(' ') - 1);
        return laststring;
    }
};


@@@@@-----=======(((((((((********))))))))======------@@@@@
@@@@@-----            END OF COMMAND.H          ------@@@@@
@@@@@-----=======(((((((((********))))))))======------@@@@@
@@@@@-----          START OF CSTRING.H          ------@@@@@
@@@@@-----=======(((((((((********))))))))======------@@@@@

////////////////////////////////////////////////////////////////////////

// File: string.h
// Date: 200420002332
// Contains "class string" and etc.
//
#ifndef _STRING_
#define _STRING_


#ifndef FILES_INCLUDED
#define FILES_INCLUDED
# include <stdio.h>
#       include <string.h>
# include <stdlib.h>
# include <stdarg.h>
# include <dos.h>
# include <errno.h>
# include <conio.h>
#       include <io.h>
# include <sys/stat.h>
# include <time.h>
# include <direct.h>
# include <errno.h>
# include <ctype.h>
#       include <dir.h>
#endif


#include <ctype.h>

#ifdef _WIN32
#include <windows.h>
#endif

#ifndef BOOL
#define BOOL unsigned char
#endif

#ifndef DWORD
#define DWORD unsigned long
#endif

#ifndef   MEMORYERROR
#define   MEMORYERROR defError

/*
#if defined(_WIN32) && !defined(D_defError)
#define D_defError
int defError(unsigned long b)
{
 MessageBox(0,
  "The Application is out of memory\nQuiting...",
  "Out Of Memory",
  MB_OK|MB_SYSTEMMODAL);
 return 0;
}
#endif
*/

#endif /* MEMORYERROR */

////////////////////////////////////////////////////////////////////////

// class String
// Created: 170919990000
// r7
// Version 1.3.22
//
// 211019990000:1:Added substring(...)
// 271119918955:2:Replaced the "int" decl. with "long".
// 131219991821:3:Added "const" in few operator definations.
// 131219992147:4:Added NULL argument handelling.
// 310120001006:5: *BUG FIX* disabled operator char* for bugs
// 310120001007:6:Added operator []
// 200420002317:7: *MAJOR CHANGE*  Added sprintf(...).

#ifdef TURBOC
#define MAX_STRING         0x4000
#else
#define MAX_STRING         0x4000
#endif
#ifndef min
#define min(x,y) ( x > y ? y : x )
#endif

#define STRING_VERSION     1

class String
{
 char ptr1[MAX_STRING];
public:
 char *str1;
//////////////////////////////////
 String()
 {
  str1 = NULL;
    }
//////////////////////////////////
    String(char*x1)
    {
  str1 = NULL;
  if(!x1)
   return;
        str1=new char[strlen(x1)+1];
        strcpy(str1,x1);
    }
//////////////////////////////////
 ~String()
 {
  if(str1 && *str1)
        {
   delete str1;
   str1=NULL;
  }
 }
//////////////////////////////////
    char* operator=(void*x1)
    {
  if(str1)
        {
   delete str1;
   str1=NULL;
  }
  if(!x1)
   return (char*)x1;
  //alloc=strlen((const char*)x1)+2;
  //DPrint("=: Allocated %lu for \"%s\"(%lu)",alloc,x1,strlen((const
char*)x1));
  str1=strdup((const char*)x1);
        return (char*)x1;
    }
//////////////////////////////////
    char* operator+=(void* x1)
    {
        int l1;
  if(!x1)
   return (char*)str1;
  unsigned long alloc = l1 = strlen(str1) + strlen((char*)x1) + 2;
  char *str2 = new char[alloc];
        ::sprintf(str2,"%s%s",str1,x1);
        if(str1)
        {
   delete str1;
   str1=NULL;
  }
  str1=str2;
        return str1;
    }
//////////////////////////////////
    char* operator+=(String &x1)
    {
        int l1;
        unsigned long alloc= l1 = strlen(str1) + strlen(x1.str1) + 1 ;
  char *str2 = new char[alloc];
        ::sprintf(str2,"%s%s",str1,x1.str1);
        if(str1)
        {
   delete str1;
   str1=NULL;
  }
  str1=str2;
        return str1;
    }
//////////////////////////////////
    char* right(int r1)
    {
        if(!str1)
   return NULL;
  strcpy(ptr1,str1);
        return (ptr1 + ( strlen(ptr1) - r1));
    }
//////////////////////////////////
    char* left(int r1)
    {
        if(!str1)
   return NULL;
        strcpy(ptr1,str1);
        ptr1[r1]=0;
        return ptr1;
    }
//////////////////////////////////
    short operator==(const char*x1)
    {
  if(!str1 && !strlen(x1))
   return 1;
  return strcmp(str1,x1)==0;
    }
//////////////////////////////////
    short operator!=(const char*x1)
    {
  if(!str1 && !strlen(x1))
   return 0;
        return strcmp(str1,x1)!=0;
    }
//////////////////////////////////
    int length()
    {
  if(!str1)
   return 0;
        return strlen(str1);
    }
//////////////////////////////////
    void toUpperCase()
    {
        if(!str1)
   return;
  unsigned long len = strlen( str1 );
  for( char *p = str1; p < (str1 + len); p++ )
        {
            if( islower( *p ) )
              *p = (char)toupper( *p );
        }
    }
//////////////////////////////////
    void toLowerCase()
    {
        if(!str1)
   return;
  unsigned long len = strlen( str1 );
  for( char *p = str1; p < (str1 + len); p++ )
        {
        if( isupper( *p ) )
           *p =(char)tolower( *p );
        }
    }
//////////////////////////////////
    char* operator+(char*x1)
    {
        if(!x1)
   return (char*)str1;
  ::sprintf(ptr1,"%s%s",str1,x1);
        return ptr1;
    }
//////////////////////////////////
/*  operator char*()
 *  {
 *      strcpy(ptr1,str1);
 *      delete str1;
 *      str1=new char[MAX_STRING];
 *      strcpy(str1,ptr1);
 *      return str1;
 *  }
 */
//////////////////////////////////
    long lastIndexOf(char x1)
    {
        if(!str1)
   return -1;
        long c1=-1;
  for(c1=length(); c1>0; c1--)
            if( str1[c1] == x1 )
                return c1;
        return c1;
    }
//////////////////////////////////
    long indexOf(char x1)
    {
        if(!str1)
   return -1;
  long c1=-1,c2=length();
  for(c1=0; c1<c2; c1++)
  {
   if( str1[c1] == x1 )
                return c1;
  }
        return -1;
    }
//////////////////////////////////
    long indexOf(char* x1)
    {
        if(!str1)
   return -1;
  char*x2;
        if( (x2=strstr(str1, x1)) == NULL)
            return -1;
        return (x2-str1+1);
    }
//////////////////////////////////
    void trim()
    {
        if(!str1)
   return;
  char str2[MAX_STRING],*ptr2;
        strcpy(str2,str1);
        int c1,l;
        String s1;
        s1=str2;
        ptr2=str2;
  for(c1=0; isspace(s1.str1[c1]); c1++);
        ptr2 += c1;
        s1 = ptr2;
        for( c1=s1.length()-1; isspace(s1.str1[c1]); c1--);
        s1.left(c1);
  if(s1.str1[(l=length())-1]==10)
   s1.str1[l-1]=0;
        strcpy(str1,s1.str1);
    }
//////////////////////////////////
    long getVersion()
    {
        return STRING_VERSION;
    }
//////////////////////////////////
 char*substring(DWORD start1, DWORD len1=0)
 {
  if(!str1)
   return NULL;
  if(len1 == 0)
   len1 = length();
  String p1;
  DWORD l1 = length();
  p1 = right( l1 - start1 );
  p1 = p1.left( len1 );
  strcpy( ptr1 , p1.str1 );
  return ptr1;
 }
//////////////////////////////////
 char operator[](int x)
 {
  if(!str1)
   return NULL;
  return str1[x];
 }
//////////////////////////////////
 char* sprintf(char* format, ...)
 {
  char buf[MAX_STRING];
  if(!format)
   return NULL;
  va_list argptr;
  va_start(argptr,format);
  vsprintf(buf,format,argptr);
  va_end(argptr);
  if(str1)
        {
   delete str1;
   str1=NULL;
  }
  return str1=strdup(buf);
 }
};

//#define PutStaticString char String::ptr1[MAX_STRING]
//#if    defined( MAIN_DEFINED ) || defined( _WINMAINISHERE_ )
//PutStaticString;
//#endif /* MAIN_DEFINED */

#endif /* _STRING_ */




__________________________________________________
Do You Yahoo!?
Talk to your friends online with Yahoo! Messenger.
http://im.yahoo.com

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019