/*
   Honey v1.30 - main source file

   Written by Michael Bevin

   (c) August 1997

   NOTE: Parts of this code may be used in any freeware package provided
   I am acknowledged, but use in anything commercial requires my approval

   e-mail: michael.bevin@stonebow.otago.ac.nz
*/


#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <allegro.h>       
#include <jpeglib.h>       
#include <sys/farptr.h>
#include <sys/segments.h>
#include <sys/movedata.h>
#include <string.h>
#include <conio.h>
#include <crt0.h>
#include <mikmod.h>        
#include "load1.h"


int _crt0_startup_flags = _CRT0_FLAG_NEARPTR;
unsigned char mod_file_name[50];
PALETTE nice;
PACKFILE *f;
PACKFILE *d02;
DATAFILE *mydata, *cfont;

volatile int  cur_verse,     
              cred          = 0,    
              ifreq         = 80,  
              icount        = 0,    
              title_count   = 0,
              no_interrupt  = 0,
              min,
              sec,
              timer;

int           height,                
              width,                 
              tfreq,                 
              quex          = 0,     
              old_height    = 0,     
              old_width     = 0,     
              pre_no        = 1000,
              hiscore       = 0;

unsigned char cpu           = 0,     
              ceffect       = 0,     
              screen_change = 0,     
              fst           = 1,     
              mod_chosen    = 0,     
              ordered       = 10,    
              title_hook    = 1,
              title_missed  = 0,
              music_off     = 0,
              puz_switch    = 0,
              draw_hook     = 0,
              tetris_start  = 0,
              puzzle_start  = 0,
              del_cur       = 0,
              prev_level,
              start_level,
              banner_no,
              l1_rep,
              old_verse[61];

int           no_verses     = 40;

int           block[4][4],
              next_block,
              map[10][20],
              block_x, block_y,
              x_size, y_size,
              current_block,
              speed,
              score, dels;

char          text[256];
BITMAP    *buff, *old_buff, *curpic, *thumb[3], *not, *fuzzy,
          *tcur, *tet_back, *tnot, *title_back, *title_back2, *tcurpic;
COLOR_MAP *tabt,  *tab;
RGB_MAP    rgb_table;
UNIMOD    *mf;
struct     jpeg_error_mgr jerr;
struct     jpeg_decompress_struct cinfo;

void jpeg_memory_src (j_decompress_ptr cinfo, const JOCTET * buffer, size_t bufsize);

void bli(BITMAP *source, BITMAP *dest, int source_x, int source_y, int dest_x, int dest_y, int width, int height)
{
   no_interrupt = 1;
   blit(source, dest, source_x, source_y, dest_x, dest_y, width, height);
   no_interrupt = 0;
   if(title_missed) {
      title_missed = 0;
      no_interrupt = 1;

      if(title_hook) {
         bli(buff, title_back2, 100, 0, 0, 0, 580, 120);
         title_hook = 0;
      }
   
      bli(title_back2, title_back, 0, 0, 0, 0, 580, 120);
      draw_rle_sprite(title_back, data[title_count].dat, 0, 0);
      bli(title_back, screen, 0, 0, 100, 0, 580, 120);

      no_interrupt = 0;
   }
}

void textou(BITMAP *bmp, FONT *f, unsigned char *s, int x, int y, int color)
{
   no_interrupt = 1;
   textout(bmp, f, s, x, y, color);
   no_interrupt = 0;
   if(title_missed) {
      title_missed = 0;
      no_interrupt = 1;

      if(title_hook) {
         bli(buff, title_back2, 100, 0, 0, 0, 580, 120);
         title_hook = 0;
      }
   
      bli(title_back2, title_back, 0, 0, 0, 0, 580, 120);
      draw_rle_sprite(title_back, data[title_count].dat, 0, 0);
      bli(title_back, screen, 0, 0, 100, 0, 580, 120);

      no_interrupt = 0;
   }
}

void draw_spr(BITMAP *bmp, BITMAP *sprite, int x, int y)
{
   no_interrupt = 1;
   draw_sprite(bmp, sprite, x, y);
   no_interrupt = 0;
   if(title_missed) {
      title_missed = 0;
      no_interrupt = 1;

      if(title_hook) {
         bli(buff, title_back2, 100, 0, 0, 0, 580, 120);
         title_hook = 0;
      }
   
      bli(title_back2, title_back, 0, 0, 0, 0, 580, 120);
      draw_rle_sprite(title_back, data[title_count].dat, 0, 0);
      bli(title_back, screen, 0, 0, 100, 0, 580, 120);

      no_interrupt = 0;
   }
}

void notes (char *p)
{
   if(!ifreq) {
      bli(not, buff, 0, 0, 0, 550, 800, 28);
      textout_centre(buff, cfont->dat, p, 400, 551, -1);
      bli(buff, screen, 0, 550, 0, 550, 800, 28);
   }

   else textout_centre(buff, cfont->dat, p, 400, 551, -1);
}

int ran_notes (int y)
{
   int(x);

   x = random() % 15;

   if(y) x = y;
   if(tetris_start == 1) notes("Loading Tetris....");
   else if(puzzle_start == 1) notes("Loading Puzzle....");
   else if(x == 0)    notes("Psa 119:103 - Your teachings are sweeter than honey");
   else if(x == 1)    notes("Press ENTER to browse all the pictures by thumbnails, SPACE to browse by verse names");
   else if(x == 2)    notes("Press F1 for help");
   else if(x == 3)    notes("Press any letter, number, or SHIFT + letter combination for the corresponding picture");
   else if(x == 4)    notes("Add HONEY /A to autoexec.bat to see a picture when your computer starts up");
   else if(x == 5)    notes("Try typing HONEY /W to create a random collage suitable for a Window's wallpaper");
   else if(x == 6)    notes("Press F8 to save the current picture to disk as TEMP.JPG");
   else if(x == 7)    notes("Press F3 - F7 to turn the picture into a 3x3 - 7x7 piece puzzle");
   else if(x == 8)    notes("Press F2 to take a screen shot of the current screen (SCRSHOT.PCX)");
   else if(x == 9)    notes("Press the UP/DOWN arrows to increase/decrease speed at which the pictures change");
   else if(x == 10)   notes("Press F10 to pause on the current picture (and again to unpause)");
   else if(x == 11)   notes("HONEY V1.3 - this program is free, please distribute");
   else if(x == 12)   notes("Press ALT 1 - ALT 9 to play Tetris starting from levels 1 - 9");
   else if(x == 13)   notes("Write to me at michael.bevin@stonebow.otago.ac.nz with comments, queries, suggestions etc");
   else if(x == 14)   notes("Psa 119:105 - Your word is a lamp that gives light");

   return(x);
}

void tickhandler (void)
{
        MP_HandleTick();
	MD_SetBPM(mp_bpm);
}

void blue_rect (int x1, int y1, int x2, int y2, BITMAP *bufft)
{
   unsigned char *p1;
   int tx, ty;

   for(ty = y1; ty < y2; ty++) {
      p1 = &bufft->line[ty][x1];
      for(tx = x1; tx < x2; tx++) {
         if (*p1 % 4 != 3) (*p1)++;
         p1++;
      }
   }
}

void inline reduce (unsigned char *p1)
{
   if (*p1 % 4) (*p1)--;                       /* Reduce blue  */

   if ((*p1 % 32) > 7) *p1 -= 8;               /* Reduce green */
   else if ((*p1 % 32) > 3) *p1 -= 4; 

   if (*p1 > 63) *p1 -= 64;                    /* Reduce red   */
   else if (*p1 > 31) *p1 -= 32;
}

void shade_rect (int x1, int y1, int x2, int y2, BITMAP *bufft)
{
   unsigned char *p1;
   int tx, ty;

   if(icount == 9991) {
      for(ty = y1; ty < y2; ty++) {
         p1 =  &bufft->line[ty][x1];

         if(ty < 225 || ty >= 425) {
            for(tx = x1; tx < x2; tx++) {
               reduce(p1);
               p1++;
            }
         }

         else for(tx = x1; tx < x2; tx++) {
            if(tx==50 || tx==300 || tx==550) {
               tx+=200; p1+=200;
            }
               reduce(p1);
               p1++;
         }
      }
   }

   else if(icount == 9993) {
      for(ty = y1; ty < y2; ty++) {
         p1 =  &bufft->line[ty][x1];
         if(ty < 170 || ty > 529) {
            for(tx = x1; tx < x2; tx++) {
               reduce(p1);
               p1++;
            }
         }

         else for(tx = x1; tx < x2; tx++) {
            if(tx==200) {
               tx+=399; p1+=399;
            }
               reduce(p1);
               p1++;
         }
      }
   }

   else for(ty = y1; ty < y2; ty++) {
      p1 =  &bufft->line[ty][x1];
      for(tx = x1; tx < x2; tx++) {
               reduce(p1);
               p1++;
      }
   }
}

