/*
==============================================================================
		      WordUp Graphics Toolkit Version 4.5
			     Demonstration Program 62                         
									      
  Yet another scrolling example to demonstrate some simple techniques.        
  The program uses rather small sprites and allows the user to configure      
  window size. Frame rates are calculated and displayed at the end of the     
  program. Elevators are available by pressing UP ARROW when standing on one. 
									      
  ħħħ PROJECT ħħħ                                                             
  This program requires the WGT45.LIB and WGTSCROL.LIB files to be linked.

  ħħħ DATA FILES ħħħ
  MUN.WMP, MUNCHMAP.SPR, MUNCHKIN.SPR
==============================================================================
*/

#include <dos.h>
#include <alloc.h>
#include <stdio.h>
#include <conio.h>

#include <wgt45.h>
#include <wgtscrol.h>

typedef short tiletypes[256];

#define YOU 37
void checkfeet (void);
void checkhead (short);
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
long 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 
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 #62\n\n");
  printf ("8-WAY SCROLLING 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-20):");
  scanf ("%i", &windx);
  printf ("\nWindow Height (2-12):");
  scanf ("%i", &windy);

  vga256 ();

  wloadsprites (palette, "munchmap.spr", munchtiles, 0, NUM_TILE - 1);
  wloadsprites (palette, "munchkin.spr", munchsprites, 0, NUM_SPR - 1);
  wsetpalette (0, 255, palette);
  
  winitscroll (MAINWIN, NORMAL, - 1, windx, windy, munchtiles);
  memset (&munchobj[0], 0, sizeof (scrollsprite)*NUM_OBJ);
  munchmap = wloadmap (MAINWIN, "mun.wmp", munchtypes, munchobj);
  
  findelevators ();
  
  wnormscreen ();
  wcls (0);
  
  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, 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 (0);
    
    
    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 - 1;
    spy = munchobj[YOU].y - worldy[MAINWIN] - windowmaxy[MAINWIN] / 2 - 1;
    
    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);
    
    wputblock (0, 0, scrollblock[MAINWIN], NORMAL);
    nosound ();
    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 (microseconds): %d", 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 (short usingelev)
{
  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;

    if (!usingelev)
       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 (1);
      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;
	}
      }
    }
  }
}
