/***************************************************************************
 *    Данный файл содержит подпрограммы для работы с окнами в графическом  *
 *  режиме. Они расчитаны на использование с файлом GRAPHICS.H и с файлом  *
 *  GRAPHICS.LIB, WND_ASM.HPP.                                             *
 *    Рекомендуется использовать их при работе с адаптерами и  мониторами  *
 *  не ниже EGA.                                                           *
 *    Подпрограммы могут вызыватся из любой модели памяти.                 *
 *    Подпрограммы используют стандартный BIOS IBM, и поэтому, при их ис-  *
 *  пользовании на IBM совместимых машинах, необходимо убедится, что фор-  *
 *  маты BIOS совпадают.        ////////////////140-141; 244-245           *
 ***************************************************************************/
#include  <wnd_asm.h>  /* Файл с прототипами функций и структур */
#include <stdio.h>      /* Файл заголовков для работы с В/В */
#include <stdarg.h>     /* Файл заголовков для работы с va_ функциями */
#include <graphics.h>   /* Файл заголовков для работы с графикой */
#include <string.h>     /* Файл заголовков для работы со строками */
#pragma inline          /*Сообщение компилятору об использованиии ассембл.*/

/**************************************************************************
 *  Подпрограмма для изменения участка экрана с использованием наложения *
 *  XOR.                                                                  *
 *  Описание переменных:                                                  *
 *  bl - указатель на структуру BLOCK, содержащую координаты  изменяемого *
 *       блока                                                            *
 *  color - цвет изменения блока                                          *
 **************************************************************************/

void  Chan_Block_Xor( BLOCK *bl, COLOR color, MODE oper ) {
   COLOR  col_pix = getpixel( bl->X1, bl->Y1 ); //Читаем цвет текущего
                                                //пиксела

   color ^= col_pix;              //Получаем необходимый цвет закраски
   Chand( bl->X1, bl->Y1, bl->X2, bl->Y2, color, oper );  //Закраска
   return;
}

/**************************************************************************
 *  Подпрограмма для изменения участка экрана, с использованием выбраного *
 *  цвета. Происходит заполнения учатка кратного 8. Количество строк  мо- *
 *  жет быть любым (допустимым). Изменение  блока возможно с  использова- *
 *  нием логических операций наложения.                                   *
 *  ВНИМАНИЕ!!! Эта функция может быть использовани толькo  с  адаптерами *
 *  не ниже ЕGA.                                                          *
 *  Описание переменных:                                                  *
 *  x - колонка для начала блока изменения                                *
 *  y - строка для начала блока изменения                                 *
 *  step_x - количество блоков х для изменения                            *
 *  step_y - количество блоков y для изменения                            *
 *  color - цвет изменения                                                *
 **************************************************************************/
void Chan_Block( int x, int y, int step_x, int step_y, COLOR color,
		 MODE oper ) {

    asm   PUSH ES         //Сохранение доп. сегмента
    asm      MOV  AX,x       //Устанавливаем х на начало сегмента
    asm      MOV  CL,03H // !!!
    asm      SHR  AX,CL     //кратного 8
    asm      MOV  BX,AX
    asm      MOV  AX,y       //Номер строки умножаем на 80 для получения
    asm      MOV  CL,04H //!!!
    asm      SHL  AX,CL     //смещения в видеобуфере
    asm      ADD  BX,AX
    asm      MOV  CL,02H //!!!
    asm      SHL  AX,CL
    asm      ADD  BX,AX
    asm      MOV  AX,Start_Video_Buf  //Указываем на начало видеобуфера
    asm      MOV  ES,AX
    asm      MOV  DX,Video_Port //Выдаем указание адаптеру о режиме записи
    asm      MOV  AL,05H       //Режим равен 0
    asm      OUT  DX,AL
    asm      INC  DX

    asm      XOR  AL,AL               //Режим
    asm      OUT  DX,AL
    asm      DEC  DX           //Разрешаем адаптеру менять все четыре
    asm      MOV  AL,08H       //битовые плоскости
    asm      OUT  DX,AL
    asm      INC  DX
    asm      MOV  AL,11111111B //Это разрешение
    asm      OUT  DX,AL
    asm      DEC  DX           //Указываем адаптеру о способе наложения
    asm      MOV  AL,03H       //изображения
    asm      OUT  DX,AL        //Указываем на регистр смещения
    asm      INC  DX
    asm      MOV  AL,oper      //Указываем на операцию
    asm      OUT  DX,AL        //Меняем регистр вращения
    asm      MOV  DX,Video_Color     //Устанавливаем цвет изменения экрана
    asm      MOV  AL,02H
    asm      OUT  DX,AL
    asm      INC  DX

    asm      MOV  AL,color           //Наш цвет
    asm      OUT  DX,AL
    asm      MOV  CX,step_y   //Указываем количетво строк замены
    asm      MOV  AH,0FFH    //Устанавливаем наложение цветов
    asm      MOV  AL,oper    //Режим наложения
    asm      CMP  AL,0FH     //Если AND, то наложение равно 0
    asm      JNZ  NEXT_LINE
    asm      XOR  AH,AH      //Наложение для AND
NEXT_LINE: asm   XOR SI,SI //Инициализируем указатель символа
REPEAT:
	   asm      MOV  AL,ES:[BX+SI] //Читаем регистры задвижки
	   asm      MOV  ES:[BX+SI],AH //Изменяем 8 пикселов

	   asm      INC  SI
	   asm      CMP  SI,step_x     //Не вся строка обработана ?
	   asm      JB   REPEAT

	   asm      ADD  BX,Line_Next_Col
	   asm      LOOP NEXT_LINE     //Не все строки обработаны ?
/*    asm      MOV  AL,03H       //
    asm      OUT  DX,AL        //Указываем на регистр смещения
    asm      INC  DX
    asm      MOV  AL,COPI      //Указываем на операцию копирования
    asm      OUT  DX,AL        //
*/
 asm      POP  ES            //Востанавливаем доплнительный сегмент
 bar(0,0,1,1);
 return;
}

