#include <atari.h>
#include <peekpoke.h>
#include <string.h>
#define SCREEN_SIZE 40
#define RANDOM PEEK(0xD20A)
#define set_char(x,y,a) video_ptr[(x)+(y)*SCREEN_SIZE]=(a);
#define get_char(x,y) video_ptr[(x)+(y)*SCREEN_SIZE]
#define pmg_memory 0x2000
#define pmg_memory_ptr ((unsigned char *) 0x2000)
#include "atari_defs.h"
#include "sounds.h"

//2000 - 2800 - pmg
//2800 - 2c00 - na razie znakis


unsigned char *video_ptr,*dl_ptr;

unsigned char slow1,slow2,antic;
unsigned char q,w,pom1,pom2,pom3,pom4;
unsigned char joy,fire;
unsigned char position,pospom;
unsigned long score,scorepom;

unsigned char lvtx[5]={44,37,54,37,44};
unsigned char mvtx[5]={45,47,54,37,51};
unsigned char sctx[5]={51,35,47,50,37};
unsigned char sltx[6]={51,37,44,37,35,52};
unsigned char yotx[3]={57,44,53};
unsigned char yrtx[4]={57,44,53,50};
unsigned char watx[5]={57,33,46,46,33};
unsigned char sttx[5]={51,52,33,50,52};
unsigned char frtx[4]={38,50,47,45};
unsigned char ortx[8]={47,50,36,37,50,0,41,52};
unsigned char eltx[8]={37,44,37,45,37,46,52,51};
unsigned char grtx[17]={39,50,58,57,34,51,47,46,41,33,36,33,0,18,16,17,18};
unsigned char gatx[9]={39,33,45,37,0,47,54,37,50};

unsigned char snakeOnPostion, snakeOnPositionIdx;
unsigned char snkx[36];
unsigned char snky[36];
unsigned char snakes[20];
unsigned char level_val[144];
unsigned char snkhead;
unsigned char level,levelpom,elements_lv,moves, moves2;

void init(void) {
POKE(SDMCTL,DMACTL_ENABLE_PLAYER_DMA | DMACTL_ENABLE_MISSLE_DMA | DMACTL_NORMAL_PLAYFIELD | DMACTL_SINGLE_LINE_RESOLUTION | DMACTL_DMA_FETCH_INSTRUCTION);
//POKE(PMBASE,pmg_memory/256);
// turn on PMG for players and missiles
POKE(GRACTL,PMG_PLAYERS | PMG_MISSILES);
// set PMG priority
POKE(GPRIOR,1); 
POKE(SIZEP0,0);
POKE(PMBASE,pmg_memory/256);
position = 0;
pospom=48;
POKE(COLOR0,4);
POKE(COLOR1,15);
POKE(COLOR2,8);
}

void placeText(unsigned char *text, unsigned char size, unsigned char x, unsigned char y) {

         for (q=0; q<size; ++q) {
             set_char(x+q,y,text[q]);
         }    

}         

void slow(void) {
     for (slow1=0; slow1<85; slow1++) {for (slow2=0; slow2<1; slow2++);}
     if (pospom<48+position*8) {
           memset(pmg_memory_ptr+0x700+pospom,0,6);                     
           memset(pmg_memory_ptr+0x600+pospom,0,6);
           pospom++;
           memset(pmg_memory_ptr+0x600+pospom,224,6);
           memset(pmg_memory_ptr+0x700+pospom,14,6);
        }
        if (pospom>48+position*8) {
           memset(pmg_memory_ptr+0x600+pospom,0,6);
           memset(pmg_memory_ptr+0x700+pospom,0,6);
           pospom--;
           memset(pmg_memory_ptr+0x600+pospom,224,6);
           memset(pmg_memory_ptr+0x700+pospom,14,6);
        }
        
}     

void changeSnake(unsigned char snake) {
     
     pom1=snakes[snake];
     snakes[snake]=snakeOnPostion;
     level_val[snakeOnPositionIdx]=pom1;
     //dopki nie wylosuje z puli czegos czego nie mam
     pom2=1;
     while(pom2==1) {
         pom1 = RANDOM % elements_lv;
         pom2=0;
         for (q=0; q<20; ++q) {
             if (snakes[q]==level_val[pom1]) pom2=1;
         }            
     }    
     
     snakeOnPostion = level_val[pom1];
     snakeOnPositionIdx = pom1;        
          
}     

