unit DoorHack;

interface

uses
  windows, sysutils, loadz, aData;

procedure Hack(x, y: byte);

implementation

uses
  MyCRT;

var
  arr: array of integer;
  DecodeStr: array of char;
  DumpStr: array of char;
  APassword: string = '';
  AlsoOpen: boolean = false;
  GlobX: integer = 0;
  GlobY: integer = 0;


var
  aRightCode: integer = 0;

  
const
  Screen: array[1..29] of string =
  (
    '+=================================+',
    '|                                 |',
    '|   +=========================+   |',
    '|   |       Получение...      |   |',
    '|   |                         |   |',
    '|   |  [                   ]  |   |',
    '|   |                         |   |',
    '|   |       В работе...       |   |',
    '|   +=========================+   |',
    '|                                 |',
    '|                                 |',
    '|   +-----+   +-----+   +-----+   |',
    '|   | [1] |   | [2] |   | [3] |   |',
    '|   +-----+   +-----+   +-----+   |',
    '|                                 |',
    '|   +-----+   +-----+   +-----+   |',
    '|   | [4] |   | [5] |   | [6] |   |',
    '|   +-----+   +-----+   +-----+   |',
    '|                                 |',
    '|   +-----+   +-----+   +-----+   |',
    '|   | [7] |   | [8] |   | [9] |   |',
    '|   +-----+   +-----+   +-----+   |',
    '|                                 |',
    '|   +-----+   +-----+   +-----+   |',
    '|   | [C] |   | [0] |   | [<] |   |',
    '|   +-----+   +-----+   +-----+   |',
    '|                                 |',
    '|                                 |',
    '|=================================|'
  );
  SecondScreen: array[1..21] of string =
  (
    '+=======================================================+',
    '|                                                       |',
    '| +==========================================+          |',
    '| |                                          |          |',
    '| |                                          |   INC    |',
    '| |                                          | property |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |          |',
    '| |                                          |  +===+   |',
    '| |                                          |  | 0 |   |',
    '| +==========================================+  +===+   |',
    '|                                               POWER   |',
    '+=======================================================+'
   );
   ThirdScreen: array [1..7] of string =
   (
      '+=======================================================+',
      '|                                                       |',
      '| +===================================================+ |',
      '| |Введите ключ:                                      | |',
      '| +===================================================+ |',
      '|                                                       |',
      '+=======================================================+'
   );
const
  Length = 15;
  MAXDUMPSIZE = 1024;
  MINDUMPSIZE = 128;
  DumpX = 43;
  Dumpy = ((RESOLUTION_Y - System.Length(Screen)) div 2) + 8;
  NumStrZ = 13;
  STRLEN = 8;
  Color = LightGreen;
  StartY = DumpY + 1;
  StartX = 12;

Function GetRandomLetter: char;
begin
  GetRandomLetter := #0;
  case Random(2) of
    0: GetRandomLetter := chr(Random(ord('F') - ord('A') + 1) + ord('A'));
    1: GetRandomLetter := chr(Random(ord('9') - ord('0') + 1) + ord('0'))
  end;
end;

Function GetRandomBukva: char;
begin
  GetRandomBukva := #0;
  case Random(2) of
    0: Result := chr(Random(ord('Z') - ord('A')) + ord('A'));
    1: Result := chr(Random(ord('z') - ord('a')) + ord('a'));
  end;
end;

Function GetRandomWord: string;
const
  MAXLEN = 16;
var
  i: integer;
begin
  Result := '';
  for i := 1 to Random(MAXLEN) + 1 do
    Result := Result + GetRandomBukva;
end;

Function GetRandomChar: char;
begin
  GetRandomChar := chr(Random(221) + 35);
end;

Procedure MakeDump(Pass: string);
var
  i, j, k: integer;
  st: string;
  x, y: integer;
