unit turn;

interface

uses
  windows, sysutils, loadz, beginz, inventar,
  speak, battle, expa, sun, monsters, svet, endgame,
  reading, using, attack, voice, LevGen, arc, aData, DoorHack;

function maketurn: boolean;

implementation

uses
  MyCRT, NewUnit1;

var
  kopat: byte;
  arr: array of byte;

procedure AddItem(i: byte);
begin
  SetLength(arr, Length(arr) + 1);
  arr[Length(arr) - 1] := i;
end;

function IsMayDropItem(x, y: byte): boolean;
begin
  IsMayDropItem := false;
  if IsBold(x, y) then
    exit
  else if cur_lev.map[x, y].AnObject <> #0 then
    exit
  else if cur_lev.map[x, y].item <> 0 then
    exit
  else if (x = WhereX) and (y = WhereY) then
    exit
  else
    IsMayDropItem := true;
end;

procedure CheckForPutting(x, y: byte; var i: integer);
begin
  if IsMayDropItem(x, y) then
    AddItem(i);
  inc(i);
end;

procedure Putting(x, y: byte; dx, dy: shortint);
begin
  cur_lev.map[x + dx, y + dy].item := cur_lev.map[x, y].item;
  cur_lev.map[x + dx, y + dy].ItemCount := cur_lev.map[x, y].ItemCount;
  cur_lev.map[x, y].item := 0;
  cur_lev.map[x, y].ItemCount := 0;
end;

procedure RandomPut(x, y: byte);
var
  i: byte;
begin
  i := random(Length(arr));
  case arr[i] of
    1: Putting(x, y, -1, -1);
    2: Putting(x, y, 0, -1);
    3: Putting(x, y, 1, -1);
    4: Putting(x, y, -1, 0);
    5: Putting(x, y, 1, 0);
    6: Putting(x, y, -1, 1);
    7: Putting(x, y, 0, 1);
    8: Putting(x, y, 1, 1);
  end;
end;

procedure PutItem(x, y: byte);
var
  i: integer;
begin
  SetLength(arr, 0);
  i := 1;
  CheckForPutting(x - 1, y - 1, i);
  CheckForPutting(x, y - 1, i);
  CheckForPutting(x + 1, y - 1, i);
  CheckForPutting(x - 1, y, i);
  CheckForPutting(x + 1, y, i);
  CheckForPutting(x - 1, y + 1, i);
  CheckForPutting(x, y + 1, i);
  CheckForPutting(x + 1, y + 1, i);
  if Length(arr) > 0 then
    RandomPut(x, y)
  else
    cur_lev.map[x, y].AnObject := #0;
end;

function ouch(x, y: shortint): boolean;
var
  tempx, tempy: byte;
  attention: Integer;
begin
  ouch := false;
  if (IsSecretDoorWithout(WhereX + x, WhereY + y)) then
  begin
    cur_lev.map[WhereX + x, WhereY + y].attrz :=
      cur_lev.map[WhereX + x, WhereY + y].attrz - 16;
    hudmessage(STR_YOU_FOUND_SECRET_DOOR, MT_COOL, false);
    ouch := true;
    cur_lev.map[WhereX + x, WhereY + y].AnObject := #0;
    cur_lev.map[WhereX + x, WhereY + y].AnObjectColor := black;
    cur_lev.map[WhereX + x, WhereY + y].lev := GetFloorChar;
    cur_lev.map[WhereX + x, WhereY + y].color := white;
    osv;
  end
  else if IsType(WhereX + x, WhereY + y, 'Trap') then
  begin
    attention := 5 - (data.vnimanie div 3);
    if (((Random(20) + 1) mod attention) = 0) then
    begin
      hudmessage(STR_YOU_NEUTRALIZED_TRAP, MT_TEXT);
      SetObject(WhereX + x, WhereY + y, '[Empty]');
      cur_lev.map[WhereX + x, WhereY + y].EffectType := 0;
      cur_lev.map[WhereX + x, WhereY + y].Effect := 0;
      ouch := true;
    end;
  end
  else if IsType(WhereX + x, WhereY + y, 'Window_crashed') then
  begin
    if (not (IsBold(WhereX + (x * 2), WhereY + (y * 2))))
      and ((WhereX + (x * 2)) in [1..RESOLUTION_X])
      and ((WhereY + (y * 2)) in [1..RESOLUTION_Y])
      and not (IsThisAMonster(WhereX + (x * 2), WhereY + (y * 2))) then
    begin
      data.posx := WhereX + (x * 2);
      data.posy := WhereY + (y * 2);
      GoToXY(data.posx, data.posy);
      osv;
      hudmessage(STR_YOU_GRAB_THROUGH_WINDOW, MT_TEXT, false);
    end
    else
      hudmessage(STR_IMPOSSIBLE_TO_GRAB, MT_ERROR, false);
    ouch := true;
    exit;
  end
  else if IsType(WhereX + x, WhereY + y, 'Statue') then
  begin
    tempx := WhereX;
    tempy := WhereY;
    ClrScr;
    TextColor(white);
    WriteCenter(STR_STATUE_LABEL);
    Writeln;
    Write(StatueArr[cur_lev.map[tempx + x, tempy + y].ObjAttrz]);
    ReadKey;
    ClrScr;
    clean_all;
    GoToXY(tempx, tempy);
    osv;
    ouch := true;
  end
  else if IsType(WhereX + x, WhereY + y, 'Chest') then
  begin
    PutItem(WhereX + x, WhereY + y);
    SetObject(WhereX + x, WhereY + y, 'Chest_open');
    osv;
    hudmessage(STR_YOU_OPEN_CHEST, MT_TEXT, false);
    ouch := true;
  end
  else if IsType(WhereX + x, WhereY + y, 'Zabor') or IsType(WhereX + x, WhereY + y, 'Fence') then
    ouch := true
  else if IsType(WhereX + x, WhereY + y, 'Zabor_horizontal') or IsType(WhereX + x, WhereY + y, 'Fence_horizontal') then
    ouch := true
  else if IsType(WhereX + x, WhereY + y, 'Stolb') or IsType(WhereX + x, WhereY + y, 'Stolb_wood')then
    ouch := true
  else if IsType(WhereX + x, WhereY + y, 'Window') then
  begin
    if (IsBoldWin(WhereX + x, WhereY + y)) then
      hudmessage(STR_GLASS_BOLD, MT_TEXT)
    else
    begin
      SetElement(WhereX + x, WhereY + y, 'Window_crashed');
      hudmessage(STR_WINDOW_CRASHED, MT_TEXT, false);
      if data.r_hand = 0 then
        if ((Random(10) + 1) mod 3 <> 0) then
        begin
          ReadKey;
          hudmessage(STR_ARE_BLOODCHOSEN, MT_INFO, false);
          data.bloodchosen := Random(2) + 1;
        end;
    end;
    ouch := true;
  end
  else if IsType(WhereX + x, WhereY + y, 'Chest_open') then
    ouch := true
  else if IsType(WhereX + x, WhereY + y, 'Wall') then
  begin
    hudmessage(STR_YOU_GO_TO_WALL, MT_TEXT, false);
    ouch := true;
  end
  else if IsType(WhereX + x, WhereY + y, 'Mountain') then
  begin
    hudmessage(STR_YOU_CANT_GO_BY_MOUNTAINS, MT_TEXT, false);
    ouch := true;
  end
  else if IsType(WhereX + x, WhereY + y, 'Rock') then
  begin
    hudmessage(STR_YOU_CANT_GO_HERE, MT_TEXT, false);
    ouch := true;
  end
  else if IsType(WhereX + x, WhereY + y, 'Water') and (data.location = MAP_MAIN) then
  begin
    hudmessage(STR_YOU_CANT_GO_HERE, MT_TEXT, false);
    ouch := true;
  end
  else if IsType(WhereX + x, WhereY + y, 'Lava') and (data.location = MAP_MAIN) then
  begin
    hudmessage(STR_YOU_CANT_GO_HERE, MT_TEXT, false);
    ouch := true;
  end
  else if IsLitter(WhereX + x, WhereY + y) then
  begin
    hudmessage(STR_CANT_GO_THIS_LITTER, MT_TEXT, false);
    ouch := true;
  end
  else if (IsType(WhereX + x, WhereY + y, 'Land') or (IsType(WhereX + X, WhereY + y, 'WallGround'))) then
  begin
      hudmessage(STR_CANT_GO_THIS_LAND, MT_TEXT, false);
      ouch := true;
  end;