void randomNewSnake() {
     
     pom2=1;
     while(pom2==1) {
         pom1 = RANDOM % elements_lv;
         pom2=0;
         for (q=0; q<20; ++q) {
             if (snakes[q]==level_val[pom1]) pom2=1;
         }            
     }    
     
     snakeOnPostion = level_val[pom1];
     snakeOnPositionIdx = pom1; 
     

}
     

void drawSingleSnake(unsigned char position, unsigned char snksize) {
     pom1 = snksize / 4;
     snkhead = snksize % 4;     
     for (pom2=2; pom2<pom1+2; ++pom2) {
         set_char(pom2,position,5);
     }    
     if (snkhead > 0) set_char(pom2,position,snkhead+1);            
     //if (snkhead == 0) set_char(pom2,position,4);            
}     

void clearPath(unsigned char position) {
     for (q=0; q<39; ++q) set_char(q,position,0);
}     

void initLevel(void) {
     
     
     ++level;
     if (level==0) level=1; //po przekręceniu licznika
     levelpom=level;
     if (levelpom>13) levelpom=13;
     
     //init snakes from 1 to 144
     for (q=0; q<144; q++) {
         level_val[q]=q+1;
     }    
     
     moves = 100 - (levelpom-1)*6;

     //hash :)     
     elements_lv = 144 - (levelpom-1)*10;
     for (w=0; w<5; ++w) {
         for (q=0; q<55; q++) {
             pom1 = RANDOM % elements_lv;
             pom2 = RANDOM % elements_lv;
             pom3 = level_val[pom1];
             level_val[pom1]=level_val[pom2];
             level_val[pom2]=pom3;
         }
     }
     
     for (q=0; q<20; q++) {
         snakes[q]=level_val[q];
     }    
     
     pom2=1;
     while(pom2==1) {
         pom1 = RANDOM % elements_lv;
         pom2=0;
         for (q=0; q<20; ++q) {
             if (snakes[q]==level_val[pom1]) pom2=1;
         }            
     }    
     
     snakeOnPostion = level_val[pom1];
     snakeOnPositionIdx = pom1;
     
}     

unsigned char checkOrder(void) {

     for (q=0; q<19; q++) {
         if (snakes[q]>snakes[q+1]) {
            return 0;
         }
     }    
     return 1;
     
}     


void snakeUp(unsigned char snake) {

  pom1 = snakes[snake] / 4;
  pom2 = snakes[snake] % 4;
  if (pom2>0) {set_char(pom1,23,5); ++pom1;  }

  //lewo
  pom2=0;
  for (q=pom1; q<40; ++q) {
      if (q<39) set_char(q,23,5);
      if (q==39) set_char(q,23,8);
      set_char(pom2,23,0);
      ++pom2;
     slow(); 
  }
  
  
  //up
  pom3=23;
  while (pom2<39 && (pom3>snake+2)) {
        pom3--;
        set_char(pom2,23,0);
        if (pom3>snake+2) set_char(39,pom3,7);       
        if (pom3==snake+2) set_char(39,pom3,6);   
        pom2++;
        slow();
  }
        
  
  while (pom3>snake+2) {
        --pom3;
        set_char(39,pom3+pom1,0);
        if (pom3>snake+2) set_char(39,pom3,7);       
        if (pom3==snake+2) set_char(39,pom3,6);       
        slow();
  }
  
  pom4=39;             
  pom3=0;
  while (pom2<39 && pom4>2) {
       set_char(pom2,23,0);
       ++pom2;
       --pom4;
       pom3++;
       set_char(pom4, snake +2 ,5);
       slow();
  }           
  
          
  pom2=pom1-pom3;        
  while (pom2>0 && pom4>2) {
        --pom4;
        --pom2;
        set_char(39,pom2+snake+2,0); 
        set_char(pom4, snake+2 ,5);
        slow();
  } 
       
  
  while (pom4>2) {
       --pom4;
       set_char(pom4+pom1,snake+2 ,0); 
       set_char(pom4, snake+2 ,5);
       slow();
  }
  
  drawSingleSnake(snake+2,snakes[snake]);
  
}     