/**************************************************************************
 *  Подпрограмма для установки русских символов в графическом режиме.     *
 *  Изменяется вектор прерывания 01Fh, старый вектор сохраняется в пере-  *
 *  менной Old_Graph_Sim, и может быть востановлен с помощью функции      *
 *  Back_Graph_Sim.                                                       *
 *  ВНИМАНИЕ!!! Эта функция может быть использована только  с  адаптерами *
 *  не ниже ЕGA.                                                          *
 **************************************************************************/
//static unsigned    Old_Vect_ES, //Переменные указывающие на старый
//		   Old_Vect_BX; //вектор 1FH

// Флаг, был ли вызов Set_Graph_Sim.
//                    0 - нет
//                    1 - был
static unsigned short Can_Back;
char near CHAR_DAT[1024] = {
0x3C,0x6C,0xCC,0xCC,0xCC,0xFC,0xCC,0xCC, //А
0xFC,0xC0,0xC0,0xF8,0xCC,0xCC,0xCC,0xF8, //Б
0xF0,0xD8,0xD8,0xF0,0xD8,0xCC,0xD8,0xF8, //В
0xFC,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0,0xC0, //Г
0x1C,0x3C,0x6C,0x4C,0x4C,0x4C,0x4C,0xFC, //Д
0xFC,0xC0,0xC0,0xF0,0xC0,0xC0,0xC0,0xFC, //Е
0xB4,0xB4,0x78,0x30,0x78,0xFC,0xB4,0xB4, //Ж
0x78,0x8C,0x1C,0x38,0x1C,0x0C,0x9C,0x78, //З
0xCC,0xCC,0xCC,0xDC,0xDC,0xFC,0xEC,0xCC, //И
0xD4,0xD4,0xC4,0xCC,0xDC,0xF4,0xE4,0xC4, //Й
0xC4,0xCC,0xD8,0xF0,0xF0,0xD8,0xCC,0xC4, //К
0x3C,0x6C,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, //Л
0xC6,0xEE,0xFE,0xD6,0xC6,0xC6,0xC6,0xC6, //М
0xCC,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC,0xCC, //Н
0x78,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0x78, //О
0xFC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC,0xCC, //П
0xF8,0xCC,0xC4,0xCC,0xF8,0xC0,0xC0,0xC0, //Р
0x78,0xC4,0xC0,0xC0,0xC0,0xC0,0xC4,0x78, //С
0xFC,0x30,0x30,0x30,0x30,0x30,0x30,0x30, //Т
0xCC,0xCC,0xCC,0x6C,0x3C,0x0C,0x9C,0x78, //У
0x30,0x78,0xB4,0xB4,0xB4,0x78,0x30,0x30, //Ф
0x84,0xCC,0x78,0x30,0x30,0x78,0xCC,0x84, //Х
0x8C,0x8C,0x8C,0x8C,0x8C,0xCC,0x7E,0x06, //Ц
0xCC,0xCC,0xCC,0x6C,0x3C,0x0C,0x0C,0x0C, //Ч
0xC4,0xC4,0xD4,0xD4,0xD4,0xD4,0xD4,0xFC, //Ш
0xC4,0xC4,0xD4,0xD4,0xD4,0xD4,0xD4,0xFE, //Щ
0xE0,0xC0,0xC0,0xF8,0xCC,0xC4,0xCC,0xF8, //Ъ
0xCC,0xCC,0xC4,0xF8,0xCC,0xC4,0xCC,0xF8, //Ы
0xC0,0xC0,0xC0,0xF8,0xCC,0xC4,0xCC,0xF8, //Ь
0x78,0x9C,0x0C,0x3C,0x3C,0x0C,0x9C,0x78, //Э
0xB8,0xAC,0xA4,0xE4,0xE4,0xA4,0xAC,0xB8, //Ю
0x7C,0xCC,0xCC,0x7C,0x3C,0x6C,0xCC,0x8C, //Я
0x00,0x00,0x74,0xDC,0x8C,0x8C,0xDC,0x74, //а
0x00,0x00,0xFC,0xC0,0xF8,0xCC,0xCC,0xF8, //б
0x00,0x00,0xF0,0xD8,0xF0,0xFC,0xCC,0xFC, //в
0x00,0x00,0xFC,0xC0,0xC0,0xC0,0xC0,0xC0, //г
0x00,0x00,0x3C,0x6C,0x4C,0x4C,0x4C,0xFC, //д
0x00,0x00,0xFC,0xC0,0xE0,0xF0,0xC0,0xFC, //е
0x00,0x00,0xB4,0x78,0x30,0x78,0xFC,0xB4, //ж
0x00,0x00,0xF8,0x0C,0x38,0x18,0x0C,0xF8, //з
0x00,0x00,0xCC,0xCC,0xDC,0xFC,0xEC,0xCC, //и
0x00,0x00,0xD4,0xC4,0xCC,0xD4,0xE4,0xC4, //й
0x00,0x00,0xCC,0xD8,0xF0,0xF0,0xD8,0xCC, //к
0x00,0x00,0x3C,0x6C,0x4C,0xCC,0xCC,0xCC, //л
0x00,0x00,0x8C,0xDC,0xFC,0xAC,0x8C,0x8C, //м
0x00,0x00,0xCC,0xCC,0xFC,0xCC,0xCC,0xCC, //н
0x00,0x00,0x78,0xCC,0xCC,0xCC,0xCC,0x78, //о
0x00,0x00,0xFC,0xCC,0xCC,0xCC,0xCC,0xCC, //п
0x88,0x22,0x88,0x22,0x88,0x22,0x88,0x22, // ░
0xcc,0x33,0xcc,0x33,0xcc,0x33,0xcc,0x33, // ▒
0xee,0x77,0xbb,0x77,0xee,0xdd,0xbb,0xee, // ▓
0x18,0x18,0x18,0x18,0x18,0x18,0x18,0x18, // │
0x18,0x18,0x18,0xf8,0xf8,0x18,0x18,0x18, // ┤
0x18,0xf8,0xf8,0x18,0x18,0xf8,0xf8,0x18, // ╡
0x66,0x66,0x66,0xe6,0xe6,0x66,0x66,0x66, // ╢
0x00,0x00,0x00,0xfe,0xfe,0x66,0x66,0x66, // ╖
0x00,0xf8,0xf8,0x18,0x18,0xf8,0xf8,0x18, // ╕
0x66,0xe6,0xe6,0x66,0x66,0xe6,0xe6,0x66, // ╣
0x66,0x66,0x66,0x66,0x66,0x66,0x66,0x66, // ║
0x00,0xfe,0xfe,0x06,0x06,0xe6,0xe6,0x66, // ╗
0x66,0xe6,0xe6,0x06,0x06,0xfe,0xfe,0x00, // ╝
0x66,0x66,0x66,0x66,0x66,0xfe,0xfe,0x00, // ╜
0x18,0xf8,0xf8,0x18,0x18,0xf8,0xf8,0x00, // ╛
0x00,0x00,0x00,0xf8,0xf8,0x18,0x18,0x18, // ┐
0x18,0x18,0x18,0x1f,0x1f,0x00,0x00,0x00, // └
0x18,0x18,0x18,0xff,0xff,0x00,0x00,0x00, // ┴
0x00,0x00,0x00,0xff,0xff,0x18,0x18,0x18, // ┬
0x18,0x18,0x18,0x1f,0x1f,0x18,0x18,0x18, // ├
0x00,0x00,0x00,0xff,0xff,0x00,0x00,0x00, // ─
0x18,0x18,0x18,0xff,0xff,0x18,0x18,0x18, // ┼
0x18,0x1f,0x1f,0x18,0x18,0x1f,0x1f,0x18, // ╞
0x66,0x67,0x67,0x66,0x66,0x67,0x67,0x66, // ╟
0x66,0x67,0x67,0x60,0x60,0x6f,0x6f,0x00, // ╚ 200
0x00,0x7f,0x7f,0x60,0x60,0x67,0x67,0x66, // ╔
0x66,0x66,0x66,0x66,0x66,0xff,0xff,0x00, // ╩
0x00,0xff,0xff,0x66,0x66,0x66,0x66,0x66, // ╦
0x66,0x67,0x67,0x66,0x66,0x67,0x67,0x66, // ╠
0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x00, // ═
0x66,0xe7,0xe7,0x66,0x66,0xe7,0xe7,0x66, // ╬
0x18,0xff,0xff,0x00,0x00,0xff,0xff,0x00, // ╧
0x66,0x66,0x66,0xff,0xff,0x00,0x00,0x00, // ╨
0x00,0xff,0xff,0x00,0x00,0xff,0xff,0x18, // ╤
0x00,0x00,0x00,0xff,0xff,0x66,0x66,0x66, // ╥ 210
0x66,0x66,0x66,0x7f,0x7f,0x00,0x00,0x00, // ╙
0x18,0x1f,0x1f,0x18,0x18,0x1f,0x1f,0x00, // ╘
0x00,0x1f,0x1f,0x18,0x18,0x1f,0x1f,0x18, // ╒
0x00,0x00,0x00,0x7f,0x7f,0x66,0x66,0x66, // ╓
0x66,0x66,0x66,0xe7,0xe7,0x66,0x66,0x66, // ╫
0x18,0xff,0xff,0x18,0x18,0xff,0xff,0x18, // ╪
0x18,0x18,0x18,0xf8,0xf8,0x00,0x00,0x00, // ┘
0x00,0x00,0x00,0x1f,0x1f,0x18,0x18,0x18, // ┌
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // █
0x00,0x00,0x00,0x00,0xff,0xff,0xff,0xff, // ▄ 220
0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0,0xf0, // ▌
0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f,0x0f, // ▐
0xff,0xff,0xff,0xff,0x00,0x00,0x00,0x00, // ▀
0x00,0x00,0xF8,0xCC,0xCC,0xF8,0xC0,0xC0, //р
0x00,0x00,0x78,0xC4,0xC0,0xC0,0xC4,0x78, //с
0x00,0x00,0xFC,0x30,0x30,0x30,0x30,0x30, //т
0x00,0x00,0xCC,0xCC,0x6C,0x3C,0x8C,0x78, //у
0x00,0x00,0x30,0xFC,0xB4,0xB4,0xFC,0x30, //ф
0x00,0x00,0xCC,0x78,0x30,0x30,0x78,0xCC, //х
0x00,0x00,0xD8,0xD8,0xD8,0xD8,0xFC,0x04, //ц
0x00,0x00,0xCC,0xCC,0xCC,0x7C,0x0C,0x0C, //ч
0x00,0x00,0x84,0x84,0xB4,0xB4,0xB4,0xFC, //ш
0x00,0x00,0x88,0x88,0xA8,0xA8,0xA8,0xFC, //щ
0x00,0x00,0xE0,0x40,0x78,0x4C,0x4C,0x78, //ъ
0x00,0x00,0x8C,0x8C,0xE4,0xB4,0xB4,0xE4, //ы
0x00,0x00,0xC0,0xC0,0xF8,0xCC,0xCC,0xF8, //ь
0x00,0x00,0x78,0x8C,0x1C,0x1C,0x8C,0x78, //э
0x00,0x00,0xB8,0xAC,0xE4,0xE4,0xAC,0xB8, //ю
0x00,0x00,0x7C,0xCC,0xEC,0x3C,0x6C,0xCC, //я
0x28,0x00,0xFC,0xC0,0xF0,0xF0,0xC0,0xFC, // 240
0x90,0xFC,0xC0,0xC0,0xF0,0xC0,0xC0,0xFC, // 241

0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff, // 242-247
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,
0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,

0x00,0x00,0x3C,0x7E,0x7E,0x3C,0x00,0x00, // ° 248
0x00,0x00,0x18,0x3C,0x3C,0x18,0x00,0x00, // ∙ 249
0x00,0x00,0x00,0x18,0x18,0x00,0x00,0x00, // · 250
0x18,0x18,0x7e,0x7e,0x18,0x18,0x00,0x7e, //251 √
0x00,0xc6,0xe6,0xd6,0xde,0xce,0xc6,0xc6, //252 №
0x81,0x42,0x18,0x24,0x24,0x18,0x42,0x81, //253 ¤
0x00,0x00,0x3C,0x3C,0x3C,0x3C,0x00,0x00, //■
0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00 //
};
void Set_Graph_Sim( void ) {
//    ТАБЛИЦА РУССКИХ СИМВОЛОВ
//asm {
	  asm{
	       PUSH  DS    //Сохраняем регистр данных
	       PUSH  ES    //Сохраняем дополнительный сегмент

	       MOV   AH,Get_Interrupt   //Функция получения вектора
	       MOV   AL,Tabl_Sim_Graph
	       INT   21H
	       MOV   AX,ES
//	       MOV   Old_Vect_ES,ES      //Сохраняем старый вектор,
//	       MOV   Old_Vect_BX,BX      //указывающий на вторую часть ASCII

	       MOV   DX,OFFSET CHAR_DAT  //Устанавливаем указатель на новые
	       MOV   AX,SEG    CHAR_DAT  //символы
	       MOV   DS,AX

	       MOV   AH,Set_Interrupt    //Функция установки прерывания
	       MOV   AL,Tabl_Sim_Graph   //Вектор для пользовательских шрифтов
	       INT   21H

//	       JMP   NEAR PTR EXIT       //Выходим из программы
	     }

EXIT:     asm{
	       POP  ES   //Востанавливаем сохраненые значения
	       POP  DS
	     }
	  Can_Back = 1;  //Объявляем о том, что шрифты загружены
   return;
}
/**************************************************************************
 *  Подпрограмма для востановления старого вектора прерывания 1FH.        *
 *  Эта подпрограмма должна вызываться только после подпрограммы          *
 *  Set_Graph_Sim.                                                        *
 *  ВНИМАНИЕ!!! Эта функция может быть использована только  с  адаптерами *
 *  не ниже ЕGA.                                                          *
 **************************************************************************/
