#warning FALSE

#define  k_up         18432
#define  k_down       20480
#define  k_left       19200
#define  k_right      19712
#define  k_enter       7181
#define  k_esc          283

#define  NewGame       TRUE

byte CapsLockStatus;

#define menuwidth 124
#define menuheigh 15
#define menunumitems 5
#define menux 320-menuwidth/2
#define menuy -menuheigh*menunumitems+200/2

#define  CpyGameItem                    1
#define  NetworkGameItem                2
#define  ChangeMusonItem                3
#define  AutorsItem        menunumitems-1
#define  ExitItem            menunumitems

void fastcall SetCapsLockStatus(AH)
{
 //Включаем CapsLock
 $push ES
  ES=0;
  IF (AH) ESBYTE[0417h]=ESBYTE[0417h]|64;
  ELSE ESBYTE[0417h]=ESBYTE[0417h]&191;
 $pop ES
}

byte fastcall GetCapsLockStatus()
{
 //Узнаем состояние CapsLock
 $push ES
  ES=0;
  AL=ESBYTE[0417h]&64>>6;
 $pop ES
}

word fastcall ReadKey()
{
 AX=0; $int 16h
}

void fastcall WaitSomeTime(ECX)
{
 $push ES
  ES=0;
  EBX=ESDWORD[046Ch];
  do{
      EAX=ESDWORD[046Ch];
  }while (EAX-EBX<ECX);
 $pop ES
}

void fastcall ClearLine(BX)
//void ClearLine(word y)
// word x;
{
// FOR (x=0; x<320; x+=8) PutChar(x,y,0DBh,255);
 $push ES,DS
  AX=BX*320; DI=AX; SI=AX;
  ES=VideoBuf; DS=WorkBuf;
  CX=320*9/4;
  $rep $movsd
 $pop DS,ES
}

//x,y,char,color
void fastcall PutChar(DI,SI,DH,DL)
 word i,i1;
 byte al;
{
 $push BP
  BP=DH; BP<<=3; BP+=FontOffs;
  $push DX
   AX=SI*320+DI; DI=AX; //Адрес в видеопамяти
  $pop DX
  GS=VideoBuf;
  FS=FontSeg;
  FOR (BX=0; BX<8; BX++){
      AL=FSBYTE[BP];
      FOR (CX=0; CX<8; CX++){
          $test AL,128 IF (NOTZEROFLAG) GSBYTE[DI+CX]=DL;
          AL<<=1;
      }
      DI+=320; BP++;
  }
 $pop BP
}

//SI = адрес строки
byte fastcall StrSize(SI)
{
 AH=0;
 do{
     $lodsb
     AH++;
 }while (AL!=0);
 return(AH-1);
}

//BX = координата X
//CX = координата Y
//AX = вордовское число
//DL = цвет
void fastcall WriteWord(BX,CX,AX,DL)
{
 $PUSHA $MOV DI,BX $MOV SI,CX $MOV BP,DX
 $MOV BX,10
 $MOV CX,5
M1:
 $XOR DX,DX
 $DIV BX
 $PUSH DX
$LOOP M1
 $MOV CX,5
M2:
 $POP DX
 $CMP DX,0
 $JZ M3
 $DEC CX
 $JMP M4
M3:
$LOOP M2
M4:
 $PUSHA BX=BP; PutChar(DI,SI,DL+48,BL); $POPA $ADD DI,8
 $CMP CX,0
 $JZ M5
 $DEC CX
 $POP DX
 $JMP M4
M5:
 $POPA
}


//x,y,offset,color
void fastcall PutStr(BX,CX,SI,DL)
{
  loop(){
     AL=DSBYTE[SI];
     IF (AL==0) BREAK;
     $push BX,CX,SI,DX
      PutChar(BX,CX,AL,DL);
     $pop DX,SI,CX,BX
     SI++; BX+=9;
  }
}

//x,y,segment,offset,color
void fastcall PutFarStr(BX,CX,DI,SI,DL)
{
  $push GS
   GS=DI;
   loop(){
      AL=GSBYTE[SI];
      IF (AL==0) BREAK;
      $push BX,CX,SI,DX,GS
       PutChar(BX,CX,AL,DL);
      $pop GS,DX,SI,CX,BX
      SI++; BX+=9;
   }
  $pop GS
}