void fuzz_edges_2 (int x1, int y1, int x2, int y2)
{
   unsigned char *p1, *p2;
   int x, y, tx, ty;

   for(y=y1; y < y2; y++) {
      p1 =  &buff->line[y][x1];
      p2 =  &old_buff->line[y][x1];

      for(x = x1; x < x2; x++) {
         if(x > x2 / 2) tx = x2 - 1 - x; else tx = x - x1;

         if(tx < 15) {
            if(random() % ((tx * tx) + 2) == 0) *p1 = *p2;
            else if(random() % ((tx *tx) + 2) == 0) *p1 = *p2;
            else if(random() % ((tx * tx) + 2) == 0) *p1 = *p2;
            else if(random() % ((tx * tx) + 2) == 0) *p1 = *p2;
            else if(random() % ((tx * tx) + 2) == 0) *p1 = *p2;
            else if(random() % ((tx * tx) + 2) == 0) *p1 = *p2;
         }

         if(y > y2/2) ty = y2-1-y; else ty = y-y1;

         if(ty < 15) {
            if(random() % ((ty * ty) + 2) == 0) *p1 = *p2;
            else if(random() % ((ty * ty) + 2) == 0) *p1 = *p2;
            else if(random() % ((ty * ty) + 2) == 0) *p1 = *p2;
            else if(random() % ((ty * ty) + 2) == 0) *p1 = *p2;
            else if(random() % ((ty * ty) + 2) == 0) *p1 = *p2;
            else if(random() % ((ty * ty) + 2) == 0) *p1 = *p2;
            else if(random() % ((ty * ty) + 2) == 0) *p1 = *p2;
         }

         if((ty*ty + tx*tx) < 80) *p1 = *p2;

         p1++;
         p2++;
      }
   }
}

int get_keys (int y)
{
   int x,z;
   char t;
   clear_keybuf();
   z=cur_verse;

   while(z==cur_verse) {
      if(key[KEY_ESC]) return(2);
      else if(key[KEY_ENTER]) return(1);
      else if(key[KEY_RIGHT] || key[KEY_DOWN]) cur_verse++;
      else if(key[KEY_LEFT] || key[KEY_UP]) cur_verse--;
      else if(key[KEY_PGDN]) cur_verse += y;
      else if(key[KEY_PGUP]) cur_verse -= y;
      else {
         x = readkey();
         if(x >> 8 == KEY_ESC) return(2);
         else if(x >> 8 == KEY_ENTER) return(1);
         else if((x >> 8 == KEY_RIGHT) || (x >> 8 == KEY_DOWN)) cur_verse++;
         else if((x >> 8 == KEY_LEFT ) || (x >> 8 == KEY_UP  )) cur_verse--;
         else if(x >> 8 == KEY_PGDN) cur_verse += y;
         else if(x >> 8 == KEY_PGUP) cur_verse -= y;
         else {
            t = (x & 0xff);
            if(t > '0' && t <= '9') cur_verse = t - 14;
            else if(t >= 'a' && t <= 'z') cur_verse = t - 89;
            else if(t >= 'A' && t <= 'Z') cur_verse = t - 21;
            if(cur_verse > no_verses + 8) cur_verse = z;
         }
      }
   }
   return(0);
}

void change_verse ()
{
   if(!music_off) MD_Update();

   if(no_verses == 200 || !ceffect) title_missed = 0;

   else {
      title_count++;
      if(title_count > 19) title_count = 0;

      if(!no_interrupt) {
         if(title_hook) {
            bli(buff, title_back2, 100, 0, 0, 0, 580, 120);
            title_hook = 0;
         }
  
         bli(title_back2, title_back, 0, 0, 0, 0, 580, 120);
         draw_rle_sprite(title_back, data[title_count].dat, 0, 0);
         bli(title_back, screen, 0, 0, 100, 0, 580, 120);
      }
      else title_missed = 1;
   }

   if(ifreq) {
      icount++;
      if(icount >= ifreq) {
         do {
            cur_verse = random() % no_verses + 8;
            for(icount = 0; icount < ordered; icount++)
               if (cur_verse == old_verse[icount]) icount = 1000;
         } while (icount >= 1000);
      }
   }

   else if(icount == 9993) {
      sec += 2;
      if(sec > 599) {
         min++;
         sec -= 600;
      }
   }
}

END_OF_FUNCTION(change_verse);

void move_credits ()
{
   cred++;
}

END_OF_FUNCTION(move_credits);

void dataerr ()
{
   printf("Error reading HONEY.DAT, make sure you are in the right directory or re-install\n");
   exit(0);
}

void d01err ()
{
   printf("Error reading HONEY.D01 or HONEY.D02, type HONEY /S to fix\n");
   exit(0);
}

void wend (int x1, int y1, int x2, int y2)
{
   if(cur_verse == old_verse[0]) {
      bli(tcur, buff, 0, 0, x1, y1 - 1, x2 - x1 + 1, y2 - y1 + 1);
      bli(curpic, buff, 0, 0, (800 - old_width) / 2 - 5, (600 - old_height) / 2 + 37, old_width, old_height);
      title_hook = 1;
      if(cpu == 1) draw_rle_sprite(buff, data[title_count].dat, 100, 0);
      bli(buff, screen, x1, y1, x1, y1, x2 - x1 + 1, y2 - y1);

      ran_notes(0);
   }

   else {
      old_width = 800;
      old_height = 600;
      fst = 2;
   }

   clear_keybuf();
   icount = 0;
   ifreq  = tfreq;
   destroy_bitmap(tcur);
}

void fstuff ()
{
  pack_fclose(f);
  f = pack_fopen("honey.dat", F_READ_PACKED);
  pack_fseek(f, 8);
}

void my_load_mod()
{
   md_dmabufsize   = 25000;                   
   md_mode         = DMODE_16BITS | DMODE_STEREO;
   md_device       = 0;            
   mp_loop         = 1;

   ML_RegisterLoader(&load_mod);

   if(mod_chosen) {
      ML_RegisterLoader(&load_s3m);
      ML_RegisterLoader(&load_uni);
      ML_RegisterLoader(&load_m15);
      ML_RegisterLoader(&load_mtm);
      ML_RegisterLoader(&load_stm);
      ML_RegisterLoader(&load_ult);
      ML_RegisterLoader(&load_xm);
   }

   MD_RegisterDriver(&drv_nos);
   MD_RegisterDriver(&drv_sb);
   MD_RegisterDriver(&drv_gus);
   MD_RegisterPlayer(tickhandler);

   if(!MD_Init()) {
       printf("Driver error: %s.\n",myerr);
       exit(0);
   }

   if(mod_chosen) mf = ML_LoadFN(mod_file_name);
      else mf = ML_LoadFN("honey.d00");

   if(mf == NULL){
      printf("MikMod Error: %s\n",myerr);
      exit(0);
   }

   MP_Init(mf);
   md_numchn = mf->numchn;
   MD_PlayStart();
}

void set_cpu (void)
{
   if(cpu == 1) {
      md_mixfreq = 11000;
      ceffect = 0;
   }
   if(cpu == 2) {
      md_mixfreq = 22050;
      ceffect = 8;
   }
   if(cpu == 3) {
      md_mixfreq = 44100;
      ceffect = 8;
   }
   if(cpu == 4) {
      md_mixfreq = 44100;
      ceffect = 16;
   }
   if(cpu == 5) {
      md_mixfreq = 44100;
      ceffect = 32;
   }
}

void init_screen (void)
{
   if(screen_change)  if (set_gfx_mode(screen_change,  800, 600, 0, 0) != 0) screen_change=0;

   if(!screen_change) if (set_gfx_mode(GFX_AUTODETECT, 800, 600, 0, 0) != 0) {
      allegro_exit();
      printf("Unsupported graphics card or card does not support 800x600, 256 colour SVGA\n\n");
      exit(1);
   }
   set_pallete(black_pallete);
}

void remove_dots (int x1, int y1, BITMAP *b)
{
   int x, y;
   unsigned char a;

   for(y = 0;y < y1; y++) {
      for(x = 0;x < x1; x++) {
         a = _getpixel(b, x, y);
         if (a > 200) _putpixel(b, x, y, 0);
         if (a == 0)  _putpixel(b, x, y, 4);
      }
   }
}

void read_map (j_decompress_ptr dinfo)
{
  dinfo->colormap = (*dinfo->mem->alloc_sarray)
    ((j_common_ptr) dinfo, JPOOL_IMAGE,
     (JDIMENSION) (MAXJSAMPLE+1), (JDIMENSION) 3);
  dinfo->actual_number_of_colors = 256;
}