begin
  aPassword := Pass;
  TextColor(LightGray);
  x := System.Length(Screen[1]) + 5;
  y := ((RESOLUTION_Y - System.Length(SecondScreen)) div 2);
  for i := 1 to System.Length(SecondScreen) do
  begin
    GotoXY(x, y + i - 1);
    write(SecondScreen[i]);
  end;
  RepaintScreen;
  j := Random(MAXDUMPSIZE - MINDUMPSIZE) + MINDUMPSIZE;
  SetLength(DumpStr, j);
  i := 0;
  while (i < j) do
  begin
    if Random(100) mod 80 = 0 then
    begin
      st := GetRandomWord;
      for k := 1 to System.Length(st) do
        if (i + k - 1) < j then
          DumpStr[i + k - 1] := st[k]
        else
          break;
      i := i + System.Length(st) - 1;
    end
    else
      DumpStr[i] := GetRandomChar;
    inc(i);
  end;
  i := Random(j - System.Length(Pass));
  for j := 1 to System.Length(Pass) do
    DumpStr[i + j - 1] := Pass[j];
  GotoXY(x + 8, y + 4);
  TextColor(LightGreen);
  write(STR_CONTENT_GETTING + ' ');
  write(STR_PZU_CHIP);
  j := System.Length(DumpStr);
  for i := 1 to j do
  begin
    GotoXY(x + 15, y + 6);
    write(STR_YACHEIKA + inttostr(i) + STR_FROM + inttostr(j));
    RepaintScreen;
    Sleep(5);
  end;
end;

Function GetThreeLength(num: integer): string;
begin
  Result := '';
  Result := inttostr(num div 100) + inttostr((num div 10) mod 10) + inttostr(num mod 10);
end;

procedure DrawLine(num: integer);
var
  i, j: integer;
  st: string;
  len: integer;
begin
  i := num * STRLEN + 1;
  len := System.Length(DumpStr);
  for j := 1 to STRLEN do
  begin
    if Len < i then
      st := st + #0
    else
      st := st + DumpStr[i];
    inc(i);
  end;
  for j := 1 to STRLEN do
    write(' ' + GetThreeLength(ord(st[j])));
  write(' ');
  for j := 1 to STRLEN do
    if st[j] <> #0 then
      write(st[j])
    else
      write('.');
  GotoXY(DumpX, wherey + 1);
end;

procedure DrawList(num: integer; aColor: byte);
var
  i: integer;
begin
  GotoXY(DumpX, DumpY);
  TextColor(aColor);
  for i := 1 to NumStrZ do
    DrawLine(num + i - 1);
end;

procedure ReadString(var text: string);
var
  c: char;
  st: string;
begin
  text := '';
  st := '';
  repeat
    c := readkey;
    if not (c in [KEY_RETURN, KEY_ESCAPE, KEY_BACKSPACE]) and (System.Length(st) < 34) then
    begin
      write(c);
      st := st + c;
    end
    else if c = KEY_BACKSPACE then
    begin
      GotoXY(wherex - 1, wherey);
      write(' ');
      GotoXY(wherex - 1, wherey);
      st := Copy(st, 1, System.Length(st) - 1);
    end;
  until (c = KEY_RETURN) or (c = KEY_ESCAPE);
  if (c = KEY_ESCAPE) then
    text := ''
  else
    text := st;
end;

procedure ClearPole;
begin
  GotoXY(DumpX, DumpY + NumStrZ + 8);
  write('                                                   ');
  GotoXY(DumpX, DumpY + NumStrZ + 8);
end;

procedure InputPassword(num: integer);
var
  i: integer;
  Pas: string;
  aCode: integer;
