#define INCL_DOS
#define INCL_VIO
#define INCL_KBD
#include <os2.h>

#include <stdlib.h>
#include <time.h>

// Color attributes for foreground text

#define FG_BLACK                   0
#define FG_BLUE                    1
#define FG_GREEN                   2
#define FG_CYAN                    3
#define FG_RED                     4
#define FG_MAGENTA                 5
#define FG_BROWN                   6
#define FG_LIGHTGREY               7
#define FG_DARKGREY                8
#define FG_LIGHTBLUE               9
#define FG_LIGHTGREEN             10
#define FG_LIGHTCYAN              11
#define FG_LIGHTRED               12
#define FG_LIGHTMAGENTA           13
#define FG_YELLOW                 14
#define FG_WHITE                  15
#define FG_BLINK                0x80

// Color attributes for text background

#define BG_BLACK                0x00
#define BG_BLUE                 0x10
#define BG_GREEN                0x20
#define BG_CYAN                 0x30
#define BG_RED                  0x40
#define BG_MAGENTA              0x50
#define BG_BROWN                0x60
#define BG_LIGHTGREY            0x70

// Monochrome attributes for foreground text

#define FG_UNDERLINE            0x01
#define FG_INTENSE              0x08

// Monochrome attributes for text background

#define BG_INTENSE              0x10

// ----------------------------------------------------------------------------

#define NUM_STARS	50

static void set( int x, int y, char ch, unsigned short attr )
{
  unsigned short out( (attr<<8) | ch );

  Vio16WrtCellStr( (PCH)&out, 2, y, x, 0 );
}

static void fillw( unsigned short attr, char ch, int x, int y, int len )
{
  unsigned short out( (attr<<8) | ch );

  Vio16WrtNCell( (PCH)&out, len, y, x, 0 );
}

struct scr_stat
{
  int xsize;
  int ysize;
};

static int scrn_blanked;
static scr_stat *scp;

void __cdecl star_saver_step()
{
  int cell;
  static char pattern[]( "...........++++***   " );
  static char colors[] = { FG_DARKGREY, FG_LIGHTGREY,
                           FG_WHITE, FG_LIGHTCYAN};
  static unsigned short stars[NUM_STARS][2];

  if( scrn_blanked <= 0 )
  {
    fillw( FG_LIGHTGREY|BG_BLACK, 0x20, 0, 0, scp->xsize * scp->ysize );
    scrn_blanked = 1;

    for( int i(0); i<NUM_STARS; i++ )
    {
      stars[i][0] = rand() % (scp->xsize*scp->ysize);
      stars[i][1] = 0;
    }
  }

  cell = rand() % NUM_STARS;

  set( stars[cell][0]%scp->xsize, stars[cell][0]/scp->xsize,
       pattern[ stars[cell][1] ], colors[rand()%sizeof(colors)] );

  if( (stars[cell][1]+=(rand()%4)) >= sizeof(pattern)-1 )
  {
    stars[cell][0] = rand() % (scp->xsize*scp->ysize);
    stars[cell][1] = 0;
  }
}

void __cdecl star_saver_load( scr_stat *sc )
{
  srand( time(0) );
  scrn_blanked = 0;
  scp = sc;
}

void __cdecl star_saver_unload()
{
  scrn_blanked = 0;
}

#ifdef TEST

static int kbhit( void )
{
  KBDKEYINFO k;
  APIRET16 ret = KbdPeek( &k, 0 );

  return ret ? 0 : k.fbStatus & KBDTRF_FINAL_CHAR_IN;;
}

void main()
{
  scr_stat scp = { 80, 25 };

  star_saver_load( &scp );

  while( !kbhit() )
  {
    star_saver_step();
    DosSleep( 1 );
  }

  star_saver_unload();
}

#endif