void RefreshPole()
 word i,i1;
{
  CapsLockStatus=GetCapsLockStatus();
  IF (GameType==Network){
     PutStr(0,0,#Out0.UserName,TextColor); WriteWord(StrSize(#Out0.UserName)+1*9,0,Out0.NumWins,TextColor);
     PutStr(0,9,#In0.UserName,TextColor); WriteWord(StrSize(#In0.UserName)+1*9,9,In0.NumWins,TextColor);
     ClearLine(170); //Очищаем строку от старого сообщения
     PutStr(0,170,#In3.Message,TextColor);}
  ELSE{
     PutStr(0,0,#User.Name,TextColor); WriteWord(StrSize(#User.Name)+1*9,0,User.NumWins,TextColor);
     PutStr(0,9,#Cpy.Name,TextColor); WriteWord(StrSize(#Cpy.Name)+1*9,9,Cpy.NumWins,TextColor);
  }
  ShowStatus();

  //Если чат, то выходим
  IF (In3.Status)||(Out3.Status) return;

  for (i=1; i<11; i++){
      for (i1=1; i1<11; i1++){
          if (CapsLockStatus){
             IF (MyPole[i*12+i1]>0)&&(MyPole[i*12+i1]<=4) PutToolToBuf(32,11,word i1-1*10+40,word i-1*10+50,11,11,VideoBuf);
             IF (MyPole[i*12+i1]==5) PutToolToBuf(11,0,word i1-1*10+40,word i-1*10+50,11,11,VideoBuf);
             IF (MyPole[i*12+i1]==0) PutToolToBuf(0,0,word i1-1*10+40,word i-1*10+50,11,11,VideoBuf);

             IF (GameType==Network){
                IF (In5.Pole[i*12+i1]>0)&&(In5.Pole[i*12+i1]<=4) PutToolToBuf(22,0,word i1-1*10+40,word i-1*10+50,11,11,VideoBuf);
                IF (In5.Pole[i*12+i1]==5) PutToolToBuf(11,0,word i1-1*10+40,word i-1*10+50,11,11,VideoBuf);}
             ELSE{
                IF (CpyHidePole[i*12+i1]>0)&&(CpyHidePole[i*12+i1]<=4) PutToolToBuf(22,0,word i1-1*10+40,word i-1*10+50,11,11,VideoBuf);
                IF (CpyHidePole[i*12+i1]==5) PutToolToBuf(11,0,word i1-1*10+40,word i-1*10+50,11,11,VideoBuf);
             }
          }
          IF (HidePole[i*12+i1]>0)&&(HidePole[i*12+i1]<=4) PutToolToBuf(32,11,word i1-1*10+180,word i-1*10+50,11,11,VideoBuf);
          IF (HidePole[i*12+i1]==5) PutToolToBuf(11,0,word i1-1*10+180,word i-1*10+50,11,11,VideoBuf);
          IF (HidePole[i*12+i1]==0) PutToolToBuf(0,0,word i1-1*10+180,word i-1*10+50,11,11,VideoBuf);
      }
  }
}

//BX = x координата в Tools буфере
//AX = y координата в Tools буфере
//DI = размер по горизонтали
//SI = размер по вертикали
void fastcall PutMouse(BX,AX,DI,SI)
{
  $push DI,SI
   AX=AX*320+BX; SI=AX;
   AX=DX*320; DI=CX>>1+AX;
  $pop AX,BX
  $push ES,DS
   ES=VideoBuf; DS=ToolsBuf;

   DH=AL; CX=320-BX;
   loop(DH){
    DL=BL; loop(DL){IF (DSBYTE[SI]!=255) ESBYTE[DI]=DSBYTE[SI]; DI++; SI++;}
    DI+=CX; SI+=CX;
   }
  $pop DS,ES
}

void fastcall PutVideoBuf()
{
  $push ES,DS
    DI=0; SI=0;
    ES=0A000h; DS=VideoBuf;
    CX=16000;
    $rep $movsd
  $pop DS,ES
}

void PutToolToBuf(word soursx,soursy,destx,desty,xsize,ysize,seg)
 word i,i1;
 word soursaddr,destaddr;
{
  $push ES,DS
   ES=seg; DS=ToolsBuf;
   soursaddr=soursy*320+soursx;
   destaddr=desty*320+destx;
   FOR (i=0; i<ysize; i++){
       AX=i*320; SI=AX+soursaddr;
       DI=AX+destaddr;
       CX=xsize;
       $rep $movsb
   }
  $pop DS,ES
}

PutWorkBufToVideoBuf()
{
 $push ES,DS
  ES=VideoBuf; DS=WorkBuf;
  DI=0; SI=0;
  CX=16000;
  $rep $movsd
 $pop DS,ES
}

// Ожидает перерисовки экрана видеоадаптером
WaitRetrace()
{
 asm{
  mov DX,03DAh
V1:
  in AL,DX
  and AL,08H
  jnz V1
V2:
  in AL,DX
  and AL,08H
  jz V2
 }
}

void MouseLimits(word xsize,ysize)
{
 CX=40<<1-1; DX=-xsize*10+140<<1-1;
 AX=7; $int 33h

 CX=50-1; DX=-ysize*10+150-1;
 AX=8; $int 33h
}

void fastcall DeleteFile(DX)
{
 AH=41h; $int 21h
}

void fastcall CloseFile(BX)
{
 AH=3Eh; $int 21h
}

//AL = Тип доступа к файлу
//DX = Имя файла
word fastcall OpenFile(DX,AL)
{
 AH=3Dh; $int 21h
}

//DX = Имя файла
//CX = Аттрибут файла (20h -> архивный)
word fastcall CreateFile(DX,CX)
{
 AH=3Ch; $int 21h
}

//BX = File Handle
//DX = Адрес буфера
//CX = Количество байт
word fastcall ReadFile(BX,DX,CX)
{
 AH=3Fh; $int 21h
}

//BX = File Handle
//AX = Сегмент буфера
//DX = Адрес буфера
//CX = Количество байт
word fastcall ReadFarFile(BX,AX,DX,CX)
{
 $push DS
  DS=AX; AH=3Fh; $int 21h
 $pop DS
}

//BX = File Handle
//DX = Адрес буфера
//CX = Количество байт
word fastcall WriteFile(BX,DX,CX)
{
 AH=40h; $int 21h
}

//DX = File Name
void fastcall FindFirstFile(DX)
{
 CX=0; AH=4Eh; $int 21h
}

byte fastcall FindNextFile()
{
 AH=4Fh; $int 21h
 IF (NOTCARRYFLAG) return(TRUE);
 return(FALSE);
}

void PutShips()
 word i,i1,i2;
 int i3,i4;
 byte rotated; //Корабль повернут горизонтально (TRUE)
 word x,y; //Координаты верхнего левого угла корабля
 byte busy;  //Можно ли ставить корабль?
 word key;
{
  //Устанавливаем лимиты
  MouseLimits(1,4);

  //Устанавливаем мышь на верхний левый угол начала игрального поля
  AX=4; CX=40<<1; DX=50; $int 33h

  rotated=FALSE; //Вертикальное положение

  //Размеры короблей
  for (i=4; i>0; i--){
      IF (rotated) MouseLimits(i,1);
      ELSE MouseLimits(1,i);

      for (i1=5-i; i1>0; i1--){
          loop(){
            //Узнаем координаты и статус мыши
            AX=3; $int 33h
            $push DX x=CX+2-80/20; $pop DX y=DX+1-50/10;
            CX=x*20+80; DX=y*10+50;

            if (BX&1){
               busy=FALSE;
               IF (rotated){
                  FOR (i3=-1; i3<=1; i3++)
                      FOR (i4=i; i4>=-1; i4--) IF (MyPole[y+i3+1*12+x+i4+1]!=0) busy=TRUE;
                  IF (!busy) FOR (i2=0; i2<i; i2++) MyPole[y+1*12+i2+x+1]=i;}
               ELSE{
                  FOR (i3=-1; i3<=1; i3++)
                      FOR (i4=i; i4>=-1; i4--) IF (MyPole[y+i4+1*12+x+i3+1]!=0) busy=TRUE;
                  IF (!busy) FOR (i2=0; i2<i; i2++) MyPole[y+1+i2*12+x+1]=i;
               }

               $push CX,DX
                do{AX=6; BX=0; $int 33h}while (AX&1);
               $pop DX,CX
               IF (!busy) break;
            }
            ELSE IF (BX&2){
               IF (rotated)&&(y+i<=10) !rotated;
               ELSE IF (!rotated)&&(x+i<=10) !rotated;

               $push CX,DX
                IF (rotated) MouseLimits(i,1);
                ELSE MouseLimits(1,i);
                //Ждем пока не отпустят правую кнопку мыши
                do{AX=6; BX=0; $int 33h}while (AX&2);
               $pop DX,CX
            }

            $push CX,DX
             PutWorkBufToVideoBuf();
             //Включаем Caps Lock
             SetCapsLockStatus(TRUE);
             RefreshPole();

            $pop DX,CX
            IF (rotated) PutMouse(word 32,word 11,word i*10+1,word 11);
            ELSE PutMouse(word 32,word 11,word 11,word i*10+1);

            NewStatus("Ждем расстановки кораблей.....",TextColor);

            //А теперь выводим видеобуфер резко на экран
            WaitRetrace();
            PutVideoBuf();

            key=0; //Обнуляем клавишу
            //Если нажат ESC, то выходим
            IF (KBHIT()!=0) key=ReadKey();
            IF (key==k_esc) Exit();
          }
      }
  }
}


byte fastcall WaitKey()
{
 FindFirstFile(#KeyFile);
 IF (CARRYFLAG) return(FALSE);
 return(TRUE);
}

void fastcall MakeKey()
{
 CloseFile(word CreateFile(#KeyFile,0));
}

void fastcall DeleteKey()
{
 DeleteFile(#KeyFile);
}


void UplinkPack(byte PackNum)
 word PackAddr,PackSize; //Адрес и размер посылаемой структуры
{
 //Создание пакетного файла
 OutPackFileHandle=CreateFile(#OutPackFile,0);
  //Узнаем размер пакета и его адрес
  IF (PackNum==0){PackAddr=#Out0; PackSize=sizeof(_NewGame_);}
  ELSE IF (PackNum==1){PackAddr=#Out1; PackSize=sizeof(_NewShot_);}
  ELSE IF (PackNum==2){PackAddr=#Out2; PackSize=sizeof(_ContinueShot_);}
  ELSE IF (PackNum==3){PackAddr=#Out3; PackSize=sizeof(_Message_);}
  ELSE IF (PackNum==4){PackAddr=#Out4; PackSize=sizeof(_Win_);}
  ELSE IF (PackNum==5){PackAddr=#Out5; PackSize=sizeof(_Pole_);}

  //Записываем в файл номер пересылаемого пакета
  WriteFile(OutPackFileHandle,#PackNum,1);

  //Записываем нужный пакет и закрываем файл
  WriteFile(OutPackFileHandle,PackAddr,PackSize);
 CloseFile(OutPackFileHandle);

 //Создаем ключ
 MakeKey();
}

byte DownlinkPack()
 byte PackNum;
 word PackAddr,PackSize;
{
  //Ждем создания пакета
  do{RefreshAll(); FindFirstFile(#InPackFile);}while (CARRYFLAG);
//  WRITESTR("\nПринимаемый пакетный файл создан"); GETCH();

  //Ждем создания ключа
  WHILE (!WaitKey()) RefreshAll();
//  WRITESTR("\nКлюч создан"); GETCH();

  //Открываем пакетный файл (режим только чтение)
  InPackFileHandle=OpenFile(#InPackFile,0);

   //Чтение из пакетного файла номер пакета
   ReadFile(InPackFileHandle,#PackNum,1);
//  WRITESTR("\nPackNum = "); WRITEWORD(PackNum); GETCH();

   //Узнаем размер пакета и его адрес
   IF (PackNum==0){PackAddr=#In0; PackSize=sizeof(_NewGame_);}
   ELSE IF (PackNum==1){PackAddr=#In1; PackSize=sizeof(_NewShot_);}
   ELSE IF (PackNum==2){PackAddr=#In2; PackSize=sizeof(_ContinueShot_);}
   ELSE IF (PackNum==3){PackAddr=#In3; PackSize=sizeof(_Message_);}
   ELSE IF (PackNum==4){PackAddr=#In4; PackSize=sizeof(_Win_);}
   ELSE IF (PackNum==5){PackAddr=#In5; PackSize=sizeof(_Pole_);}

   //Читаем из файла пакет в структуру пакета
   ReadFile(InPackFileHandle,PackAddr,PackSize);

   //Закрываем файл и удаляем его вместе с ключем
  CloseFile(InPackFileHandle);
  DeleteFile(#InPackFile);
  DeleteKey();
//  WRITESTR("\nКлюч удален"); GETCH();
  return(PackNum);
}


//SI = Откуда копировать
//DI = Куда копировать
void fastcall CopyString(SI,DI)
{
 $push ES
  ES=DS;
  do{
      $lodsb
      $stosb
  }while (AL!=0);
 $pop ES
}

//AX = Sours Seg
//SI = Sours Offset
//BX = Dest Seg
//DI = Dest Offset
void CopyFarString(word soursseg,soursoffs,destseg,destoffs)
{
 $push DS,ES
  SI=soursoffs; DI=destoffs;
  ES=destseg; DS=soursseg;
  do{
      $lodsb
      $stosb
  }while (AL!=0);
 $pop ES,DS
}

void MakeShot()
 word x,y; //Относительные координаты мыши (1..10)
 word mx,my; //Координаты мыши
 int i,i1;
{
 loop(){
   //Мессага о ходе
   NewStatus("Ходим.........",TextColor);

   AX=3; $int 33h
   $push BX
    mx=CX; my=DX; //Сохраняем координаты мыши в переменных
    x=mx-360/20+1; //Высчитываем относительные координаты мыши
    y=my-50/10+1;  //Аналогично предыдущему

    mx=x-1*20+360; my=y-1*10+50; //Округляем координаты мыши
   $pop BX

   //Если нажата левая кнопка мыши
   IF (BX&1){
     //Если еще сюда не стреляли
     AX=y*12+x;
     IF (HidePole[AX]==0){
         IF (GameType==Network){
            Out1.x=x;
            Out1.y=y;}
         ELSE{
            User.Shot.x=x;
            User.Shot.y=y;
         }
         BREAK;
      }
   }

//   IF (inp(60h)==1){GETCH(); EXIT();}
   IF (KBHIT()!=0){
      GETCH();
      IF (AL==27) Exit();
      IF (AL==13)&&(GameType==Network) SendMessage();
   }

   //Копируем рабочий буфер в видеобуфер
   PutWorkBufToVideoBuf();

   RefreshPole();
   CX=mx; DX=my;

   PutMouse(word 73,word 11,word 11,word 11);

   //Выводим имена  и очки игроков
   WaitRetrace();
   PutVideoBuf();
 }
}


void fastcall GetFont()
{
 // Узнаем сегмент и смещение фонта
 $push ES,BP
  $mov AX,1130h
  $mov BH,1
  $int 10h
  FontSeg=ES;
  FontOffs=BP;
 $pop BP,ES
}

//addr = адрес буфера
//number = номер строки
byte ReadCfgLine(word addr,number)
 word i;
 byte tmp;
{
  CfgFileHandle=OpenFile(#CfgFile,0);
   WHILE (number!=0){
     do{
       ReadFile(CfgFileHandle,#tmp,1);
     }while (tmp!=0Ah);
     number--;
   }

   FOR (i=0; i<128; i++){
       ReadFile(CfgFileHandle,addr+i,1);
       IF (DSBYTE[addr+i]==20h)||(DSBYTE[addr+i]==0Dh){DSBYTE[addr+i]=0; BREAK;}
   }
  CloseFile(CfgFileHandle);
  return(i);
}


SendMessage()
 word x,y;
 word i=0; //положение в массиве сообщения
 byte letter;
{
  //Выключаем Caps Lock
  SetCapsLockStatus(FALSE);

  NewStatus("Ну че, поболтаем ? ? ?", TextColor);

  Out3.Message[0]=0; //Ставим заглушку на начало буфера
  In3.Message[0]=0;  //Ставим заглушку на начало буфера

  PutWorkBufToVideoBuf();

  loop(){
       //Если нажата клавиша считываем символ

       letter=FALSE; //Сбрасываем

       IF (KBHIT()!=0) letter=GETCH();

       IF (letter==8)&&(i>0){i--; Out3.Message[i]=0;}
       ELSE IF (letter==27) BREAK;
       ELSE IF (letter>=20h)&&(letter<=0F1h)&&(i<35){
            Out3.Message[i]=letter; i++; Out3.Message[i]=0;
       }

       //Устанавливаем чат активным
       Out3.Status=TRUE;

       //Отправляем мессагу
       UplinkPack(3);
       //Ждем ответа
       DownlinkPack();

//       ClearLine(170); //Очищаем строку от старого сообщения
//       PutStr(0,170,#In3.Message,TextColor);
       //Освежаем поле
       RefreshPole();

       ClearLine(180); //Очищаем строку от старого сообщения
       PutStr(0,180,#Out3.Message,TextColor);

       WaitRetrace();
       PutVideoBuf();
  }

  //Восстанавливаем Caps Lock по статусу
  IF (CapsLockStatus) SetCapsLockStatus(TRUE);
  ELSE SetCapsLockStatus(FALSE);

  //Деактивируем чат
  Out3.Status=FALSE;

  //Отправляем мессагу
  UplinkPack(3);

  //Ждем ответа
  DownlinkPack();
}

GetSendedMessage()
 word x,y;
 word i=0; //положение в массиве сообщения
 byte letter;
{
  //Выключаем Caps Lock
  SetCapsLockStatus(FALSE);

  NewStatus("Ну че, поболтаем ? ? ?", TextColor);

  Out3.Message[0]=0; //Ставим заглушку на начало буфера
  In3.Message[0]=0;  //Ставим заглушку на начало буфера

  PutWorkBufToVideoBuf();

  loop(){
       //Если нажата клавиша считываем символ

       letter=FALSE; //Сбрасываем

       IF (KBHIT()!=0) letter=GETCH();

       IF (letter==8)&&(i>0){i--; Out3.Message[i]=0;}
       ELSE IF (letter>=20h)&&(letter<=0F1h)&&(i<35){
            Out3.Message[i]=letter; i++; Out3.Message[i]=0;
       }

       //Ждем поступления данных
       DownlinkPack();

       //Отправляем мессагу
       UplinkPack(3);

//       ClearLine(170); //Очищаем строку от старого сообщения
//       PutStr(0,170,#In3.Message,TextColor);
       //Освежаем поле
       RefreshPole();

       ClearLine(180); //Очищаем строку от старого сообщения
       PutStr(0,180,#Out3.Message,TextColor);

       WaitRetrace();
       PutVideoBuf();

       IF (In3.Status==FALSE) BREAK;
  }
  ClearLine(180); //Очищаем строку от старого сообщения
  //Выводим имена  и очки игроков
  PutStr(0,0,#Out0.UserName,TextColor); WriteWord(StrSize(#Out0.UserName)+1*9,0,Out0.NumWins,TextColor);
  PutStr(0,9,#In0.UserName,TextColor); WriteWord(StrSize(#In0.UserName)+1*9,9,In0.NumWins,TextColor);

  //Восстанавливаем Caps Lock по статусу
  IF (CapsLockStatus) SetCapsLockStatus(TRUE);
  ELSE SetCapsLockStatus(FALSE);
}


//Возвращает FALSE если нажат ESC
word GetString(word x,y,addr; byte size,color)
 byte letter;
 word i=0;
{
  DSBYTE[addr]=0; //Ставим заглушку на начало буфера

  loop(){
    WaitRetrace();
    PutVideoBuf();

    letter=0; //Сбрасываем нажатую клавишу

    IF (KBHIT()!=0) letter=ReadKey(); //Считываем один символ

    IF (letter==13) return(TRUE);
    ELSE IF (letter==27) return(FALSE);
    ELSE IF (letter==8)&&(i>0){i--; DSBYTE[addr+i]=0;}
    ELSE IF (letter>=20h)&&(letter<=0F1h)&&(i<size){
         DSBYTE[addr+i]=letter; DSBYTE[addr+1+i]=0;
         i++;
    }

    ClearLine(y); //Очищаем 180 строку
    PutStr(x,y,addr,color); //Выводим буфер с мессагой
  }
}

void NetworkGame()
{
  if (MainPlayer){
     //Отсылаем нулевой пакет (начало игры)
     //Содержание пакета:     Имя игрока (128 байт)
     //                       Количество выиграных партий
     UplinkPack(0); //Отправляем нулевой пакет

     //Ждем нулевой пакет
     NumPack=DownlinkPack(); //Узнаем имя противника

     //Расстанавливаем корабли
     PutShips();

     //Устанавливаем лимиты на правое поле
     AX=7; CX=180*2; DX=180*2+180; $int 33h
     AX=8; CX=50; DX=140; $int 33h

     //Устанавливаем мышь на левый верхний угол поля противника
     AX=4; CX=180<<1; DX=50; $int 33h

     //Ходим (первыми)
     MakeShot(); //Делаем выстрел
     AX=Out1.y*12+Out1.x; HidePole[AX]=5;
     UplinkPack(1); //Отсылаем 1 пакет с координатами выстрела

     do{
//        ClearLine(190); //Очищаем строку от старого сообщения
        ClearLine(170); //Очищаем строку от старого сообщения
        NewStatus("Ждем ответа.......",TextColor);
        PutStr(0,170,#In3.Message,TextColor);
        RefreshPole();
        PutVideoBuf();

        //Получаем очередной пакет
        NumPack=DownlinkPack();

        //Если пришел 2 пакет
        IF (NumPack==2){
           AX=Out1.y*12+Out1.x; SI=AX; HidePole[SI]=In2.NumPalubs;
           ClearKilledShip(Out1.x,Out1.y,#HidePole);

           //Обмениваемся пакетами с подбитыми кораблями
            //Заполняем поле с подбитыми кораблями
            DX=144; loop(DX) Out5.Pole[DX]=HidePole[DX];
            UplinkPack(5);
            DownlinkPack();

           //Если мы выиграли
           IF (byte CheckWin(#HidePole)){
              //Прибавляем себе количество побед
              Out0.NumWins++;

              //Отправляем пакет о победе
              UplinkPack(4);

              //Ждем пакет с ответом
              DownlinkPack();

              //Теперь идем на начало новой игры
              return;
           }

           MakeShot(); //Делаем выстрел
           AX=Out1.y*12+Out1.x; HidePole[AX]=5;
           UplinkPack(1); //Отсылаем 1 пакет с координатами выстрела
        }
        else IF (NumPack==1){
             //Если в нас попали
             AX=In1.y*12+In1.x; SI=AX;
             IF (MyPole[SI]!=0){
                Out2.NumPalubs=MyPole[SI];
                //Посылаем продолжение хода
                UplinkPack(2);
             }
             ELSE{
               //Обмениваемся пакетами с подбитыми кораблями
                //Заполняем поле с подбитыми кораблями
                DX=144; loop(DX) Out5.Pole[DX]=HidePole[DX];
                UplinkPack(5);
                DownlinkPack();
               MakeShot(); //Делаем выстрел
               AX=Out1.y*12+Out1.x; HidePole[AX]=5;
               //Заполняем поле с подбитыми кораблями
               DX=144; loop(DX) Out5.Pole[DX]=HidePole[DX];
               UplinkPack(1); //Отсылаем 1 пакет с координатами выстрела
             }
        }
        ELSE IF (NumPack==4){
             //А теперь идем на начало новой игры
             return;
        }
        ELSE IF (NumPack==3){
             //Чат
             //Посылаем ответный пакет
             UplinkPack(3);
             GetSendedMessage();
        }
        ELSE IF (NumPack==5){
             //Новое поле с подбитыми кораблями
             RefreshPole();
             //Заполняем поле с подбитыми кораблями
             DX=144; loop(DX) Out5.Pole[DX]=HidePole[DX];
             UplinkPack(5);
        }
     }while (inp(60h)!=1);
     GETCH();
  }
  else{
     //Ждем пакета (нулевого)
     NumPack=DownlinkPack();

     //Отсылаем нулевой пакет
     UplinkPack(0);

     //Расстанавливаем корабли
     PutShips();

     //Устанавливаем лимиты на правое поле
     AX=7; CX=180*2; DX=180*2+180; $int 33h
     AX=8; CX=50; DX=140; $int 33h

     //Устанавливаем мышь на левый верхний угол поля противника
     AX=4; CX=180<<1; DX=50; $int 33h

     // Ждем хода
     do{
//        ClearLine(190); //Очищаем строку от старого сообщения
        ClearLine(170); //Очищаем строку от старого сообщения
        NewStatus("Ждем ответа.......",TextColor);
        PutStr(0,170,#In3.Message,TextColor);
        RefreshPole();
        PutVideoBuf();
        //Получаем очередной пакет
        NumPack=DownlinkPack();

        //Если пришел 2 пакет
        if (NumPack==2){
           AX=Out1.y*12+Out1.x; SI=AX; HidePole[SI]=In2.NumPalubs;
           ClearKilledShip(Out1.x,Out1.y,#HidePole);


           //Обмениваемся пакетами с подбитыми кораблями
            //Заполняем поле с подбитыми кораблями
            DX=144; loop(DX) Out5.Pole[DX]=HidePole[DX];
            UplinkPack(5);
            DownlinkPack();

           //Если мы выиграли
           IF (byte CheckWin(#HidePole)){
              //Прибавляем себе количество побед
              Out0.NumWins++;

              //Отправляем пакет о победе
              UplinkPack(4);

              //Теперь идем на начало новой игры
              return;
           }

           MakeShot(); //Делаем выстрел
           AX=Out1.y*12+Out1.x; HidePole[AX]=5;
           //Заполняем поле с подбитыми кораблями
           DX=144; loop(DX) Out5.Pole[DX]=HidePole[DX];
           UplinkPack(1); //Отсылаем 1 пакет с координатами выстрела
        }
        else IF (NumPack==1){
             //Если в нас попали
             AX=In1.y*12+In1.x; SI=AX;
             IF (MyPole[SI]!=0){
                Out2.NumPalubs=MyPole[SI];
                //Посылаем продолжение хода
                UplinkPack(2);
             }
             ELSE{
               //Обмениваемся пакетами с подбитыми кораблями
                //Заполняем поле с подбитыми кораблями
                DX=144; loop(DX) Out5.Pole[DX]=HidePole[DX];
                UplinkPack(5);
                DownlinkPack();

               MakeShot(); //Делаем выстрел
               AX=Out1.y*12+Out1.x; HidePole[AX]=5;
               UplinkPack(1); //Отсылаем 1 пакет с координатами выстрела
             }
        }
        ELSE IF (NumPack==4){
             //Посылаем ответ
             UplinkPack(4);
             //А теперь идем на начало новой игры
             return;
        }
        ELSE IF (NumPack==3){
             //Чат
             //Посылаем ответный пакет
             UplinkPack(3);
             GetSendedMessage();
        }
        ELSE IF (NumPack==5){
             //Новое поле с подбитыми кораблями
             RefreshPole();
             //Заполняем поле с подбитыми кораблями
             DX=144; loop(DX) Out5.Pole[DX]=HidePole[DX];
             UplinkPack(5);
        }
     }while (inp(60h)!=1);
     GETCH();
  }
}


//Проверка на выигрыш
byte CheckWin(word addr)
 word i;
 byte count=0;
{
 FOR (i=0; i<144; i++) IF (DSBYTE[i+addr]>=1)&&(DSBYTE[i+addr]<=4) count++;
 IF (count==20) return(TRUE);
 return(FALSE);
}

void NewStatus(word addr,byte color)
{
    CopyString(addr,#StatusLine);
    StatusLineColor=color;
}

/********************* Подключение библиотеки с AdLib ***********************/
#include "mbAdLib.h--"


void Exit()
{
  // Менюшка
  loop(){
      AL=GetMenuItem();
      IF (AL==CpyGameItem){
         // Если была сетевая игра
         IF (GameType==Network){
            DeleteKey();
            DeleteFile(#OutPackFile);
            DeleteFile(#InPackFile);
         }
         GameType=0;
         goto Start_New_Game;
      }
      ELSE IF (AL==NetworkGameItem){
           // Если была сетевая игра
           IF (GameType==Network){
              DeleteKey();
              DeleteFile(#OutPackFile);
              DeleteFile(#InPackFile);
           }
           GameType=1;
           goto Start_New_Game;
      }
      ELSE IF (AL==AutorsItem) Autors();
      ELSE IF (AL==ExitItem) BREAK;
      ELSE IF (AL==ChangeMusonItem) ChangeMuson();
      IF (AL==0) return;
  }

  //Удаляем все рабочие файлы
  IF (GameType==Network){
     DeleteKey();
     DeleteFile(#OutPackFile);
     DeleteFile(#InPackFile);
  }

  // Вырубаем музон
  IF (SoundBlasterStatus) StopAdlib();

  // Выключаем Caps Lock
  SetCapsLockStatus(FALSE);

  //Устанавливаем текстовый видеорежим
  AX=3; $int 10h

  //Выводим мессагу
  WRITESTR(DinMessage);

  //А теперь выходим в материнский процесс
  $int 20h
}

void MakeConnect()
 word key;
{
  MainPlayer=FALSE; //Сбрасываем флаг главного компа

  IF (!WaitKey()){
     MakeKey(); MainPlayer=TRUE;
     WHILE (WaitKey()){
           //Выдаем мессагу на экран
           PutWorkBufToVideoBuf();
           NewStatus("Ждем коннекта с другим компом......",TextColor);
           ShowStatus();
           PutVideoBuf();

           key=0; //Сбрасываем нажатую клавишу
           IF (KBHIT()!=0) key=ReadKey();
           IF (key==k_esc) Exit();
     }
  }
  ELSE DeleteKey();

  //Присваиваем имена
  NewStatus("Введи свое имя.......",TextColor);
  ShowStatus();
  WHILE (GetString(0,0,#Out0.UserName,30,TextColor)==FALSE);
  NewStatus("Ждем имя противника.......",TextColor);
  ShowStatus();
  PutVideoBuf();
}

void PutTransparentToolToBuf(word x,y,x1,y1,width,heigh,seg,seg1)
{
  $push GS,FS
   AX=y*320+x; SI=AX;    //Откуда копировать
   AX=y1*320+x1; DI=AX;  //Куда копировать

   GS=seg; FS=seg1;     //Устанавливаем сегменты

   DX=320-width;
   BX=heigh;
   loop(BX){
        CX=width; loop(CX){AL=GSBYTE[SI]; IF (AL!=255) FSBYTE[DI]=AL; DI++; SI++;}
       DI=DI+DX; SI=SI+DX;
   }

  $pop FS,GS
}


byte item=0; //Номер пункта меню

//Возвращает номер выбранного пункта (1 - первый; 0-ничего)
byte GetMenuItem()
 word key; //Нажатая клавиша
 word i;
{
  loop(){
    PutWorkBufToVideoBuf();
    //Выводим меню
    FOR (i=0; i<menunumitems; i++) /*IF (i!=item)*/ PutTransparentToolToBuf(0,i*menuheigh+55,menux,i*menuheigh+menuy,menuwidth,menuheigh,ToolsBuf,VideoBuf);
    //Выводим активное меню
    PutTransparentToolToBuf(0,menuheigh*item+55,menux+1,item*menuheigh+menuy,menuwidth,menuheigh,ToolsBuf,VideoBuf);
    WaitRetrace();
    PutVideoBuf();

    //Считываем нажатую клавишу
    key=ReadKey();
    IF (key==k_esc) return(0);
    ELSE IF (key==k_enter) return(item+1);
    ELSE IF (key==k_up)&&(item>0) item--;
    ELSE IF (key==k_down)&&(item+1<menunumitems) item++;
  }
}


word randseed[2]={0,0};  //Переменная знакогенератора

:int RAND()
{
  $push BX,CX
   AX=randseed[2];
   CX=randseed[0];
   AH=AL;
   AL=CH;
   CH=CL;
   $XOR CL,CL
   $RCR AX,1
   $RCR CX,1
   randseed[0]+=CX;
   $ADC AX,randseed[2]
   randseed[0]+=0x62E9;
   $ADC AX,0x3619
   randseed[2]=AX;
  $pop CX,BX
}

:void fastcall Randomize()
{
  $push ES
   ES=0x0000;
   randseed[0]=ESWORD[0x46E];
   randseed[2]=ESWORD[0x46C];
  $pop ES
}

CpyPutShips()
 byte rotated;
 word x,y;
 word i;
 byte numpalubs; //Сколькипалубный
 byte busy;
 word count;
{
 for (numpalubs=4; numpalubs>0; numpalubs--){
     for (count=5-numpalubs; count>0; count--){
         do{
             rotated=RAND()%2; // (0..1)
             loop(){
                 x=RAND()%10+1; y=RAND()%10+1;
                 IF (x+numpalubs<=10)&&(rotated) BREAK;
                 IF (y+numpalubs<=10)&&(!rotated) BREAK;
             }

             busy=FALSE; //Сбрасываем флаг занятости
             IF (rotated){
                FOR (i=0; i<numpalubs; i++) IF (byte CheckBusyArround(word y*12+x+i+#CpyPole)==TRUE) busy=TRUE;}
             ELSE{
                FOR (i=0; i<numpalubs; i++) IF (byte CheckBusyArround(word y+i*12+x+#CpyPole)==TRUE) busy=TRUE;
             }
         }while (busy);
         IF (rotated) FOR (i=0; i<numpalubs; i++) CpyPole[y*12+x+i]=numpalubs;
         ELSE FOR (i=0; i<numpalubs; i++) CpyPole[y+i*12+x]=numpalubs;
     }
 }
}


byte CheckBusyArround(word addr)
 int i,i1;
{
 FOR (i=-1; i<=1; i++)
     FOR (i1=-1; i1<=1; i1++)
         IF (DSBYTE[i*12+i1+addr]>0) return(TRUE);
 return(FALSE); //Не занято
}





//Очищает вокруг убитого корабля
byte ClearKilledShip(word x,y,addr)
 int delta1=0,delta2=0;
 byte NumPalubs; //Количество палуб у корабля
 byte NumFoundedPalubs=1;
 int i;
{
 addr=y*12+x+addr;
 NumPalubs=DSBYTE[addr];
 IF (DSBYTE[addr-1]==NumPalubs) delta1=-1;
 IF (DSBYTE[addr+1]==NumPalubs) delta2=1;
 IF (DSBYTE[addr-12]==NumPalubs) delta1=-12;
 IF (DSBYTE[addr+12]==NumPalubs) delta2=12;

 CX=NumPalubs;
 $push addr
  IF (delta1!=0) loop(CX){IF (DSBYTE[addr+delta1]==NumPalubs) NumFoundedPalubs++; ELSE BREAK; addr+=delta1;}
 $pop addr

 CX=NumPalubs;
// $push addr
  IF (delta2!=0) loop(CX){IF (DSBYTE[addr+delta2]==NumPalubs) NumFoundedPalubs++; ELSE BREAK; addr+=delta2;}
// $pop addr

 if (NumPalubs==NumFoundedPalubs){
//    WRITESTR("\nУбил\naddr = "); WRITEWORD(addr); GETCH();
    IF (delta1==0)&&(delta2==1) delta1=-1;
    IF (delta1==0)&&(delta2==12) delta1=-12;

    for (i=0; i<NumPalubs; i++){
        IF (DSBYTE[addr-1]==0) DSBYTE[addr-1]=5;
        IF (DSBYTE[addr+1]==0) DSBYTE[addr+1]=5;
        IF (DSBYTE[addr+12]==0) DSBYTE[addr+12]=5;
        IF (DSBYTE[addr-12]==0) DSBYTE[addr-12]=5;

        IF (DSBYTE[addr-13]==0) DSBYTE[addr-13]=5;
        IF (DSBYTE[addr-11]==0) DSBYTE[addr-11]=5;
        IF (DSBYTE[addr+13]==0) DSBYTE[addr+13]=5;
        IF (DSBYTE[addr+11]==0) DSBYTE[addr+11]=5;
        addr+=delta1;
    }
    return(TRUE);
 }
 return(FALSE);
}

void GetUserName()
{
 //Освежаем видеобуфер
 PutWorkBufToVideoBuf();

 //Узнаем имя игрока
 NewStatus("Введи свое имя.......",TextColor);
 ShowStatus();
 WHILE (GetString(0,0,#User.Name,30,TextColor)==FALSE);

 //Устанавливаем имя компутера
 CopyString("Компьютер",#Cpy.Name);
}

void GetNewWay(word tmp)
{
  //Выбираем направление
  loop(){
      LastShot.way=RAND()%4;
      IF (LastShot.way==0)&&(CpyHidePole[tmp-12]==0)&&(LastShot.y>1) BREAK;
      IF (LastShot.way==1)&&(CpyHidePole[tmp+1]==0)&&(LastShot.x<10) BREAK;
      IF (LastShot.way==2)&&(CpyHidePole[tmp+12]==0)&&(LastShot.y<10) BREAK;
      IF (LastShot.way==3)&&(CpyHidePole[tmp-1]==0)&&(LastShot.x>1) BREAK;
  }

  //Устанавливаем приращение
  IF (LastShot.way==0) LastShot.delta=-12;
  ELSE IF (LastShot.way==1) LastShot.delta=1;
  ELSE IF (LastShot.way==2) LastShot.delta=12;
  ELSE IF (LastShot.way==3) LastShot.delta=-1;
}

ShowStatus()
{
  ClearLine(190); //Очищаем строку от старого сообщения
  PutStr(0,190,#StatusLine,StatusLineColor);
}


byte RefreshAll()
 word key=0;
{
 //Если чат, то выходим
 IF (In3.Status)||(Out3.Status) return;
 //Копируем буфер с задним планом в видеобуфер
 PutWorkBufToVideoBuf();
 //Освежаем поля и мессаги
 RefreshPole();
 //Синхронизируемся с обратным ходом луча
 WaitRetrace();
 //Выводим видеобуфер
 PutVideoBuf();
 //Опрашиваем клаву
 IF (KBHIT()!=0) key=ReadKey();
 IF (key==k_esc) Exit();
}

void fastcall ResetAllSettings()
{
  //Устанавливаем количество побед в 0
  Out0.NumWins=0;
  In0.NumWins=0;
  User.NumWins=0;
  Cpy.NumWins=0;

  //Очистка имен игроков
  User.Name[0]=0;
  Cpy.Name[0]=0;
  Out0.UserName[0]=0;
  CopyString("???",#In0.UserName);

  //чат
  In3.Status=FALSE;
  Out3.Status=FALSE;

  //Тушим Caps Lock
  SetCapsLockStatus(FALSE);
}


void InitGame()
{
  //Очищаем массивы от левых данных
  FOR (CX=0; CX<144; CX++){
   MyPole[CX]=0;
   HidePole[CX]=0;
   In5.Pole[CX]=0;
   Out5.Pole[CX]=0;
   CpyHidePole[CX]=0;
   CpyPole[CX]=0;
  }

  Out3.Message[0]=0; //Ставим заглушку на начало буфера
  In3.Message[0]=0;  //Ставим заглушку на начало буфера

  RefreshPole();

  IF (GameType==Network) NetworkGame();
  ELSE CpyGame();
}


void CpyGame()
 word i,i1;
 word tmp; //Временная переменная
{
 //Устанавливаем знакогенератор
 Randomize();

 //Расставляем корабли
 PutShips();

 //Теперь корабли расстанавливает Cpy (немного быстрее чем мы ;)
 CpyPutShips();

 //Устанавливаем лимиты на правое поле
 AX=7; CX=180*2; DX=180*2+180; $int 33h
 AX=8; CX=50; DX=140; $int 33h

 //Устанавливаем мышь на левый верхний угол поля противника
 AX=4; CX=180<<1; DX=50; $int 33h

 //Устанавливаем координаты последнего выстрела компа
 LastShot.x=RAND()%10+1; LastShot.y=RAND()%10+1;

 //Сбрасываем флаги
 LastShot.flag=FALSE;
 LastShot.way=RAND()%4;  //( - 0,  - 1,  - 2,  - 3)

 //Основной цикл
 loop(){
     //Освежаем видеобуфер и экран
     NewStatus("Ходим......",TextColor);
     RefreshPole();
     WaitRetrace(); PutVideoBuf();

     loop(){
         //Делаем выстрел
         MakeShot();

         tmp=User.Shot.y*12+User.Shot.x;
         //Переносим данные в скрытое поле
         HidePole[tmp]=CpyPole[tmp];

         //Если промахнулись, то передаем ход Cpy
         IF (HidePole[tmp]==0){HidePole[tmp]=5; BREAK;}

         ClearKilledShip(User.Shot.x,User.Shot.y,#HidePole);

         //Проверяем на выигрыш
         IF (CheckWin(#HidePole)){
            //Освежаем поле
            NewStatus("Мы выиграли.........  8-)",TextColor);
            RefreshPole(); WaitRetrace(); PutVideoBuf();

            //Пресани кей
            ReadKey();

            User.NumWins++;
            return;
         }
     }

     //Освежаем видеобуфер и экран
     NewStatus("Ждем хода......",TextColor);
     RefreshPole();
     WaitRetrace(); PutVideoBuf();

     //Теперь очередь Cpy
     loop(){
         // Cpy делает очередной выстрел

         // Если установлен флаг
         if (LastShot.flag){
            // Вычисляем адрес
            tmp=LastShot.y*12+LastShot.x;

            // Выбираем направление
            GetNewWay(word tmp);

            // Стреляем пока не промахнемся или пока можно в эту сторону
            // или пока не убъем
            loop(){
                IF (tmp+LastShot.delta<12)||(tmp+LastShot.delta>132)||(tmp+LastShot.delta%12<1)||(tmp+LastShot.delta%12>10){
                   // Вычисляем адрес
                   tmp=LastShot.y*12+LastShot.x;
                   // Выбираем направление
                   GetNewWay(word tmp);
                }
                tmp+=LastShot.delta;

                // Записываем результат выстрела
                CpyHidePole[tmp]=MyPole[tmp];

                // Если Cpy не попал
                IF (CpyHidePole[tmp]==0){
                   CpyHidePole[tmp]=5;
                   // Делаем небольшую паузу
                   WaitSomeTime(Time); RefreshPole(); PutVideoBuf();
                   break 1;
                }

                // Проверяем на уничтожение корабля
                IF (byte ClearKilledShip(tmp%12,tmp/12,#CpyHidePole)==TRUE){
                   LastShot.flag=FALSE;
                   // Делаем небольшую паузу
                   WaitSomeTime(Time); RefreshPole(); PutVideoBuf();

                   // Проверяем на выигрыш
                   IF (CheckWin(#CpyHidePole)){
                      // Освежаем поле
                      NewStatus("Мы проиграли.........  Ж-(",TextColor);
                      RefreshPole(); WaitRetrace(); PutVideoBuf();

                      // Пресани кей
                      ReadKey();

                      Cpy.NumWins++;
                      return;
                   }
                   BREAK;
                }
                // Делаем небольшую паузу
                WaitSomeTime(Time); RefreshPole(); PutVideoBuf();
            }
         }
//         ELSE{
        loop(){
            Cpy.Shot.x=RAND()%10+1; Cpy.Shot.y=RAND()%10+1;

            tmp=Cpy.Shot.y*12+Cpy.Shot.x;

            // Если попали в еще не открытую область то выходим
            IF (CpyHidePole[tmp]<5) BREAK;
        }
//         }

         // Записываем в скрытое поле Cpy результат выстрела
         CpyHidePole[tmp]=MyPole[tmp];

         // Если промахнулся, то мы ходим
         IF (CpyHidePole[tmp]==0){
            CpyHidePole[tmp]=5;
            // Делаем небольшую паузу
            WaitSomeTime(Time); RefreshPole(); PutVideoBuf();
            BREAK;
         }

         // Если это не очередное попадание
         IF (!LastShot.flag){
            LastShot.flag=TRUE;
            LastShot.x=Cpy.Shot.x;
            LastShot.y=Cpy.Shot.y;
         }

         IF (byte ClearKilledShip(Cpy.Shot.x,Cpy.Shot.y,#CpyHidePole)==TRUE) LastShot.flag=FALSE;

         // Делаем небольшую паузу
         WaitSomeTime(Time); RefreshPole(); PutVideoBuf();

         // Проверяем на выигрыш
         IF (CheckWin(#CpyHidePole)){
            // Освежаем поле
            NewStatus("Мы проиграли.........  Ж-(",TextColor);
            RefreshPole(); WaitRetrace(); PutVideoBuf();

            // Пресани кей
            ReadKey();

            Cpy.NumWins++;
            return;
         }
     }
 }
}

// Подключение библы с интрушкой
#include "intro.h--"

void Autors()
 word key;
{
 // Вывод моей интрушки ;)
 Intro();
}


