/* Simple ASCII demo for deadline
 * Thrown together in a couple of hours.
 * By the Introx team 2005 
 * 
 *
 * TODO:
 *       Optimise. Gagh too fucking lazy.
 *
 *
 * */

#include "main.h"
#define MAINTEXT "             HELLO SCENERS AND SCENERETTES!       INTROX BRINGS YOU THIS SIMPLE 48K ASCII DEMO, THROWN TOGETHER IN A FEW HOURS...   SO, WHAT DID YOU THINK ABOUT PSILODUMPS PERFORMANCE YESTERDAY?    GREAT SHIT, IF YOU ASK ME!   IT'S ALWAYS FUN TO WATCH DRUNKEN SCENERS SHARE THEIR LOVE ON THE DANCEFLOOR!  SO WHAT REALLY HAPPENED? FINNS VISITED THE PARTY, PSILODUMP ROCKED THE DANCEFLOOR, BEER FLOWED LIKE THE GREAT FALLS AND EVERYONE SEEMS TO HAVE HAD A GREAT TIME!  NOW LETS GET ON WITH THE CREDS AND GREETS SO WE CAN WATCH/HEAR THE REST OF THE COMPOS!    CODE: GAMKILLER, FREDD#                GUEST MUSIC:         CRAZY Q#        GREETS: THE ENTIRE DEADLINE CREW, EVERYONE AT DEADLINE (ESPECIALLY MARVIN, NICON, ZIBO, KALASPUFF, LEO, THEO, CAR BICYCLE REHEATED PEPSI SAUSAGE) AND YOU!       BRING ON THE OTHER COMPOS!!                 \0"

FMUSIC_MODULE *tuneptr;

void clipmvaddch(int y, int x, int c){
  if(x < 80)
    mvaddch(y, x, c);
}

