unit monsters;
interface
uses
  sysutils, loadz, aData;


function notryadom(x, y: byte): boolean;
procedure movemon(x, y: integer; dx, dy: shortint);
function prohod(x, y, sila: byte; canopen: boolean): boolean;
function getclass(aclass: word): string;
function getsila(aClass: word): integer;
function gethealth(montype: word): word;
function rasst(x, dx: byte): byte;
procedure movetopoint(x, y: byte);
procedure mon_shoot(x, y: byte);

implementation

uses
  MyCRT;

procedure mon_shoot(x, y: byte);
var
  enemy: TEnemy;
  item: TItem;
  x1, y1: integer;
  count: integer;
begin
  mon_info(cur_lev.map[x, y].Monster.montype, enemy);
  iteminfo(cur_lev.map[x, y].Monster.item.number, item);
  x1 := data.posx;
  y1 := data.posy;
  count := item.ShootsCount;
  for count := count downto 1 do
    if (cur_lev.map[x, y].Monster.item.ammo > 0) then
    begin
      BulletWay(x, y, x1, y1, aBulletColor(item.number), aMayXplode(item.number),
                 false, enemy.Accuracy, enemy.strength, item.number);
      dec(cur_lev.map[x, y].Monster.item.ammo);
    end;
end;

procedure movetopoint(x, y: byte);
var
  dest_x, dest_y: byte;
  hodx, hody: shortint;
begin
  dest_x := cur_lev.map[x, y].Monster.point div 256;
  dest_y := cur_lev.map[x, y].Monster.point mod 256;
  hodx := 0;
  hody := 0;
  if (x < dest_x) and not sten(x + 1, y) then
    hodx := 1
  else if (x > dest_x) and not sten(x - 1, y) then
    hodx := -1
  else if (x = dest_x) then
    hodx := 0;
  if (y < dest_y) and not sten(x + hodx, y + 1) then
    hody := 1
  else if (y > dest_y) and not sten(x + hodx, y - 1) then
    hody := -1
  else if (y = dest_y) then
    hody := 0;
  movemon(x, y, hodx, hody);
end;


function gethealth(montype: word): word;
var
  item: TEnemy;
begin
  gethealth := 0;
  mon_info(montype, item);
  if item.montype = montype then
    gethealth := item.health;
end;


function getsila(aClass: word): integer;
var
  res: integer;
  enemy: TEnemy;
  ll: Titem;
  l_hand, head, costume, legs, plashch, trousers, gloves: integer;
  l_hand1, head1, costume1, legs1, plashch1, trousers1, gloves1: integer; 
begin
  res := 0;
  mon_info(aClass, enemy);
  if enemy.montype = aClass then
    res := enemy.strength;
  iteminfo(data.l_hand, ll);
  l_hand := ll.Effect;
  if (l_hand < 2) then
    l_hand1 := l_hand
  else
    l_hand1 := l_hand div 2;
  iteminfo(data.head, ll);
  head := ll.Effect;
  if (head < 3) then
    head1 := head
  else
    head1 := head div 3;
  iteminfo(data.legs, ll);
  legs := ll.Effect;
  if (legs < 3) then
    legs1 := legs
  else
    legs1 := legs div 3;
  iteminfo(data.costume, ll);
  costume := ll.Effect;
  if (costume < 3) then
    costume1 := costume
  else
    costume1 := costume div 3;
  iteminfo(data.gloves, ll);
  gloves := ll.Effect;
  if (gloves < 2) then
    gloves1 := gloves
  else
    gloves1 := gloves div 2;
  res := res - random(l_hand div 2) - l_hand1 - random((head div 3) * 2) - head1 - random((legs div 3) * 2) - legs1
  - random(costume div 3) - costume1 * 2 - random(plashch div 2) - plashch1 - random(trousers div 2) - trousers1 - random(gloves div 2) - gloves1;
  if res < 0 then
    getsila := 0
  else
    getsila := res;
end;


function getClass(aClass: word): string;
var
  enemy: TEnemy;
begin
  enemy.name := '';
  mon_info(aClass, enemy);
  if enemy.montype = aClass then
    getclass := enemy.name;
end;



function prohod(x, y, sila: byte; canopen: boolean): boolean;
var
  ran: byte;
begin
  prohod := false;
  if IsBold(x, y) and not IsDoor(x, y) then
    exit;
  if IsDoor(x, y) then
  begin
    if not canopen then
      exit;
    SetElement(x, y, 'Door_open');
    ran := random(255);
    if ran div 2 <= sila then
      cur_lev.map[x, y].objAttrz := (cur_lev.map[x, y].ObjAttrz or 256);
  end;
  prohod := true;
end;

function rasst(x, dx: byte): byte;
begin
  rasst := abs(x - dx);
end;