void Back_Graph_Sim( void ) {
  if ( Can_Back )       //Если шрифты загружались, то востановление
  {
     asm{
	   PUSH  DS                  //Сохраняем регистр данных

//	   MOV   DX,Old_Vect_BX      //Востанавливаем указатель на старые
//	   MOV   AX,Old_Vect_ES      //символы
	   MOV   DS,AX

	   MOV   AH,Set_Interrupt    //Функция установки прерывания
	   MOV   AL,Tabl_Sim_Graph
	   INT   21H

	   POP   DS                  //Востанавливаем регистр
	}
  } // endif
  return;
}

/**************************************************************************
 *  Подпрограмма для форматного текста на экран. Формат вывода совпадает  *
 *  с форматом функции printf. При выводе используется стандартная функ-  *
 *  ция outtextxy.                                                        *
 *  Описание переменных:                                                  *
 *  xcol - колонка вывода                                                 *
 *  ycol - строка вывода                                                  *
 *  fmt  - формат для вывода                                              *
 **************************************************************************/
void Gprintf( int xloc, int yloc, char far *fmt, ... ) {
  va_list  argptr;                       //Указатель на переданные аргументы
  char str[ Va_Str_Buf ];                //Буфер для преобразования аргументов

  va_start( argptr, fmt );               //Инициализиция va_  функции
  vsprintf( str, fmt, argptr );          //Преобразование строки в буфере
  CURSOR_OFF();
  outtextxy( xloc, yloc, str );          //Вывод полученной строки
  CURSOR_ON();
  va_end( argptr );                      //Закрываем  va_ функцию
  return;
}

