/*
==============================================================================
		      WordUp Graphics Toolkit Version 5.0                     
			     Demonstration Program 63                         
									      
 This is the same as example 62 except for the fact that it runs in                                                                              
 VESA using 640x480x256. A VESA driver is required of course.....

 *** PROJECT ***                                                             
 This program requires the WGT5_WC.LIB, WVESA_WC.LIB and WSCR_WC.LIB files 
 to be linked.   
									      
 *** DATA FILES ***                                                          
 MUN.WMP, MUNCHMAP.SPR, MUNCHKIN.SPR                                         
							   WATCOM C++ VERSION 
==============================================================================
*/
#include <dos.h>
#include <malloc.h>
#include <stdio.h>
#include <conio.h>

#include <wgt5.h>
#include <wgtscrol.h>
#include <wgtvesa.h>

#define _XSIZE_ 640
#define _YSIZE_ 480
#define DESIRED_MODE V640x480


typedef short tiletypes[256];


#define YOU 37
void checkfeet (void);
void checkhead (void);
void checkright (void);
void checkleft (void);
void findelevators (void);
void upelev (void);
void downelev (void);
void checkelevators (void);
void moveguys (void);

short ox,oy,dir,anim;
short jumping,addy;
short spx,spy;

int timer;
// The number of times the screen is updated
int updates;

short feet1,feet2,head1,head2;
short windx,windy;

wgtmap munchmap;                        // our world map
tiletypes munchtypes;

#define UP 72
#define DOWN 80
#define LEFT 75
#define RIGHT 77
#define CTRL 29
#define ESC 1

#define NUM_SPR 51
#define NUM_TILE 255
#define NUM_OBJ 101
#define TILE_SIZE 16

#define MAINWIN 0

color palette[256];             // our palette of colours

block munchtiles[NUM_TILE];             // our blocks for the map
block munchsprites[NUM_SPR];            // our sprites 
block screenbuf;
scrollsprite munchobj[NUM_OBJ];

short i;

typedef struct {
    short curheight;
    short origy,origx;
    short timer;
    } elevator;

short replace[200];
short elevup=-1;
short oldmode;

elevator elev[30];
short numelev=0;


void timerctr (void)
{
  timer++;
}