int read_JPEG_file (int dat_no, int scale_f)
{
  int x;
  JSAMPARRAY buffer;

  if(dat_no > 47) {
     pack_fclose(f);
     f = pack_fopen("honey.add", F_READ_PACKED);
     pack_fseek(f, 8);
     if((mydata = my_load(f, dat_no - 48)) == NULL) dataerr();
  }
  else if(pre_no >= dat_no) {
     fstuff();
     if((mydata = my_load(f, dat_no - 4)) == NULL) dataerr();
  }
  else if((mydata = my_load(f, dat_no - pre_no - 1)) == NULL) dataerr();

  pre_no = dat_no;

  jpeg_memory_src(&cinfo, mydata->dat, (size_t) mydata->size);
  jpeg_read_header(&cinfo, TRUE);

  if(scale_f != 7) {
     read_map(&cinfo);
     for(x = 0; x < 256; x++) {
        cinfo.colormap[0][x] = pal[x].r << 2;
        cinfo.colormap[1][x] = pal[x].g << 2;
        cinfo.colormap[2][x] = pal[x].b << 2;
     }
  }

  cinfo.desired_number_of_colors = 256;
  cinfo.quantize_colors = TRUE;

  if(scale_f == 2) {
     cinfo.do_fancy_upsampling = FALSE;
     cinfo.scale_num = 1;
     cinfo.scale_denom = scale_f;
  }

  jpeg_start_decompress(&cinfo);

  height = 0;
  width  = cinfo.output_width;

  if(del_cur) destroy_bitmap(curpic);
  curpic = create_bitmap(width, cinfo.output_height); clear(curpic);

  buffer = (*cinfo.mem->alloc_sarray) ((j_common_ptr) &cinfo, JPOOL_IMAGE, width * cinfo.output_components, 1);

  while (cinfo.output_scanline < cinfo.output_height) {
     if(draw_hook && keypressed()) {
        jpeg_abort_decompress(&cinfo);
        unload_datafile_object(mydata);
        return(0);
     }
     (void) jpeg_read_scanlines(&cinfo, buffer, 1);
     memcpy(&curpic->line[height][0], buffer[0], width);
     height++;
  }

  if(scale_f == 7) {
     for(x = 0; x < 256; x++) {
        nice[x].r = cinfo.colormap[0][x] >> 2;
        nice[x].g = cinfo.colormap[1][x] >> 2;
        nice[x].b = cinfo.colormap[2][x] >> 2;
     }
  }

  height = cinfo.output_height;
  jpeg_finish_decompress(&cinfo);
  unload_datafile_object(mydata);
  draw_hook = 0;
  del_cur = 1;
  return(1);
}

void new_setup (void)
{
   FILE *fq;
   PACKFILE *fp;
   int x;

   printf("\nHoney v1.30 - Setup\n");

   if((fq = fopen("honey.add", "rb"))!=NULL) {
      printf("\nAdditional 20 JPEGs detected!\n");
      fclose(fq);
   }

   printf("\nPlease select computer type from list below:\n");
   printf("   1.   386  :-(\n");
   printf("   2.   486 (choose this if you don't know)\n");
   printf("   3.   slow Pentium\n");
   printf("   4.   fast Pentium\n");
   printf("   5.   Pentium II etc\n");
   cprintf("   Selection: ");

   clear_keybuf();
   cpu = 0;
   while(cpu == 0) {
      x=readkey();
      if(x >> 8 == KEY_1) cpu = 1;
      if(x >> 8 == KEY_2) cpu = 2;
      if(x >> 8 == KEY_3) cpu = 3;
      if(x >> 8 == KEY_4) cpu = 4;
      if(x >> 8 == KEY_5) cpu = 5;
   }

   set_cpu();
   if((fq = fopen("honey.add", "rb")) != NULL) {
      no_verses = 60;
   }

   printf("\n\nCreating data files... please be patient\n");
   cprintf("<");

   for(x = 0; x < (no_verses + ceffect + 2); x++) cprintf(".");
   cprintf(">\r<");

   fq = fopen("honey.d01", "wb");
   putc(cpu, fq);     
   putw(hiscore, fq); 
   putw(no_verses, fq);
   tcurpic = create_bitmap(200, 200);
   clear(tcurpic);

   for(x = 0; x < no_verses; x++) {
      read_JPEG_file(x + 8, 2);
      stretch_blit(curpic, tcurpic, 0, 0, width, height, 0, 0, 200, 200);
      fwrite(tcurpic->line[0], 40000, 1, fq);
      cprintf("*");
   }

   destroy_bitmap(tcurpic);

   fclose(fq);

   if((fp=pack_fopen("honey.d02", "wp")) == NULL) d01err();

   read_JPEG_file(4, 1);
   pack_fwrite(curpic->line[0], 302 * 174, fp);
   cprintf("*");

   if(ceffect) {
      rgb_map = (RGB_MAP *) &map_b;
      tab = (COLOR_MAP *) malloc(sizeof(COLOR_MAP));
      for(x = 0; x < ceffect; x++) {
         my_create_trans_table(tab, pal, x * (256 / ceffect), x * (256 / ceffect), x * (256 / ceffect));
         pack_fwrite(tab, sizeof(COLOR_MAP), fp);
         cprintf("*");
      }
      free(tab);
   }

   read_JPEG_file(5, 1);
   pack_fwrite(curpic->line[0], height * width, fp);
   cprintf("*");

   pack_fclose(fp);
}

void wind (int x1, int y1, int x2, int y2, char *p, char *q)
{
   int x,y, xo, yo;

   tcur=create_bitmap(x2 - x1 + 1, y2 - y1 + 1);
   bli(buff, tcur, x1, y1 - 1, 0, 0, x2 - x1 + 1, y2 - y1 + 1);

   x = (800 - old_width) / 2 - 5;
   y = (600 - old_height) / 2 + 37;
   xo = x + old_width; yo = y + old_height;

   if(x1 > x) x = x1;   if(y1 > y) y = y1;
   if(x2 < xo) xo = x2; if(y2 < yo) yo = y2;

   shade_rect  (x,  y,  xo, yo, buff);
   shade_rect  (x1, y1, x2, y2, buff);
   blue_rect   (x1, y1, x2, y1 + 29, buff);
   fuzz_edges_2(x1, y1, x2, y2);

   if(icount == 9993 || icount == 9995) {
      tnot = create_bitmap(x2 - x1 + 1, 29);
      bli(buff, tnot, x1, y1, 0, 0, x2 - x1 + 1, 29);
   }

   textout_centre(buff, cfont->dat, p, 400, y1 + 5, -1);
   notes(q);
}

void rem_redgr (BITMAP *the_pic, int x, int y, int am)
{
   int x1, y1;
   unsigned char *p;

   if(am == 1) {
      for(y1 = 0; y1 < y; y1++) {
         p = &the_pic->line[y1][0];
         for(x1 = 0; x1 < x; x1++) {

            if(*p) *p -= 36;
 
            p++;
         }
      }
   }

   if(am == 2) {
      for(y1 = 0; y1 < y; y1++) {
         p = &the_pic->line[y1][0];
         for(x1 = 0; x1 < x; x1++) {

            if(*p) {
               *p -= 36;

               if ((*p % 32) > 3) *p -= 4;
               if (*p > 31) *p -= 32;
            }

            p++;
         }
      }
   }

   if(am == 3) {
      for(y1 = 0; y1 < y; y1++) {
         p = &the_pic->line[y1][0];
         for(x1 = 0; x1 < x; x1++) {
            if(*p) {
               *p -= 36;

               if ((*p % 32) > 3) *p -= 4;
               if (*p > 31) *p -= 32;

               if ((*p % 32) > 3) *p -= 4;
               if (*p > 31) *p -= 32;
            }

            p++;
         }
      }
   }
}