/**************************************************************************
 *  Подпрограмма для изменения участка экрана, с использованием выбраного *
 *  цвета. Происходит заполнение произвольного уч.  Количество строк  мо- *
 *  жет быть любым (допустимым). Изменение  блока возможно с  использова- *
 *  нием логических операций наложения.                                   *
 *  ВНИМАНИЕ!!! Эта функция может быть использована только  с  адаптерами *
 *  не ниже ЕGA.                                                          *
 *  Описание переменных:                                                  *
 *  X1 - колонка для начала блока изменения                               *
 *  Y1 - строка для начала блока изменения                                *
 *  X2 - колонка для конца блока изменения                                *
 *  Y2 - строка для конца блока изменения                                 *
 *  color - цвет изменения                                                *
 **************************************************************************/
void Chand( int X1, int Y1, int X2, int Y2, COLOR color, MODE oper ) {
 CURSOR_OFF();
    asm{  //Производим начальные установки
	  PUSH ES         //Сохранение доп. сегмента
	  MOV  AX,Start_Video_Buf  //Указываем на начало видеобуфера
	  MOV  ES,AX
	  MOV  DX,Video_Port     //Выдаем указание адаптеру о режиме записи
	  MOV  AL,05H            //Режим равен 0
	  OUT  DX,AL
	  INC  DX
	  XOR  AL,AL             //Режим
	  OUT  DX,AL
	  DEC  DX           //Указываем адаптеру о способе наложения
	  MOV  AL,03H       //изображения
	  OUT  DX,AL        //Указываем на регистр смещения
	  INC  DX
	  MOV  AL,oper      //Указываем на операцию
	  OUT  DX,AL        //Меняем регистр вращения
	  MOV  DX,Video_Color   //Устанавливаем цвет изменения экрана
	  MOV  AL,02H
	  OUT  DX,AL
	  INC  DX
	  MOV  AL,color         //Наш цвет
	  OUT  DX,AL
	  MOV  AX,Y1      //Номер строки умножаем на 80 для получения
	  MOV  CL,04H //!!!
	  SHL  AX,CL     //смещения в видеобуфере
	  MOV  BX,AX
	  MOV  CL,02H //!!!
	  SHL  AX,CL
	  ADD  BX,AX
	  //Блок проверки размерa блока
	  MOV  CX,X1
	  MOV  AX,CX   //Сохраняем первую координату для дальнйшего использ.
	  MOV  DX,X2
	  PUSH DX      //Сохраняем вторую координату для дальнейшего использ.
	  SHR  CX,01H  //Находим смещение координат от начала видео блока
	  SHR  CX,01H
	  SHR  CX,01H
	  PUSH  CX
	  MOV  CL,03H
	  SHR  DX,CL  //Для этого делим их на 8 (один пиксел на байт)
	  POP  CX     // !!!
	  ADD  BX,CX   //Записываем смещение в указатель
	  CMP  CX,DX   //Если не равны, то на обработку нескольких блоков
	  JNZ  MANY_BL
// ************ БЛОК ОБРАБОТКИ НЕБОЛЬШИХ УЧАСТКОВ ЭКРАНА ************
	  NOT  AL            //Блок для нахожд. смещения пиксела х1 в байте
	  AND  AL,00000111B  //Выделение нужных битов
	  MOV  CL,AL
	  XOR  CH,CH
	  MOV  AL,01H
	  OR   CL,CL
	  JZ   IGN3
	}
REP1:asm{ STC                //Устанавливаем флаг переноса
	  RCL  AL,01H        //Дополнение байта справа 1 битом
	  LOOP REP1
	}
IGN3:asm{ POP  DX            //Востанавливаем значение второго байта
	  NOT  DL            //Блок для нахождения смещ. пиксела х2 в байте
	  AND  DL,00000111B  //Выделение битов
	  MOV  CL,DL
	  XOR  CH,CH
	  XOR  AH,AH

	  OR   CL,CL
	  JZ   IGNO
	}
REP2:asm{ STC                //Устанавливаем флаг переноса
	  RCL  AH,01H        //Дополнение байта справа 1 битом
	  LOOP REP2
	}
IGNO:asm{
	  XOR  AL,AH        //Получаем разрешеные битовые плоскости
	  MOV  DX,Video_Port          //Разрешаем адаптеру менять
	  MOV  AH,AL
	  MOV  AL,08H                 //битовые плоскости
	  OUT  DX,AL
	  MOV  AL,AH
	  INC  DX
	  OUT  DX,AL

	  MOV  DX,Y1        //Указываем количетво строк замены
	  MOV  CX,Y2
	  SUB  CX,DX
	  INC  CX           //Увеличение номера на 1 для включения нижней
			    //строки
	  MOV  AH,0FFH    //Устанавливаем наложение цветов
	  MOV  AL,oper    //Режим наложения
	  CMP  AL,0FH     //Если AND, то наложение равно 0
	  JNZ  NEXT_LINE1
	  XOR  AH,AH      //Наложение для AND
	}
NEXT_LINE1:asm{  //Непосредственно замена
		 MOV  AL,ES:[BX] //Читаем регистры задвижки
		 MOV  ES:[BX],AH //Изменяем 8 пикселов
		 ADD  BX,Line_Next_Col //Переход к следующей строке
		 LOOP NEXT_LINE1       //Не все строки обработаны ?
		 JMP  NEAR PTR EXIT       //Выход на конец модуля
	      }
// ************* БЛОК ДЛЯ ОБРАБОТКИ НЕСКОЛЬКИХ СЕГМЕНТОВ ИЗОБРАЖЕНИЯ
MANY_BL:   asm{
		 NOT  AL            //Блок для нахожд. смещения пиксела х1
		 AND  AL,00000111B  //Выделение битов
		 MOV  CL,AL
		 XOR  CH,CH
		 MOV  AL,01H
		 OR   CL,CL
		 JZ   IGN1
	      }
REP3:      asm{  STC                //Устанавливаем флаг переноса
		 RCL  AL,01H        //Сдвиг влево
		 LOOP REP3
	      }
IGN1:      asm{  MOV  DX,Video_Port        //Разрешаем адаптеру менять
		 MOV  AH,AL
		 MOV  AL,08H                //битовые плоскости
		 OUT  DX,AL
		 MOV  AL,AH
		 INC  DX
		 OUT  DX,AL
		 MOV  DX,Y1        //Указываем количетво строк замены
		 MOV  CX,Y2
		 SUB  CX,DX
		 INC  CX           //Для нижней строки
		 MOV  AH,0FFH    //Устанавливаем наложение цветов
		 MOV  AL,oper    //Режим наложения
		 CMP  AL,0FH     //Если AND, то наложение равно 0
		 JNZ  NEXT_LINE2
		 XOR  AH,AH      //Наложение для AND
	       }
NEXT_LINE2:asm{  //Непосредственно замена
		 MOV  AL,ES:[BX] //Читаем регистры задвижки
		 MOV  ES:[BX],AH //Изменяем 8 пикселов
		 ADD  BX,Line_Next_Col
		 LOOP NEXT_LINE2       //Не все строки обработаны ?
		 //Подблок для обработки второй координаты
		 MOV  AX,Y1      //Номер строки умножаем на 80 для получения
		      PUSH CX //!!!
		 MOV  CL,04H//!!!
		 SHL  AX,CL     //смещения в видеобуфере
		 MOV  BX,AX
		 MOV  CL,02H //!!!
		 SHL  AX,CL

		 ADD  BX,AX
		 POP  DX         //Востанавливаем значение второй координаты
		 MOV  AX,DX      //Нахождение смещения в видео блоке

		 MOV  CL,03H
		 SHR  DX,CL
		      POP  CX //!!!
		 ADD  BX,DX
		 NOT  AL         //Устанавливаем разрешенные биты в блоке 2
		 AND  AL,00000111B
		 MOV  CL,08H
		 SUB  CL,AL
		 XOR  AX,AX
		 XOR  CH,CH
		 OR   CL,CL
		 JZ   IGN2
	      }
REP4:      asm{  STC             //Устанавливаем флаг переноса
		 RCR  AL,01H
		 LOOP REP4
	      }
IGN2:      asm{  MOV  DX,Video_Port   //Разрешаем адаптеру менять
		 MOV  AH,AL
		 MOV  AL,08H          //битовые плоскости
		 OUT  DX,AL
		 MOV  AL,AH
		 INC  DX
		 OUT  DX,AL
		 MOV  DX,Y1        //Указываем количетво строк замены
		 MOV  CX,Y2
		 SUB  CX,DX
		 INC  CX
		 MOV  AH,0FFH    //Устанавливаем наложение цветов
		 MOV  AL,oper    //Режим наложения
		 CMP  AL,0FH     //Если AND, то наложение равно 0
		 JNZ  NEXT_LINE3
		 XOR  AH,AH      //Наложение для AND
	       }
NEXT_LINE3:asm{  //Непосредственно замена
		 MOV  AL,ES:[BX] //Читаем регистры задвижки
		 MOV  ES:[BX],AH //Изменяем 8 пикселов
		 ADD  BX,Line_Next_Col
		 LOOP NEXT_LINE3       //Не все строки обработаны ?
		 MOV  CX,X1     //Определяем нужна ли внутренняя обр. блока
		 MOV  AX,X2
		 SHR  CX,01H    //Деление столбцов на 8
		 SHR  CX,01H
		 SHR  CX,01H
		 SHR  AX,01H
		 SHR  AX,01H
		 SHR  AX,01H
		 SUB  AX,CX     //Если их разность >1, то обработка нужна
		 CMP  AX,01H
		 JZ   EXIT     //Если не нужна, то выход из подпрограммы
		 SHL  CX,01H  //Нужна, находим параметры для передачи
		 SHL  CX,01H
		 SHL  CX,01H
		 ADD  CX,08H
		 MOV  X1,CX    //в функцию Chen_Block
		 DEC  AX
		 MOV  X2,AX

		 MOV  DX,Y1        //Указываем количество строк замены
		 MOV  CX,Y2
		 SUB  CX,DX
		 INC  CX
		 MOV  Y2,CX
	      }
	   Chan_Block( X1, Y1, X2, Y2, color, oper ); //Обр. внутр. блок

EXIT:      asm   POP  ES     //Востанавливаем дополнительный сегмент
 bar (0,0,0,0);
 CURSOR_ON();
 return;
}