void main (void)
{
  oldmode = wgetmode ();
  if (!vgadetected ())
  {
    printf ("VGA is required to run this program...");
    exit (1);
  }

  printf ("WGT Example #63\n\n");
  printf ("8-WAY SCROLLING SVGA DEMO\n");
  printf ("Arrow keys move, CTRL jumps. Up/down looks in direction or operates\n");
  printf ("elevators.  ESC quits the program.\n");
  printf ("\n\nWindow Width (2-40):");
  scanf ("%i", &windx);
  printf ("\nWindow Height (2-24):");
  scanf ("%i", &windy);

  vga256 ();
  if (wvesa_detected ())
  {
    wvesa_getmodeinfo (DESIRED_MODE);
    wvesa_init (DESIRED_MODE);
  }
  wloadsprites (palette, "munchmap.spr", munchtiles, 0, NUM_TILE - 1);
  wloadsprites (palette, "munchkin.spr", munchsprites, 0, NUM_SPR - 1);
  wsetpalette (0, 255, palette);
  
  screenbuf = wallocblock (_XSIZE_, _YSIZE_);
  wsetscreen (screenbuf);
  
  winitscroll (MAINWIN, NORMAL, - 1, windx, windy, munchtiles);
  memset (&munchobj[0], 0, sizeof (scrollsprite)*NUM_OBJ);
  munchmap = wloadmap (MAINWIN, "mun.wmp", munchtypes, munchobj);
  
  findelevators ();
  
  wshowwindow (MAINWIN, 0, 0);
  
  installkbd ();
  
  munchobj[YOU].on = 1;
  munchobj[YOU].x = 16;
  munchobj[YOU].y = 242;
  munchobj[YOU].num = 1;
  
  jumping = 0; addy = 0;
  anim = 2;
  
  timer = 0;
  winittimer ();
  wstarttimer (timerctr, TICKS(100));
  do
  {
    spx = 0;
    spy = 0;
    ox = munchobj[YOU].x;
    oy = munchobj[YOU].y;
    
    if  (jumping == 1)
      addy += 2;
    if  (addy > 15)
      addy = 15;
    
    if  ((kbdon[CTRL]) & (jumping == 0))
    {
      jumping = 1;
      addy = - 14;
    }
    
    if  (kbdon[LEFT])
    {
      munchobj[YOU].x -= 8;
      checkleft ();
      if  (dir != 1)
      {
	dir = 1;
	anim = 5;
      }
      anim++;
      if  (anim > 8)
	anim = 5;
    }
    else if  (kbdon[RIGHT])
    {
      munchobj[YOU].x += 8;
      checkright ();
      if  (dir != 2)
      {
	dir = 2;
	anim = 1;
      }
      anim++;
      if  (anim > 4)
	anim = 1;
    }
    
    munchobj[YOU].num = anim;
    if  (munchobj[YOU].x == ox)
      if  (dir == 1)
	munchobj[YOU].num = 9;
    else munchobj[YOU].num = 1;
    
    munchobj[YOU].y += addy;
    if  (munchobj[YOU].y < 0) munchobj[YOU].y = 0;
    if  (addy < 0)
      checkhead ();
    
    
    if  ((jumping == 1))
      if  (dir == 1)
	munchobj[YOU].num = 6;
    else munchobj[YOU].num = 2;
    
    checkfeet ();
    
    spx = munchobj[YOU].x - worldx[MAINWIN] - windowmaxx[MAINWIN] / 2;
    spy = munchobj[YOU].y - worldy[MAINWIN] - windowmaxy[MAINWIN] / 2;
    
    if  (kbdon[UP])
    {
      if  ((feet1 == 105) | (feet2 == 105))
	upelev ();
      else
	spy = - 4;
    }
    if  (kbdon[DOWN])
    {
      if  ((feet1 == 105) | (feet2 == 105))
	downelev ();
      else
	spy = + 4;
    }
    
    checkelevators ();
    // make sure they come back down when not standing on them
    
    moveguys ();
    
    wscrollwindow (MAINWIN, spx, spy);
    wshowobjects (MAINWIN, 1, NUM_OBJ - 1, munchsprites, munchobj);
    
    wtextcolor (10);
    wtexttransparent (TEXTFGBG);
    wgtprintf (0, 0, NULL, "Free ram: %d", getmemfree ());
    
    wsetscreen (NULL);
    wvesa_clip (0, 0, 639, 479);
    wvesa_putblock (0, 0, scrollblock[MAINWIN], NORMAL);
    wsetscreen (screenbuf);
    updates++;
  } while  (kbdon[ESC] != 1);          /* until ESC key is pressed */
  wstoptimer ();  
  wdonetimer ();

  uninstallkbd ();
  
  wendscroll (MAINWIN);
  wfreesprites (munchtiles, 0, NUM_TILE - 1);
  wfreesprites (munchsprites, 0, NUM_SPR - 1);
  wfreemap (munchmap);
  wsetmode (oldmode);
  printf ("\nElapsed time (hundredths of seconds): %i", timer);
  printf ("\n# updates: %d", updates);
  printf ("\nMicroseconds per frame: %g", (float)(timer) / (float)(updates));
  printf ("\nAverage frame rate: %2.2f frames/sec\n", (float)updates / ((float)(timer) / 100.0));
}


void checkright (void)
{
  short j,k;
  short x;
    
  j = wgetworldblock (MAINWIN, munchobj[YOU].x + 16, munchobj[YOU].y + 1);
  k = wgetworldblock (MAINWIN, munchobj[YOU].x + 16, munchobj[YOU].y + 15);
  if  ((j >= 100) | (k >= 100))
  {
      x = munchobj[YOU].x / TILE_SIZE;
      munchobj[YOU].x = x * TILE_SIZE;
  }
}


void checkleft (void)
{
  short j,k;
  short x;
    
  j = wgetworldblock (MAINWIN, munchobj[YOU].x, munchobj[YOU].y);
  k = wgetworldblock (MAINWIN, munchobj[YOU].x, munchobj[YOU].y + 15);
  if  ((j >= 100) | (k >= 100))
  {
      x = munchobj[YOU].x / TILE_SIZE;
      x++;
      munchobj[YOU].x = x * TILE_SIZE;
  }
}


void checkfeet (void)
{
  short j,k,y;
  
  feet1 = wgetworldblock (MAINWIN, munchobj[YOU].x, munchobj[YOU].y + 16);
  feet2 = wgetworldblock (MAINWIN, munchobj[YOU].x + 15, munchobj[YOU].y + 16);
  if  ((feet1 < 50) & (feet2 < 50))
    jumping = 1;
  else 
  {
    y = munchobj[YOU].y / TILE_SIZE;
    munchobj[YOU].y = y * TILE_SIZE;

    jumping = 0;
    addy = 0;
  }
}


void checkhead (void)
{
  short j,k,y;
  
  head1 = wgetworldblock (MAINWIN, munchobj[YOU].x, munchobj[YOU].y - 1);
  head2 = wgetworldblock (MAINWIN, munchobj[YOU].x + 15, munchobj[YOU].y - 1);
  if  ((head1 < 50) & (head2 < 50))
    jumping = 1;
  else 
  {
    y = munchobj[YOU].y / TILE_SIZE;
    y++;
    munchobj[YOU].y = y * TILE_SIZE;

    jumping = 0;
    addy = 0;

  }
}


