/*
im_daxy@mail.ru
2:5063/47.11@fidoned
Coded: Constantine Stanislavski, Russia, Kasnodar 2004.
*/

#resize TRUE
#pragma option argc

#define __MODPLAYER__ TRUE


#include "soundsys\write.h--"    // Библа для вывода данных на экран
#include "soundsys\sb.h--"       // Библа для работы с Sound Blaster-ом
#include "soundsys\wave.h--"     // Библа для подгрузки семплов в формате WAV
#include "soundsys\modplay.h--"  // Библа для проигрывания MOD-модулей
#define SCREENSIZE 0xFA00
#define MEMBLOCKSIZE SCREENSIZE/16
#define STARS 1000              //Количество звезд
#define SRCY 100                //Сколько памяти выделять под скролл
#define SRCLINE 19              //Ширина текста скролла
#define SRCMAXLINE 8*SRCLINE    //Максимальное ширина скролла = SRCLINE * количесто X бит в букве
#define ZSTARMAX 255            //Максимальное удаление звезды. Оставить без изменений
#define XCENTR   160            //Центровка X
#define YCENTR   100            //Центровка Y
#define SPSTAR   2              //Скорость полета звезд. К сожалению констану на -е значение менять нельзя
#define PALSIZE 256*3           //Размер палитры
#define HALTSCR 5               //Задержка прорисовки скролла. Если = 1 то сколл летит в прерывание, но очень быстро
#define HOW 2                   //Для смягчения скролла. Поставь 0 и будет понятно.
#define SCROLLDL 9              //Длина скролла по Y видимое на экране+1
#define SCROLLSTR SRCMAXLINE*8  //Максимальное ширина * количесто Y бит в букве
#define SCROLLA SCROLLSTR*SCROLLDL
#define SCRMEM 0xA000           //Адресс экрана
#define muzlen 5970             //Длина музыки

int starx[STARS];        //Координаты звезды по X
int stary[STARS];        //Координаты звезды по Y
int starz[STARS];        //Координаты звезды по Z

word scrsm[SRCY];        //Эканное смещение для скролла
word scrot[SRCY];        //Cмещение нахождения скролла
word scrre[SRCY];        //Ширина линии скролла для resized
 int scrco[SRCY];         //Здесь записывается значение выхода горизонтальной линии за пределы экрана для корректного изображения

byte palette[PALSIZE];   //Здесь будем сохранять готовую палитру

byte font[768] = FROM "amiga.fnt";
byte texta = FROM "info.txt";
byte netgf1= FROM "netto.gf1";
byte netgf2= FROM "netto.gf2";
byte stgfx[16] = FROM "netto.gf3";
byte jump = {0,0,1,1,2,3,3,4,5,6,7,8,9,10,11,12,12,13,14,14,15,15,15,14,13,13,12,11,10,09,8,7,6,5,4,3,3,2,1,1,255};
byte muz = FROM "netto.muz";
byte muzname = "dax.mod";
byte music;              //Здесь указывается работает музыка или нет


byte pal= {000,000,000,000,  //1- Номер цвета, 2,3,4 палитра;
           064,000,000,000,  //
           065,250,250,210,  //A
           066,255,000,000,  //
           067,248,248,096,  //C
           068,205,133,063,  //
           069,000,255,255,  //E
           070,150, 69, 20,  //
           071,056, 71, 79,  //G
           };


word scrollw=0;


word rand;   //Специальное слово для процедуры RND

word numstar; //Номер звезды с которой будет работать процедура CREATESTAR

word SCREEN;
word SCRSCREEN;



word wa,wb,wc,wd; //Свободные переменные для циклов и тп.
byte ba,bb; //Свободные переменные для циклов и тп.

//Переменные для инициализации скролла
word oldy,oldwsm;
int oldco,wff,wco;

word scrline=0;
word wsm,wot,wre,oldwre;

byte scrhalt=0;  //Счетчик задержки прорисовки скролла
byte scrscht=7;  //Счетчик задержки вывода новой линии
word scrollsm=0;

word textsm=SCROLLA-SCROLLSTR;

byte textcol; //Цвет текста


byte jumpp=0;
byte pp=1;
byte oldvek=0;