/**************************************************************************
 *  Подпрограмма для вывода разноцветного текста на экран в графическом   *
 *  режиме. Символ '$' задает ключ изменения цвета. Символ '&' задает     *
 *  ключ перехода на новую строку.                                        *
 *  Описание переменных:                                                  *
 *  x - колонка вывода                                                    *
 *  y - строка вывода                                                     *
 *  color1 - основной цвет для вывода                                     *
 *  color2 - альтернативный цвет для вывода                               *
 *  s - строка для вывода                                                 *
 **************************************************************************/

void Print( int x, int y, COLOR color1, COLOR color2, char *s ) {
 char  *d = s;     //Дублируем указатель на строку
 COLOR c;          //Временный указатель цвета
 int t=x,          //Указатель начала
     v=x;          //Указатель текущего вывода
 CURSOR_OFF();setcolor( color1 ); //Установка начального цвета
 while( *d )  { //Продолжать обработку до конца строки
  switch ( *d )  {   //Проверка текущего символа
   case '$':
    c=color1;           //Блок изменения цвета и вывода
    color1=color2;      //части строки на экран
    color2=c;
    *d = '\0';       //Получаем строку
    outtextxy(x,y,s);   //Вывод полученной строки
    setcolor(color1);   //Меняем цвет на обратный
    *d++ = '$'; //Восстанавливаем значение строки для дальнейшего использования
    x = v;              //Изменяем координату вывода
    s = d;              //Совмещаем указатели на строку
   break;
   case '&':
    *d = '\0';        //Блок переноса текста на экран
    outtextxy(x,y,s); //и вывода части строки
    *d++ = '&';         //Восстанавливаем измененное значение
    y += 10;            //Переход на следующюю строку
    x = v = t;          //Востанавливаем позицию начала вывода
    s = d;              //Совмещаем указатели на строку
   break;
   default:
    d++;                //Блок перехода к следующему символу
    v += 8;             //Переход к следующей позиции
  }             // switch
 }               // while
 outtextxy( x, y, s);  //Вывод последней части строки на экран
 CURSOR_ON();return;
}