int main(int argc, char **argv){
  
  short running;
  short fademusic;

  /* Spectrum code */
  float *dspspect;
  int curval;
  int cline;
  int spectrumcolor[40];
  
  /* Timer code */
  struct timeval tv;
  float time_start;
  float time_stop;
  int frames;
  float ctime;
  int goslow;
  
  /* snake */
  typedef struct snakeEx{
    int x;
    int y;
  } snake;
  
  snake destination;
  snake position[55];
  snake move;
  int score;
  int delay;
  int delaycount;
  int length;
  
  /* scroller */
  char textbuffer[17];
  int sintable[80];
  int costable[80];
  short scrollpause;
  
  /* plasma */
  float si, siv;
  float sa, sav;
  float sm, smv;
  int c;
  int plasmalookup[256];

  /* scroller */
  int loffsetx;
  int clipx, clipy;
  int xoffset;
  int textscroll;
  int letter;
  double sinemove;
  double sinemovef;
  chtype byte;

  int i;

  printf("Hold on, loading..\n");
  initncurses();
  start_color();
  
  initgfx();

  srand(time(NULL));
  
  /* Initialise snake */
  length = 5;
  destination.x = 40;
  destination.y = 12;
  for(i = 0; i < length; i++){
    position[i].x = 10;
    position[i].y = 20;
  }
  score = 0;
  delay = 2;
  delaycount = 0;
  
  /* Initialise textscroller */
  bzero(textbuffer, 17);
  strncpy(textbuffer, MAINTEXT, 17);
  loffsetx = 0;
  xoffset = 0;
  textscroll = 0;
  sinemove = 0;
  sinemovef = 1;
  scrollpause = 0;

  /* Initialise plasma */
  si = 40;
  siv= 0.05;
  sa = 0;
  sav= 0.05;
  sm = 5;
  smv= 0.001;
  c = 0;
  for(c = 0; c < 255; c++)
    plasmalookup[c] = (c % 93) + 33;

  /* Initialise fmod and stuff */
  if(initfmod(argv[0]) == -1){
    refresh();
    sleep(5);
    endwin();
    exit(1);
  }
    
  /* Initialise colors */
  init_pair(1, COLOR_BLUE, COLOR_BLACK);
  init_pair(2, COLOR_BLACK, COLOR_GREEN);  

  init_pair(3, COLOR_BLACK, COLOR_RED);
  init_pair(4, COLOR_BLACK, COLOR_CYAN);
  init_pair(5, COLOR_BLACK, COLOR_MAGENTA);
  init_pair(6, COLOR_BLACK, COLOR_YELLOW);
  init_pair(7, COLOR_BLACK, COLOR_WHITE);
  init_pair(8, COLOR_GREEN, COLOR_BLACK);

  /* Initialise timer */
  frames = 0;
  time_start = 0;
  time_stop = 0;
  ctime = 0;
  goslow = 1;

  /* Initialise spectrum */
  dspspect = FSOUND_DSP_GetSpectrum();
  for(i = 0; i < 10; i++){
    spectrumcolor[i] = 3;
  }
  for(i = 10; i < 20; i++){
    spectrumcolor[i] = 5;
  }
  for(i = 20; i < 30; i++){
    spectrumcolor[i] = 6;
  }
  for(i = 30; i < 40; i++){
    spectrumcolor[i] = 4;
  }
  
  refresh();
  sleep(1);
      
  FMUSIC_PlaySong(tuneptr);

  gettimeofday(&tv, 0);
  time_start = tv.tv_usec;

  running = 1;
  fademusic = 0;

  /* Main loop */
  while(running){
        
    if(getch() == 27)
      running = 0;
    /*erase();*/
    
    /* Plasma */
    attron(COLOR_PAIR(1)|A_BOLD); /* |A_BOLD for projector. Otherwise, remove */
    for(clipx = 0; clipx < 80; clipx++){
      for(clipy = 0; clipy < 25; clipy++){
	/* EEEWWWWWW */
	c = (int)sm*(sa*cos((clipx+si)/25)+cos((clipy+si)/25)+(si*cos(5/10))+cos(clipx/(si*0.7)+20)+15*cos(si/30)-sin((sa*si)/40));
	mvprintw(clipy, clipx, "%c", plasmalookup[c]);
      }
    }
    attroff(COLOR_PAIR(1));

    si += siv;
    if(si > 50 || si < 40)
      siv = -siv;

    sa += sav;
    if(sa>4 || sa <-4)
      sav= -sav;

    sm += smv;
    if(sm >= 5.5 || sm <= 4.5)
      smv = -smv;
    
    /* Textscroller */
    sinemovef++;
    sinemove = sinemovef;
    for(i = 0; i < 80; i++){
      sinemove+= .5;
      if(sinemove == 65){
	sinemove = 0;
	sinemovef = 0;
      }
      sintable[i] = (int) (2 * sin(sinemove/4)) +1;
      costable[i] = (int) (2 * cos(sinemove/4)) +1;
    }
      
    letter = (textbuffer[0] - 32);
    for(clipx = loffsetx; clipx < 4; clipx++){
      xoffset = clipx - loffsetx;
      for(clipy = 0; clipy < 4; clipy++){
	byte = font[letter].data[clipx+(clipy*4)];
	if(byte != 32){
	  attron(COLOR_PAIR(byte));
	  mvaddch(clipy+sintable[xoffset], xoffset, 32);
	  attroff(COLOR_PAIR(byte));
	  mvaddch(4+((4+-clipy)+costable[xoffset]), xoffset+((4+-clipy)), 32);
	}
      }
    }
    for(i = 1; i < 16; i++){
      letter = (textbuffer[i] - 32);
      for(clipx = 0; clipx < 4; clipx++){
	xoffset = clipx - loffsetx;
	for(clipy = 0; clipy < 4; clipy++){
	  byte = font[letter].data[clipx+(clipy*4)];
	  if(byte != 32){
	    attron(COLOR_PAIR(byte));
	    mvaddch(clipy+sintable[(i * 5) + xoffset], (i * 5) + xoffset, 32);
	    attroff(COLOR_PAIR(byte));
	    if(i == 15){
	      clipmvaddch(4+((4+-clipy)+costable[(i * 5) + xoffset]), (i * 5) + xoffset+((4+-clipy)), 32);
	    }else{
	      mvaddch(4+((4+-clipy)+costable[(i * 5) + xoffset]), (i * 5) + xoffset+((4+-clipy)), 32);
	    }
	  }
	}
      }
    }
    letter = (textbuffer[16] - 32);
    for(clipx = 0; clipx < 4 - (4 - loffsetx); clipx++){
      xoffset = (80 + clipx) - loffsetx;
      for(clipy = 0; clipy < 4; clipy++){
	byte = font[letter].data[clipx+(clipy*4)];
	if(byte != 32){
	  attron(COLOR_PAIR(byte));
	  mvaddch(clipy+sintable[xoffset], xoffset, 32);
	  attroff(COLOR_PAIR(byte));
	  clipmvaddch(4+((4+-clipy)+costable[xoffset]), xoffset+((4+-clipy)), 32);
	}
      }
    }

    if(scrollpause == 0){
      loffsetx++;
      if(loffsetx > 4){
	loffsetx = 0;
	textscroll++;
	if(textscroll == strlen(MAINTEXT) - 16)
	  fademusic = 1;
	if(textscroll == strlen(MAINTEXT))
	  textscroll = 0;
	for(i = 0; i < 17; i++)
	  textbuffer[i] = MAINTEXT[(i + textscroll) % strlen(MAINTEXT)];
 
	if(textbuffer[16] == 35)
	  scrollpause = 50;
      }
    }else{
      scrollpause--;
    }

    /* Snake */
    attron(COLOR_PAIR(8));
    mvprintw(destination.y, destination.x, "%d", score);
    attroff(COLOR_PAIR(8));
    attron(COLOR_PAIR(2));
    delaycount++;
    if(delaycount > delay){
      delaycount = 0;
     
      if(position[0].y == destination.y && position[0].x == destination.x){
        score++;
	for(i = length; i != (length + 5); i++){
	  position[i].x = position[i-1].x;
	  position[i].y = position[i-1].y;
	}
	length+=5;
        if(score > 9){
          score = 0;
          length = 5;
        }
        destination.x = rand()%80;
        destination.y = 8 + rand()%14;
      }
 
      if(position[0].x > destination.x){
	  move.y = 0;
	  move.x = -1;	
      }else if(position[0].x < destination.x){
	  move.y = 0;
	  move.x = 1;
      }
      if(position[0].y > destination.y){
	  move.x = 0;
	  move.y = -1;
      }else if(position[0].y < destination.y){
	  move.x = 0;
	  move.y = 1;
      }
    
      for(i = (length-1); i > 0; i--){
	position[i].x = position[i-1].x;
	position[i].y = position[i-1].y;
      }

      position[0].x += move.x;
      position[0].y += move.y;

    }
    
    for(i = 0; i < length;i++)
      mvprintw(position[i].y, position[i].x, " ");

    attroff(COLOR_PAIR(2));

    /* Spectrum */

    for(i = 0; i < 40; i++){
      attron(COLOR_PAIR(spectrumcolor[i]));
      curval = dspspect[i] * 40;
      if(curval > 15)
	curval = 15;
      for(cline = 1; cline < curval; cline++){
	mvprintw(25-cline, i, " ");
	mvprintw(25-cline, 79-i, " ");
      }
      attroff(COLOR_PAIR(spectrumcolor[i]));
    }

    if(fademusic){
      FMUSIC_SetMasterVolume(tuneptr, FMUSIC_GetMasterVolume(tuneptr) - 6);
      if(FMUSIC_GetMasterVolume(tuneptr) <= 6)
	running = 0;
    }

    refresh();

    /* Timing */
    frames++;

    if(frames == 50){
      frames = 0;    
      gettimeofday(&tv, 0);
      time_stop = tv.tv_usec;
      time_stop /= 1000000;
      time_start /= 1000000;
      ctime = time_stop-time_start;
      if(ctime < 1){
	goslow = 1;
      }else{
	goslow = 0;
      }
      
      time_stop = 0;
      gettimeofday(&tv, 0);
      time_start = tv.tv_usec;
      
    }

    if(goslow) 
      usleep(10000);
    
  }
  
  erase();
  refresh();
  endwin();

  kill_sound();
  return 0;
}