void browse_words (void)
{
   char s[2];
   unsigned char *versinf[] = {
      "Psalm 127:1", "Unless the Lord builds the house its builders labor in vain",
      "1 Thes 5:17", "Pray without ceasing",
      "Isaiah 40:31", "Those who hope in the Lord will renew their strength",
      "Psalms 23:2", "He leads me beside quiet waters, he restores my soul",
      "Romans 15:5", "May the God who gives endurance and encouragement give you",
      "Psalm 63:1", "Earnestly I seek you! My body longs for you!",
      "Isaiah 2:4", "They will beat their swords into plowshares",
      "Psalm 93", "The Lord reigns! He is robed in majesty!",
      "John 7:37-39", "Whoever believes in me streams of living water will flow",
      "1 Peter 2:5, Ephesians 2:22","You, like living stones, are being built into",
      "1 Corinthians 6:11", "You were washed, sanctified, justified",
      "Psalm 42:2", "My soul thirsts for God",
      "Romans 15:13", "May the God of hope fill you with joy and peace",
      "Hebrews 12:1", "Let us run with perseverance the race marked out for us",
      "Psalm 17:5", "My steps have held to your paths; my feet have not slipped!",
      "Romans 12:2", "Do not conform any longer to the standards of this world",
      "Matthew 5:16", "Let the light of your life shine",
      "Psalm 36:5-6", "Your love, O God, reaches to the heavens", 
      "Luke 1:78-79", "Because of the mercy of our God",
      "Acts 1:11", "This same Jesus will come back!",  
      "Psalm 68:4", "Sing to God, sing praise to his name", 
      "Matthew 24:27", "So will be the coming of the Son of Man!",
      "1 Corinthians 13:12", "Now we see but as a poor reflection in a mirror",
      "James 4:14", "What is your life? You are a mist that appears for a little",  
      "Psalm 103:12", "As far as the east is from the west",     
      "Psalm 19:1", "The heavens declare the glory of God",  
      "Psalm 51:1-2", "Have mercy on me, O God, according to your unfailing love;",
      "1 Cor 13:7,8, SoS 8:6", "Love ... always protects, trusts, hopes, perseveres",
      "Prov 24:25-27", "Let your eyes look straight ahead",
      "Amos 5:24", "But let justice roll on like a river",    
      "Psalm 95:3-5", "For the Lord is the great God the great King above all gods", 
      "Psalm 42:1", "As the deer pants for the water, so my soul longs after you!",   
      "Proverbs 23:5", "Cast but a glance at riches, and they are gone",
      "Matthew 6:34", "Do not worry about tomorrow", 
      "Matthew 6:28-30", "If that is how God clothes the grass of the field",
      "Psalm 139:1,12", "O Lord, You have searched me and known me",
      "Psalm 50:2", "Perfect in beauty, God shines forth",
      "Psalm 89:37", "His throne will be established forever like the moon",
      "1 Corinthians 15:51", "We will not all sleep, but we will all be changed",
      "MUM", "I pray that she will see in me a love that leads to You!", NULL                          
   };
   int x, z, ret = 0, tno;

   if(ifreq) tfreq = ifreq;
   ifreq = 0;
   icount = 9992;
   tno = no_verses;
   no_verses = 40;

   tcurpic = create_bitmap(500, 24);

   bli(buff, old_buff, 0, 100, 0, 100, 800, 400);
   wind(70, 170, 729, 470, "VERSE BROWSER", "Use the UP & DOWN arrows, and PGUP & PGDN to find a verse, and ENTER to select");
   bli(buff, old_buff, 20, 199, 20, 199, 760, 252);
   title_hook = 1;

   while(!ret) {
      if(cur_verse < 8) cur_verse += no_verses;
      if(cur_verse > no_verses + 7) cur_verse -= no_verses;

      bli(old_buff, buff, 20, 199, 20, 199, 760, 252);

      s[1] = 0;
      for(x = 0; x < 12; x++) {
         z = cur_verse+x;
         if(z < 8) z += no_verses;
         if(z > no_verses + 7) z -= no_verses;

         if (z < 34) s[0] = 'a' + z - 8;
         else if (z < 44) s[0] = '0' + z - 34;
         else s[0] = 'A' + z - 44;

         clear(tcurpic);
         textou(tcurpic, cfont->dat, s, 0, 0, -1);
         if(x) rem_redgr(tcurpic, text_length(cfont->dat, s), 24, 3);
         else  rem_redgr(tcurpic, text_length(cfont->dat, s), 24, 2);
         draw_spr(buff, tcurpic, 102, 205 + x * 20);

         clear(tcurpic);
         textou(tcurpic, cfont->dat, versinf[(z - 8) * 2], 0, 0, -1);
         if(x) rem_redgr(tcurpic, text_length(cfont->dat, versinf[(z - 8) * 2]), 24, 2);
         else  rem_redgr(tcurpic, text_length(cfont->dat, versinf[(z - 8) * 2]), 24, 1);
         draw_spr(buff, tcurpic, 125, 205 + x * 20);

         clear(tcurpic);
         textou(tcurpic, cfont->dat, versinf[(z - 8) * 2 + 1], 0, 0, -1);
         if(x) rem_redgr(tcurpic, text_length(cfont->dat, versinf[(z - 8) * 2 + 1]), 24, 1);
         draw_spr(buff, tcurpic, 134 + text_length(cfont->dat, versinf[(z - 8) * 2]), 205 + x * 20);
      }

      bli(buff, screen, 20, 169, 20, 169, 760, 301);
      ret = get_keys(11);
      if(ret == 2) cur_verse = old_verse[0];
   }

   wend(70, 170, 729, 470);

   destroy_bitmap(tcurpic);
   no_verses = tno;
}

void browse (void)
{
   char s[2];
   int x, z, oldpos, ret = 0;
   FILE *fp;

   if(ifreq) tfreq = ifreq;
   ifreq = 0;
   icount = 9991;

   for(x = 0; x < 3; x++) thumb[x] = create_bitmap(200, 200);

   fp = fopen("honey.d01","rb");

   bli(buff, old_buff, 0, 100, 0, 100, 800, 400);
   wind(10, 170, 789, 470, "PICTURE BROWSER", "Use the LEFT & RIGHT arrows, and PGUP & PGDN to find a verse, and ENTER to select");
   bli(buff, old_buff, 0, 425, 0, 425, 800, 25);
   title_hook = 1;

   oldpos = 1000;
   while(!ret) {
      if(cur_verse < 8) cur_verse += no_verses;
      if(cur_verse > no_verses + 7) cur_verse -= no_verses;
      bli(old_buff, buff, 0, 425, 0, 425, 800, 25);

      if (oldpos - cur_verse == 1) {
         bli(thumb[1], thumb[2], 0, 0, 0, 0, 200, 200);
         bli(thumb[0], thumb[1], 0, 0, 0, 0, 200, 200);
      }
      if (cur_verse - oldpos == 1) {
         bli(thumb[1], thumb[0], 0, 0, 0, 0, 200, 200);
         bli(thumb[2], thumb[1], 0, 0, 0, 0, 200, 200);
      }

      s[1] = 0;
      for(x = 0; x < 3; x++) {
         z = cur_verse + x;
         if(z < 9) z = no_verses + 8;
         if(z > no_verses + 8) z = 9;
         if( (oldpos - cur_verse != 1 || x == 0) &&
             (cur_verse - oldpos != 1 || x == 2)) {
            fseek(fp, 40000 * (z-9) + 9, SEEK_SET);
            if(!fread(thumb[x]->line[0], 40000, 1, fp)) d01err();
         }
         bli(thumb[x], buff, 0, 0, 50 + (x*250), 225, 200, 200);
         if (z < 35) s[0] = 'a' + z - 9;
         else if (z < 45) s[0] = '0' + z - 35;
         else s[0] = 'A' + z - 45;
         textout_centre(buff, cfont->dat, s, 150 + (x*250), 425, -1);
      }

      bli(buff, screen, 10, 169, 10, 169, 780, 301);
      oldpos = cur_verse;
      ret = get_keys(3);
      if(ret == 2) cur_verse = old_verse[0];
   }
   for(x = 0; x < 3; x++) destroy_bitmap(thumb[x]);

   wend(10, 170, 789, 470);
   fclose(fp);
}

int cross_fade (int tx, int ty, BITMAP *tbuff, BITMAP *told_buff, int wid, int hei, int pau)
{
   BITMAP *temp_buff;
   int toc;

   temp_buff = create_bitmap(wid, hei);
   bli(tbuff, temp_buff, tx, ty, 0, 0, wid, hei);
   tab = tabt;
   if(pau == 2) set_clip(buff, 100, 0, 700, 130);
   for(toc = 0; toc < ceffect; toc++) {
      if(pau == 1) quex = cred;
      bli(temp_buff, tbuff, 0, 0, tx, ty, wid, hei);
      if(key[KEY_ESC]) return(1);
      color_map = tab++;
      draw_trans_sprite(tbuff, told_buff, tx, ty);

      if(pau == 2) {
         bli(tbuff, buff, tx, ty, tx, ty, wid, hei);
         draw_rle_sprite(tbuff, data[title_count].dat, 100, 0);
      }

      title_hook = 1;
      bli(tbuff, screen, tx, ty, tx, ty, wid, hei);
      if(pau == 1) do {} while ((cred - quex) < (128 / ceffect));
   }

   set_clip(buff, 0, 0, 799, 599);
   bli(told_buff, buff, 0, 0, tx, ty, wid, hei);

   destroy_bitmap(temp_buff);

   return(0);
}

void my_fade_from_range(PALLETE source, PALLETE dest, int speed, int from, int to)
{
   PALLETE temp;
   int c;

   for (c=0; c<PAL_SIZE; c++)
      temp[c] = source[c];

   for (c=0; c<64; c+=speed) {
      mp_volume = 63-c;
      fade_interpolate(source, dest, temp, c, from, to);
      set_pallete(temp);
      set_pallete(temp);
   }
   set_pallete(dest);
}

void quit_honey(int fade)
{
   PALLETE temp;

   if(fade) {
      get_pallete(temp);
      my_fade_from_range(temp, black_pallete, fade, 0, 255);
   }
   clear_keybuf();

   if(fade<2 && !music_off) {
      MD_PlayStop();          
      ML_Free(mf);            
      MD_Exit();
   }

   pack_fclose(f);
   allegro_exit();
   exit(0);
}