void snakeDown(unsigned char snake) {
 
  pom1 = snakes[snake] / 4;
  pom2 = snakes[snake] % 4;
  
  
  if (pom2>0) {set_char(pom1,snake+2,5); ++pom1;  }
  //pom1 - ilosc znakow
  
  
  
  pom2=0;
  
  //lewo
  for (q=pom1; q<40; ++q) {
      
      if (q<39) set_char(q,snake+2,5);
      if (q==39) set_char(q,snake+2,6);
      set_char(pom2,snake+2,0);
      ++pom2;
     slow(); 
  }    
  
  //dol
  pom3=0;
  while (pom2<40 && (snake+2+pom3<24)) {
        pom3++;
        set_char(pom2,snake+2,0);
        set_char(39,snake+2+pom3,7);       
        pom2++;
        slow();
  }      
  
  while (pom2<40) {
      slow();  
      set_char(pom2,snake+2,0);
      pom2++;
  }       
  
  pom2=snake+3;
  while (snake+2+pom3<24) {
     pom3++;
     set_char(39,snake+2+pom3,7);
     set_char(39,pom2,0);
     pom2++;
     slow();
  }      
  
  
  while (pom2<24) {
     set_char(39,pom2,0);   
     pom2++;
     slow();
  }      
  
  
}     

placeNbr(unsigned char x, unsigned char y, unsigned char number) {
set_char(x,y,number/100 + 16);
number = number - (number/100)*100;
set_char(x+1,y,number/10 + 16);
number = number - (number/10)*10;
set_char(x+2,y,number % 10 + 16);
}                  
     
void placeScr(void) {
scorepom=score;
set_char(30,0,16);
set_char(31,0,16);
set_char(32,0,16);
set_char(33,0,scorepom/100000 + 16);
scorepom = scorepom - (scorepom/100000)*100000;
set_char(34,0,scorepom/10000 + 16);
scorepom = scorepom - (scorepom/10000)*10000;
set_char(35,0,scorepom/1000 + 16);
scorepom = scorepom - (scorepom/1000)*1000;
set_char(36,0,scorepom/100 + 16);
scorepom = scorepom - (scorepom/100)*100;
set_char(37,0,scorepom/10 + 16);
scorepom = scorepom - (scorepom/10)*10;
set_char(38,0,scorepom % 10 + 16);
}                  

     