void findelevators (void)
{
  short i,j,k;
  for  (i = 0; i <= mapheight[MAINWIN]; i++)
    for  (j = 0; j <= mapwidth[MAINWIN]; j++)
  {
    k = wgetworldblock (MAINWIN, j*16, i*16);
    if  (k == 105)
    {
      elev[numelev].curheight = i;
      elev[numelev].origx = j;
      elev[numelev].origy = i;
      elev[numelev].timer = 0;
      
      for  (k = 0; k < 200; k++)
	replace[k] = 0;
      numelev++;
    }
  }
}


void upelev (void)
{
  short ii,jj;
  for  (ii = 0; ii < numelev; ii++)
  {
    if  ((elev[ii].origx >= (munchobj[YOU].x / 16) - 1)
	& (elev[ii].curheight >= (munchobj[YOU].y / 16) - 1)
	& (elev[ii].origx <= (munchobj[YOU].x / 16) + 1)
	& (elev[ii].curheight <= (munchobj[YOU].y / 16) + 1)
	& ((elevup == - 1) | (elevup == ii))
	& (munchobj[YOU].y > 16))
    {
      checkhead ();
      if  ((head1 < 50) & (head2 < 50))
      {
	replace[elev[ii].curheight - 1] = wgetworldblock (MAINWIN, elev[ii].origx*16, (elev[ii].curheight - 1)*16);
	wputworldblock (MAINWIN, elev[ii].origx*16, elev[ii].curheight*16, 104);
	wputworldblock (MAINWIN, elev[ii].origx*16, (elev[ii].curheight - 1)*16, 105);
	elev[ii].curheight--;
	elevup = ii;
	munchobj[YOU].y -= 16;
	elev[ii].timer = 10;
      }
    }
  }
}


void downelev (void)
{
  short ii,jj;
  for  (ii = 0; ii < numelev; ii++)
  {
    if  ((elev[ii].origx >= (munchobj[YOU].x / 16) - 1)
	& (elev[ii].curheight >= (munchobj[YOU].y / 16) - 1)
	& (elev[ii].origx <= (munchobj[YOU].x / 16) + 1)
	& (elev[ii].curheight <= (munchobj[YOU].y / 16) + 1)
	& (elev[ii].curheight != elev[ii].origy))
    {
      wputworldblock (MAINWIN, elev[ii].origx*16, elev[ii].curheight*16, replace[elev[ii].curheight]);
      wputworldblock (MAINWIN, elev[ii].origx*16, (elev[ii].curheight + 1)*16, 105);
      elev[ii].curheight++;
      if  (elev[ii].curheight == elev[ii].origy)
	elevup = - 1;
      munchobj[YOU].y += 16;
      elev[ii].timer = 10;
    }
  }
}


void checkelevators (void)
{
  short ii;
  
  for  (ii = 0; ii < numelev; ii++)
  {
    if  ((elev[ii].curheight != elev[ii].origy))
    {
      if  (elev[ii].timer == 0)
      {
	wputworldblock (MAINWIN, elev[ii].origx*16, elev[ii].curheight*16, replace[elev[ii].curheight]);
	wputworldblock (MAINWIN, elev[ii].origx*16, (elev[ii].curheight + 1)*16, 105);
	elev[ii].curheight++;
	if  (elev[ii].curheight == elev[ii].origy)
	  elevup = - 1;
	elev[ii].timer = 0;
      }
      else elev[ii].timer--;
    }
  }
}


void moveguys (void)
{
  short j,k;
  
  for  (i = 0; i <= 36; i++)
  {
    if  (munchobj[i].on == 1) 
      if (munchsprites[munchobj[i].num] != NULL)
	// sprite made
    {
      if  (is_in_window (MAINWIN, munchobj[i].x, munchobj[i].y, 100))
      {
	if  (munchobj[i].num < 16)     // walking right
	{
	  munchobj[i].num++;
	  if  (munchobj[i].num > 15) munchobj[i].num = 12;
	  // walking animation loop
	  munchobj[i].x += 3;
	  j = wgetworldblock (MAINWIN, munchobj[i].x + 16, munchobj[i].y + 16);
	  k = wgetworldblock (MAINWIN, munchobj[i].x + 16, munchobj[i].y + 8);
	  if  ((j < 50) | (k >= 50)) munchobj[i].num = 16;
	}
	if  (munchobj[i].num > 15)     // walking left
	{
	  munchobj[i].num++;
	  if  (munchobj[i].num > 19) munchobj[i].num = 16;
	  // walking animation loop
	  munchobj[i].x -= 3;
	  j = wgetworldblock (MAINWIN, munchobj[i].x, munchobj[i].y + 16);
	  k = wgetworldblock (MAINWIN, munchobj[i].x, munchobj[i].y + 8);
	  if  ((j < 50) | (k >= 50)) munchobj[i].num = 12;
	}
      }
    }
  }
}