/***************************************************************************
 *  Данная подпрограмма проверяет,есть ли в данной строке символов введен- *
 *  ный с клавиатуры код. Если он есть, то выдается его порядковый номер   *
 *  в данной строке, обработанный по "модулю 4". Если данного символа нет, *
 *  то выдается значение 100.                                              *
 *  Описание переменых:                                                    *
 *  str - стока, где производится поиск                                    *
 *  sim - код клавиатуры                                                   *
 ***************************************************************************/
MODE Find_Key( char *str, char sim ) {
 MODE i = 0; //Смещение в строке
 //Цикл до совпадения или конца строки
 while( ( *str ) && ( *str++ != sim) )
  i++;
 if ( *str )    //Был ли конец строки
  i >>= 2;    //Нет, тогда MOD 4
 else i = 100;    //Да, возвращаем 100
 return( i );
}

/***************************************************************************
 *  Подпрограммa для считывания символа из буфера клавиатуры. Отслеживают- *
 *  ся все комбинации клаваш. Возможную мнемонику смотрите в файле         *
 *  KEY.H. Перед обращением к буферу клавиатуры считывает символ из внутре-*
 *  ннего буфера, если он есть.                                            *
 ***************************************************************************/
static KEY Buf[ MAX_BUF ];  //Внутренний буфер клавиатуры
/*static*/ KEY Start = 0,       //Указатели в буфере
	   End = 0;