void main ()  //Начнем прогу???
{

        IF (PARAMCOUNT()>1)    //Есть параметры в коммандной строке? Если да музыки не будет
           {music=0;
           GOTO DALEEL1;
           }
        @FCREATE ( , , 0, #muzname);  //Создаем файл с музыкой
        write (AX,#muz,muzlen);
        @FCLOSE (,wc);

        IF (!SbAutoDetect())   //Если нет SB или он занят музыки не будет
           {
           music=0;
           GOTO DALEEL1;
           }
        music=1;               //Всетаки музыка будет
        InitSb();
        InitModSystem();
        LoadModFile(#muzname); // Подгружаем мод-файл
        PlayModModule=TRUE;     // Начинаем воспроизведение мод-модуля
DALEEL1:


        SCREEN=GETMEM(MEMBLOCKSIZE);      //Выделяем память
        IF (AX==0)Error();           //Если отказано выходим.

        SCRSCREEN=GETMEM(MEMBLOCKSIZE);   //Выделяем память
        IF (AX==0)Error();           //Если отказано выходим.

        AX=0x13;    //Устанавливаем видеорежим VGA320x200
        $int 0x10;  //Аналогично @SETVIDEOMODE(byte 0x13), но на 1 байт короче HEH!

        $Cli                           // ; Вырубаем прерывания
        $MOV DX,21h
        $IN AL,DX
        oldvek=AL;
        $OR AL,11b                     // ; Вырубаем кнопку pause
        $OUT DX,AL
        $Sti


        init_palette (); //Инициализируем палитру

        INITSTARS();     //Инициализируем звезды

        INITSCR();       //Инициализируем скролл

        ES=SCRSCREEN;
        CLEARSCREEN();   //Отчищаем экран скролла

        ES=SCREEN;       //В ES будем работать с виртуальным экраном
        CLEARSCREEN();   //Отчищаем виртуальный экран


        FS=SCRMEM;       //В FS будем работать с реальным экраном
        GS=SCRSCREEN;    //В GS будем работать со скроллом



MAINLOOP:   //Основной цикл программы

        SETSTARS();     //Рисуем в виртуальном экране звезды
        SHOWSCROLL();   //Рисуем в виртуальном экране скролл
        PUTNETTO();     //Рисуем в виртуальном экране neTTo Show
        @WAITVSYNC();   //Ждем вертикальной (видео) синхронизации (HALT)
        SHOWscreen();   //Выводим на экран виртуальный экран


        $IN AL,60h      //Проверка клаву на ESC
        $CMP AL,1
        $JNZ MAINLOOP



        $Cli                         //   Врубаем клавиатуру
        $MOV DX,21h
        AL=oldvek;
        $OUT DX,AL
        $STI

IF (music==1)  // Деинициализация всего
{
  DeInitSb();
  DeInitModSystem();
}
  @REMOVE(#muzname);

        @KBCLEAR(); //Отчищаем буфер клавиатуры

        AX=0x3;     //Устанавливаем текстовый видеорежим
        $int 0x10;  //Аналогично @SETVIDEOMODE(byte 0x3), но на 1 байт короче




        WRITESTR("neTTo BBS_2:5063/51@FidoNet\nSysOp: Misha Grekov, tel: 62-63-40\nWorkTime: 23.30-06.00\nPnone number and time actually on coding moment.\nCoded by DAX'y, Russia, Krasnodar. May, 2004");

}




void SETSTARS ()  //Эта процедура рисует звезды в виртуальном экране
{
for (numstar=0;numstar<STARS;numstar++)
{

$cmp starz[numstar],0;
$jnbe  MMM1
$JMP MAKENEWSTAR                    // STARZ=0 создаем новую звезду

MMM1:
    AX=starx[numstar];
    $movsx   dx,ah
    $shl     ax,8                   // ax = X * 256 (AH=AL; AL=0)
    CX=starz[numstar];
    $idiv    cx                     // ax = ax / Z
    $add     ax,XCENTR              // ax = ax + XCENTR
    $cmp     ax,320-4               // nn > ax ?
    $jae   MAKENEWSTAR              // Если да создаем новую звезду
    $mov     di,ax
    AX=stary[numstar];
    $movsx   dx,ah
    $shl     ax,8                   // ax = Y * 256 (AH=AL; AL=0)
    $idiv    cx                     // ax = ax / Z
    $add     ax,YCENTR              // ax = ax + YCENTR
    $cmp     ax,200-4               // nn > ax ?
    $jae     MAKENEWSTAR            // Если да создаем новую звезду
    $mov     bx,320
    $imul    bx
    $add     di,ax
    CX=starz[numstar]/4;            //Цвет звезды от 0 до 63
    ba=CX/16;
    ba=ba*4;                        //Считаем размер звезды от 0 до 3


        CH=4;              //Собссно рисуем звездочку

MET1:
        AL=stgfx[ba];

        BX=4;
             loop (BX)
                  {
                   $RCL AL,1;
                   $JNC ASMET1;
                   ESBYTE[DI]=CL;
                   ASMET1:
                   $inc DI;
                  }

             DI+=316;
             ba+=1;
             $dec CH;
             $cmp CH,0;
$jnz MET1;

             starz[numstar]-=SPSTAR; //Заставляем звезду лететь
             GOTO CONTINUESTAR;

MAKENEWSTAR:
            CREATESTAR();  //Создаем новую звезду

CONTINUESTAR:

}
}


void INITSTARS()  //Инициализируем все звездочки
{
FOR (numstar=0;numstar<STARS;numstar++)
{
CREATESTAR();
}
}


void CREATESTAR()
{
    CX=320;
    RND();
    DX-=XCENTR;
    starx[numstar]=DX;

    CX=200;
    RND();
    DX-=YCENTR;
    stary[numstar]=DX;
    starz[numstar]=ZSTARMAX;
}





void RND()
{
// =================================
// RND : герерирует случайное число
// Для работы процедуре необходимо объявить переменную word rand;
// Input : cx = range
// Output: dx = random number
// =================================
asm{
    mov     ax,rand
    add     ax,1234
    xor     al,ah
    rol     ah,1
    add     ax,4321
    ror     al,1
    xor     ah,al
    mov     rand,ax
    xor     dx,dx
    div     cx
}

}

void init_palette ()
{
BX = 0;
DI = 0;
do {
    palette[DI] = 63-BX;
    palette[DI+1] = 63-BX;
    palette[DI+2] = 63-BX;
    DI+=3;
    BX++;
    } while( BX < 64);


BX=0;
do {
DX=pal[BX];
DX*=3;
BX++;
palette[DX] = pal[BX];
BX++;
palette[DX+1] = pal[BX];
BX++;
palette[DX+2] = pal[BX];
BX++;
}while (BX<9*4);   //Длина палитры

@ SETVGADAC(0, ,PALSIZE, , ,#palette);

}


void CLEARSCREEN()
{
for (wa=0;wa<64000;wa+=4)
{
ESDWORD[wa]=0;
}
}


void SHOWscreen()         //Выводим на экран и отчищаем.
{
FOR (wa=0;wa<64000;wa+=4)
{
FSDWORD[wa]=ESDWORD[wa];
ESDWORD[wa]=0;
}
}


void INITSCR ()
{
//        FS=SCRMEM;
        wot=0;
for (wc=75;wc>14;wc--)                 //Z
{
    AX=13;
    $movsx   dx,ah
    $shl     ax,8
    CX=wc;
    $idiv    cx
    $add     ax,XCENTR-1
    $mov     di,ax
    wa=AX;                              //X
    AX=7;
    $movsx   dx,ah
    $shl     ax,8
    $idiv    cx
    $add     ax,YCENTR-20
    $mov     bx,320
    $imul    bx
    $add     di,ax
    wb=AX;                              //Y
//    FSBYTE[DI]=1;
    wco=320-wa;
    wd=wco;
    wsm=wd+wb;  //Новое Смещение на экране
    wre=wa-wd+1;




IF (scrline==0)GOTO ENDF1;

IF (wb==oldy)
{
wot+=SRCMAXLINE; //Пребавляем в нахождение скролла
goto ENDF;
}


wa=wsm;
wd=wre;
wff=wco;
IF (wb-oldy>320)
{
        do{
        oldwsm+=320;
        oldy+=320;
        oldco-=HOW;
        oldwsm-=HOW;
        oldwre+=HOW+HOW;
        wsm=oldwsm;
        wre=oldwre;
        wco=oldco;
        SETSCRD ();
        }while(oldy+320<wb);
}
wsm=wa;
wre=wd;
wco=wff;



ENDF1:

        wot+=SRCMAXLINE; //Пребавляем в нахождение скролла
        SETSCRD ();
        oldwsm=wsm;
        oldy=wb;
        oldwre=wre;
        oldco=wco;


ENDF:


}

  /*  //Этот код не компилится от сюда

        WRITESTR("Параметр SRCY не менее: ");
        WRITEWORD(scrline);
MAINLO:

        $IN AL,60h      //Проверка клаву на ESC
        $CMP AL,1
        $JNZ MAINLO

  */  //До сюда

}


void SETSCRD()      //Установка координат
{
//FSBYTE[wsm]=1;
scrsm[scrline]=wsm;  //Эканное смещение для скролла
scrot[scrline]=wot;  //Смещение нахождения скролла
scrre[scrline]=wre;  //Ширина линии скролла для resized
scrco[scrline]=wco;  //Значение выхода горизонтальной линии
scrline+=1;
}


void SHOWSCROLL()  //Покажем скролл???
{

FOR (wa=0;wa<scrline;wa++)
{
wsm=scrsm[wa];  //Эканное смещение для скролла
wot=scrot[wa];  //Смещение нахождения скролла
wre=scrre[wa];  //Ширина линии скролла для resized
wco=scrco[wa];  //Значение выхода горизонтальной линии
wot=wot+scrollsm;

IF (wot>=SCROLLA)wot-=SCROLLA;
SHOWLINE();
}

scrhalt++;
IF (scrhalt==HALTSCR)
{scrhalt=0;
scrollsm+=SRCMAXLINE;

IF (scrollsm>=SCROLLA)scrollsm=0;
scrscht++;

IF (scrscht==8)
{
scrscht=0;
OUTTXT();
}
}
}

void SHOWLINE()       //Процедура рисует resized линию на экран
{
    SI=SRCMAXLINE;
    CX=0;             //CX=0 Начинаем с первой точки линии
    DI=wsm;           //DI=Эканное смещение для скролла
    do{
      AX=CX*SI;       //AX=Умножаем CX на ширину линии real
      $DIV wre        //AX=Полученое делим на ширину линии resized
      BX=AX+wot;      //BX=AX+смещение нахождения скролла
      IF (wco>0) && (wco<320)IF (GSBYTE[BX]!=0)ESBYTE[DI]=GSBYTE[BX];
      wco++;
      DI++;
      CX++;
    }while(CX<wre);   //Пока меньше ширины resized
}




void OUTTXT()  //Эта процедура рисует текстовую строку
{
FOR (wa=0;wa<SCROLLSTR;wa+=4)
{
GSDWORD[wa+textsm]=0;
}
wd=textsm;

for (ba=0;ba<SRCLINE;ba++)
 {
  wa=texta[scrollw];
 wa-=32;
 wa=wa*8;
 wc=textsm;
 scrollw+=1;

   FOR (bb=0;bb<8;bb++)
   {
   AL=font[wa];
   CX=8;
   loop(CX){
   $RCL AL,1;
      IF(CARRYFLAG){
         $push AX;
         GSBYTE[textsm]=textcol;
         GSBYTE[textsm+1]=textcol-1;
         GSBYTE[textsm+SRCMAXLINE+1]=textcol-1;
         $pop AX;
         }
   textsm+=1;
   }
 wa++;
 textsm+=SRCMAXLINE-8;
 }
textsm=wc+8;
}
textsm=wd+SCROLLSTR;

IF (texta[scrollw]==251)scrollw=0;
ELSE
    {
    textcol=texta[scrollw];
    scrollw+=3;
    }
IF (textsm>=SCROLLA)textsm=0;
}


void PUTNETTO()  //Чисто нетто show. Написано за 10 мин
{

wa=320*35+32;
wb=0;


pp--;
IF (pp==0)pp=63;
CL=pp;


FOR (bb=0;bb<6;bb++)
{
DI=wa;


FOR (ba=0;ba<32;ba++)
{
AL=netgf2[wb];


BITGFX();
wb++;
}
wa=wa+320;
}
jumpp++;
IF (jump[jumpp]==255)jumpp=0;
wd=jumpp;
wa=22;
wb=0;
for (wot=0;wot<9;wot++)
{
IF (wot==3)||(wot==7)wb-=3*8*2;
wsm=wa;

FOR (wre=0;wre<7;wre++)  //Поменяй здесь и будет тебе счастье ;)
{
wd++;
IF (jump[wd]==255)wd=0;
}


wc=jump[wd];
wc=wc*320;
wa=wa+wc;
FOR (bb=0;bb<16;bb++)
{
DI=wa;
FOR (ba=0;ba<3;ba++)
{
AL=netgf1[wb];
$push ax
CX=255;
RND();
$pop ax
$AND AX,DX;
CL=69;
BITGFX();
wb++;
}
wa=wa+320;
}
wa=wsm+32;
}
}


void BITGFX()
{
        BX=8;
             loop (BX)
                  {
                   $RCL AL,1;
                   $JNC BITGF;
                   ESBYTE[DI]=CL;
                   BITGF:
                   $inc DI;
                  }
}

void Error()
{
  @WRITESTR("Не хватает памяти");
  @ABORT();
}

