(*~\Глагол\ПриложенияГОС\Игры\~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
(**)                          ОТДЕЛ Тетрис+;
(*============================================================================*)
(* НАЗНАЧЕНИЕ: игра "Тетрис"                                                  *)
(* ОБОЗНАЧЕНИЯ:                                                               *)
(*   уровень - скоростной уровень игры (0-самый медленный, 9-самый быстрый)   *)
(*   слой    - заполненных и провалившихся слоёв                              *)
(*   кирпич  - падающая фигура                                                *)
(*   ящик    - то место, в котором падают кирпичи                             *)
(*   клетки  - квадратики, из которых построенны кирпичи                      *)
(*============================================================================*)

ИСПОЛЬЗУЕТ 
  Игра    ИЗ "..\..\Отделы\Игры\Тетрис\",                    (* алгоритм игры *)
(*
  НаЭкран ИЗ "..\..\Отделы\Обмен\ВводВывод\";
*)
  ОС      ИЗ "..\..\Отделы\Обмен\",
(*
 цМатем   ИЗ "..\..\Отделы\ЧисАн\32\ц\",
*)
 дМатем   ИЗ "..\..\Отделы\ЧисАн\64\д\",

  Ввод    ИЗ "..\..\Отделы\Обмен\",
  Окно    ИЗ "..\..\Отделы\Обмен\",

  Поле    ИЗ "..\..\Отделы\Поле\",
  Надел   ИЗ "..\..\Отделы\Поле\",
 Подложка ИЗ "..\..\Отделы\Поле\",
  Записка ИЗ "..\..\Отделы\Поле\",
  Черта   ИЗ "..\..\Отделы\Поле\",
  Кнопка  ИЗ "..\..\Отделы\Поле\";

ПОСТ
  слоёвНаУровень=10; (* для перевода на следующий уровень *)
  уровней       =10;
                     (* действия *)
  діяПредУровень =1;
  діяСледУровень =2;
  діяЗаново      =3;
  діяВыход       =4;
  діяПриостановка=5;

ПЕР
     уровень:ЦЕЛ;
    задержка:ЦЕЛ;                 (* между сменой кадров *)
  будетСлоёв:ЦЕЛ;                 (* для перевода на следующий уровень *)

   текстСлоёвД,
   текстУровеньД:Записка.Доступ;  (* надписи *)

      играем:КЛЮЧ;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Случ(до:ЦЕЛ):ЦЕЛ;                     (* Цель:  выдать случайное число *)
УКАЗ
  ВОЗВРАТ УЗК(ВШИРЦЕЛ(дМатем.случ()*до))
КОН Случ;

(*----------------------------------------------------------------------------*)
ЗАДАЧА рисоватьКлетку(x,y,цвет:ЦЕЛ);
(*
 * прорисовка на экране клетки ящика, 
 * передаётся в распоряжение отделу Ящик
 *)
ПЕР
  к,с:ЦЕЛ;                              (* экранные координаты клетки *)
УКАЗ
  с:=1+y*1;
  к:=1+x*2;                             (* расширим клетку на 2 колонки *)
  Окно.Цвет(с,к,с,к+1,ВЗНАК(цвет));
  ЕСЛИ
       цвет = Игра.Пустоцвет
  ТО
    Окно.ЦепьЗнаков(с,к,с,к+1," .")
  ИНАЧЕ
    Окно.ЦепьЗнаков(с,к,с,к+1,"  ")
  КОН
КОН рисоватьКлетку;

(*----------------------------------------------------------------------------*)
ЗАДАЧА НачатьЗаново;                            (* подготовиться к новой игре *)
УКАЗ
   уровень:=0;
  задержка:=0;
  будетСлоёв:=слоёвНаУровень;
  играем:=ВКЛ;
  Игра.НачатьЗаново
КОН НачатьЗаново;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Показания;                            (* обновляет показания на экране *)
УКАЗ
  Записка.Из4хЦел(текстСлоёвД,"Слоёв: %d",Игра.слоёв,0,0,0);
  Записка.Из4хЦел(текстУровеньД,"%d",уровень,0,0,0)
КОН Показания;

(*----------------------------------------------------------------------------*)
ЗАДАЧА ПредУровень;
УКАЗ
  ЕСЛИ
      уровень > 0
  ТО  
    УМЕНЬШИТЬ(уровень);
    Показания
  КОН
КОН ПредУровень;

(*----------------------------------------------------------------------------*)
ЗАДАЧА СледУровень;
УКАЗ
  ЕСЛИ
       уровень < уровней-1
  ТО 
    УВЕЛИЧИТЬ(уровень); 
    Показания
  КОН
КОН СледУровень;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Приём(   полеД:Поле.Доступ;
             посылка+:Ввод.нПосылка);
(*
 * получить и обработать управляющие послания
 *)
ПЕР
  код:ЦЕЛ;
УКАЗ
  ДЛЯ
      посылка
  ВИДА
  | Ввод.нОтКлавиш:
              код:=посылка.код;
      посылка.код:=0;                      (* скорее всего отработаем посылку *)
      ВЫБРАТЬ 
              код
      ИЗ
      | 25H: ЕСЛИ играем ТО Игра.КирпичВлево     КОН (* Стрелки *)
      | 26H: ЕСЛИ играем ТО Игра.ПовернутьКирпич КОН
      | 27H: ЕСЛИ играем ТО Игра.КирпичВправо    КОН
      | 28H: ЕСЛИ играем ТО Игра.КирпичУронить   КОН
      | 1BH: полеД.состояние:=діяВыход               (* Esc *)
      | 58H: ЕСЛИ
                  посылка.упрАльт
             ТО                                      (* Alt+'X' *)
               полеД.состояние:=діяВыход
             ИНАЧЕ
               посылка.код:=код
             КОН
      ИНАЧЕ
        посылка.код:=код
      КОН
  | Кнопка.нПосылка:
      ВЫБРАТЬ
              посылка.кнопкаД.действие
      ИЗ
      | діяЗаново:       НачатьЗаново
      | діяПредУровень:  ПредУровень
      | діяСледУровень:  СледУровень
      | діяВыход:        полеД.состояние:=діяВыход
      | діяПриостановка: играем:=НЕ играем
      КОН
  ИНАЧЕ
  КОН
КОН Приём;

(*----------------------------------------------------------------------------*)
ЗАДАЧА СоздатьПоле():Поле.Доступ;
                              (* создаёт рабочее поле экрана с кнопочным меню *)
ПЕР
      полеД:    Поле.Доступ;                      (* рабочее поле экрана *)
  подложкаД:Подложка.Доступ;                      (* подложка поля       *)

  чЧерта1Д,
  чЧерта2Д,
  чЧерта3Д,
  чЧерта4Д:Черта.Доступ;                          (* черты               *)

  кнопВыход,
  кнопЗаново,
  кнопМеньше,
  кнопБольше,
  кнопПриостановить:Кнопка.Доступ;                (* экранные кнопки     *)

  словоУровеньД:Записка.Доступ;                   (* слово "Уровень"     *)
УКАЗ
                                                              (* создаём поле *)
      полеД:=Поле.Создать(0,0,25,46,ПУСТО,ОТКЛ,Приём);
                                                            (* создаём наделы *)
  подложкаД:=Подложка.Создать(0,0,0,0,"");

  текстСлоёвД  :=Записка.Создать( 6,22,1,11,""); 
  текстУровеньД:=Записка.Создать(21,33,1, 2,""); 

  словоУровеньД:=Записка.Создать(20,30,1,7,"Уровень"); 
                                                             (* создаём черты *)
  чЧерта1Д:=Черта.Создать( 0,21,0,1); 
  чЧерта2Д:=Черта.Создать(19,21,1,0); 
  чЧерта3Д:=Черта.Создать(22,21,1,0); 
  чЧерта4Д:=Черта.Создать(17,21,1,0); 
                                                            (* создаём кнопки *)
  кнопМеньше:=Кнопка.Создать(21,22,"[ ~Меньше ]",діяПредУровень,ВКЛ); 
  кнопБольше:=Кнопка.Создать(21,35,"[ ~Больше ]",діяСледУровень,ВКЛ); 
  кнопЗаново:=Кнопка.Создать(23,22,"[ ~Заново ]",діяЗаново,ВКЛ); 
  кнопВыход :=Кнопка.Создать(23,35,"[ ~Выход  ]",діяВыход,ВКЛ); 
  кнопПриостановить:=Кнопка.Создать(18,25,"[ ~Приостановка ]",діяПриостановка,ВКЛ); 

                    (* добавляем наделы в порядке отрисовки и получения ввода *)
  Поле.ДобавитьНадел(полеД,подложкаД);

  Поле.ДобавитьНадел(полеД,текстСлоёвД);
  Поле.ДобавитьНадел(полеД,текстУровеньД);

  Поле.ДобавитьНадел(полеД,словоУровеньД);

  Поле.ДобавитьНадел(полеД,чЧерта1Д);
  Поле.ДобавитьНадел(полеД,чЧерта4Д);
  Поле.ДобавитьНадел(полеД,чЧерта3Д);
  Поле.ДобавитьНадел(полеД,чЧерта2Д);
  Поле.ДобавитьНадел(полеД,кнопПриостановить);
  Поле.ДобавитьНадел(полеД,кнопМеньше);
  Поле.ДобавитьНадел(полеД,кнопБольше);
  Поле.ДобавитьНадел(полеД,кнопЗаново);
  Поле.ДобавитьНадел(полеД,кнопВыход);
  ВОЗВРАТ полеД
КОН СоздатьПоле;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Пауза(мс:ЦЕЛ);
УКАЗ
  Окно.Отработать;
  ОС.Спать(мс)
КОН Пауза;

(*----------------------------------------------------------------------------*)
ЗАДАЧА Переход(номерЧасов:ЦЕЛ);
УКАЗ
  ЕСЛИ
       играем И (задержка <= 0)
  ТО                                  (* каждый проход - смена картинки *)
    ЕСЛИ
         Игра.состояние = Игра.состУпор
    ТО
      играем:=ОТКЛ;
      Игра.КонецИгры(Пауза);
      НачатьЗаново
    КОН;
    ЕСЛИ
         Игра.состояние = Игра.состНовый
    ТО
      Показания;
      ЕСЛИ
           Игра.слоёв >= будетСлоёв
      ТО
        будетСлоёв:=Игра.слоёв+слоёвНаУровень;
        СледУровень
      КОН;
      Игра.НовыйКирпич(Случ(Игра.Кирпичей-1),(9+Случ(6))*16)
    КОН;
    задержка:=уровней-уровень+1;
    Игра.Переход
  КОН;
  УМЕНЬШИТЬ(задержка)
КОН Переход;

(*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*)
ЗАДАЧА Поехали;
ПЕР
  полеД:Поле.Доступ; (* рабочее поле экрана *)
   часы:ЦЕЛ;
УКАЗ
  Окно.Графическое("Тетрис","Lucida Console",24,Переход);
(*
  Окно.Текстовое(Переход);
*)
                     полеД:=СоздатьПоле();
  Поле.ОкноНаВсёПоле(полеД);
  Поле.Рисовать(полеД);

  часы:=Окно.СоздатьЧасы(1,50);  (* самый быстрый переход за 50 мс *)
        Окно.Показать;
  ПОКА
       полеД.состояние = Поле.состРабота
  ВЫП                            (* проверяем и обрабатываем ввод от человека *)
    Поле.Проверить(полеД)
  КОН;
  Окно.УдалитьЧасы(часы)
КОН Поехали;

(*-++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-*)
УКАЗ
  Игра.Подготовить(рисоватьКлетку);
  НачатьЗаново;
  Поехали
КОН Тетрис.