end;

procedure Zamena;
var
  Rec: TSearchRec;
  f: file;
begin
 if SysUtils.FindFirst(MAPFOLDER + '*.saz.dat', faAnyFile, Rec) = 0 then
  try
    repeat
      CopyFile(PChar(MAPFOLDER + Rec.Name), PChar(MAPFOLDER + Copy(Rec.Name, 1, Length(Rec.Name) - 8) + '.sav.dat'), false);
      AssignFile(f, MAPFOLDER + Rec.Name);
      Erase(f);
    until SysUtils.FindNext(Rec) <> 0;
  finally
    SysUtils.FindClose(Rec);
  end;
end;

procedure save;
var
  save: file of dataz;
  nado: file of level_rec;
  s: string;
begin
  s := SetSaveFolder;
  data.posx := WhereX;
  data.posy := WhereY;
  if (data.PrisonLevel >= data.LastSavedLevel) then
    data.LastSavedLevel := data.PrisonLevel;
  AssignFile(save, s + SAVEFILENAME);
  ReWrite(save);
  System.Write(save, data);
  CloseFile(save);
  DoCompress(s + SAVEFILENAME, s + ARC_SAVEFILENAME);
  Erase(save);
  AssignFile(nado, MAPFOLDER + data.location + SAZ_EXTENSION);
  ReWrite(nado);
  System.Write(nado, cur_lev);
  CloseFile(nado);
  DoCompress(MAPFOLDER + data.location + SAZ_EXTENSION, MAPFOLDER + data.location + SAZ_EXTENSION + ARC_EXTENSION);
  Erase(nado);
  Zamena;
  DeleteAll('*.saz.dat', s);
  DeleteAll('*.sav.dat', s);
  DeleteAll('prison*.*', s);
  DeleteAll('random.*', s);
  CopyAll('*.saz.dat', MAPFOLDER, s);
  CopyAll('*.sav.dat', MAPFOLDER, s);
  CopyAll('prison*.*', MAPFOLDER, s);
  CopyAll('random.*', MAPFOLDER, s);
end;

procedure obmorok;
var
  sleep: byte;
  hod: word;
begin
  data.sleep := true;
  ClrScr;
  Write(STR_YOU_SWOONED);
  ReadKey;
  ClrScr;
  sleep := random(5);
  for hod := 1 to sleep * 20 do
    mon_move;
  ClrScr;
  Write(STR_YOU_AWAKENED);
  ReadKey;
  data.sleep := false;
  inc(data.ustal, sleep * 100);
  inc(data.hours, sleep);
  check_time;
  Write(STR_YOU_AWAKENED2);
  GoToXY(data.posx, data.posy);
  clean_all;
  osv(data.Light_color)
end;

procedure GoDown;
var
  f: file of level_rec;
begin
  if (data.PrisonLevel = 0) then
  begin
    data.MaxLevel := cur_lev.map[WhereX, WhereY].ObjAttrz;
    data.UniqueItem := cur_lev.map[WhereX, WhereY].levAttrz;
    data.LastLocationX := data.posx;
    data.LastLocationY := data.posy;
  end;
  saveizm;
  if (data.PrisonLevel <= data.LastSavedLevel) then
  begin
    AssignFile(f, MAPFOLDER + 'prison' + Inttostr(data.PrisonLevel + 1) + LEV_EXTENSION);
    {$I-}
      Reset(f);
    {$I+}
    if IOResult = 0 then
    begin
      CloseFile(f);
      inc(data.PrisonLevel);
      data.location := 'prison' + Inttostr(data.PrisonLevel);
      level_load;
      clean_all;
      data.posx := cur_lev.gamer_x;
      data.posy := cur_lev.gamer_y;
      GoToXY(data.posx, data.posy);
      osv;
    end
    else
      GenerateAPrison(GetPrisonName(data.location, data.posx, data.posy), false);
  end
  else
    GenerateAPrison(GetPrisonName(data.location, data.posx, data.posy), false);
end;

procedure GoUp;
begin
  dec(data.PrisonLevel);
  data.posx := cur_lev.map[WhereX, WhereY].levAttrz div 256;
  data.posy := cur_lev.map[WhereX, WhereY].levAttrz mod 256;
  if (data.PrisonLevel > 0) then
    data.location := 'prison' + IntToStr(data.prisonLevel)
  else
    data.location := data.LastLocation;
  level_load;
  clean_all;
  GoToXY(data.posx, data.posy);
  osv;
  if data.PrisonLevel = 0 then
  begin
    DeletePrison;
    data.LastSavedLevel := 0;
    data.MaxLevel := 0;
    data.UniqueItem := 0;
    save;
    hudmessage(STR_GAME_SAVED, MT_TEXT, false);
  end;
end;

function GetStrIndex: string;
var
  once: boolean;
begin
  GetStrIndex := '';
  once := (cur_lev.map[data.posx, data.posy].StrIndex >= 32768);
  if cur_lev.map[data.posx, data.posy].StrIndex >= 32768 then
    cur_lev.map[data.posx, data.posy].StrIndex := cur_lev.map[data.posx, data.posy].StrIndex - 32768;
  if cur_lev.map[data.posx, data.posy].StrIndex <= StrIndexCount then
    GetStrIndex := StrIndexArr[cur_lev.map[data.posx, data.posy].StrIndex];
  if once then
    cur_lev.map[data.posx, data.posy].StrIndex := 0;
end;

procedure endhod;
var
  r, temp: integer;