void main(void) {

   _graphics(28);
    video_ptr=(unsigned char*)(PEEKW( PEEKW(560)+4 ));
    dl_ptr = (unsigned char*)PEEKW(560);
    POKE(dl_ptr+6,PEEK(dl_ptr+6) | 128);  
    POKEW(512,0x3000);
    POKE(0x02F4,0x0028);



    
    init();  
    
    GAME:
    for(q=0;q<255;++q) for (w=0;w<50;w++);     
    POKE(54286,64); 
    POKE(HPOSP3,0);
    POKE(HPOSP2,0);    
    memset(video_ptr,0,24*40);
    
    placeText(ortx,8,16,8);
    placeText(grtx,17,12,10);
    fire=PEEK(0x284);
    while(fire>0) {fire=PEEK(0x284);}    
    
    level=0;
    
    SDS:        
    initLevel();
    
    POKE(54286,64);            
    memset(video_ptr,0,24*40);
    
    placeText(lvtx,5,14,8);placeNbr(25,8,level);
    placeText(mvtx,5,14,10);placeNbr(25,10,moves);
    placeText(eltx,8,14,12);placeNbr(25,12,elements_lv);
    
    fire=PEEK(0x284);
    for (q=0;q<255;++q) { for (pom1=0;pom1<10;++pom1);}
    while(fire>0) {fire=PEEK(0x284);}    
               
    memset(video_ptr,0,24*40);            
    POKE(54286,192);
    antic = PEEK(559);
    POKE(559,0);
    
    
    placeNbr(19,0,moves);
    placeText(lvtx,sizeof(lvtx),2,0);
    placeText(mvtx,sizeof(mvtx),13,0);
    
    placeNbr(8,0,level);
    placeScr();
    placeText(sctx,sizeof(sctx),24,0);
    
    
    for (pom4=0; pom4<20; ++pom4) {
        clearPath(pom4+2);
        drawSingleSnake(pom4+2,snakes[pom4]);
    }       
    clearPath(23);
    drawSingleSnake(23,snakeOnPostion);
    
    POKE(559,antic);
    
    POKE(HPOSP3,48);
    POKE(PCOLR3,33);
    
    pom2 = ((levelpom-1)*10);
    pom1 = 205 - pom2;
    POKE(HPOSP2,pom1);
    POKE(PCOLR2,133);
    
    
    memset(pmg_memory_ptr+0x600+pospom,0,6);
    memset(pmg_memory_ptr+0x700+pospom,0,6);
    
    memset(pmg_memory_ptr+0x600+pospom,128+64+32,6);
    memset(pmg_memory_ptr+0x700+pospom,14,6);
    for(;;) {
    
        joy=PEEK(632); fire=PEEK(0x284);
        POKE(77,0);
        //gora
        if (joy == 14) {
                //memset(pmg_memory_ptr+0x700+48+position*8,0,8);
                if (position>0) --position;
                //memset(pmg_memory_ptr+0x700+48+position*8,255,8);
                
        }        
        //dol  
        if (joy == 13) {
                //memset(pmg_memory_ptr+0x700+48+position*8,0,8);
                if (position<19) ++position;
                //memset(pmg_memory_ptr+0x700+48+position*8,255,8);
        }       
        
        if (joy == 7 || joy == 11) {
           
              pom1 = snakeOnPostion/ 4;
              pom2 = snakeOnPostion % 4;
              
              
              if (pom2>0) {set_char(pom1,23,5); ++pom1;  }
              //pom1 - ilosc znakow
            
              pom2=0;
                
              //lewo
              for (q=pom1; q<40; ++q) {
                  
                  if (q<39) set_char(q,23,5);
                  if (q==39) set_char(q,23,6);
                  set_char(pom2,23,0);
                  ++pom2;
                 slow(); 
              }    
              
                    
              while (pom2<40) {
                  slow();  
                  set_char(pom2,23,0);
                  pom2++;
              }
           
           randomNewSnake();          
           drawSingleSnake(23,snakeOnPostion);
           moves2++;
           if (moves2%2 == 0) moves--;
           placeNbr(19,0,moves);
        }        
        
        if (fire == 0 && pospom==48+position*8) {
             snakeDown(position);
             changeSnake(position);
             snakeUp(position); 
             
             drawSingleSnake(23,snakeOnPostion);
             --moves;
             placeNbr(19,0,moves);
             
             if (position < 19 && snakes[position+1]>snakes[position]) {
                pom1 = snakes[position+1]-snakes[position];
                if (pom1<10) score=score+(10-pom1);
                placeScr();
             }             
             
             if (position > 0 && snakes[position]>snakes[position-1]) {
                pom1 = snakes[position]-snakes[position-1];
                if (pom1<10) score=score+(10-pom1);
                placeScr();
             }
             
             
        }                                         
        slow();slow();slow();slow();slow();slow();
        POKE(PCOLR2,RANDOM);POKE(PCOLR3,RANDOM);
        
        if (checkOrder() == 1) {
         //level completed
         pom1=moves;
         POKE(HPOSP3,0);
         POKE(HPOSP2,0);    

         for (q=0; q<pom1; ++q) {
             score=score+10;
             --moves;
             placeScr();
             placeNbr(19,0,moves);
         }   
             
          
         goto SDS;
        }                 
        
        if (moves == 0) {
           //game over kup se rower
                      
           memset(video_ptr+40,0,23*40);
           POKE(HPOSP3,0);
           POKE(HPOSP2,0);    

           placeText(gatx,9,14,8);
           
           fire=PEEK(0x284);
           for (q=0;q<255;++q) { for (pom1=0;pom1<10;++pom1);}
           while(fire>0) {fire=PEEK(0x284);}
           
           goto GAME;
        }          
        
        
    }
       
}          