char near  CHAR_TABL[128] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07, //00H
0x08,0x09,0x0A,0x0B,0x0C,0x0D,0x0E,0x0F, //08H
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17, //10H
0x18,0x19,0x1A,0x1B,0x1C,0x1D,0x1E,0x1F, //18H
0x20,0x21,0x9D,0x2F,0xFD,0x3A,0x2E,0xED, //20H  !"# $%&'
0x3F,0x25,0x3B,0x2B,0xA1,0x2D,0xEE,0xF0, //28H ()*+ ,-./
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37, //30H 0123 4567
0x38,0x39,0x86,0xA6,0x81,0x3D,0x9E,0xF1, //38H 89:; <=>?
0x22,0x94,0x88,0x91,0x82,0x93,0x80,0x8F, //40H @ABC DEFG
0x90,0x98,0x8E,0x8B,0x84,0x9C,0x92,0x99, //48H HIJK LMNO
0x87,0x89,0x8A,0x9B,0x85,0x83,0x8C,0x96, //50H PQRS TUVW
0x97,0x8D,0x9F,0xE5,0x5C,0xEA,0x2C,0x5F, //58H XYZ[ \]^_
0x29,0xE4,0xA8,0xE1,0xA2,0xE3,0xA0,0xAF, //60H `abc defg
0xE0,0xE8,0xAE,0xAB,0xA4,0xEC,0xE2,0xE9, //68H hijk lmno
0xA7,0xA9,0xAA,0xEB,0xA5,0xA3,0xAC,0xE6, //70H pqrs tuvw
0xE7,0xAD,0xEF,0x95,0x7C,0x9A,0x28,0x7F  //78H xyz{ |}~
};

KEY  Get_Key( void ) {
  KEY  sim;              //Символ, кторый будет содержать значение буфера

//   ТАБЛИЦА ПРЕОБРАЗОВАНИЯ К РУССКИМ СИМВОЛАМ
//asm {

  if (Start != End)      //Есть ли символ во внутреннем буфере
  {
    sim = Buf[ End++ ];  //Есть, считать символ
    End %= MAX_BUF;    //Контроль выхода за пределы буфера
  }
  else
  {
       asm{
	    PUSH ES         //Cохраняем дополнительный сегмент
	    MOV  AH,Get_Key_BIOS     //Считываем символ из буфера клавиатуры
	    INT  16H
	    CMP  AL,00H     //Если расширеный код, то выход
	    JNZ   NEXT1
	    JMP  NEAR PTR EXIT
	  }
NEXT1: asm{
	    XOR  AH,AH      //Обнуление верхнего байта
//            mov  Hu,al //!!!
	    CMP  AL,080H    //Если символ из стандарта ASCII, то выходим
	    JB   NEXT2
	    JMP  NEAR PTR EXIT
	  }
NEXT2: asm{
	    MOV  CX,AX      //Сохраняем полученный байт
	    MOV  AH,Chack_Key_BIOS   //Действует ли режим Scroll
	    INT  16H
	    TEST AL,00010000B
	    MOV  AX,CX            //Востанавливаем значение байта
	    JNZ  NEXT3            //Если нет, то выходим
	    JMP  NEAR PTR EXIT
	  }
NEXT3: asm{
	    MOV  BX,OFFSET CHAR_TABL    //Преобраз. полученный символ в русский
	    MOV  CX,SEG CHAR_TABL       //Сегмент нашей  таблицы
	    MOV  ES,CX
	    ADD  BX,AX
	    MOV  AL,ES:[BX]           //Считываем перобразованный символ
//	    JMP  NEAR PTR EXIT
	  }
EXIT:       asm{
		 MOV  sim,AX   //Востанавливаем его
		 POP  ES       //Востанавливаем дополнительный сегмент
	       }
   } //Конец else

   return (sim);              //Возвращаем полученный символ
}