function prov_v_monmove(monx, mony: byte): boolean;
begin
  prov_v_monmove := ((not IsBold(monx, mony))
    and (not IsThisAMonster(monx, mony))
    and (not IsType(monx, mony, 'Door_open'))
    and (mony <> data.posy) and (monx <>  data.posx));
end;

function IsCanPickup(x, y: integer): boolean;
begin
  with cur_lev.map[x, y] do
    IsCanPickup := (item.number <> 0) and (item.count <> 0) and (Monster.item.number = 0) and (CanPickup(Monster.montype));
end;

procedure SetMonster(var monx, mony: integer; dx, dy: shortint);
var
  mon: TEnemy;
  item: TItem;
begin
  cur_lev.map[monx + dx, mony + dy].Monster := cur_lev.map[monx, mony].Monster;
  mon_info(cur_lev.map[monx, mony].Monster.montype, mon);
  cur_lev.map[monx, mony].Monster := EmptyMonster;
  cur_lev.map[monx + dx, mony + dy].Monster.shod := true;
  if (IsCanPickup(monx + dx, mony + dy)) then
  begin
    iteminfo(cur_lev.map[monx + dx, mony + dy].item.number, item);
    if cur_lev.map[monx + dx, mony + dy].now <> #0 then
      hudmessage(mon.name + STR_PICKUP + item.name, MT_TEXT);
    cur_lev.map[monx + dx, mony + dy].Monster.item := cur_lev.map[monx + dx, mony + dy].item;
    cur_lev.map[monx + dx, mony + dy].item := EmptySlot;
  end;
  if dx > 0 then
    inc(monx, dx);
end;

procedure movemon(x, y: integer; dx, dy: shortint);
var
  enemy: TEnemy;
begin
  if not ((x + dx) in [2..RESOLUTION_X - 1]) or not ((y + dy) in [2..RESOLUTION_Y - 1]) then
    exit;
  mon_info(cur_lev.map[x, y].Monster.montype, enemy);
  if not ((x + dx) in [2..RESOLUTION_X - 1]) or not ((y + dy) in [2..RESOLUTION_Y - 1]) then
  begin
    if cur_lev.map[x, y].now <> #0 then
      cur_lev.map[x, y].Monster.point := 0;
    exit;
  end
  else if (x + dx = data.posx) and (y + dy = data.posy) then
  begin
    if cur_lev.map[x, y].now <> #0 then
      cur_lev.map[x, y].Monster.point := 0;
    exit
  end
  else if IsThisAMonster(x + dx, y + dy) then
  begin
    if cur_lev.map[x, y].now <> #0 then
      cur_lev.map[x, y].Monster.point := 0;
    exit
  end
  else if IsType(x + dx, y + dy, 'Window_crashed') and (CanGrab(enemy.Attrz)) then
  begin
    if (not IsBold(x + (dx * 2), y + (dy * 2))) and ((x + (dx * 2)) in [1..RESOLUTION_X])
      and ((y + (dy * 2)) in [1..RESOLUTION_Y]) and (not IsThisAMonster(x + (dx * 2), y + (dy * 2)))
        and (x + (dx * 2) <> data.posx) and (y + (dy * 2) <> data.posy) then
    begin
      dx := dx * 2;
      dy := dy * 2;
    end
    else
    begin
      if cur_lev.map[x, y].now <> #0 then
        cur_lev.map[x, y].Monster.point := 0;
      exit
    end;
  end
  else if IsBold(x + dx, y + dy) then
  begin
    if cur_lev.map[x, y].now <> #0 then
      cur_lev.map[x, y].Monster.point := 0;
    exit
  end
  else if (IsType(x + dx, y + dy, 'Door')) and (not IsDoorClosedForMonster(x + dx, y + dy, x, y)) then
  begin
    SetElement(x + dx, y + dy, 'Door_open');
    exit;
  end
  else if (IsType(x + dx, y + dy, 'Door')) and (IsDoorClosedForMonster(x + dx, y + dy, x, y)) then
  begin
    if cur_lev.map[x, y].now <> #0 then
      cur_lev.map[x, y].Monster.point := 0;
    exit;
  end;
  SetMonster(x, y, dx, dy);
  if (cur_lev.map[x + dx, y + dy].Monster.point <> 0) and ((cur_lev.map[x + dx, y + dy].Monster.point div 256) = (x + dx))
    and ((cur_lev.map[x + dx, y + dy].Monster.point mod 256) = (y + dy)) then
      cur_lev.map[x + dx, y + dy].Monster.point := 0;
end;


function notryadom(x, y: byte): boolean;
begin
  notryadom := false;
  if (x - 1 <> data.posx) and (x + 1 <> data.posx) and (x <> data.posx) then
    notryadom := false;
  if (y - 1 <> data.posy) and (y + 1 <> data.posy) and (y <> data.posy) then
    notryadom := false;
end;

end.