begin
  DrawList(num, DarkGray);
  GotoXY(DumpX - 3, DumpY + NumStrZ + 5);
  TextColor(white);
  for i := 1 to System.Length(ThirdScreen) do
  begin
    write(ThirdScreen[i]);
    GotoXY(DumpX - 3, wherey + 1);
  end;
  RepaintScreen;
  GotoXY(DumpX, DumpY + NumStrZ + 8);
  TextColor(LightGreen);
  write(STR_INPUT_THE_KEY);
  TextColor(LightRed);
  ReadString(Pas);
  if Pas <> '' then
  begin
    ClearPole;
    TextColor(Yellow);
    write(STR_UNCRYPTING);
    for i := 1 to 3 do
    begin
      write('.');
      RepaintScreen;
      Sleep(400);
    end;
    ClearPole;
    TextColor(LightGreen);
    write(STR_CODE_GOT);
    TextColor(white);
    if Pas <> aPassword then
      aCode := Random(maxint)
    else
      aCode := aRightCode;
    write(IntToStr(aCode));
    RepaintScreen;
    Sleep(1200);
    ClearPole;
    write(STR_CHECKING);
    for i := 1 to 3 do
    begin
      write('.');
      RepaintScreen;
      Sleep(300);
    end;
    ClearPole;
    if aCode <> aRightCode then
    begin
      TextColor(LightRed);
      write(STR_ERROR_404);
      readkey;
    end
    else
    begin
      cur_lev.map[GlobX, GlobY].DoorCode := 0;
      TextColor(LightGreen);
      write(STR_CORRECT_CODE);
      readkey;
      AlsoOpen := true;
      exit;
    end;
  end;
  GotoXY(DumpX - 3, DumpY + NumStrZ + 5);
  TextColor(DarkGray);
  for i := 1 to System.Length(ThirdScreen) do
  begin
    write(ThirdScreen[i]);
    GotoXY(DumpX - 3, wherey + 1);
  end;
  RepaintScreen;
end;

procedure Dump;
var
  numstr: integer;
  StartStr: integer;
  c: char;
begin
  numstr := System.Length(DumpStr) div STRLEN;
  if System.Length(DumpStr) mod STRLEN <> 0 then
    inc(numstr);
  StartStr := 0;
  repeat
    DrawList(StartStr, white);
    c := readkey;
    case c of
      KEY_DOWN:
        if StartStr < numstr then
          inc(StartStr);
      KEY_UP:
        if StartStr > 0 then
          dec(STartStr);
      KEY_PASS_INPUT:
      begin
        InputPassword(StartStr);
        if AlsoOpen then
          exit;
      end;
    end;
  until (c = KEY_ESCAPE);
end;

procedure Init;
var
  i: integer;
begin
  SetLength(arr, Length);
  SetLength(DecodeStr, Length);
  for i := 1 to Length do
  begin
    arr[i - 1] := i - 1;
    DecodeStr[i - 1] := #0;
  end;
end;

procedure DeleteElement(num: integer);
var
  i: integer;
  c: char;
begin
  TextColor(White);
  c := GetRandomLetter;
  WriteChrXY(StartX + arr[num], StartY, c);
  DecodeStr[arr[num]] := c;
  for i := num to System.Length(arr) - 2 do
    arr[i] := arr[i + 1];
  SetLength(arr, System.Length(arr) - 1);
end;

procedure WriteRandom;
var
  i: integer;
begin
  TextColor(Color);
  i := Random(Length) + 1;
  for i := i downto 1 do
    WriteChrXY(StartX + arr[Random(System.Length(arr))], StartY, GetRandomLetter);
  Sleep(40);
end;

procedure Decode;
begin
  Repeat
    WriteRandom;
    if Random(10) mod 5 = 0 then
      DeleteElement(Random(System.Length(arr)));
    RepaintScreen;
  until System.Length(arr) = 0;
  GotoXY(7, StartY - 2);
  TextColor(DarkGray);
  write(STR_STRING_GOT);
  TextColor(LightCyan);
  GotoXY(7, StartY + 2);
  write(STR_SUCCESS);
end;

Procedure DrawScreen(aColor: byte);
var
  i: integer;
begin
  clrscr;
  GotoXY(2, DumpY - 4);
  TextColor(aColor);
  for i := 1 to System.Length(Screen) do
  begin
    write(Screen[i]);
    GotoXY(2, wherey + 1);
  end;
  RepaintScreen;
end;

Function GetRandomPassword: string;
begin
  GetRandomPassword := PassArr[Random(System.Length(PassArr)) + 1];
end;

procedure Hack(x, y: byte);
begin
  GlobX := x;
  GlobY := y;
  clrscr;
  aRightCode := cur_lev.map[x, y].DoorCode;
  DrawScreen(lightGray);
  Init;
  Decode;
  MakeDump(GetRandomPassword);
  Dump;
end;

begin
end.