void exit_honey ()
{
   int x, y, oc = 0;
   unsigned char *message[] = {
      "HONEY - Psalm 119:103-105",
      "programmed by Michael Bevin",
      "pictures by Phil Ware and Paul Lee",
      "music by Kjetil Hoem",
      "thanks to DJ Delorie, Shawn Hargreaves & Andrew Deren",
      "and thanks to the one who died for our sins",
      "this program is freeware, please distribute",
      "God bless you", " ", NULL
   };

   set_clip(buff, 0, 0, 799, 599);

   no_verses = 200;

   if(quex) quit_honey(1);

   clear_keybuf();
   if(!ceffect || cpu < 4) fade_out(2);

   destroy_bitmap(curpic); destroy_bitmap(fuzzy);
   width = 550; height = 413;
   curpic = create_bitmap(width, height);
   if(!pack_fread(curpic->line[0], width * height, d02)) d01err();
   pack_fclose(d02);

   x = (800 - width) / 2;
   y = (600 - height) / 2 - 5;

   if(ceffect && cpu > 3) {
      draw_rle_sprite(buff, data[title_count].dat, 100, 0);
      clear(old_buff);
      bli(curpic, old_buff, 0, 0, x, y, width, height);
      if(cross_fade(0, 0, buff, old_buff, 800, 600, 0)) quit_honey(1);
   }

   clear(buff);
   bli(curpic, buff, 0, 0, x, y, width, height);
   bli(buff, screen, 0, 0, 0, 0, 800, 600);

   if(!ceffect || cpu < 4) fade_in(pal, 2);
   install_int(move_credits, 16);
   oc = 0;
   destroy_bitmap(old_buff);
   old_buff = create_bitmap(width, 25);
   clear(old_buff);

   while(!keypressed()) {
      if(cred/1000 > oc && oc < 9) {
         if(ceffect) {
            clear(buff);
            bli(old_buff, buff, 0, 0, x, y+height+2, width, 25);
            clear(old_buff);
            textout_centre(old_buff, cfont->dat, message[oc], width/2, 0, -1);
            if(cross_fade(x, y+height+2, buff, old_buff, width, 25, 1)) quit_honey(1);
         }
         clear(buff);
         textout_centre(buff, cfont->dat, message[oc], 400, y+height+2, -1);
         bli(buff, screen, x, y+height+2, x, y+height+2, width, 25);
         oc++;
      }
   }

   quit_honey(1);
}

void load_d02_map (void)
{
      char x;

      if(cpu > 1) {
         if((tabt = (COLOR_MAP *) malloc(sizeof(COLOR_MAP) * ceffect)) == NULL) {
            printf("Unable to allocate color map memory\n");
            exit(0);
         }
         tab = tabt;
         for(x = 0; x < ceffect; x++) if(!pack_fread(tab++, sizeof(COLOR_MAP), d02)) d01err();
      }
}

void load_d02_pics (void)
{
   if((d02=pack_fopen("honey.d02", "rp")) == NULL) d01err();

   if(!pack_fread(fuzzy->line[0], 302 * 174, d02)) d01err();
}

void puzzle (int dim)
{
   int x, y, z, pos[dim * dim], cblank, oblank;

   min = 0;
   sec = 0;
   puzzle_start = 0;
   if(ifreq) tfreq = ifreq;
   ifreq = 0;
   icount = 9993;

   pos[(dim * dim) - 1] = dim * dim;
   cblank = (dim * dim) - 1;

   for(x = 0; x < (dim * dim - 1); x++) pos[x] = x;

   for(z = 0; z < 7000; z++) {
      oblank = cblank;
      x = random() % 4;
      if(x == 0 && (cblank > (dim - 1))) cblank -= dim;
      if(x == 1 && (cblank < (dim * dim - dim))) cblank += dim;
      if(x == 2 && (cblank % dim)) cblank--;
      if(x == 3 && ((cblank % dim) != (dim - 1))) cblank++;
      pos[oblank] = pos[cblank];
      pos[cblank] = dim * dim;
      if(cblank == (dim * dim - 1) && z > (dim * 100)) z = 7500;
   }

   bli(buff, old_buff, 130, 120, 130, 120, 539, 430);
   wind(130, 120, 669, 550, "PUZZLE", "Use the arrows to move the squares until the pieces are in order, S switches the arrow keys");

   stretch_blit(curpic, old_buff, 0, 0, old_width, old_height, 0, 0, 400, 360);
   rectfill(old_buff, (pos[cblank] % dim) * 400 / dim, (pos[cblank] / dim) * 360 / dim, (pos[cblank] % dim) * 400 / dim + 400 / dim,     (pos[cblank] / dim) * 360 / dim + 360 / dim, 0);
   rect    (old_buff, (pos[cblank] % dim) * 400 / dim, (pos[cblank] / dim) * 360 / dim, (pos[cblank] % dim) * 400 / dim + 400 / dim - 1, (pos[cblank] / dim) * 360 / dim + 360 / dim - 1, 255);

   z = 0;
   for(y = 0; y < dim; y++) {
      for(x = 0; x < dim; x++) {
         bli(old_buff, buff, (pos[z] % dim) * 400 / dim, (pos[z] / dim) * 360 / dim, 200 + (x * 400 / dim), 170 + (y * 360 / dim), 400 / dim, 360 / dim);
         z++;
      }
   }

   title_hook = 1;
   bli(buff, screen, 130, 120, 130, 120, 539, 430);

   title_hook = 1;

   while(!key[KEY_ESC]) {
      for(x = 0;x < (dim * dim - 1); x++) if (pos[x] != x) x = 100;

      if(x<100) {
         bli(tnot, buff, 0, 0, 130, 120, 540, 29);
         destroy_bitmap(tnot);
         sprintf(text, "WELL DONE - your time was: %d:%02d", min, sec/10);
         textout_centre(buff, cfont->dat, text, 400, 125, -1);
         bli(buff, screen, 130, 120, 130, 120, 539, 29);
         bli(old_buff, screen, 0, 0, 200, 170, 400, 360);

         title_hook = 1;

         rest(1000);
         clear_keybuf();
         x = readkey();
         goto che;
      }

      oblank = cblank;

      while(oblank == cblank && !key[KEY_ESC]) {
         x = readkey();
         x = x >> 8;

         if((cblank > dim - 1) && ((x == KEY_UP && !puz_switch) || (x == KEY_DOWN && puz_switch)))
            cblank -= dim;

         if((cblank < dim * dim - dim) && ((x == KEY_DOWN && !puz_switch) || (x == KEY_UP && puz_switch)))
            cblank += dim;

         if((cblank % dim) && ((x == KEY_LEFT && !puz_switch) || (x == KEY_RIGHT && puz_switch)))
            cblank--;

         if(((cblank % dim) != (dim - 1)) && ((x == KEY_RIGHT && !puz_switch) || (x == KEY_LEFT && puz_switch)))
            cblank++;

         if(x == KEY_S) puz_switch = (puz_switch + 1) % 2;
      }

      pos[oblank] = pos[cblank];
      pos[cblank] = dim * dim;

      bli(old_buff, screen, (pos[oblank] % dim) * 400 / dim, pos[oblank] / dim * 360 / dim, 200 + ((oblank % dim) * 400 / dim), 170 +((oblank / dim) * 360 / dim), 400 / dim, 360 / dim);
      bli(old_buff, screen, (pos[cblank] % dim) * 400 / dim, pos[cblank] / dim * 360 / dim, 200 + ((cblank % dim) * 400 / dim), 170 +((cblank / dim) * 360 / dim), 400 / dim, 360 / dim);
   }

che:
   wend(130, 120, 669, 550);
}

void create_wall (void)
{
   int x, y, z, centre_x, centre_y, x1, y1;

   printf("\nCreating wallpaper WALLPAP.PCX\n");
   cprintf("<...............>\r<");

   for(x=0;x<15;x++) {
      do {
         cur_verse = random() % no_verses + 8;
         for(icount = 0; icount < no_verses - 1; icount++)
            if (cur_verse == old_verse[icount]) icount = 1000;
      } while (icount >= 1000);

      for(y = (no_verses - 1); y > 0; y--) {
         old_verse[y] = old_verse[y - 1];
      }

      old_verse[0] = cur_verse;
      read_JPEG_file(cur_verse, 1);
      centre_x = (800 - width) / 2;
      centre_y = (600 - height) / 2;

      if(x < 9) z = 3;
           else z = x;

      y = x       % 3 - 1; x1 = y * (400 - (z * 27));
      y = (x / 3) % 3 - 1; y1 = y * (300 - (z * 20));

      bli(curpic, buff, 0, 0, centre_x + random() % 50 - 25 + x1, centre_y + random() % 50 - 25 + y1, width, height);
      cprintf("*");
   }

   save_pcx("wallpap.pcx", buff,  pal);
   exit(0);
}

void help ()
{
   FILE *fp;
   int x, y, z, ret = 0, line_no = 0, no_lines = 0;
   char helpfile[300][100];

   if(ifreq) tfreq = ifreq;
   ifreq = 0;
   icount = 9992;

   fp = fopen("honey.txt", "r");
   while(!feof(fp)) {
      fgets(helpfile[no_lines], 99, fp);
      no_lines++;
   }
   fclose(fp);
   bli(buff, old_buff, 0, 100, 0, 100, 800, 400);
   wind(70, 170, 729, 470, "HELP - viewing file honey.txt", "Use the UP & DOWN arrows, and PGUP & PGDN keys");
   bli(buff, old_buff, 20, 199, 20, 199, 760, 252);
   title_hook = 1;
   while(!ret) {
      if(line_no < 0) line_no = 0;
      if(line_no > no_lines - 15) line_no = no_lines - 15;
      bli(old_buff, buff, 20, 199, 20, 199, 760, 252);

      for(x = 0; x < 14; x++) {
         z = line_no + x;
         textou(buff, font, helpfile[z], 90, 205 + x * 18, 255);
      }

      bli(buff, screen, 20, 169, 20, 169, 760, 301);

      y = line_no;
      while (y == line_no && !ret) {
         if(key[KEY_ESC] || key[KEY_ENTER]) ret = 1;
         else if(key[KEY_DOWN]) line_no++;
         else if(key[KEY_UP])   line_no--;
         else if(key[KEY_PGDN]) line_no += 11;
         else if(key[KEY_PGUP]) line_no -= 11;
     }
   }

   wend(70, 170, 729, 470);
}