begin


  if (IsThisAMonster(data.posx - 1, data.posy)) and (cur_lev.map[data.posx - 1, data.posy].Monster.montype < FRIEND) then
    mon_attack(cur_lev.map[data.posx - 1, data.posy].Monster.montype, cur_lev.map[data.posx - 1, data.posy].Monster.health, data.posx - 1, data.posy);
  if (IsThisAMonster(data.posx - 1, data.posy - 1)) and (cur_lev.map[data.posx - 1, data.posy - 1].Monster.montype < FRIEND) then
    mon_attack(cur_lev.map[data.posx - 1, data.posy - 1].Monster.montype, cur_lev.map[data.posx - 1, data.posy - 1].Monster.health,
      data.posx - 1, data.posy - 1);
  if (IsThisAMonster(data.posx - 1, data.posy + 1)) and (cur_lev.map[data.posx - 1, data.posy + 1].Monster.montype < FRIEND) then
    mon_attack(cur_lev.map[data.posx - 1, data.posy + 1].Monster.montype, cur_lev.map[data.posx - 1, data.posy + 1].Monster.health,
      data.posx - 1, data.posy + 1);
  if (IsThisAMonster(data.posx + 1, data.posy - 1)) and (cur_lev.map[data.posx + 1, data.posy - 1].Monster.montype < FRIEND) then
    mon_attack(cur_lev.map[data.posx + 1, data.posy - 1].Monster.montype, cur_lev.map[data.posx + 1, data.posy - 1].Monster.health,
      data.posx + 1, data.posy - 1);
  if (IsThisAMonster(data.posx + 1, data.posy + 1)) and (cur_lev.map[data.posx + 1, data.posy + 1].Monster.montype < FRIEND) then
    mon_attack(cur_lev.map[data.posx + 1, data.posy + 1].Monster.montype, cur_lev.map[data.posx + 1, data.posy - 1].Monster.health,
      data.posx + 1, data.posy + 1);
  if (IsThisAMonster(data.posx + 1, data.posy)) and (cur_lev.map[data.posx + 1, data.posy].Monster.montype < FRIEND) then
    mon_attack(cur_lev.map[data.posx + 1, data.posy].Monster.montype, cur_lev.map[data.posx + 1, data.posy].Monster.health,
      data.posx + 1, data.posy);
  if (IsThisAMonster(data.posx, data.posy - 1)) and (cur_lev.map[data.posx, data.posy - 1].Monster.montype < FRIEND) then
    mon_attack(cur_lev.map[data.posx, data.posy - 1].Monster.montype, cur_lev.map[data.posx, data.posy - 1].Monster.health,
      data.posx, data.posy - 1);
  if (IsThisAMonster(data.posx, data.posy + 1)) and (cur_lev.map[data.posx, data.posy + 1].Monster.montype < FRIEND) then
    mon_attack(cur_lev.map[data.posx, data.posy + 1].Monster.montype, cur_lev.map[data.posx, data.posy + 1].Monster.health,
      data.posx, data.posy + 1);


  if (data.age < data.DeathAge) then
    temp := 0
  else
    temp := data.age - data.DeathAge;
  if cur_lev.map[data.posx, data.posy].StrIndex <> 0 then
    hudmessage(GetStrIndex, MT_TEXT, false);
  if data.invisible > 0 then
    dec(data.invisible);
  dec(data.hunger);
  {if (cur_lev.map[data.posx, data.posy].EffectType <> 0) then
    UseEffect(cur_lev.map[data.posx, data.posy].EffectType, cur_lev.map[data.posx, data.posy].Effect);}
  if (data.Blind > 0) and (not data.prizrak) then
  begin
    if (data.age < data.DeathAge) then
      dec(data.Blind)
    else if (Random(MAXSTAROSTYEARS) > (data.age - data.DeathAge)) then
      Dec(data.Blind);
    if data.Blind = 0 then
      hudmessage(STR_NOT_BLIND, MT_TEXT, false);
  end;
  if (data.Ed > 0) and (not data.prizrak) then
  begin
    if (data.age < data.DeathAge) then
      dec(data.Ed)
    else if (Random(MAXSTAROSTYEARS) > (data.age - data.DeathAge)) then
      Dec(data.Ed);
    if data.Ed = 0 then
      hudmessage(STR_NOT_ED, MT_TEXT, false);
  end;
  if (data.Poisoned > 0) and (not data.prizrak) then
  begin
    if (data.age < data.DeathAge) then
      dec(data.poisoned)
    else if (Random(MAXSTAROSTYEARS) > (data.age - data.DeathAge)) then
      Dec(data.Poisoned);
    if data.Poisoned = 0 then
      hudmessage(STR_NOT_POISONED, MT_TEXT, false)
    else
    begin
      if (Random(10) + 1) mod 9 = 0 then
      begin
        hudmessage(STR_YOU_VOMIT, MT_TEXT, false);
        dec(data.health, Random(10));
      end;
    end;
  end;
  if (data.Contusioned > 0) and (not data.prizrak) then
  begin
    if (data.age < data.DeathAge) then
      dec(data.Contusioned)
    else if (Random(MAXSTAROSTYEARS) > (data.age - data.DeathAge)) then
      Dec(data.Contusioned);
    if data.Contusioned = 0 then
      hudmessage(STR_NOT_CONTUSIONED, MT_TEXT, false);
  end;
  if (data.Palsy > 0) and (not data.prizrak) then
  begin
    dec(data.Palsy);
    if data.Palsy = 0 then
      hudmessage(STR_NOT_PALSED, MT_TEXT, false);
  end;
  if data.hunger = 10000 then
    hudmessage(STR_YOU_HUNGRY, MT_WARNING)
  else if data.hunger = 1000 then
    hudmessage(STR_YOU_VERY_HUNGRY, MT_ERROR)
  else if data.hunger = 100 then
    hudmessage(STR_YOU_VERY_VERY_HUNGRY, MT_CRITICAL);
  if data.hunger <= 0 then
    dead(STR_DEAD);
  if (data.bloodchosen > 0) and (not data.prizrak) then
    dec(data.health, data.bloodchosen);
  {if (data.health < 0) then
    dead(STR_DEAD);}
  if (data.bloodchosen > 0) and (not data.prizrak) then
  begin
    r := random(3);
    if r = 0 then
    begin
      if (data.age < data.DeathAge) then
        dec(data.bloodchosen)
      else if (Random(MAXSTAROSTYEARS) > (data.age - data.DeathAge)) then
        Dec(data.bloodchosen);
    end
    else if r = 2 then
    begin
      inc(data.bloodchosen);
      if ((Random(MAXSTAROSTYEARS) < (data.age - data.DeathAge)) and (Random(2) = 0)) then
        Inc(data.bloodchosen);
      if data.bloodchosen = 5 then
        hudmessage(STR_BLOODCHOSEN_CONTINIE, MT_ERROR)
      else if data.bloodchosen = 10 then
        hudmessage(STR_BLOODCHOSEN_VERY, MT_CRITICAL);
    end;
    if data.bloodchosen <= 0 then
    begin
      hudmessage(STR_BLOODCHOSEN_STOP, MT_COOL);
      data.bloodchosen := 0;
    end;
  end;
  r := random(AllWeight - (data.vinoslivost * 10));
  Dec(data.ustal);
  if (r > 40) and (not data.prizrak) then
  begin
    dec(data.ustal, r div 40);
    if (data.age >= data.DeathAge) then
      Dec(data.ustal);
  end;
  if data.ustal = (10000 + 1000 * temp) then
    hudmessage(STR_YOU_TIRED, MT_WARNING)
  else if data.ustal = (1000 + 100 * temp) then
    hudmessage(STR_YOU_VERY_TIRED, MT_ERROR)
  else if data.ustal = (100 + 10 * temp) then
    hudmessage(STR_YOU_VERY_VERY_TIRED, MT_CRITICAL);
  if data.ustal <= temp then
    obmorok;
  if (data.toPortal > 1) then
    dec(data.toPortal)
  else if (data.toPortal = 1) then
  begin
    data.toPortal := 0;
    data.location := data.LastLocation;
    data.PrisonLevel := 0;
    level_load;
    clean_all;
    GoToXY(data.LastLocationX, data.LastLocationY);
    osv;
    DeletePrison;
    data.LastSavedLevel := 0;
    data.MaxLevel := 0;
    data.UniqueItem := 0;
    save;
    hudmessage(STR_GAME_SAVED, MT_TEXT, false);
  end;
  if ((data.bolezn > 0) and ((temp <= 0) or (Random(MAXSTAROSTYEARS) > temp))) then
    dec(data.health, (3 * data.bolezn * (10 - (data.vinoslivost div 5))));
  if (data.bolezn < 5) and (data.bolezn > 0) then
  begin
    r := random(3);
    if ((r = 0) and (data.age < data.DeathAge)) then
      dec(data.bolezn)
    else if ((r = 2) and ((temp = 0) or (Random(MAXSTAROSTYEARS) < temp))) then
      inc(data.bolezn);
  end
  else if (data.bolezn >= 5) then
  begin
    r := random(2);
    if r = 0 then
      inc(data.bolezn);
  end;
end;

procedure closedoor(x, y: shortint);
begin
  if (not IsDoorBroken(WhereX + x, WhereY + y)) then
  begin
    if (IsElement(WhereX + x, WhereY + y, 'Door_open')) then
      SetElement(WhereX + x, WhereY + y, 'Door')
    else if (IsObject(WhereX + x, WhereY + y, 'Door_open')) then
      SetObject(WhereX + x, WhereY + y, 'Door');
    osv(data.Light_color)
  end
  else
    hudmessage(STR_DOOR_BROKEN, MT_ERROR, false);
end;

function CheckForPolet(x, y: byte): boolean;
begin
  CheckForPolet := ((IsType(x, y, 'Lava') or IsType(x, y, 'Boloto') or IsType(x, y, 'Water')) and (data.polet > 0))
                     or ((not IsType(x, y, 'Lava')) and (not IsType(x, y, 'Water')) and (not IsType(x, y, 'Boloto')));
end;

procedure movehero(x, y: shortint);
var
  cx, cy: byte;
  aCode: boolean;
  zx, zy: byte;