/***************************************************************************
 *  Подпрограммa для записывания символов во внутренний буфер программы.   *
 *  Эти символы будут считаны при следующем обращении к функции Get_Key.   *
 *  Внутренний буфер организован циклически, при большом количетве запи-   *
 *  писей данные в буфере могут затираться. Размер буфера можно изменить   *
 *  испльзуя переменную MAX_BUF.                                           *
 *  Подпрограмма имеет переменное число параметров.                        *
 *  kol - количество записываемых символов                                 *
 ***************************************************************************/
void Set_Key( KEY kol, ... ) {
  KEY  *ptr = &kol;           //Указываем на первый символ в строке парам.
  for(; kol != 0; kol-- )   {
    Buf[ Start++ ] = *++ptr;  //Последовательно записываем все символы
    Start %= (MAX_BUF);     //во внутренний буфер
  }
  return;
}

/***************************************************************************
 *  Подпрограммa для записывания символов во внутренний буфер программы.   *
 *  Эти символы будут считаны при следующем обращении к функции Get_Key.   *
 *  Внутренний буфер организован циклически, при большом количетве запи-   *
 *  писей данные в буфере могут затираться. Размер буфера можно изменить   *
 *  испльзуя переменную MAX_BUF.                                           *
 *  Символ, который был последним при обращении к фукнкции будет в буфере  *
 *  первым, т.е. будет исполнен первым                                     *
 *  Подпрограмма имеет переменное число параметров.                        *
 *  kol - количество записываемых символов                                 *
 ***************************************************************************/

void Set_Insert_Key( KEY kol, ... ) {
  KEY  *ptr = &kol;           //Указываем на первый символ в строке парам.
  for(; kol != 0; kol-- )   {
    if( !(End)-- )        //Последовательно записываем все символы
      End = MAX_BUF-1;
    Buf[ End ] = *++ptr;   //во внутренний буфер
  }
  return;
}

 /***************************************************************************
 *                                                                         *
 *  Подпрограммa очистки буфера клавиатуры.                                *
 *                                                                         *
 ***************************************************************************/
void Clear_Buf( void ) {
  End = Start;
  asm{
      PUSH  ES            //Сохраняем доплнительный сегмент
      CLI                 //Запрещаем прерывания
      SUB   AX,AX
      MOV   ES,AX
      MOV   AX,ES:[41AH] //Устанавливаем указатели буфера на
      MOV   ES:[41CH],AX //одно и тоже значение
      STI                 //Разрешаем прерывания
      POP   ES            //Восстанавливаем дополнительный сегмент
     }
 return;
}

KEY Hit_Key (void) {
if (Start != End) return (1);
asm push es;
asm  mov ax,0;
asm  mov es,ax;
asm  mov ax,es:[41ah];
asm  mov cx,es:[41ch];
asm pop es;
 if (_AX==_CX) return (0);
 return (1);
}


/****************************************************************************
 *     Данная подпрограмма производит звук заданной частоты и длительности  *
 * Подпрограмма может работать на любой машине IBM.                         *
 * Подпрограмма может использоваться для выдачи предупредительных сигналов  *
 * или для произведения музыки.                                             *
 *                                                                          *
 * Описание переменных:                                                     *
 * chastota - частота звучания                                              *
 * pause - длительность ( 1 = 1 милисекунды )                               *
 ****************************************************************************/
void Sound( int chastota, int pause ) {
extern char SOUND;

 if( SOUND )  { // Если сигнал разрешен, то выдать его
   asm{
	  PUSH  AX   //Сохраняем используемые регистры
	  PUSH  BX
	  PUSH  CX
	  PUSH  DX
	  PUSH  DI

	  CLI                  //Запрещаем прерывания
	  MOV   DI,chastota    //Переносим значения в регистры
	  MOV   BX,pause

	  MOV   AL,0B6H      //Записать в регистр режима таймера
	  OUT   43H,AL
	  MOV   DX,14H       //Длительность времени =
	  MOV   AX,4F38H     //1331000 / частота
	  DIV   DI

	  OUT   42H,AL       //Записать младший байт счетчика таймера 2
	  MOV   AL,AH
	  OUT   42H,AL       //Записать старший байт счетчика таймера 2

	  IN    AL,61H       //Считать текущую установку порта В
	  MOV   AH,AL        //и сохранить ее в регистре AH
	  OR    AL,03H       //Включить динамик
	  OUT   61H,AL
	}
WAIT:asm  MOV   CX,2A00H     //Выждать 10 мс
SPKR:asm{
	  LOOP  SPKR
	  DEC   BX           //Счетчик длительности исчерпан ?
	  JNZ   WAIT         //Нет. Продолжить звучание

	  MOV   AL,AH        //Да. Восстаносить исходную установку порта
	  OUT   61H,AL

	  POP   DI           //Востановить регистры
	  POP   DX
	  POP   CX
	  POP   BX
	  POP   AX
	  STI                //Разрешить прерывания
	}
 } // if
 return;
}

/* void Locate( char kol, char strok, char page ) {
  asm  MOV    DL,kol    ;
  asm  MOV    DH,strok  ;
  asm  MOV    BH,page   ;
  asm  MOV    AH,02h    ;
  asm INT    10h        ;
}  */


// Void function
void Nop( void ){ return; }