void fuzz_edges (void)
{
   int x, y, z, tx, ty;
   char *p;

   for(x = 0; x < 800; x += 302)
      for(y = 0; y < 600; y += 174) bli(fuzzy, buff, 0, 0, x, y, 302, 174);

   p = &buff->line[0][0];

   for(y=0; y < 600; y++) {
      for(x=0; x < 800; x++) {
         if(x > 400) tx = 799-x; else tx = x;

         if(tx < 15) {
            for(z = 0; z < 3; z++) if(random() % (((tx*tx)+2)/2) == 0) reduce(p);
         }

         if(*p) {
            if(y > 300) ty = 599-y; else ty = y;
            if(ty < 15) {
               for(z = 0; z < 3; z++) if(random() % (((ty*ty)+2)/2) == 0) reduce(p);
            }
            if(ty + tx < 13) reduce(p);
         }

         p++;
      }
   }
}

int draw_screen (void)
{
   int x, y, max_width, max_height;
   if(ceffect && !fst && cpu > 2) bli(buff, old_buff, 0, 0, 0, 0, 800, 600);

   if(!fst) {
      tcur = curpic;
      draw_hook = 1;
      del_cur = 0;
      read_JPEG_file(cur_verse, 1);
      if(draw_hook) {
         destroy_bitmap(curpic);
         del_cur      = 0;
         curpic       = tcur;
         draw_hook    = 0;
         cur_verse    = old_verse[1];
         old_verse[0] = cur_verse;
         return(0);
      }
      destroy_bitmap(tcur);
   }
   else {
      if(fst == 1) del_cur = 0;
      read_JPEG_file(cur_verse, 1);
   }

   fuzz_edges();

   x          = (800 - width)  / 2 - 5;
   y          = (600 - height) / 2 + 37;
   max_width  = width  > old_width  ? width  : old_width;
   max_height = height > old_height ? height : old_height;

   shade_rect(x + 10, y + height, x + width + 11, y + height + 11, buff);
   shade_rect(x + width, y + 10, x + width + 11, y + height, buff);
   bli(curpic, buff, 0, 0, x, y, width, height);

   if(cpu == 1) draw_rle_sprite(buff, data[title_count].dat, 100, 0);
   x = (800 - max_width) / 2 - 5;
   y = (600 - max_height) / 2 + 37;

   hline(buff, 3, 550, 796, 255);
   hline(buff, 3, 578, 796, 255);
   blue_rect(0, 551, 799, 577, buff);
   bli(buff, not, 0, 550, 0, 0, 800, 28);
   if(max_height > 420 && !fst && ceffect && cpu > 2) banner_no = ran_notes(banner_no);
   else banner_no = ran_notes(0);

   if(ceffect && !fst && cpu > 2) {
      tcur = create_bitmap(max_width + 11, max_height + 11);
      bli(buff, tcur, x, y, 0, 0, max_width+11, max_height+11);
      if(cross_fade(x, y, old_buff, tcur, max_width + 11, max_height + 11, 2)) return(0);
      destroy_bitmap(tcur);
   }

   if(fst!=1) {
      bli(buff, old_buff, 0, 0, 0, 0, 800, 600);
      draw_rle_sprite(old_buff, data[title_count].dat, 100, 0);
      title_hook = 1;
      bli(old_buff, screen, x, y, x, y, max_width + 11, max_height + 11);
      bli(old_buff, screen, 10, 551, 10, 551, 780, 27);
   }

   fst = 0;
   old_width = width; old_height = height;
   return(0);
}

void IncrementTimer ()
{
	timer++;
}

END_OF_FUNCTION (IncrementTimer);

void back_pic (void)
{
   int i, p_verse;
   p_verse = cur_verse;
   while(p_verse == cur_verse) {
      i = random() % 8;
      if(!i) cur_verse = 16;
      else if(i == 1) cur_verse = 18;
      else if(i == 2) cur_verse = 22;
      else if(i == 3) cur_verse = 36;
      else if(i == 4) cur_verse = 44;
      else if(i == 5) cur_verse = 35;
      else if(i == 6) cur_verse = 25;
      else if(i == 7) cur_verse = 19;
   }
   read_JPEG_file(cur_verse, 1);
   stretch_blit(curpic, tet_back, 0, 0, width, height, 0, 0, 200, 400);
}


void ClearBlock (void)
{
   int i, j;

   for (i = 0; i < 4; i++)
      for (j = 0; j < 4; j++)
         block[i][j] = 0;
}

void GenerateBlock (int kind)
{
	ClearBlock ();
	switch (kind) {
	case 1:
        case 21:
		block[1][0] = block[2][0] = block[0][1] = block[1][1] = 1;
		break;

	case 11:
	case 31:
		block[0][0] = block[0][1] = block[1][1] = block[1][2] = 1;
		break;

	case 2:
	case 22:
		block[0][0] = block[1][0] = block[1][1] = block[2][1] = 2;
		break;

	case 12:
	case 32:
		block[1][0] = block[1][1] = block[0][1] = block[0][2] = 2;
		break;

	case 3:
	case 13:
	case 23:
	case 33:
		block[0][0] = block[0][1] = block[1][0] = block[1][1] = 3;
		break;

	case 4:
		block[1][0] = block[0][1] = block[1][1] = block[2][1] = 4;
		break;
	case 14:
		block[0][0] = block[0][1] = block[0][2] = block[1][1] = 4;
		break;
	case 24:
		block[0][0] = block[1][0] = block[2][0] = block[1][1] = 4;
		break;
	case 34:
		block[0][1] = block[1][0] = block[1][1] = block[1][2] = 4;
		break;

	case 5:
		block[2][0] = block[0][1] = block[1][1] = block[2][1] = 5;
		break;
	case 15:
		block[0][0] = block[0][1] = block[0][2] = block[1][2] = 5;
		break;
	case 25:
		block[0][0] = block[1][0] = block[2][0] = block[0][1] = 5;
		break;
	case 35:
		block[0][0] = block[1][0] = block[1][1] = block[1][2] = 5;
		break;

	case 6:
		block[0][0] = block[0][1] = block[1][1] = block[2][1] = 6;
		break;
	case 16:
		block[0][0] = block[1][0] = block[0][1] = block[0][2] = 6;
		break;
	case 26:
		block[0][0] = block[1][0] = block[2][0] = block[2][1] = 6;
		break;
	case 36:
		block[1][0] = block[1][1] = block[1][2] = block[0][2] = 6;
		break;

	case 7:
	case 27:
		x_size = 4;
		y_size = 1;
		block[0][0] = block[1][0] = block[2][0] = block[3][0] = 7;
		break;

	case 17:
	case 37:
		x_size = 1;
		y_size = 4;
		block[0][0] = block[0][1] = block[0][2] = block[0][3] = 7;
		break;
	}

        if (kind % 10 == 3) {
		x_size = 2;
		y_size = 2;
	}
	else if ((kind / 10 == 0) || (kind / 10 == 2)) {
		x_size = 3;
		y_size = 2;
	}
	else if ((kind / 10 == 1) || (kind / 10 == 3)) {
		x_size = 2;
		y_size = 3;
	}
	current_block = kind;
}

int can_put (void)
{
   int i, j;
   for (i = 0; i < 4; i++) {
      for (j = 0; j < 4; j++) {
         if (block[i][j] != 0) {
            if (block_x + i > 9)  return FALSE;
            if (block_x + i < 0)  return FALSE;
            if (block_y + j > 19) return FALSE;
            if (map[block_x + i][block_y + j] != 0) return FALSE;
         }
      }
   }
   return TRUE;
}

int generate_new (void)
{
   int temp, i, j;
   BITMAP *empty;

   empty = create_bitmap(20, 20);
   clear_to_color(empty, 4);

   temp       = next_block;
   next_block = random() % 7 + 1;
   GenerateBlock (next_block);

   for (i = 0; i < 4; i++) {
      for (j = 0; j < 2; j++) {
         if (block[i][j] != 0)
            draw_spr(screen, data[block[i][j]+22].dat, 470 + i * 20, 185 + j * 20);
         else
            draw_spr(screen, empty, 470 + i * 20, 185 + j * 20);
      }
   }

   GenerateBlock (temp);
   block_x = 3;
   block_y = 0;

   if (!can_put ()) return(1);

   destroy_bitmap(empty);
   return(0);
}