begin
  aCode := false;
  if not IsThisAMonster(WhereX + x, WhereY + y) then
    ClearEnemyHealth;
  if data.Contusioned > 0 then
  begin
    case x of
      -128..-1: x := x + Random(3);
      0: x := x + Random(3) - 1;
      1..127: x := x - Random(3);
    end;
    case y of
      -128..-1: y := y + Random(3);
      0: y := y + Random(3) - 1;
      1..127: y := y - Random(3);
    end;
  end;
  if (not ((WhereX + x) in [2..RESOLUTION_X - 1]))
    or (not ((WhereY + y) in [2..RESOLUTION_Y - 1])) then
      exit;
  if data.bloodchosen > 2 then
    SetBlood(WhereX + x, WhereY + y, true);
  if not IsBold(WhereX + x, WhereY + y) then
  begin
    if CheckForPolet(WhereX + x, WhereY + y) then
    begin
      if not IsThisAMonster(WhereX + x, WhereY + y) then
      begin
        if (cur_lev.map[WhereX + x, WhereY + y].DoorCode <> 0) then
        begin
          aCode := true;
          dverka(x, y);
          clean_all;
          endhod;
        end
        else
          dverka(x, y);
        if (not door) and (closed <> true) then
        begin
          cx := WhereX;
          cy := WhereY;
          GoToXY(cx, cy);
          if IsType(WhereX, WhereY + 1, 'Door_open') and (IsDoorSelfClosing(WhereX, WhereY + 1))
            and not ((x = 0) and (y = 1)) then
              SetElement(WhereX, WhereY + 1, 'Door');
          if IsType(WhereX + 1, WhereY, 'Door_open') and (IsDoorSelfClosing(WhereX + 1, WhereY))
            and not ((x = 1) and (y = 0)) then
              SetElement(WhereX + 1, WhereY, 'Door');
          if IsType(WhereX - 1, WhereY, 'Door_open') and (IsDoorSelfClosing(WhereX - 1, WhereY))
            and not ((x = -1) and (y = 0)) then
              SetElement(WhereX - 1, WhereY, 'Door');
          if IsType(WhereX, WhereY - 1, 'Door_open') and (IsDoorSelfClosing(WhereX, WhereY - 1))
            and not ((x = 0) and (y = -1)) then
              SetElement(WhereX, WhereY - 1, 'Door');
          if not aCode then
            GoToXY(cx + x, cy + y)
          else
            GoToXY(cx, cy);
          if not aCode then
          begin
            if (IsThisAMonster(data.posx - 1, data.posy)) and (cur_lev.map[data.posx - 1, data.posy].Monster.montype < FRIEND) then
              mon_attack(cur_lev.map[data.posx - 1, data.posy].Monster.montype, cur_lev.map[data.posx - 1, data.posy].Monster.health, data.posx - 1, data.posy);
            if (IsThisAMonster(data.posx - 1, data.posy - 1)) and (cur_lev.map[data.posx - 1, data.posy - 1].Monster.montype < FRIEND) then
              mon_attack(cur_lev.map[data.posx - 1, data.posy - 1].Monster.montype, cur_lev.map[data.posx - 1, data.posy - 1].Monster.health,
                data.posx - 1, data.posy - 1);
            if (IsThisAMonster(data.posx - 1, data.posy + 1)) and (cur_lev.map[data.posx - 1, data.posy + 1].Monster.montype < FRIEND) then
              mon_attack(cur_lev.map[data.posx - 1, data.posy + 1].Monster.montype, cur_lev.map[data.posx - 1, data.posy + 1].Monster.health,
                data.posx - 1, data.posy + 1);
            if (IsThisAMonster(data.posx + 1, data.posy - 1)) and (cur_lev.map[data.posx + 1, data.posy - 1].Monster.montype < FRIEND) then
              mon_attack(cur_lev.map[data.posx + 1, data.posy - 1].Monster.montype, cur_lev.map[data.posx + 1, data.posy - 1].Monster.health,
                data.posx + 1, data.posy - 1);
            if (IsThisAMonster(data.posx + 1, data.posy + 1)) and (cur_lev.map[data.posx + 1, data.posy + 1].Monster.montype < FRIEND) then
              mon_attack(cur_lev.map[data.posx + 1, data.posy + 1].Monster.montype, cur_lev.map[data.posx + 1, data.posy - 1].Monster.health,
                data.posx + 1, data.posy + 1);
            if (IsThisAMonster(data.posx + 1, data.posy)) and (cur_lev.map[data.posx + 1, data.posy].Monster.montype < FRIEND) then
              mon_attack(cur_lev.map[data.posx + 1, data.posy].Monster.montype, cur_lev.map[data.posx + 1, data.posy].Monster.health,
                data.posx + 1, data.posy);
            if (IsThisAMonster(data.posx, data.posy - 1)) and (cur_lev.map[data.posx, data.posy - 1].Monster.montype < FRIEND) then
              mon_attack(cur_lev.map[data.posx, data.posy - 1].Monster.montype, cur_lev.map[data.posx, data.posy - 1].Monster.health,
                data.posx, data.posy - 1);
            if (IsThisAMonster(data.posx, data.posy + 1)) and (cur_lev.map[data.posx, data.posy + 1].Monster.montype < FRIEND) then
              mon_attack(cur_lev.map[data.posx, data.posy + 1].Monster.montype, cur_lev.map[data.posx, data.posy + 1].Monster.health,
                data.posx, data.posy + 1);
            inc(data.posx, x);
            inc(data.posy, y);
            GoToXY(data.posx, data.posy);
          end;
          Wave(data.posx, data.posx, data.voiceStrength, VOICE_HERO);
        end;
      end
      else if (cur_lev.map[WhereX + x, WhereY + y].Monster.montype < FRIEND) then
        bitva(x, y)
      else if (cur_lev.map[WhereX + x, WhereY + y].Monster.montype >= FRIEND) then
        talking(x, y);
      inc(data.seconds, 1);
      check_time;
      UseTrap(WhereX, WhereY);
      osv(data.Light_color);
      CheckForTraps(data.posx, data.posy);
    end
  end
  else if IsMoveable(WhereX + x, WhereY + y) then
  begin
    if (not IsBold(WhereX + (x * 2), WhereY + (y * 2)))
         and (cur_lev.map[WhereX + (x * 2), WhereY + (y * 2)].AnObject = #0) and
           not (IsThisAMonster(WhereX + (x * 2), WhereY + (y * 2))) then
    begin
      cur_lev.map[WhereX + (x * 2), WhereY + (y * 2)].AnObject := cur_lev.map[WhereX + x, WhereY + y].AnObject;
      cur_lev.map[WhereX + (x * 2), WhereY + (y * 2)].AnObjectcolor := cur_lev.map[WhereX + x, WhereY + y].AnObjectcolor;
      cur_lev.map[WhereX + x, WhereY + y].AnObject := #0;
      cur_lev.map[WhereX + x, WhereY + y].AnObjectColor := white;
      GoToXY(WhereX + x, WhereY + y);
      inc(data.seconds, 1);
      check_time;
      Wave(WhereX + x, WhereY + y, data.voiceStrength + 4, VOICE_MOVEABLE);
      osv(data.Light_color)
    end
    else
      hudmessage(STR_CANT_MOVE, MT_TEXT);
  end;
  endhod;
end;

procedure Teleport;
begin
  GoToXY(cur_lev.map[WhereX, WhereY].ObjAttrz div 256, cur_lev.map[WhereX, WhereY].ObjAttrz mod 256);
  clean_all;
  osv;
end;

procedure Camera;
var
  x, y: byte;
begin
  x := WhereX;
  y := WhereY;
  GoToXY((cur_lev.map[WhereX, WhereY].ObjAttrz div 256), cur_lev.map[WhereX, WhereY].ObjAttrz mod 256);
  clean_all;
  osv(white, false, false);
  ReadKey;
  GoToXY(x, y);
  clean_all;
  osv;
end;

function vokrug2hack(x, y: byte): integer;
begin
  Result := 0;
  if (x > 1) and (cur_lev.map[x - 1, y].DoorCode <> 0) then
    inc(Result);
  if (x < RESOLUTION_X) and (cur_lev.map[x + 1, y].DoorCode <> 0) then
    inc(Result);
  if (y > 1) and (cur_lev.map[x, y - 1].DoorCode <> 0) then
    inc(Result);
  if (y < RESOLUTION_Y) and (cur_lev.map[x, y + 1].DoorCode <> 0) then
    inc(Result);
end;

Function IsHackDoor(x, y: byte; c: char): boolean;
begin
  Result := true;
  if (c = KEY_UP) and (y > 1) and (cur_lev.map[x, y - 1].DoorCode <> 0) then
    exit
  else if (c = KEY_DOWN) and (y < RESOLUTION_Y) and (cur_lev.map[x, y + 1].DoorCode <> 0) then
    exit
  else if (c = KEY_LEFT) and (x > 1) and (cur_lev.map[x - 1, y].DoorCode <> 0) then
    exit
  else if (c = KEY_RIGHT) and (x < RESOLUTION_X) and (cur_lev.map[x + 1, y].DoorCode <> 0) then
    exit
  else if (c = KEY_LEFTUP) and (x > 1) and (y > 1) and (cur_lev.map[x - 1, y - 1].DoorCode <> 0) then
    exit
  else if (c = KEY_LEFTDOWN) and (x > 1) and (y < RESOLUTION_Y) and (cur_lev.map[x - 1, y + 1].DoorCode <> 0) then
    exit
  else if (c = KEY_RIGHTUP) and (x < RESOLUTION_X) and (y > 1) and (cur_lev.map[x + 1, y - 1].DoorCode <> 0) then
    exit
  else if (c = KEY_RIGHTDOWN) and (x < RESOLUTION_X) and (y < RESOLUTION_Y) and (cur_lev.map[x + 1, y + 1].DoorCode <> 0) then
    exit
  else
    Result := false;
end;

Function IsHack(x, y: byte): boolean;
begin
  IsHack := (cur_lev.map[x, y].DoorCode <> 0);
end;

procedure Reload;
var
  item: TItem;
  i, j: integer;
begin
  if data.Palsy > 0 then
  begin
    hudmessage(STR_YOU_PALSED, MT_TEXT);
    exit;
  end;
  iteminfo(data.r_hand, item);
  if (not item.IsShooting) or (item.InOboyma = 0) then
  begin
    hudmessage(STR_IMPOSSIBLE_RELOAD, MT_ERROR, false);
    exit;
  end
  else if HasAmmoLeft = 0 then
  begin
    hudmessage(STR_HAVENT_AMMO_IN_INV, MT_ERROR, false);
    exit;
  end
  else if (data.InRozhok = item.InOboyma) then
  begin
    hudmessage(STR_OBOYMA_FULL, MT_TEXT, false);
    exit;
  end;
  if (HasAmmoLeft < (item.InOboyma - data.InRozhok)) then
  begin
    j := HasAmmoLeft;
    for i := 1 to j do
      decammo(true);
    data.InRozhok := data.InRozhok + j;
  end
  else
  begin
    j := (item.InOboyma - data.InRozhok);
    for i := 1 to j do
      decammo(true);
    data.InRozhok := item.InOboyma;
  end;
end;

procedure Unload;
var
  aType: integer;
  item: TItem;
begin
  if data.Palsy > 0 then
  begin
    hudmessage(STR_YOU_PALSED, MT_TEXT);
    exit;
  end;
  iteminfo(data.r_hand, item);
  if (not item.IsShooting) or (item.InOboyma = 0) then
  begin
    hudmessage(STR_UNLOAD_IMPOSSIBLE, MT_ERROR, false);
    exit;
  end
  else if (data.InRozhok = 0) then
  begin
    hudmessage(STR_WEAPON_ALREADY_EMPTY, MT_TEXT, false);
    exit;
  end
  else
  begin
    aType := AMMO_BOWS;
    case item.itemtype of
      ITBows: aType := AMMO_BOWS;
      ITFire: aType := AMMO_FIRE;
      ITShells: aType := AMMO_SHELLS;
      ITElectric: aType := AMMO_ELECTRICAL;
      ITRockets: aType := AMMO_ROCKETS;
      ITCell: aType := AMMO_CELLCHARGE;
      ITPsi: aType := AMMO_PSI;
    end;
    if Hasinv(aType, data.InRozhok) then
    begin
      addammo(aType, data.InRozhok);
      data.InRozhok := 0;
    end;
  end;
end;

procedure GoUpToPrison;
begin
  if (data.PrisonLevel > 1) then
    Info(STR_UP_TO_LEVEL + IntToStr(data.PrisonLevel - 1) + '...')
  else
    Info(STR_UP);
  cur_lev.gamer_x := data.posx;
  cur_lev.gamer_y := data.posy;
  if (data.PrisonLevel > 0) then
    SavePrison;
  GoUp;
end;

procedure MakeExitFromLocation;
begin
  Info(STR_EXIT_FROM_LOCATION);
  saveizm;
  data.location := MAP_MAIN;
  ClrScr;
  level_load;
  GoToXY(data.global_x, data.global_y);
  clean_map_all;
  osv_map;
  save;
  hudmessage(STR_GAME_SAVED, MT_TEXT, false);
end;

procedure MakeLocationEntrace;
begin
  Info(STR_ENTER_TO_LOC);
  saveizm;
  data.location := read_loc(WhereX, WhereY, data.newposx, data.newposy);
  level_load;
  if (data.hours < 22) and (data.hours > 7) and (cur_lev.street) then
  begin
    clearshadows;
    sunlight(data.hours);
    vidall;
  end;
  clean_all;
  GoToXY(data.newposx, data.newposy);
  osv(data.Light_color)
end;

procedure GoDownToPrison;
begin
  Info(STR_DOWN_TO_LEVEL + IntToStr(data.PrisonLevel + 1) + '...');
  if (data.PrisonLevel > 0) then
    SavePrison
  else
    Saveizm;
  GoDown;
end;

procedure GoMap(dx, dy: shortint);
begin
  DeleteRandom;
  GoToXY(WhereX + dx, WhereY + dy);
  inc(data.hours, (6 - (data.vinoslivost div 10) + (data.ustal div 1000)));
  inc(data.minutes, random(12));
  inc(data.seconds, random(30));
  osv_map;
end;

procedure Moved(dx, dy: shortint; var maketurn: boolean);
begin
  if data.Palsy > 0 then
  begin
    hudmessage(STR_YOU_PALSED, MT_TEXT);
    exit;
  end;
  if ouch(dx, dy) then
  begin
    maketurn := true;
    exit;
  end
  else if (data.location <> MAP_MAIN) then
    movehero(dx, dy)
  else if (not IsBold(WhereX + dx, WhereY + dy)) then
    GoMap(dx, dy);
end;

procedure GoFromGlobalMap;
var
  s: string;
begin
  Info(STR_ENTER_TO_LOC);
  if data.location = MAP_MAIN then
  begin
    data.global_x := WhereX;
    data.global_y := WhereY;
    saveizm;
    s := read_loc(WhereX, WhereY, data.newposx, data.newposy);
    data.location := s;
    level_load;
    if (cur_lev.map[data.newposx, data.newposy].Light = 0) then
      data.cur_osv := DEFAULTLIGHTRADIUS;
    if (data.hours < 22) and (data.hours > 7) and (cur_lev.street) then
    begin
      clearshadows;
      sunlight(data.hours);
      vidall;
    end;
    ClrScr;
    clean_all;
    GoToXY(data.newposx, data.newposy);
    osv(data.Light_color);
  end;
end;

function IsPerson(x, y: integer; IsAutoOpen: boolean): boolean;
var
  enemy: TEnemy;
begin
  IsPerson := false;
  if not (x in [1..RESOLUTION_X]) or not (y in [1..RESOLUTION_Y]) then
    exit;
  IsPerson := true;
  if (x = data.posx) and (y = data.posy) then
    exit
  else if (IsThisAMonster(x, y)) then
  begin
    mon_info(cur_lev.map[x, y].Monster.montype, enemy);
    if (IsAutoOpen) and (CanOpenAutoDoors(enemy.Attrz)) then
      exit
    else if (not IsAutoOpen) and (not CanOpenDoors(enemy.Attrz)) then
      exit
  end;
  IsPerson := false;
end;

function VokrugPersonz(x, y: integer): integer;
var
  i, j: integer;
begin
  Result := 0;
  for j := -1 to 1 do
    for i := -1 to 1 do
      if IsPerson(x + i, y + j, IsAutoOpen(x, y)) then
        inc(Result);
end;

procedure MakeWithDoors;
var
  i, j: integer;
begin
  for j := 1 to RESOLUTION_Y do
    for i := 1 to RESOLUTION_X do
      if (IsType(i, j, 'Door_open')) and (IsAutoClosed(i, j)) and (VokrugPersonz(i, j) = 0) then
      begin
        SetElement(i, j, 'Door');
        if cur_lev.map[i, j].now <> #0 then
          osvkletka(i, j, data.Light_color);
        osv(White, False);
      end
      else if (IsType(i, j, 'Door')) and (IsAutoOpen(i, j)) and (VokrugPersonz(i, j) > 0) then
      begin
        SetElement(i, j, 'Door_open');
        if cur_lev.map[i, j].now <> #0 then
          osvkletka(i, j, data.Light_color);
        osv(White, False);
      end;
end;

procedure WriteLastMessages;
var
  i: integer;
begin
  ClrScr;
  Ramka(LightGray, HUDSIZE);
  GoToXY(((RESOLUTION_X - Length(STR_LAST_MESSAGES)) div 2) - 2, 1);
  TextColor(LightGray);
  Write('[ ');
  TextColor(White);
  Write(STR_LAST_MESSAGES);
  TextColor(LightGray);
  Write(' ]');
  for i := 1 to RESOLUTION_Y - 4 do
  begin
    GoToXY(3, i + 2);
    Write(data.LastMessages[i]);
  end;
  ReadKey;
end;

{$Warnings Off}
function maketurn: boolean;
var
  c1: char;
  r: word;
  tempx, tempy: integer;
  tempstr: string;
begin
    data.posx := WhereX;
    data.posy := WhereY;
    c := ReadKey;
    CleanVoice;
    case c of
      KEY_ESCAPE:
      begin
        textcolor(white);
        ClrScr;
        Write(STR_EXIT_QUESTION);
        repeat
          c := ReadKey;
        until (c in ['y', 'n', #27, #13]);
        case c of
          #13, 'y':
          begin
            if DontDeleteSaves then
            begin
              GoToXY(1, WhereY + 1);
              Write(STR_CHANGESSAVE_QUESTION);
              repeat
                c := ReadKey;
              until (c in [#13, #27, 'y', 'n']);
              case c of
                #13, 'y':
                begin
                  GoToXY(data.posx, data.posy);
                  save;
                end;
              end;
            end
            else
            begin
              GoToXY(data.posx, data.posy);
              save;
            end;
            DeleteAll('*.saz.dat', MAPFOLDER);
            DeleteAll('*.sav.dat', MAPFOLDER);
            DeleteAll('prison*.*', MAPFOLDER);
            DeleteAll('random.*', MAPFOLDER);
            maketurn := false;
            exit;
          end;
          #27, 'n':
          begin
            clean_all;
            if data.location <> MAP_MAIN then
            begin
              GoToXY(data.posx, data.posy);
              clean_all;
              osv(data.Light_color);
              hud;
              maketurn := true;
              exit;
            end
            else
            begin
              GoToXY(data.posx, data.posy);
              clean_all;
              osv_map;
              hud;
              maketurn := true;
              exit;
            end;
          end;
        end;
      end;
      KEY_DOWN: Moved(0, 1, Result);
      KEY_UP: Moved(0, -1, Result);
      KEY_LEFT: Moved(-1, 0, Result);
      KEY_RIGHT: Moved(1, 0, Result);
      KEY_LEFTUP: Moved(-1, -1, Result);
      KEY_LEFTDOWN: Moved(-1, 1, Result);
      KEY_RIGHTUP: Moved(1, -1, Result);
      KEY_RIGHTDOWN: Moved(1, 1, Result);
      KEY_LAST_MESSAGES:
      begin
        data.posx := WhereX;
        data.posy := WhereY;
        WriteLastMessages;
        GoToXY(data.posx, data.posy);
        clean_all;
        osv(data.Light_color, false);
      end;
      KEY_HELP:
      begin
        tempx := WhereX;
        tempy := WhereY;
        Ramka(brown);
        help;
        ClrScr;
        clean_all;
        GoToXY(tempx, tempy);
        osv;
      end;
      KEY_INFRARED:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if not data.prizrak then
        begin
          if not hasitem(ITEM_IRGLASSES) then
            hudmessage(STR_HAVENT_GLASSES, MT_TEXT, false)
          else
            data.infrared := not data.infrared;
          osv(data.Light_color, false);
        end
        else
          hudmessage(STR_GHOSTS_CANT_USE_IRGLASSES, MT_TEXT, false);
      end;
      KEY_CHARACTER:
      begin
        charactz;
        if data.location = MAP_MAIN then
        begin
          clean_map_all;
          osv_map;
        end
        else
        begin
          clean_all;
          osv(data.Light_color, false);
        end;
      end;
      KEY_DIG:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if not data.prizrak then
        begin
          if (hasitem(ITEM_LOPATA)) and (litter(WhereX, WhereY) + vokrug(WhereX, WhereY, 'Land') + vokrug(WhereX, WhereY, 'WallGround') > 0) then
          begin
            kopat := litter(WhereX, WhereY);
            if (kopat > 1) then
            begin
              hudmessage(STR_DIG_DIRECTION_QUESTION, MT_INFO, false);
              repeat
                c1 := ReadKey;
              until (c1 in [KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_LEFTUP, KEY_LEFTDOWN, KEY_RIGHTUP, KEY_RIGHTDOWN, KEY_ESCAPE]) ;
              case c1 of
                KEY_UP: runk(0, -1);
                KEY_DOWN: runk(0, 1);
                KEY_LEFT: runk(-1, 0);
                KEY_RIGHT: runk(1, 0);
                KEY_LEFTUP: runk(-1, -1);
                KEY_LEFTDOWN: runk(-1, 1);
                KEY_RIGHTUP: runk(1, -1);
                KEY_RIGHTDOWN: runk(1, 1);
                KEY_ESCAPE: hudmessage('', MT_TEXT, false);
              end;
            end
            else
            begin
              if (IsLitter(WhereX - 1, WhereY)) then
                runk(-1, 0)
              else if (IsLitter(WhereX + 1, WhereY)) then
                runk(1, 0)
              else if (IsLitter(WhereX, WhereY - 1)) then
                runk(0, -1)
              else if (IsLitter(WhereX, WhereY + 1)) then
                runk(0, 1)
              else if (IsLitter(WhereX - 1, WhereY - 1)) then
                runk(-1, -1)
              else if (IsLitter(WhereX - 1, WhereY + 1)) then
                runk(-1, 1)
              else if (IsLitter(WhereX + 1, WhereY - 1)) then
                runk(1, -1)
              else if (IsLitter(WhereX + 1, WhereY + 1)) then
                runk(1, 1);
            end;
            osv(data.Light_color)
          end
          else if (not hasitem(ITEM_LOPATA)) then
            hudmessage(STR_I_HAVENOT_SHOVEL, MT_TEXT, false)
          else if (litter(WhereX, WhereY) + vokrug(WhereX, WhereY, 'Land') + vokrug(WhereX, WhereY, 'WallGround') = 0) then
            hudmessage(STR_NOTHING_TO_DIG, MT_TEXT, false);
        end
        else
          hudmessage(STR_GHOSTS_CANT_USE_SHOVELS, MT_TEXT, false);
      end;
      KEY_NEUTRALIZE_TRAP:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else
        begin
          if (vokrug(WhereX, WhereY, 'Trap') > 0) then
          begin
            kopat := vokrug(WhereX, WhereY, 'Trap');
            if (kopat > 1) then
            begin
              hudmessage(STR_TRAP_DIRECTION_QUESTION, MT_INFO, false);
              repeat
                c1 := ReadKey;
              until (c1 in [KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_LEFTUP, KEY_LEFTDOWN, KEY_RIGHTUP, KEY_RIGHTDOWN, KEY_ESCAPE]) ;
              case c1 of
                KEY_UP: TryNeutralizeTrap(WhereX, WhereY - 1);
                KEY_DOWN: TryNeutralizeTrap(WhereX, WhereY + 1);
                KEY_LEFT: TryNeutralizeTrap(WhereX - 1, WhereY);
                KEY_RIGHT: TryNeutralizeTrap(WhereX + 1, WhereY);
                KEY_LEFTUP: TryNeutralizeTrap(WhereX - 1, WhereY - 1);
                KEY_LEFTDOWN: TryNeutralizeTrap(WhereX - 1, WhereY + 1);
                KEY_RIGHTUP: TryNeutralizeTrap(WhereX + 1, WhereY - 1);
                KEY_RIGHTDOWN: TryNeutralizeTrap(WhereX + 1, WhereY + 1);
                KEY_ESCAPE: hudmessage('', MT_TEXT, false);
              end;
            end
            else
            begin
              if (IsType(WhereX - 1, WhereY, 'Trap')) then
                TryNeutralizeTrap(WhereX - 1, WhereY)
              else if (IsType(WhereX + 1, WhereY, 'Trap')) then
                TryNeutralizeTrap(WhereX + 1, WhereY)
              else if (IsType(WhereX, WhereY - 1, 'Trap')) then
                TryNeutralizeTrap(WhereX, WhereY - 1)
              else if (IsType(WhereX, WhereY + 1, 'Trap')) then
                TryNeutralizeTrap(WhereX, WhereY + 1)
              else if (IsType(WhereX - 1, WhereY - 1, 'Trap')) then
                TryNeutralizeTrap(WhereX - 1, WhereY - 1)
              else if (IsType(WhereX - 1, WhereY + 1, 'Trap')) then
                TryNeutralizeTrap(WhereX - 1, WhereY + 1)
              else if (IsType(WhereX + 1, WhereY - 1, 'Trap')) then
                TryNeutralizeTrap(WhereX + 1, WhereY - 1)
              else if (IsType(WhereX + 1, WhereY + 1, 'Trap')) then
                TryNeutralizeTrap(WhereX + 1, WhereY + 1)
            end;
            osv(data.Light_color)
          end
          else
            hudmessage(STR_NOTHING_TO_NEUTRALIZE, MT_TEXT, false);
        end;
      end;
      KEY_INVENTORY:
      begin
        if (data.palsy > 0) then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if (data.prizrak) then
          hudmessage(STR_GHOSTS_CANT_USE_INVENTORY, MT_TEXT)
        else
        begin
          xc := WhereX;
          yc := WhereY;
          data.IsInInv := true;
          showinv;
          data.IsInInv := false;
          ClrScr;
          if data.location <> MAP_MAIN then
          begin
            GoToXY(xc, yc);
            clean_all;
            osv(data.Light_color)
          end
          else
          begin
            GoToXY(xc, yc);
            clean_map_all;
            osv_map;
          end;
        end;
      end;
      KEY_HACK:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if not data.prizrak then
        begin
          if hasitem(ITEM_HACKGADGET) then
          begin
            xc := WhereX;
            yc := WhereY;
            if vokrug2hack(xc, yc) > 1 then
            begin
              hudmessage(STR_IN_WHAT_DIRECTION, MT_TEXT, false);
              repeat
                c1 := ReadKey;
              until (c in [KEY_UP, KEY_DOWN, KEY_LEFT, KEY_RIGHT, KEY_LEFTUP, KEY_LEFTDOWN, KEY_RIGHTUP, KEY_RIGHTDOWN, KEY_ESCAPE]) and
                (IsHackDoor(xc, yc, c));
              case c1 of
                KEY_UP: Hack(xc, yc - 1);
                KEY_DOWN: Hack(xc, yc + 1);
                KEY_LEFT: Hack(xc - 1, yc);
                KEY_RIGHT: Hack(xc + 1, yc);
                KEY_LEFTUP: Hack(xc - 1, yc - 1);
                KEY_LEFTDOWN: Hack(xc - 1, yc + 1);
                KEY_RIGHTUP: Hack(xc + 1, yc - 1);
                KEY_RIGHTDOWN: Hack(xc + 1, yc + 1);
              end;
            end
            else if vokrug2hack(xc, yc) = 1 then
            begin
              if IsHack(xc - 1, yc) then
                Hack(xc - 1, yc)
              else if IsHack(xc + 1, yc) then
                Hack(xc + 1, yc)
              else if IsHack(xc, yc - 1) then
                Hack(xc, yc - 1)
              else if IsHack(xc, yc + 1) then
                Hack(xc, yc + 1);
            end
            else
              hudmessage(STR_DONT_HACK, MT_TEXT, false);
            ClrScr;
            GoToXY(xc + 1, yc + 1);
            clean_all;
            GoToXY(xc, yc);
            osv;
          end
          else
            hudmessage(STR_I_HAVE_NOT_HACKGADGET, MT_TEXT, false);
        end
        else
          hudmessage(STR_GHOSTS_CANT_USE_HACKGADGET, MT_TEXT, false);
      end;
      KEY_NOW:
      begin
        xc := WhereX;
        yc := WhereY;
        shownow;
        ClrScr;
        if data.location <> MAP_MAIN then
        begin
          GoToXY(xc, yc);
          clean_all;
          osv(data.Light_color)
        end
        else
        begin
          GoToXY(xc, yc);
          clean_map_all;
          osv_map;
        end;
      end;
      KEY_PRISON_UP:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if (not data.prizrak) then
          if (IsType(WhereX, WhereY, 'Global_exit')) then
            MakeExitFromLocation
          else if IsType(WhereX, WhereY, 'PrisonUp') then
            GoUpToPrison
        else
          hudmessage(STR_GHOSTS_CANT_USE_LADDERS, MT_TEXT, false)
      end;
      KEY_PRISON_DOWN:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if not data.prizrak then
        begin
          if IsType(WhereX, WhereY, 'Entrace') then
          begin
            if data.location <> MAP_MAIN then
              MakeLocationEntrace
            else
              GoFromGlobalMap
          end
          else if IsType(WhereX, WhereY, 'PrisonDown') then
            GoDownToPrison
          else if (data.location = MAP_MAIN) then
            GenerateRandomLocation(WhereX, WhereY, true);
        end
        else
          hudmessage(STR_GHOSTS_CANT_USE_LADDERS, MT_TEXT, false)
      end;
      KEY_EXIT:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if not data.prizrak then
        begin
          if IsType(WhereX, WhereY, 'Global_exit') then
          begin
            if MonstersInView <= 0 then
              MakeExitFromLocation
            else
              hudmessage(STR_YOU_CANT_ESCAPE, MT_TEXT);
          end;
        end
        else
          hudmessage(STR_GHOSTS_CANT_USE_LADDERS, MT_TEXT, false)
      end;
      KEY_SAVE:
      begin
        if data.location = MAP_MAIN then
        begin
          data.global_x := WhereX;
          data.global_y := WhereY;
        end
        else
        begin
          data.posx := WhereX;
          data.posy := WhereY;
        end;
        save;
        hudmessage(STR_GAME_SAVED, MT_TEXT, false);
      end;
      KEY_SLEEP:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if not data.prizrak then
        begin
          data.posx := WhereX;
          data.posy := WhereY;
          data.invisible := 0;
          ClrScr;
          Write(STR_YOU_GO_TO_SLEEP);
          ReadKey;
          data.sleep := true;
          r := 1;
          for r := 1 to (random(10) * 20) do
            mon_move;
          ClrScr;
          Write(STR_YOU_SLEPT1 + IntToStr(r div 20) + STR_YOU_SLEPT2 + HoursSklon(r div 20) + STR_YOU_SLEPT3);
          inc(data.hours, (r div 20));
          inc(data.minutes, (r mod 20) * 3);
          inc(data.seconds, Random(60));
          check_time;
          ReadKey;
          data.sleep := false;
          r := r div 20;
          if data.ustal + (r * 1000) < 65535 then
            data.ustal := data.ustal + (r * 1000)
          else
            data.ustal := 65535;
          if (cur_lev.street) then
          begin
            clearshadows;
            sunlight(data.hours);
            vidall;
          end;
          ClrScr;
          GoToXY(data.posx, data.posy);
          clean_all;
          osv(data.Light_color)
        end
        else
          hudmessage(STR_GHOSTS_CANT_SLEEP, MT_TEXT, false);
      end;
      KEY_MISS:
      begin
        if (data.Palsy = 0) then
          hudmessage(STR_YOU_PASSED_TURN, MT_TEXT, false);
        osv(data.Light_color);
        inc(data.seconds);
        endhod;
      end;
      KEY_LEVELUP:
      begin
        xc := WhereX;
        yc := WhereY;
        if data.location <> MAP_MAIN then
          inc(xc);
        levelup;
        ClrScr;
        GoToXY(xc, yc);
        if data.location = MAP_MAIN then
        begin
          clean_map_all;
          osv_map;
        end
        else
        begin
          clean_all;
          osv(data.Light_color)
        end;
      end;
      KEY_SCREENSHOT_HTML:
      begin
        screenshot_html;
        hudmessage(STR_SCREENSHOT_SAVED, MT_INFO, false);
      end;
      KEY_SCREENSHOT_TXT:
      begin
        screenshot_txt;
        hudmessage(STR_SCREENSHOT_SAVED, MT_INFO, false);
      end;
      KEY_TIME:
      begin
        if data.location <> MAP_MAIN then
        begin
          tempstr := GetDate + ' ' + GetTime;
          hudmessage(tempstr, MT_TEXT, false);
        end;
      end;
      KEY_CLOSE:
      begin
        if (data.Palsy > 0) then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if dveri(WhereX, WhereY) = 1 then
        begin
          if (IsType(WhereX - 1, WhereY, 'Door_open') and (cur_lev.map[WhereX - 1, WhereY].levAttrz = 0) and (cur_lev.map[WhereX - 1, WhereY].DoorCode = 0)) then
            closedoor(-1, 0)
          else if (IsType(WhereX + 1, WhereY, 'Door_open') and (cur_lev.map[WhereX + 1, WhereY].levAttrz = 0) and (cur_lev.map[WhereX + 1, WhereY].DoorCode = 0)) then
            closedoor(1, 0)
          else if (IsType(WhereX, WhereY - 1, 'Door_open') and (cur_lev.map[WhereX, WhereY - 1].levAttrz = 0) and (cur_lev.map[WhereX, WhereY - 1].DoorCode = 0)) then
            closedoor(0, -1)
          else if (IsType(WhereX, WhereY + 1, 'Door_open') and (cur_lev.map[WhereX, WhereY + 1].levAttrz = 0) and (cur_lev.map[WhereX, WhereY + 1].DoorCode = 0)) then
            closedoor(0, 1)
          else if (IsType(WhereX - 1, WhereY - 1, 'Door_open') and (cur_lev.map[WhereX - 1, WhereY - 1].levAttrz = 0) and (cur_lev.map[WhereX - 1, WhereY - 1].DoorCode = 0)) then
            closedoor(-1, -1)
          else if (IsType(WhereX + 1, WhereY - 1, 'Door_open') and (cur_lev.map[WhereX + 1, WhereY - 1].levAttrz = 0) and (cur_lev.map[WhereX + 1, WhereY - 1].DoorCode = 0)) then
            closedoor(1, -1)
          else if (IsType(WhereX - 1, WhereY + 1, 'Door_open') and (cur_lev.map[WhereX - 1, WhereY + 1].levAttrz = 0) and (cur_lev.map[WhereX - 1, WhereY + 1].DoorCode = 0)) then
            closedoor(-1, 1)
          else if (IsType(WhereX + 1, WhereY + 1, 'Door_open') and (cur_lev.map[WhereX + 1, WhereY + 1].levAttrz = 0) and (cur_lev.map[WhereX + 1, WhereY + 1].DoorCode = 0)) then
            closedoor(1, 1);
        end
        else if dveri(WhereX, WhereY) > 1 then
        begin
          tempx := WhereX;
          tempy := WhereY;
          hudmessage(STR_DIRECTION_QUESTION, MT_INFO, false);
          GoToXY(tempx, tempy);
          repeat
            c1:= ReadKey;
          until ((c1 = KEY_UP) and (doorli(WhereX, WhereY - 1))) or ((c1 = KEY_DOWN)
            and (doorli(WhereX, WhereY + 1))) or ((c1 = KEY_LEFT) and (doorli(WhereX - 1, WhereY))) or ((c1 = KEY_RIGHT)
              and (doorli(WhereX + 1, WhereY))) or ((c1 = KEY_LEFTUP) and (doorli(WhereX - 1, WhereY - 1))) or ((c1 = KEY_LEFTDOWN) and (doorli(WhereX - 1, WhereY + 1))) or
                ((c1 = KEY_RIGHTUP) and (doorli(WhereX + 1, WhereY - 1))) or ((c1 = KEY_RIGHTDOWN) and (doorli(WhereX + 1, WhereY + 1))) or (c1 = KEY_ESCAPE);
          GoToXY(data.posx, data.posy);
          case c1 of
            KEY_UP: closedoor(0, -1);
            KEY_DOWN: closedoor(0, 1);
            KEY_LEFT: closedoor(-1, 0);
            KEY_RIGHT: closedoor(1, 0);
            KEY_LEFTDOWN: closedoor(-1, 1);
            KEY_LEFTUP: closedoor(-1, -1);
            KEY_RIGHTUP: closedoor(1, -1);
            KEY_RIGHTDOWN: closedoor(1, 1);
          end;
          GoToXY(data.posx, data.posy);
        end;
      end;
      KEY_READ:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if IsAnObject(WhereX, WhereY, 'Readable') then
        begin
          xc:=WhereX;
          yc:=WhereY;
          readz;
          inc(data.seconds, 10);
          check_time;
          GoToXY(xc, yc);
          clean_all;
          osv(data.Light_color);
          GoToXY(xc, yc);
          textcolor(data.herocolor);
          Write(data.hero);
          GoToXY(WhereX-1, WhereY);
        end;
      end;
      KEY_SUICIDE:
        if (data.prizrak) then
        begin
          data.health := -1;
          osv;
        end
        else
          hudmessage(STR_NOT_IN_PRIZRAK, MT_TEXT);
      KEY_USE:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if IsType(WhereX, WhereY, 'Entrace') then
          if not data.prizrak then
            if data.location <> MAP_MAIN then
              MakeLocationEntrace
            else
              GoFromGlobalMap
          else
            hudmessage(STR_GHOSTS_CANT_USE_LADDERS, MT_TEXT, false)
        else if (cur_lev.map[WhereX, WhereY].item <> 0) then
          if not data.prizrak then
            put_item
          else
            hudmessage(STR_GHOSTS_CANT_PICKUP, MT_TEXT, false)
        else if IsAnObject(WhereX, WhereY, 'Readable') then
          readz
        else if (IsAnObject(WhereX, WhereY, 'Richag') or (IsAnObject(WhereX, WhereY, 'Richag_2'))) then
          richag
        else if IsAnObject(WhereX, WhereY, 'Teleportator') then
          teleport
        else if IsAnObject(WhereX, WhereY, 'CameraTerminal') then
          camera
        else if IsAnObject(WhereX, WhereY, 'Terminal') then
        begin
          talking(0, 0);
          clean_all;
          osv;
        end
        else if (IsType(WhereX, WhereY, 'PrisonDown')) then
          if not data.prizrak then
            GoDownToPrison
          else
            hudmessage(STR_GHOSTS_CANT_USE_LADDERS, MT_TEXT, false)
        else if (IsType(WhereX, WhereY, 'PrisonUp')) then
          if not data.prizrak then
            GoUpToPrison
          else
            hudmessage(STR_GHOSTS_CANT_USE_LADDERS, MT_TEXT, false);
      end;
      KEY_LOAD:
      begin
        if not DontDeleteSaves then
          save;
        loadgame;
        ClrScr;
        if data.location=MAP_MAIN then
        begin
          clean_map_all;
          GoToXY(data.global_x, data.global_y);
          osv_map;
        end
        else
        begin
          GoToXY(data.posx, data.posy);
          clean_all;
          osv(data.Light_color)
        end;
      end;
      KEY_ATTACK:
      begin
        if data.Palsy > 0 then
          hudmessage(STR_YOU_PALSED, MT_TEXT)
        else if (data.location <> MAP_MAIN) then
          ataka;
      end;
      KEY_HEAR:
      begin
        if data.Ed = 0 then
        begin
          if (data.location <> MAP_MAIN) then
            prihear_bez;
        end
        else
          hudmessage(STR_YOU_ED, MT_TEXT);
      end;
      KEY_LOOKMODE:
      begin
        GoToXY(data.posx, data.posy);
        pricel(data.posx, data.posy, true);
      end;
      KEY_SMELL:
      begin
        if data.location <> MAP_MAIN then
          prismell_bez;
      end;
      KEY_RELOAD:
      begin
        Reload;
        GoToXY(data.posx, data.posy);
        osv;
      end;
      KEY_UNLOAD:
      begin
        Unload;
        GoToXY(data.posx, data.posy);
        osv;
      end;
    end;
    deczapah;
    pri_hear;
    MakeWithDoors;
    check_time;
    hud;
    endhod;
    if (data.location <> MAP_MAIN) and (cur_lev.map[WhereX, WhereY].item <> 0) then
      itemz;
    read_nazv;
    cur_lev.map[data.posx, data.posy].Zapah := data.zapahStrength;
    cur_lev.map[data.posx, data.posy].ZapahType := ZAPAH_HERO;
    cur_lev.map[data.posx, data.posy].Voice := data.voiceStrength;
    cur_lev.map[data.posx, data.posy].VoiceType := VOICE_HERO;
    if (data.location = MAP_MAIN) and ((Random(100) + 1) mod 20 = 0) then
      GenerateRandomLocation(data.posx, data.posy, false);    
    maketurn := (c <> KEY_ESCAPE);
end;
{$Warnings On}

begin
end.