void rotate_block (void)
{
   int old_block = current_block;
   current_block += 10;
   if (current_block > 40)
      current_block -= 40;
   GenerateBlock (current_block);

   if (!can_put ()) {
      current_block = old_block;
      GenerateBlock (current_block);
   }
}

void draw_map (void)
{
   int i, j;
   if(prev_level != (int) dels / 10) {
      prev_level = (int) dels / 10;
      sprintf(text, "Level: %d", prev_level+1);
      textout_centre(screen, cfont->dat, text, 320, 260, -1);
      back_pic();
   }

   bli(tet_back, old_buff, 0, 0, 0, 0, 200, 400);

   for (i = 0; i < 10; i++) {
      for (j = 0; j < 20; j++) {
         if (map[i][j] != 0)
            draw_spr(old_buff, data[map[i][j]+22].dat, i * 20, j * 20);
      }
   }

   for (i = 0; i < 4; i++) {
      for (j = 0; j < 4; j++) {
         if (block[i][j] != 0)
               draw_spr(old_buff, data[block[i][j] + 22].dat, block_x * 20 + i * 20, block_y * 20 + j * 20);
      }
   }

   bli(old_buff, screen, 0, 0, 240, 145, 200, 400);
   text_mode(0);

   sprintf(text, "%d", score);
   textou(screen, cfont->dat, text, 470, 255, -1);
   rectfill(screen, 470 + text_length (cfont->dat, text), 255, 550, 281, 4);

   sprintf(text, "%d", dels / 10 + 1);
   textou(screen, cfont->dat, text, 470, 315, -1);
   rectfill(screen, 470 + text_length (cfont->dat, text), 315, 550, 341, 4);

   sprintf(text, "%d", hiscore);
   textou(screen, cfont->dat, text, 470, 375, -1);
   rectfill(screen, 470 + text_length (cfont->dat, text), 375, 550, 401, 4);

   text_mode(-1);
}

void delete_row (void)
{
   int sum, i, j, k, del = 0;
   for (i = 19; i >= 0; i--) {
      sum = 0;
      for (j = 0; j < 10; j++) {
         if (map[j][i] != 0) sum++;
      }

      if (sum == 10) {
         for (j = i; j >= 1; j--)
            for (k = 0; k < 10; k++)
               map[k][j] = map[k][j - 1];
         i += 2;
         del++;
      }
   }

   dels += del;

   if(l1_rep > 0 && del > 0) {dels -= del; l1_rep--;}
   if(del > 0) score += (100 * del) + ((del - 1) * 25) + (dels / 10) * 50;

   speed = 25 - (dels / 10) * 2;
   if(speed < 2) speed = 2;
}

void put_block (void)
{
   int i, j;

   for (i = 0; i < 4; i++) {
      for (j = 0; j < 4; j++) {
         if (block[i][j] != 0)
            map[block_x + i][block_y + j] = block[i][j];
      }
   }
   delete_row ();
}

void new_game (void)
{
   int i, j;

   for (i = 0; i < 20; i++)
      for (j = 0; j < 10; j++)
         map[j][i] = 0;

   score      = 0;
   l1_rep     = 10 + start_level * 2;
   next_block = random() % 7 + 1;

   clear(thumb[0]);
   textou(thumb[0], cfont->dat, "Next Block:", 0, 0, -1);
   rem_redgr(thumb[0], text_length(cfont->dat, "Next Block:"), 25, 3);
   draw_spr(screen, thumb[0], 470, 155);

   clear(thumb[0]);
   textou(thumb[0], cfont->dat, "Score:", 0, 0, -1);
   rem_redgr(thumb[0], text_length(cfont->dat, "Score:"), 25, 3);
   draw_spr(screen, thumb[0], 470, 225);

   clear(thumb[0]);
   textou(thumb[0], cfont->dat, "Level:", 0, 0, -1);
   rem_redgr(thumb[0], text_length(cfont->dat, "Level:"), 25, 3);
   draw_spr(screen, thumb[0], 470, 285);

   clear(thumb[0]);
   textou(thumb[0], cfont->dat, "High Score:", 0, 0, -1);
   rem_redgr(thumb[0], text_length(cfont->dat, "High Score:"), 25, 3);
   draw_spr(screen, thumb[0], 470, 345);

   generate_new ();
   draw_map ();
   speed = 25 - (dels / 10) * 2;

   timer = 0;
}



void play_game (void)
{
   int ch, space_on = 0;

   new_game ();

   while (1 == 1) {
      if (keypressed()) {
         ch = readkey();

         if (((ch >> 8) == KEY_SPACE) || ((ch >> 8) == KEY_ENTER)) space_on = 1;

         if ((ch >> 8) == KEY_LEFT) {
            block_x--;
            if (!can_put()) block_x++;
            space_on = 0;
         }

         if ((ch >> 8) == KEY_RIGHT) {
            block_x++;
            if (!can_put ()) block_x--;
            space_on = 0;
         }

         if (((ch >> 8) == KEY_UP) || ((ch >> 8) == KEY_5_PAD)) {
            rotate_block ();
            space_on = 0;
         }

         if ((ch >> 8) == KEY_DOWN) {
            if (can_put()) {
               draw_map();
               block_y++;
            }
            if (!can_put()) block_y--;
            clear_keybuf();
            space_on = 0;
         }

         if ((ch >> 8) == KEY_R) new_game ();

         else if ((ch >> 8) == KEY_ESC) break;

         else if ((ch >> 8) == KEY_P) {
            textout_centre(screen, cfont->dat, "Paused", 320, 260, -1);
            clear_keybuf();
            ch = readkey();
         }

         else if(ch >> 8 == KEY_F9) {
            if(!music_off) {
               MD_PlayStop();
               music_off = 1;
            }
            else {
               if(mp_loop != 1) my_load_mod();
               else MD_PlayStart();
               music_off = 0;
            }
         }

         clear_keybuf ();
      }

      if (timer > speed || space_on) {
         block_y++;
         if (!can_put()) {
            block_y--;
            put_block();
            if(generate_new()) goto outtahere;
            space_on = 0;
         }
         timer = 0;
      }
      if (!can_put()) {
         put_block();
         generate_new();
      }
      draw_map();
   }

outtahere:
}


void tetris (int s_level)
{
   int t_verse;
   FILE *file;

   if(ifreq) tfreq = ifreq;
   ifreq = 0;
   icount = 9995;
   t_verse = cur_verse;
   timer = 0;
   tetris_start = 0;
   LOCK_VARIABLE(timer);
   LOCK_FUNCTION(IncrementTimer);
   install_int  (IncrementTimer, 20);

   start_level = s_level;
   dels        = start_level * 10;
   prev_level  = start_level;

   thumb[0]    = create_bitmap(200, 200);
   tet_back    = create_bitmap(200, 400);
   tcurpic     = curpic;
   del_cur     = 0;

   bli(buff, old_buff, 200, 100, 200, 100, 400, 465);

   if(cur_verse == 16 || cur_verse == 18 || cur_verse == 22 || cur_verse == 36 ||
      cur_verse == 44 || cur_verse == 35 || cur_verse == 25 || cur_verse == 19)
         stretch_blit(tcurpic, tet_back, 0, 0, old_width, old_height, 0, 0, 200, 400);
   else back_pic();

   wind (210, 110, 590, 555, "TETRIS", "Use the ARROWS to move and rotate, SPACE to move to bottom, P to pause, and R to restart");

   title_hook = 1;
   bli(buff, screen, 210, 110, 210, 110, 380, 445);

   while(start_level < 9) {
      play_game();

      if(score > hiscore) {
         hiscore = score;
         file = fopen("honey.d01", "r+b");
         putc(cpu, file);
         putw(hiscore, file);
         fclose(file);
      }

      bli(tnot, buff, 0, 0, 210, 110, 380, 29);
      sprintf(text, "GAME OVER, press level no. to restart or ESC");
      textout_centre(buff, cfont->dat, text, 400, 115, -1);
      bli(buff, screen, 210, 110, 210, 110, 380, 29);
      title_hook  = 1;
      start_level = 99;
      clear_keybuf();

      while(start_level > 10) start_level = readkey() >> 8;

      if(start_level != 1) {
         start_level -= 2;
         timer = 0;
         dels = start_level * 10;
         prev_level = start_level;
 
         bli(tnot, buff, 0, 0, 210, 110, 380, 29);
         sprintf(text, "TETRIS");
         textout_centre(buff, cfont->dat, text, 400, 115, -1);
         bli(buff, screen, 210, 110, 210, 110, 380, 29);
         title_hook  = 1;
      }
      else start_level = 100;
   }

   destroy_bitmap(tnot);
   destroy_bitmap(tet_back);
   destroy_bitmap(thumb[0]);

   clear_keybuf();

   cur_verse = t_verse;
   curpic    = tcurpic;
   remove_int(IncrementTimer);
   wend (210, 110, 590, 555);
}

void check_param (char *p)
{
   int x, y;
   char *q;
   q = p;
   if(*p == 45) *p = 47;

   while(*p) {
      if(*p > 96 && *p < 123) *p -= 32;
      p++;
   }

   if(strstr(q, "/M")) {
      p = strstr(q, "/M");
      p++; p++;
      if(*p == '0') music_off = 1;
      else {
         strcpy(mod_file_name, p);
         mod_chosen = 1;
      }
   }

   if(strstr(q, "/Q")) quex = 1;

   if(strstr(q, "/N")) ordered = no_verses - 1;

   if(strstr(q, "/B")) {
      p = strstr(q, "/B");
      p++; p++;
      if(*p >= '0' && *p <= '9') cur_verse = *p - 14;
      else if(*p >= 'a' && *p <= 'z') cur_verse = *p - 89;
      else if(*p >= 'A' && *p <= 'Z') cur_verse = *p - 57;
      else if(*p =='^') {
         p++;
         if(*p >= 'A' && *p <= 'Z') cur_verse = *p - 21;
      }
      if(cur_verse > no_verses + 8) cur_verse = random() % no_verses + 8;
      for(y = 0; y < no_verses - 1; y++) old_verse[y] = cur_verse;
   }

   if(strstr(q, "/A")) {
      if(key[KEY_LSHIFT] || key[KEY_RSHIFT]) exit(0);
      read_JPEG_file(cur_verse, 7);
      if (screen_change) if (set_gfx_mode(screen_change,  640, 480, 0, 0) != 0) screen_change=0;
      if(!screen_change) if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0) != 0) {
         allegro_exit();
         printf("Unsupported graphics card or card does not support 640x480, 256 colour SVGA\n\n");
         exit(1);
      }

      set_pallete(black_pallete);
      bli(curpic, screen, 0, 0, (640-width)/2, (480-height)/2, width, height);
      fade_in(nice, 8);
      clear_keybuf();
      y = 0; x = 0;

      do {
         while((!keypressed() && y < 10) || x==1) {
            y++;
            rest(400);
            if(key[KEY_F10] && x) x= 2;
         }

         if(key[KEY_F2]) save_pcx("picshot.pcx", curpic, nice);
         if(key[KEY_F10] && !x) x = 1;

      } while(key[KEY_F10] && x != 2);

      quit_honey(8);
   }

   if(strstr(q, "/W")) create_wall();

   if(strstr(q, "/D")) {
      if(strstr(q, "VESA1"))    screen_change =  3;
      if(strstr(q, "VESA2B"))   screen_change =  4;
      if(strstr(q, "CIRRUS64")) screen_change = 10;
      if(strstr(q, "CIRRUS54")) screen_change = 11;
      if(strstr(q, "S3"))       screen_change = 12;
      if(strstr(q, "TRIDENT"))  screen_change = 13;
      if(strstr(q, "ET3000"))   screen_change = 14;
      if(strstr(q, "ET4000"))   screen_change = 15;
   }

   if(strstr(q, "/?") || strstr(q, "/H")) {
      fstuff();
      if((mydata = my_load(f, 2)) == NULL) dataerr();
      puttext(1, 1, 80, 24, mydata->dat);
      gotoxy(1, 24);
      exit(0);
   }

   if(strstr(q, "/S")) new_setup();

   if(strstr(q, "/T")) tetris_start = 1;
   if(strstr(q, "/P")) puzzle_start = 1;
} 

void main (int argc, char *argv[])
{
   int x, y;
   unsigned char t;
   FILE *infile;

   x = time(0); srandom(x);
   cur_verse = random() % no_verses + 8;
   title_count = random() % 19;

   allegro_init();
   install_keyboard();
   install_timer();

   cinfo.err = jpeg_std_error(&jerr);
   jpeg_create_decompress(&cinfo);

   buff  = create_bitmap(800, 600);
   fuzzy = create_bitmap(302, 174);
   clear(buff);
   mp_loop = 0;

   for(x = 1; x < argc; x++) check_param(argv[x]);
   for(x = 0; x < 60; x++) old_verse[x]=cur_verse;
   f = pack_fopen("honey.dat", F_READ_PACKED);

   if((infile = fopen("honey.d01", "rb")) == NULL)
      new_setup();
   else {
      cpu = getc(infile);
      hiscore = getw(infile);
      no_verses = getw(infile);
      fclose(infile);
   }
   init_screen();

   draw_rle_sprite(screen, &intro, 237, 164);
   fade_in(z_intropal, 16);

   load_d02_pics();

   not         = create_bitmap(800, 28);
   title_back  = create_bitmap(580, 120);
   title_back2 = create_bitmap(580, 120);
   old_buff    = create_bitmap(800, 600);
   text_mode(-1);

   fstuff();

   if((cfont = my_load(f, 3)) == NULL) dataerr();

   pre_no = 7;

   draw_screen();
   fade_out(4);
   bli(buff, screen, 0, 0, 0, 0, 800, 600);

   set_cpu();

   LOCK_VARIABLE(title_count);  LOCK_VARIABLE(buff); LOCK_VARIABLE(sec);
   LOCK_VARIABLE(cur_verse);    LOCK_VARIABLE(cred); LOCK_VARIABLE(ifreq);
   LOCK_VARIABLE(title_back);   LOCK_VARIABLE(min);  LOCK_VARIABLE(icount);
   LOCK_FUNCTION(change_verse); LOCK_FUNCTION(move_credits);

   install_int(change_verse, 200);

   fade_in(pal, 4);

   load_d02_map();
   if(!music_off) my_load_mod();

   while(!key[KEY_ESC]) {
      if(tetris_start)                  tetris(1);
      else if(puzzle_start)             puzzle(4);
      if(keypressed()) {
         x=readkey();
              if(x >> 8 == KEY_ESC)     exit_honey();            
         else if(x >> 8 == KEY_ENTER)   browse();
         else if(x >> 8 == KEY_SPACE)   browse_words();

         else if(x >> 8 >= KEY_F3 && x >> 8 <= KEY_F7)
                                        puzzle((x >> 8) - KEY_F3 + 3);

         else if(x >= (KEY_1 << 8) && x <= (KEY_9 << 8))
                                        tetris((x - (KEY_1 << 8)) / 256);
                                       
         else if(x >> 8 == KEY_F1)      help();

         else if(x >> 8 == KEY_F9) {
            if(!music_off) {
               MD_PlayStop();
               music_off = 1;
            }
            else {
               if(mp_loop != 1) my_load_mod();
               else MD_PlayStart();
               music_off = 0;
            }
            rest(200);
         }

         else if(x >> 8 == KEY_F2) {
            bli(buff, old_buff, 0, 0, 0, 0, 800, 600);
            draw_rle_sprite(old_buff, data[title_count].dat, 100, 0);
            save_pcx("scrshot.pcx", old_buff, pal);
            tfreq  = ifreq;
            ifreq  = 0;
            sprintf(text, "Screen saved to SCRSHOT.PCX");
            notes(text);
            ifreq  = tfreq;
         }
         else if(x >> 8 == KEY_UP && ifreq > 10) {
            ifreq -= 5;
            tfreq  = ifreq;
            ifreq  = 0;
            sprintf(text, "Time between verses = %d seconds", tfreq/5);
            notes(text);
            ifreq  = tfreq;
         }

         else if(x >> 8 == KEY_DOWN && ifreq < 1000 && ifreq) {
            ifreq += 5;
            tfreq  = ifreq;
            ifreq  = 0;
            sprintf(text, "Time between verses = %d seconds", tfreq / 5);
            notes(text);
            ifreq  = tfreq;
         }

         else if(x >> 8 == KEY_F10) {
            if(ifreq) {
               tfreq   = ifreq;
               ifreq   = 0;
               icount  = 0;
               sprintf(text, "Verse paused - press F10 again to unpause");
               notes(text);
            }
            else {
               ran_notes(0);
               ifreq = tfreq;
            }
         }

         else {  
            t = (x & 0xff);
            if(t > '0' && t <= '9') cur_verse = t - 14;
            else if(t >= 'a' && t <= 'z') cur_verse = t - 89;
            else if(t >= 'A' && t <= 'Z') cur_verse = t - 21;
            if(cur_verse > no_verses + 7) cur_verse = old_verse[0];
         }                                                
      }

      else if(key[KEY_F8]) {
         infile = fopen("temp.jpg","wb");
         if(cur_verse > 47) {
            pack_fclose(f);
            f = pack_fopen("honey.add", F_READ_PACKED);
            pack_fseek(f, 8);
            if((mydata = my_load(f, cur_verse - 48)) == NULL) dataerr();
         }
         else {
            fstuff();
            if((mydata = my_load(f, cur_verse - 4)) == NULL) dataerr();
         }
         fwrite(mydata->dat, mydata->size, 1, infile);
         unload_datafile_object(mydata);
         fclose(infile);
         pre_no = 1000;

         tfreq  = ifreq;
         ifreq  = 0;
         sprintf(text, "Picture saved to TEMP.JPG");
         notes(text);
         ifreq  = tfreq;
      }

      if((cur_verse != old_verse[0]) || (fst == 2)) {
         icount = 0;
         for(y = (ordered - 1); y > 0; y --) {    
            old_verse[y] = old_verse[y-1]; 
         }
         old_verse[0] = cur_verse;
         draw_screen();         
      }
   }

   exit_honey();
}
