unit GMMap;

interface
     uses OpenGl,Windows,GMVars,GMUtilite,Textures,log,Dialogs,math,SysUtils,IDX_sound;


type
  TSmallType=record
  active:byte;
  x,y:integer;
  w,h:integer;
  types:byte;
  subtypes:byte;
  name:string;
  end;

type
  Tblood=record
   alive:boolean;
   Id:cardinal;
   x,y:integer;
   xscale, yscale:integer;
   delay:integer;
   angle:integer;
   alpha:byte;
  end;

type
 TEffect=record
 alive:boolean;
 delay:integer;
 AnimID:integer;
 CurrFrame:integer;
 CurrTime:integer;
 rotation:integer;
 x:integer;
 y:integer;
 xscale, yscale:integer;
 light:boolean;
end;

type
  TAnimation=record
  MaxFrame:integer;
  FrameW,FrameH:integer;
  Frames:array of cardinal;
  MaxFrameDelay:integer;
end;

type
 OEnemy =object
 index:integer;
 _x,_y        :real;
 w,h:integer;
 w2,h2:integer;
 alpha:integer;
 CurrFrame:integer;
 CurrTime:integer;
 AnimID:integer;
 target_x,target_y:real;
 force_x      :real;
 force_y      :real;
 Alive        :boolean;
 etype        :string;
 weight       :integer;
 explode      :integer;
 explode_dam  :integer;
 metallic     :boolean;
 no_ai        :boolean;
 dog          :boolean;
 can_run      :boolean;
 melee_damage :integer;
 health       :integer;
 walk_speed   :real;
 score        :integer;
 rotation       :integer;
 target_rotation:integer;
 stuck_time     :real;
 node           :integer;
 running        :integer;
 boss           :boolean;
 animating      :integer;
 current_state  :string;
 diag_speed     :real;
 goX,goY:integer;
 moving:boolean;
 procedure Draw(dx,dy:integer);
 procedure Init(_index,x, y, angle:integer; _types:string; noalpha:boolean; _boss:boolean; _life:integer);
 function EnemyHit(damage, angle:integer; push:real):boolean;
 procedure DoEnemy;
 procedure ChangeState(newstate:string);
 procedure DoEnemyAI;
 procedure DoEnemyMovement;
 procedure EnemyMelee;
 end;


 OPlayer=object
 _x,_y:real;

 w,h:integer;
 w2,h2:integer;

 legs_rotation:integer;
 legs_target_rotation:integer;
 torso_target_rotation:integer;
 torso_rotation:integer;

 moving:boolean;
 walk:boolean;
 fire:boolean;
 cycled:boolean;
 dying:boolean;

 bloodspeed:integer;

 walk_speed:real;
 diag_speed:real;

 reload_time:real;
 current_gun:integer;
 gun_limit:integer;

 health,max_health:integer;
 armour_protect,armour_max_health,armour_health:integer;
 
 Weapon:array of TWeaponData;
 max_guns:integer;
 accuracy,base_accuracy,target_accuracy:integer;

 reload_multi:real;
 current_shot_time:integer;

 current_cadr_torse:integer;
 current_pause_ta:integer;

 base_critical:integer;
 

 procedure Init(dx,dy:integer);
 function  MovePlayer(dx, dy:integer):boolean;
 procedure Procces;
 procedure Draw;

 procedure Damage(health_dam:real);

 function  AddInventory(types:string; ammo, isweapon:integer):integer;
 function  FindInventory(find_item:string):integer;
 procedure ClearInventory(inv_place:integer);

 procedure CalculateScore;
 function  AddWeapon(code:string; ammoloaded, invplace:integer):boolean;
 procedure RemoveWeapon(num:integer);
 procedure FireGun;
 procedure MakeShot(_angle, x, y, _size, _calliber, _addshot, hit, melee, explosive:integer; noknockback:boolean=false);
 procedure FireWeapon(startx,
                            starty:real;
                           _angle,
                           _shots,
                           _spread,
                           _accuracy,
                           _size,
                           _calliber,
                           _addshot,
                           _explosive,
                           _crit:integer);

 procedure ReloadGun(no_sound:boolean);
 procedure CycleWeapon;

end;

   Tmap=object
     SmeshX : Integer;
     SmeshY : Integer;
     
     Width  : Integer;
     Height : Integer;
     W,H    : Integer;

     Cells:array[0..20,0..20] of record
                               id:cardinal; 
                               x,y:integer;
                               end;

     Kompas:array[0..3] of record
                           x,y,w,h:integer;
                           level:integer;
                           end;

     MapObjects:array of TMapObjects;

     ActiveLevel:integer;
     ShowBlok:boolean;
     CCounter:integer;

     Total:integer;
     Winner:integer;

     screen_shake:real;
     screen_shake_speed:real;
     bkgXmove,bkgYmove:integer;
  procedure Init;
  procedure Load;
  procedure Close;
  procedure Draw;

  procedure CreateLevel(Level:integer);
  procedure ScreenShake(amount:integer=0);
  procedure DoScreenShake;
  procedure DoBackground(var player:OPlayer);
  procedure ActionLoop;
  procedure StartGame;
  procedure DoLevel;
  end;

 type
 TVec3d = record
 X, Y, Z : single;
 end;

var
 Mymap:Tmap;
 MyHero:OPlayer;
 Enemies:array of OEnemy;
 Explosion:array of TExplosion;
 Effects:array of TEffect;
 DrawObj:integer=0;
 MenTexture,FonTexture,CursorTexture:cardinal;
 Bochka1,Bochka2:cardinal;
 ArmorPic,HealthPic:cardinal;
 BloodPic:cardinal;
 TrupPic:cardinal;
 WeaponPic:array[0..5] of cardinal;
 sWeaponPic:array[0..5] of cardinal;
 AmmoPic:array[0..3] of cardinal;
 MenTorsTexture:array[0..18] of cardinal;
 Animation:array of TAnimation;

 Bloods:array of Tblood;

 TestString:integer=0;
 soundon:boolean;
 wait_for_end:integer;
 exterior:boolean=true;

 DrawBlood:boolean=false;
 SelectedEnemy:integer;
 intersectXY:record
            x,y:integer;
           end;
 bonustext:record
           x,y:integer;
           text:string;
           alpha:integer;
           end;

 Script:array of TSmallType;
 EditStatus:byte;
 EditSubStatus:integer;
 SelectedBlok:integer;
 EditMode:boolean=true;

procedure ProccesGame;
procedure Render;
Procedure InitGame;
Procedure CloseGame;

procedure DrawHSprite(x,y:real;id:integer;Color:integer=$FFFFFF; Alpha : byte=255);
function SceneCollide(Objects:byte;Id:integer; noenemy, nogood:boolean):byte;
function intersect(x1, y1, x2, y2, x3, y3, x4, y4:real):integer;
procedure MakeExplosion(x, y:real; size, calliber, delay:integer);
function RectInRect(r1x,r1y,r1W,r1H,r2x,r2y,r2W,r2H:real):boolean;
function GetAngle(px1, py1, px2, py2:real):integer;
procedure CreateBonus(types:string; x, y:integer;nocollide:boolean);
function FindInventory(find_item:string):integer;
function CreateEnemy(x, y, angle:integer; types:string; noalpha:boolean; boss:boolean; life:integer):boolean;
procedure DoBonus;
procedure ExteriorEnemySpawn(zombie_type:string; _boss:boolean; _life:integer; _force:boolean=false);
procedure MakeBonusText(msg:string);
implementation
        uses GMWindow;

procedure CreateBlood(x, y, angle, sx, sy, delay:integer);
var
i,k:integer;
begin

k:=-1;
   for i:=0 to high(Bloods) do
   if  Bloods[i].alive=false then
   begin
   k:=i;
   break;
   end;

   if k=-1 then
   begin
   k:=high(Bloods)+1;
   setlength(Bloods,k+1);
   end;
     Bloods[k].Id:=Animation[1].Frames[random(7)];
     Bloods[k].x := x;
     Bloods[k].y := y;
     Bloods[k].xscale := sx;
     Bloods[k].yscale := sy;
     Bloods[k].angle := angle;
     Bloods[k].delay := delay;
     Bloods[k].alpha := random(150)+105;
     Bloods[k].alive:=true;
end;

function CreateEffect(types:byte; x, y, angle, sx, sy, delay:integer; light:boolean):integer;
var
i,k:integer;
begin

k:=-1;
   for i:=0 to high(Effects) do
   if Effects[i].alive=false then
   begin
   k:=i;
   break;
   end;

   if k=-1 then
   begin
   k:=high(Effects)+1;
   setlength(Effects,k+1);
   end;

     Effects[k].x := x;
     Effects[k].y := y;
     Effects[k].xscale := sx;
     Effects[k].yscale := sy;
     Effects[k].rotation := angle;
     Effects[k].delay := delay;
     Effects[k].light := light;
     Effects[k].alive:=true;
     Effects[k].AnimID:=types;
     Effects[k].CurrFrame:=0;
     Effects[k].CurrTime:=0;

result:=k;
end;

procedure DoBloods;
var
i:integer;
begin
for i:=0 to high(Bloods) do
   if Bloods[i].alive then
 begin
    Bloods[i].delay:=Bloods[i].delay-1;
    if Bloods[i].delay<=0 then
    begin
    Bloods[i].delay:=0;
    Bloods[i].alive:=false;
    end;

 end;

end;


procedure DoEffect;
var
i:integer;
begin
for i:=0 to high(Effects) do
   if Effects[i].alive then
 begin
  if Effects[i].AnimID in [0,1,2] then
   begin
  inc(Effects[i].CurrTime);
  if Effects[i].CurrTime>=Animation[Effects[i].AnimID].MaxFrameDelay then
     begin
    Effects[i].CurrTime:=0;
    inc(Effects[i].CurrFrame);
  if Effects[i].CurrFrame>Animation[Effects[i].AnimID].MaxFrame then
     begin
    Effects[i].CurrFrame:=0;
    Effects[i].alive:=false;
    end;
   end;
  end;

   if Effects[i].AnimID=254 then
   begin

   end;

   if Effects[i].AnimID=255 then
   begin
    Effects[i].delay:=Effects[i].delay-1;
    if Effects[i].delay<=0 then
    begin
    Effects[i].delay:=0;
    Effects[i].alive:=false;
    end;
   end;

 end;

end;


procedure DrawEffect;
var
i:integer;
begin
for i:=0 to high(Effects) do
   if Effects[i].alive then
      if RectInRect(0,0,scrw,scrh,
                 Effects[i].x,
                 Effects[i].y,Effects[i].xscale,Effects[i].yscale) then
   begin

   if Effects[i].AnimID in [0,1,2] then
   begin
   if Effects[i].light then glblend(2) else glblend(1);
   DrawTextureBox(Effects[i].x,
                  Effects[i].y,
                  Effects[i].xscale,
                  Effects[i].yscale,
                  Animation[Effects[i].AnimID].Frames[Effects[i].CurrFrame],true,Effects[i].rotation);
// end;
  end;

  if Effects[i].AnimID =254 then
  begin
  //
  DrawTextureBox( Effects[i].x ,
                  Effects[i].y ,
                  Effects[i].xscale,
                  Effects[i].yscale,
                  BloodPic,true,Effects[i].rotation);
 end;

  if Effects[i].AnimID =255 then
  begin
  DrawLine2D(Effects[i].x,Effects[i].y,Effects[i].xscale,Effects[i].yscale,$FFFFFF);
  end;

  end;
end;

procedure DrawBloods;
var
i:integer;
begin
for i:=0 to high(Bloods) do
   if Bloods[i].alive then
   if RectInRect(0,0,scrw,scrh,
                 Bloods[i].x +mymap.SmeshX,
                 Bloods[i].y +mymap.SmeshY,Bloods[i].xscale,Bloods[i].yscale) then
   begin
  DrawTextureBox( Bloods[i].x +mymap.SmeshX ,
                  Bloods[i].y +mymap.SmeshY ,
                  Bloods[i].xscale,
                  Bloods[i].yscale,
                  Bloods[i].Id,true,Bloods[i].angle);
  end;
end;

procedure DoExplosion;
var
i:integer;
begin
for i:=0 to high(Explosion) do
if Explosion[i].alive then
begin
 Explosion[i].delay := Explosion[i].delay - speedFactor;
            if (Explosion[i].delay < 0) then
            begin
                MakeExplosion(Explosion[i]._x, Explosion[i]._y, Explosion[i].esize, Explosion[i].calliber,0);
                Explosion[i].alive:=false;
           end;
end;
end;

procedure MakeExplosion(x, y:real; size, calliber, delay:integer);
var
i,k,angle,kk:integer;
begin
    if (delay > 0) then
    begin
   k:=-1;
    for i:=0 to high(Explosion) do
    if Explosion[i].alive=false then begin k:=i;break;end;
       if k=-1 then
       begin
        i:=high(Explosion)+1;
        setlength(Explosion,i+1);
       end
       else
       i:=k;

        Explosion[i].alive:=true;
        Explosion[i].delay:=delay;
        Explosion[i].esize:=size;
        Explosion[i]._x:=trunc(x);
        Explosion[i]._y:=trunc(y);
        Explosion[i].calliber:= calliber;
       exit;
    end;
     mymap.ScreenShake(2);
  // MakeDecalPreloaded(x, y, 0, Scorch, 90, 60);
    //if (soundon) then _root.explosion1_sound.start();

     PlayEffect('Boom.mp3');

    kk:=CreateEffect(0, trunc(x), trunc(y), random(360), size, size, frameDelay * 2, true);
          if RectInRect(myhero._x-myhero.w2,myhero._y-myhero.h2,myhero.w,myhero.h,
                  (Effects[kk].x-(Effects[kk].xscale div 2)),
                  (Effects[kk].y-(Effects[kk].yscale div 2)),
                   Effects[kk].xscale,
                   Effects[kk].yscale)
   then
       myhero.Damage(1 + calliber / 3);

    for  i:=0 to high(Enemies) do
    begin
    if (Enemies[i].current_state<> 'death') then
    if Enemies[i].Alive then
    if RectInRect(Enemies[i]._x-Enemies[i].w2,Enemies[i]._y-Enemies[i].h2,Enemies[i].w,Enemies[i].h,
                 (Effects[kk].x-(Effects[kk].xscale div 2)),
                 (Effects[kk].y-(Effects[kk].yscale div 2)),
                  Effects[kk].xscale,
                  Effects[kk].yscale)
    then
     begin
                angle := GetAngle(x, y, Enemies[i]._x, Enemies[i]._y);
                Enemies[i].EnemyHit(1 + calliber, angle, 1 + calliber * 0.500000);
                current_profile.shots_hit := current_profile.shots_hit + 1;
            end; // end if
    end; // end of for
end;

function GetDist(ax, ay, bx, by:real):integer;
begin
    result:=round( abs(bx - ax) + abs(by - ay));
end;


function RectInRect(r1x,r1y,r1W,r1H,r2x,r2y,r2W,r2H:real):boolean;
begin
result:=
  ((R1X < R2X+R2W) and
  (R1X+R1W > R2X) and
  (R1Y < R2Y+R2H) and
  (R1Y+R1H > R2Y)) or
  ((R2X < R1X+R1W) and
  (R2X+R2W > R1X) and
  (R2Y < R1Y+R1H) and
  (R2Y+R2H > R1Y));

end;

function ArcTan2(const Y, X: single): single;
asm
 FLD     Y
 FLD     X
 FPATAN
 FWAIT
end;

function GetAngle(px1, py1, px2, py2:real):integer;
var
angle:real;
begin
    angle := arctan2(px1 - px2, py1 - py2);
    angle := angle / 3.140000 * 180;
    result:= round(-angle);
end;


function ReachAngle(currentAngle, targetAngle, amount, locking, forcedirection:integer):integer;
var
_l2,_l3,_l4,_l5,TurnedDirection:integer;
CA,TA,NewAngle,Dist:integer;
gah:integer;
begin
    _l3 := currentAngle + 180;
    _l2 := targetAngle + 180;
    TurnedDirection := 0;
    CA := _l3 mod 360;
    TA := _l2 mod 360;
    _l5 := 1;
    if (CA < 0) then CA := 360 + CA;
    if (TA < 0) then TA := 360 + TA;
    if (CA > (TA - amount)) and (CA < (TA + amount)) then
    begin
        if (CA < TA) then TurnedDirection := 1;
        if (CA > TA) then TurnedDirection := -1;
        if (CA = TA) then TurnedDirection := 0;

        CA := TA;
        NewAngle := CA;
    end
    else
    begin
        CA := _l3 mod 360;
        TA := _l2 mod 360;
        _l5 := 1;
        if (CA < 0) then CA := 360 + CA;
        if (TA < 0) then TA := 360 + TA;

        Dist := CA - TA;
        if (forcedirection = 0) then
        begin
            if (Dist > 0) and (Dist < 180) or (Dist < -180) then
            begin
                NewAngle := CA - amount;
                TurnedDirection := -1;
            end
            else
            begin
                NewAngle := CA + amount;
                TurnedDirection := 1;
            end; // end if
        end
        else if (forcedirection = -1) then
        begin
            NewAngle := CA - amount;
            TurnedDirection := -1;
        end
        else
        begin
            NewAngle := CA + amount;
            TurnedDirection := 1;
        end; // end if
        if (NewAngle > (TA - amount)) and (NewAngle < (TA + amount)) then NewAngle := TA;
    //end;
    end; // end if

    result:=(NewAngle - 180);
end; // End of the function

procedure ActionLoop;
var
i,temp:integer;
zombie_type:string;
begin

 myhero.Procces;
 DoBonus;
 DoExplosion;
 DoEffect;
 DoBloods;

   bonustext.alpha := bonustext.alpha - 1 * speedFactor;
   if (bonustext.alpha < 0) then bonustext.alpha := 0;



    for i :=0 to high(Enemies) do Enemies[i].DoEnemy;

    game_time := game_time +  speedFactor * 0.850000;

      mymap.DoBackground(myhero);
      mymap.DoLevel;

    if (wait_for_end < 2) then
        zombietime := zombietime + speedFactor;

    if (wait_for_end = 2) and (EnemiesInplay = 0) then
    begin
        wait_for_end := 3;
        myhero.CalculateScore();
    end; // end if

    current_profile.survived_time := current_profile.survived_time + speedFactor;

    if (zombietime > next_zombietime) then
    begin
        zombietime := 0;
        temp := random(3) + 1;
        zombie_type := zombie_types[random(5) + 1];
        if (not exterior) then
        begin
          i := random(3) + 1;
        if (i = 1) then
            if (CreateEnemy(StartPoints[0].x, StartPoints[0].y, StartPoints[0].angle , zombie_type,false,false,0) = false) then
                i:= 2
            else
                i:= 0;

        if (i = 2) then
            if (CreateEnemy(StartPoints[1].x, StartPoints[1].y, StartPoints[1].angle, zombie_type,false,false,0) = false) then
                i:= 3;

        if (i = 3) then
            if (CreateEnemy(StartPoints[2].x, StartPoints[2].y, StartPoints[2].angle, zombie_type,false,false,0) = false) then
                i := 1;
     end
        else
        begin
           ExteriorEnemySpawn(zombie_type, false, 0, false);
        end;
    end;

end;


function CreateEnemy(x, y, angle:integer; types:string; noalpha:boolean; boss:boolean; life:integer):boolean;
var
i:integer;
k:integer;
begin
k:=-1;
result:=false;
 for i:=0 to high(Enemies) do
 if Enemies[i].Alive=false then
 begin
 k:=i;
 break;
 end;

 if k=-1 then
 begin
 k:=high(Enemies)+1;
 setlength(Enemies,k+1);
 end;

 SelectedEnemy:=k;
 Enemies[k].Init(k,x,y,angle,types,noalpha,boss,life);
 if Enemies[k].Alive then
 result:=true;
end;


procedure OEnemy.Draw(dx,dy:integer);
var
Tx,Ty:integer;
Gx,Gy:integer;
begin
Tx:= trunc(_x);
Ty:= trunc(_y);

if RectInRect(0,0,scrw,scrh,tx-16,ty-16,32,32)=false then exit;

inc(DrawObj);

 glblend(1);

 if  (etype = 'Zombie')           or
     (etype = 'ZombieDogWalk')    or
     (etype = 'ZombieCrawler')    or
     (etype = 'ZombieSlowRunner') or
     (etype = 'ZombieRunner')     or
     (etype = 'ZombieDogRun')     or
     (etype = 'ZombieBigDog')     or
     (etype = 'ZombieGiant')then
 begin

 DrawTextureBox(tx,ty,
                  Animation[AnimID].FrameW,
                  Animation[AnimID].FrameH,
                  Animation[AnimID].Frames[CurrFrame],true,rotation);
 end;

  if (etype = 'Barrel1') then  DrawTextureBox(tx,ty,64,64,Bochka1,true,rotation);
  if (etype = 'Barrel2') then  DrawTextureBox(tx,ty,64,64,Bochka2,true,rotation);
  if (etype = 'Barrel3') then  DrawTextureBox(tx,ty,64,64,Bochka2,true,rotation);

 end;


function OEnemy.EnemyHit(damage, angle:integer; push:real):boolean;
var
pushx,pushy:real;
push2:real;
begin

    if alive=false then exit;

    health := health - damage;

    push2 := push / weight;
    angle := angle - 90;
    pushx := cos(angle * 3.141593 / 180) * push2;
    pushy :=  sin(angle * 3.141593 / 180) * push2;
    force_x := force_x + pushx;
    force_y := force_y + pushy;
    if (force_x > 15) then force_x := 15;
    if (force_y > 15) then force_y := 15;
    if (force_x < -15) then force_x := -15;
    if (force_y < -15) then force_y := -15;

end;


procedure OEnemy.ChangeState(newstate:string);
var
_l1:string;
begin
    current_state := newstate;
end;

procedure ExteriorEnemySpawn(zombie_type:string; _boss:boolean; _life:integer; _force:boolean=false);
var
temp:integer;
again,done,i:boolean;
begin
i:=false;
    again := true;
    repeat
        again:= false;
        done:= false;
        temp:= random(4) + 1;
        if (temp = 1) then
        begin
            if (CreateEnemy(-30, random(scrh), 90, zombie_type, true, _boss, _life) =false) then
            temp := 2
            else
            done := true;
        end; // end if
        if (temp = 2) then
        begin
            if (CreateEnemy(random(scrw), scrh+20, 180, zombie_type, true, _boss, _life) = false) then
                temp := 3
                else
                done := true;
         end; // end if
        if (temp = 3) then
        begin
            if (CreateEnemy(random(scrw)-10, random(scrh), 270, zombie_type, true, _boss, _life) = false) then
                temp := 4
            else
               done := true;
         end; // end if
        if (temp = 4) then
        begin
            if (CreateEnemy(random(scrw), -30, 0, zombie_type, true, _boss, _life) = false) then
               temp := 1
            else
               done := true;
        end; // end if
        if (temp = 1) and (done = false) then
        begin
            if (CreateEnemy(-30, random(scrh), 90, zombie_type, true, _boss, _life) = false) then
            begin
                again := i;
                continue;
            end; // end if
            done := true;
        end; // end if
    until (again=false);

end;


procedure OEnemy.DoEnemyAI;
var
diffx,diffy:real;
begin

    if (no_ai) then exit;

 if alive then
   begin
  inc(CurrTime);
  if  CurrTime>=Animation[AnimID].MaxFrameDelay then
     begin
     CurrTime:=0;
    inc(CurrFrame);
  if  CurrFrame>Animation[AnimID].MaxFrame then
     begin
    CurrFrame:=0;
   end;
  end;
 end;


    if RectInRect(myhero._x-myhero.w2,myhero._y-myhero.h2,myhero.w,myhero.h,
                  _x-w2+goX,_y-h2+goY,w,h ) or
     (current_state = 'attack') or
     (current_state = 'death') then
    begin
        moving := false;
        if (current_state <> 'stun')   and
           (current_state <> 'death')  and
           (current_state <> 'attack') then ChangeState('attack');

         if (current_state = 'attack') then
        target_rotation := GetAngle(_x, _y, myhero._x, myhero._y);

    end
    else
    begin
        if (stuck_time > 5) then
        begin
            stuck_time := 0;
            if (node = 0) and (not exterior) then
            begin
                node := 999;

            end
            else if (not exterior) then
            begin
                 node := 0;

            end
            else if (node = 9999) then
            begin
            node := 0;
            end
            else
            begin
                node := 9999;
                diffx := myhero._x - _x;
                diffy := myhero._y - _y;
                diffx := diffx * -100;
                diffy := diffy * -100;
                target_x := _x + diffx;
                target_y := _y + diffy;
                
            end; // end if
        end; // end if
        if (node > 0) then
        begin

        end; // end if
        if (node <> 9999) then
        begin
            if (node = 0) then
            begin
                target_x := myhero._x;
                target_y := myhero._y;
            end
            else
            begin

            end; // end if
        end; // end if

    goX := 0;
    goY := 0;

        if (target_x > _x + 5) then goX := 1;
        if (target_x < _x - 5) then goX := -1;
        if (target_y > _y + 5) then goY := 1;
        if (target_y < _y - 5) then goY := -1;

    end; // end if

    if (alpha < 90) then
    begin
        goY := 0;
        goX := 0;
    end; // end if
end;


procedure OEnemy.EnemyMelee;
begin

if RectInRect(myhero._x-myhero.w2,myhero._y-myhero.h2,myhero.w,myhero.h,_x-w2,_y-h2,w,h ) then
  begin
        myhero.Damage(melee_damage);
    end; // end if

end;


procedure OEnemy.DoEnemyMovement;
var
force:boolean;
stuckmod:real;
mods,speed:real;
x,y:integer;
diag:boolean;
backx,backy,direct:real;
collide:byte;
begin
    force := false;
    stuckmod := 1;
    mods := 1;
    if (running = 1) then mods := 1.600000;

    x := goX;
    y := goY;
    if (current_state = 'death') then
    begin
        x := 0;
        y := 0;
    end;

    moving := false;

    if (force_x <> 0) or (force_y <> 0) then
    begin
        force := true;
        x := 0;
        y := 0;
    end;

    if (x <> 0) or (y <> 0) then
    begin
        speed := walk_speed * speedFactor * mods;
        diag := false;
        if (x <> 0) and (y <> 0) then
        begin
            speed := diag_speed * speedFactor * mods;
            diag := true;
        end; // end if

        backx := _x;
        backy := _y;
        _y := _y + y * speed * 1;
        _x := _x + x * speed * 1;
        moving := true;
        speed := walk_speed * speedFactor * mods;
        collide := SceneCollide(1,index, true, false);
        if (collide>0) then
        begin
            if (collide = 2) then stuckmod := 0.100000;

            _x := backx;
            _y := backy;

            if (diag) then
            begin
                _y := _y + y * speed * 1;

                collide := SceneCollide(1,index, true, false);
                if (collide > 0) then
                begin
                    if (collide = 2) then stuckmod := 0.100000;

                    y := 0;
                   _y := backy;
                end; // end if
                if (y = 0) then
                begin
                    _x := _x + x * speed * 1;

                    collide := SceneCollide(1,index, true, false);
                    if (collide > 0) then
                    begin
                        if (collide = 2) then stuckmod := 0.100000;
                        x := 0;
                       _x := backx;
                    end; // end if
                end
                else
                begin
                    x := 0;
                end;
            end
            else
            begin
                y := 0;
                x := 0;
            end;
        end;

        if (x = 0) and (y = 0) then moving := false;
        if (x > 0) and (y = 0) then target_rotation := 270;
        if (x < 0) and (y = 0) then target_rotation := 90;
        if (x = 0) and (y > 0) then target_rotation := 0;
        if (x = 0) and (y < 0) then target_rotation := 180;
        if (x > 0) and (y > 0) then target_rotation := 315;
        if (x > 0) and (y < 0) then target_rotation := 225;
        if (x < 0) and (y > 0) then target_rotation := 45;
        if (x < 0) and (y < 0) then target_rotation := 135;
        if (x = 0) and (y = 0) then
        begin
            moving := false;
            stuck_time := stuck_time + stuckmod * speedFactor;
        end
        else
        begin
            target_rotation := target_rotation - 180;
            stuck_time := 0;
        end; // end if
    end; // end if
    if (force) then
    begin
        if (force_x <> 0) then
        begin
            direct := force_x / abs(force_x);
            force_x := force_x - abs(force_x / 10) * direct * speedFactor;
            if (force_x > -0.500000) and (direct < 0) then force_x := 0;
            if (force_x < 0.500000) and (direct > 0) then force_x := 0;

        end;
        if (force_y <> 0) then
        begin
            direct := force_y / abs(force_y);
            force_y := force_y - abs(force_y / 10) * direct * speedFactor;
            if (force_y > -0.500000) and (direct < 0) then force_y := 0;
            if (force_y <  0.500000) and (direct > 0) then force_y := 0;
        end; // end if
        backx := _x;
        backy := _y;
        _x := _x + force_x * speedFactor;
        _y := _y + force_y * speedFactor;
        y := 1;
        x := 1;
        if (SceneCollide(1,index, true, false)>0) then
        begin
            _x := backx;
            _y := backy;
            _y := _y + force_y * speedFactor;
            if (SceneCollide(1,index, true, false)>0) then
            begin
                y := 0;
               _y := backy;
            end; // end if
            if (y = 0) then
            begin
                _x := _x + force_x * speedFactor;
                if (SceneCollide(1,index, true, false)>0) then _x := backx;
            end; // end if
        end; // end if
    end; // end if
    if (no_ai =false) then
    rotation := ReachAngle(rotation, target_rotation, 3 * speedFactor, 1, 0);

end;


procedure OEnemy.DoEnemy;
var
randomnum,inv_place2,i:integer;
begin
if Alive=false then exit;

    if (GamePaused) then exit;

    if (can_run) and (random(trunc(300 / speedFactor)) <>0) then
    begin
        running := running * -1;
       if (current_state = 'move') then ChangeState('move');
    end;

    if (current_state <> 'death') and (alpha < 100) then
        alpha := alpha + 1 * speedFactor;

    if (alpha > 100) then alpha := 100;

    if (no_ai = false)then
    begin
        DoEnemyAI;
        DoEnemyMovement;
    end;

    if (moving =false) and
       (current_state = 'move') and (stuck_time > 10)
       then
       ChangeState('stand');

    if (moving) and (current_state <> 'move') then ChangeState('move');
    if (alpha < 90) and (current_state = 'move') then ChangeState('stand');
    if ((force_x <> 0) or (force_y<> 0)) and
          (current_state <> 'stun') and
          (current_state <> 'death') then
          ChangeState('stun');

    if (force_x = 0) and
       (force_y = 0) and
       (current_state = 'stun') then
       ChangeState('stand');

    if (health <= 0) and (current_state <> 'death') then
    begin
        ChangeState('death');
         alive:=false;
        if (no_ai = false) then
        begin
            dec(EnemiesInplay);
            inc(current_profile.enemies_killed);
        end; // end if

       if (explode > 0) then MakeExplosion(_x, _y, explode, explode_dam, 0);

        current_profile.score := current_profile.score + score;
        if (boss) then wait_for_end := wait_for_end + 1;

        score := 0;

        if ((random(100) + 1) < 76) or (force_next_bonus <> '') then
        begin
            randomnum := random(5) + 1;
            if (force_next_bonus <> '') then
            begin
                CreateBonus(force_next_bonus, trunc(_x), trunc(_y), true);
                force_next_bonus := '';
            end
            else
            begin

                if (randomnum = 1) then
                    CreateBonus('Bonus35Bullets', trunc(_x), trunc(_y), true);

                if (randomnum = 2) then
                begin
                    inv_place2 := -1;
                    inv_place2 := FindInventory('colt45');
                    if (inv_place2 > -1) then
                        CreateBonus('Bonus45Bullets', trunc(_x), trunc(_y), true);
                end; // end if

                if (randomnum = 3) then
                begin
                    inv_place2 := -1;
                    inv_place2 := FindInventory('mossberg500');
                    if (inv_place2 > -1) then
                        CreateBonus('Bonus12GaugeShells', trunc(_x), trunc(_y), true);
                 end;
                if (randomnum = 4) then
                begin
                    inv_place2 := -1;
                    inv_place2 := FindInventory('gm94launcher');
                    if (inv_place2 > -1) then
                        CreateBonus('BonusGrenadeAmmo', trunc(_x), trunc(_y), true);
                end;

                if (randomnum = 5) then
                begin
                    if (myhero.health < myhero.max_health) then
                        CreateBonus('BonusHealth', trunc(_x), trunc(_y), true);
                end; // end if
            end; // end if
        end; // end if
    end; // end if

    if  (exterior)and
        (no_ai =false) and
        (current_state <> 'death') and
        ((_x > scrw) or (_x < -200) or (_y > scrh) or (_y < -200)) then
      begin
        if (no_ai =false) then dec(EnemiesInplay);
        alive:=false;
        ExteriorEnemySpawn(etype, boss, health, true);
    end; // end if
end;


procedure OEnemy.Init(_index,x, y, angle:integer; _types:string; noalpha:boolean; _boss:boolean; _life:integer);
var
baselevel:integer;
 begin

  if (_types = 'ZombieGiant') then baselevel := 105;

    weight      := 1;
    explode     := 0;
    explode_dam := 0;
    metallic    := false;
    no_ai       := false;
    dog         := false;
    can_run     := false;
    alive       := true;
    index       :=_index;

   w:=32;
   h:=32;
   w2:=w div 2;
   h2:=h div 2;

   AnimID:=2;
   CurrFrame:=0;
   CurrTime:=0;


   health := _life;
    etype := _types;
    _x := x;
    _y := y;

    if (_types = 'Zombie') then
    begin
        melee_damage := 10;
        health := 14;
        walk_speed := 0.700000;
        score := 5;
        AnimID:=4;
    end
    else
    if (_types = 'ZombieCrawler') then
    begin
        melee_damage := 10;
        health       := 14;
        walk_speed   := 0.500000;
        score        := 7;
         AnimID:=5;

    end // end if j
    else
    if (_types = 'ZombieSlowRunner') then
    begin
        melee_damage := 12;
        health       := 16;
        walk_speed   := 1.200000;
        score        := 10;
         AnimID:=6;
    end // end if
    else
    if (_types = 'ZombieRunner') then
    begin
        melee_damage := 12;
        health       := 16;
        walk_speed   := 1.600000;
        score        := 15;
         AnimID:=6;
    end // end if
    else
    if (_types = 'ZombieGiant') then
    begin
        melee_damage := 20;
        health       := 150;
        walk_speed   := 1.200000;
        score        := 400;
        weight       := 2;
         AnimID:=7;
    end // end if
    else
    if (_types = 'ZombieDogWalk') then
    begin
        melee_damage := 8;
        health       := 16;
        walk_speed   := 0.900000;
        score        := 15;
        dog          := true;
        AnimID:=2;
    end // end if
    else
    if (_types = 'ZombieDogRun') then
    begin
        melee_damage := 8;
        health := 19;
        walk_speed := 1.800000;
        score := 15;
        dog := true;
        AnimID:=3;
    end // end if
    else
    if (_types = 'ZombieBigDog') then
    begin
        melee_damage := 12;
        health := 300;
        walk_speed := 1.200000;
        score := 15;
        dog := true;
        can_run := true;
        AnimID:=3;
    end // end if
    else
    if (_types = 'Barrel1') or (_types = 'Barrel2') or (_types = 'Barrel3') then
    begin
        melee_damage := 0;
        health       := 4;
        walk_speed   := 0;
        score        := 400;
        weight       := 1;
        no_ai        := true;
        metallic     := true;
        explode      := 120;
        explode_dam  := 60;
    end; // end if



    if (SceneCollide(1,SelectedEnemy, true, false)>0) then
    begin
      alive:=false;
      exit;
    end;

    force_x := 0;
    force_y := 0;
    rotation := angle;

    target_rotation := angle;
    stuck_time := 0;
    node := 0;
    running := -1;
    boss := _boss;
    animating := 0;

    if ( no_ai = false) then inc(EnemiesInplay);

    current_state := 'stand';
    diag_speed := sqrt(walk_speed * walk_speed / 2);
end;


procedure OPlayer.FireWeapon(startx,
                            starty:real;
                           _angle,
                           _shots,
                           _spread,
                           _accuracy,
                           _size,
                           _calliber,
                           _addshot,
                           _explosive,
                           _crit:integer);
var
i, best_dist, best_x, best_y,dist,hit,k:integer;
rads:real;
stepx,stepy:real;
tx,ty:integer;
x1,x2,x3,x4,y1,y2,y3,y4:real;
begin
    _angle := _angle + (random(_accuracy * 2) - _accuracy);

   if (_shots > 3) then mymap.ScreenShake(-6);

    if (_shots > 1) then
    begin
        for i:= 1 to _shots do
        FireWeapon(startx, starty, _angle, 1, _spread, _spread, _size, _calliber, _addshot,_explosive, _crit);

    end; // end if
    rads := 0.017453;
    stepx :=  sin(_angle * rads);
    stepy := -cos(_angle * rads);
    best_dist := 3000;
    best_x := 3000;
    best_y := 3000;
    x1 := startx;
    y1 := starty;
    x2 := startx + stepx * 450;
    y2 := starty + stepy * 450;


    for i:= 0 to high(mymap.MapObjects) do
    for k := 1 to 4 do
            begin
                if ((k = 1) and ((_angle > 90) and (_angle < 270))) or
                   ((k = 2) and (_angle < 0)) or
                   ((k = 3) and ((_angle > -90) and (_angle < 90))) or
                   ((k = 4) and (_angle > 0)) then
                    begin
                    if (k = 1) then
                    begin
                        x3 := mymap.MapObjects[i].x {- (mymap.MapObjects[i].w div 2)};
                        y3 := mymap.MapObjects[i].y {- (mymap.MapObjects[i].h div 2)};
                        x4 := mymap.MapObjects[i].x +mymap.MapObjects[i].w{+ (mymap.MapObjects[i].w div 2)};
                        y4 := mymap.MapObjects[i].y {- (mymap.MapObjects[i].h div 2)};
                    end; // end if
                    if (k = 2) then
                    begin
                        x3 := mymap.MapObjects[i].x +mymap.MapObjects[i].w {+ (mymap.MapObjects[i].w div 2)};
                        y3 := mymap.MapObjects[i].y {- (mymap.MapObjects[i].h div 2)};
                        x4 := mymap.MapObjects[i].x +mymap.MapObjects[i].w{+ (mymap.MapObjects[i].w div 2)};
                        y4 := mymap.MapObjects[i].y +mymap.MapObjects[i].h{+ (mymap.MapObjects[i].h div 2)};
                    end; // end if
                    if (k = 3) then
                    begin
                        x3 := mymap.MapObjects[i].x +mymap.MapObjects[i].w{- (mymap.MapObjects[i].w div 2)};
                        y3 := mymap.MapObjects[i].y +mymap.MapObjects[i].h{+ (mymap.MapObjects[i].h div 2)};
                        x4 := mymap.MapObjects[i].x {+ (mymap.MapObjects[i].w div 2)};
                        y4 := mymap.MapObjects[i].y +mymap.MapObjects[i].h{+ (mymap.MapObjects[i].h div 2)};
                    end; // end if
                    if (k = 4) then
                    begin
                        x3 := mymap.MapObjects[i].x {- (mymap.MapObjects[i].w div 2)};
                        y3 := mymap.MapObjects[i].y {- (mymap.MapObjects[i].h div 2)};
                        x4 := mymap.MapObjects[i].x {- (mymap.MapObjects[i].w div 2)};
                        y4 := mymap.MapObjects[i].y +mymap.MapObjects[i].h{+ (mymap.MapObjects[i].h div 2)};
                     end; // end if
                    if (intersect(x1, y1, x2, y2, x3, y3, x4, y4) = 2) then
                    begin

                      tx := intersectXY.x;
                      ty := intersectXY.y;
                      dist := GetDist(x1, y1, tx, ty);
                    if (dist <= best_dist) then
                    begin
                        best_dist := dist;
                        best_x := tx;
                        best_y := ty;
                    end; // end if
                end; // end if
            end; // end if
    end; // end of for
     hit := -1;

   for i:= 0 to high(Enemies) do
   if Enemies[i].Alive then
   begin
            for k:= 1 to 2 do
            begin
                if (k = 1) then
                begin
                    x3 := Enemies[i]._x;
                    y3 := Enemies[i]._y - Enemies[i].h2;
                    x4 := Enemies[i]._x;
                    y4 := Enemies[i]._y + Enemies[i].h2;
                end; // end if
                if (k = 2) then
                begin
                    x3 := Enemies[i]._x - Enemies[i].w2;
                    y3 := Enemies[i]._y;
                    x4 := Enemies[i]._x + Enemies[i].w2;
                    y4 := Enemies[i]._y;
                end; // end if
                if (intersect(x1, y1, x2, y2, x3, y3, x4, y4) = 2) then
                begin
                    tx := intersectXY.x;
                    ty := intersectXY.y;
                    dist := GetDist(x1, y1, tx, ty);
                    if (dist <= best_dist) then
                    begin
                        best_dist := dist;
                        best_x := tx;
                        best_y := ty;
                        hit := i;
                    end; // end if
                end; // end if
            end; // end of for
       end; // end of for

    if (best_x=3000) and (best_y=3000) then
    CreateEffect(255,trunc(x1), trunc(y1),0,MousePos.X,MousePos.Y,15,false)
    else
    CreateEffect(255,trunc(x1), trunc(y1),0,best_x,best_y,15,false);

    MakeShot(_angle, best_x, best_y, _size, _calliber, _addshot, hit, 0, _explosive);
    PlayEffect('Glock.mp3');

     if (_crit=1) and (hit > -1) then
    begin
       mymap.ScreenShake();
       MakeShot(_angle, best_x + (random(10) - 5), best_y + (random(20) - 5), _size, _calliber, _addshot, hit, 0, _explosive);
       MakeShot(_angle, best_x + (random(10) - 5), best_y + (random(20) - 5), _size, _calliber, _addshot, hit, 0, _explosive);
       MakeShot(_angle, best_x + (random(10) - 5), best_y + (random(20) - 5), _size, _calliber, _addshot, hit, 0, _explosive,true);
      end; // end if

end;


procedure OPlayer.MakeShot(_angle, x, y, _size, _calliber, _addshot, hit, melee, explosive:integer; noknockback:boolean=false);
var
addshot2,size:integer;
knockback:real;
begin

    current_profile.shots_fired := current_profile.shots_fired + _addshot;


  if (explosive > 0) then
    begin
        MakeExplosion(x, y, _size, _calliber, explosive);
        exit;
    end; // end if
    if (hit =-1) then
    begin

   //if (Not (melee = 1)) then CreateEffect('ShotHitEffectHolder', x, y, 0, size, size, _root.frameDelay / 1);

    end
    else
    begin
        addshot2 := 0;
        if (_addshot > 0) then addshot2 := 1;
        current_profile.shots_hit := current_profile.shots_hit + addshot2;

        knockback := 1 + _calliber * 0.500000;

        if (noknockback) then knockback := 0;

         if hit<0 then exit;

        Enemies[hit].EnemyHit(1 + _calliber, _angle, knockback);

        if (Enemies[hit].metallic = false) then
        begin
        CreateBlood(x-mymap.SmeshX,y-mymap.SmeshY,_angle,128,128,2000);
            size := random(20) + 40;
            CreateEffect(1, x, y, _angle, size, size, trunc(frameDelay / 2),false);

        end
        else
        begin

        end; // end if

    end; // end if

end;


procedure OPlayer.FireGun;
var
soundon:boolean;
critchance:real;
soundplayed:boolean;
crit,i,hit,x,y,ll:integer;
begin
 critchance := base_critical * weapon[current_gun].critical;
    crit:=0;
    ll:=0;
    if (random(100) + 1 <= critchance) then crit:=1;
////-------------------------------------------------------------
    if (weapon[current_gun].melee) then
    begin
        if (Not fire) then
        begin
            fire:=true;
            current_shot_time := 0;
            hit := 0;
            for i:= 0 to MaxEnemies + MaxBarrels do
            begin

            end; // end of for
            if (hit > 0) then
            begin

            end; // end if
        end; // end if
    end
    else if (weapon[current_gun].bullets_loaded > 0) and (reload_time = 0) then
    begin
        if (weapon[current_gun].explosive = 0) then
        begin
        end; // end if
        dec(weapon[current_gun].bullets_loaded);
        fire := true;
        soundplayed := false;
            if (weapon[current_gun].types= 'shotgun') then
            begin
                soundplayed := true;
                ll:=50;

            end; // end if
            if (weapon[current_gun].types= 'grenadelauncher') then
            begin
                soundplayed := true;

            end; // end if

        current_shot_time := 0;
        if (weapon[current_gun].explosive > 0) then
        begin
            x := trunc(MousePos.x + (random(accuracy * 10) - accuracy * 5));
            y := trunc(MousePos.y + (random(accuracy * 10) - accuracy * 5));
            MakeShot(torso_rotation, x, y, weapon[current_gun].shot_size,
                                           weapon[current_gun].calliber_type,
                                           2, 0, 0,
                                           weapon[current_gun].explosive);
        end
        else
        begin
              FireWeapon(_x, _y, torso_rotation, weapon[current_gun].shots_fired,
                                           weapon[current_gun].spread,
                                           accuracy+ll,
                                           weapon[current_gun].shot_size,
                                           weapon[current_gun].calliber_type,
                                           1,
                                           weapon[current_gun].explosive,
                                           crit);
        end;


        if (weapon[current_gun].bullets_loaded= 0) and (weapon[current_gun].melee= false) then
            ReloadGun(true);

    end
    else
          ReloadGun(false);

end;


procedure OPlayer.ReloadGun(no_sound:boolean);
var
inv_place,ammo_remaining,i,gunwithammo:integer;
begin
    current_shot_time := 0;

    if (reload_time > 0) or (weapon[current_gun].bullets_loaded= weapon[current_gun].bullet_capacity) then exit;
    ammo_remaining := 0;
    inv_place := -1;
    inv_place := FindInventory(weapon[current_gun].ammo_type);
    if (inv_place > -1) then ammo_remaining := current_profile.inventory[inv_place].params[0];

    if (ammo_remaining > 0) then
    begin
    reload_time := weapon[current_gun].reload_time * reload_multi;
     PlayEffect('Reload.mp3');
    end
    else
    begin

      if (weapon[current_gun].bullets_loaded> 0) then exit;
         PlayEffect('NoAmmo.mp3');
         MakeBonusText('Нет патронов');
           gunwithammo := 0;
        for i:= 1 to max_guns do
        begin
            ammo_remaining := 0;
            inv_place := -1;
            inv_place := FindInventory(weapon[i].ammo_type);
            if (inv_place > -1) then
            ammo_remaining := current_profile.inventory[inv_place].params[0];
            ammo_remaining := ammo_remaining + weapon[i].bullets_loaded;
            if (ammo_remaining > 0) then gunwithammo := i;

        end; // end of for
        if (gunwithammo > 0) then
        begin
            current_gun := gunwithammo;
            dec(current_gun);
            if current_gun < 1 then current_gun := max_guns;
            CycleWeapon;
        end; // end if
    end; // end if
end;

procedure OPlayer.Damage(health_dam:real);
var
armour_dam:integer;
_l3:integer;
begin
    armour_dam := 0;
    _l3 := round(health_dam);
    armour_dam := round(_l3 / 100 * armour_protect);
    _l3 := _l3 - armour_dam;
    armour_health := armour_health - armour_dam;
    if (armour_health < 0) then
    begin
        _l3 := _l3 - armour_health;
        armour_health := 0;
    end; // end if
    health := health - _l3;

    current_profile.damage_taken := current_profile.damage_taken + _l3;
    bloodspeed := 10;
    CreateBlood(trunc(_x)-mymap.SmeshX,trunc(_y)-mymap.SmeshY,random(360),128,128,2000);
end;


procedure OPlayer.CycleWeapon;
begin
    if (reload_time > 0) then
    begin
        reload_time := 0;
    end; // end if
    inc(current_gun);
    if (current_gun > max_guns) then current_gun := 1;
end;

function OPlayer.AddWeapon(code:string; ammoloaded, invplace:integer):boolean;
var
added:boolean;
i,num:integer;
begin
    added := false;

    if (max_guns < gun_limit) then
    begin
        num := 0;
        for i:= 0 to high(WeaponData) do if (WeaponData[i].code = code) then num := i;

        if (num > 0) then
        begin
            added := true;
            inc(max_guns);
            weapon[max_guns]:=WeaponData[num];
            weapon[max_guns].inventory_place := invplace;
            weapon[max_guns].bullets_loaded  := ammoloaded;
        end;
    end;
    if (added) and (weapon[max_guns].preference > weapon[current_gun].preference) then
    begin
        current_gun := max_guns;
    end;
    result:=added;
end;

procedure OPlayer.RemoveWeapon(num:integer);
var
i:integer;
mustcycle:boolean;
begin
    mustcycle := false;
    if (current_gun = num) then mustcycle := true;

    Weapon[num].inventory_place := 0;
    Weapon[num].shot_time       := 0;
    Weapon[num].types           := '';
    Weapon[num].shots_fired     := 0;
    Weapon[num].spread          := 0;
    Weapon[num].shot_size       := 0;
    Weapon[num].calliber_type   := 0;
    Weapon[num].ammo_type       := '';
    Weapon[num].bullet_capacity := 0;
    Weapon[num].reload_time     := 0;
    Weapon[num].name            := '';
    Weapon[num].pic             := 0;
    Weapon[num].bullets_loaded  := 0;
    Weapon[num].melee           :=false;
    Weapon[num].chainsaw        :=false;
    Weapon[num].flamethrower    := false;
    Weapon[num].explosive       := 0;
    Weapon[num].preference      := 0;
    Weapon[num].critical        := 0;

    if (num < max_guns) then
    begin
        for i:= num + 1 to max_guns do
        begin
            Weapon[i-1]:= Weapon[i];
            if (i = current_gun) then dec(current_gun);
        end;
    end; // end if
    dec(max_guns);
    if (reload_time > 0) then
    begin
        reload_time := 0;
    end; // end if
    if (mustcycle) then
    begin
        CycleWeapon;
    end; // end if
end; 


procedure OPlayer.ClearInventory(inv_place:integer);
var
i:integer;
begin
    current_profile.inventory[inv_place].name := '';

    for i:=0 to 3 do current_profile.inventory[inv_place].params[i]:= 0;

    for i:= 0 to max_guns do
    if (weapon[i].inventory_place = inv_place) then
          RemoveWeapon(i);
end;


function OPlayer.FindInventory(find_item:string):integer;
var
i:integer;
begin
    result:= -1;
    for i:= 0 to high(current_profile.inventory) do
    begin
        if (current_profile.inventory[i].name = find_item) then
        begin
            result:= i;
        end; // end if
    end;
end;

procedure OPlayer.Procces;
var
amount:real;
tempangle,ammo_remaining,amount2,i:integer;
inv_place:integer;
begin

    if (GamePaused) then exit;

   if (reload_time > 0) then
    begin
        reload_time := reload_time - 1 * speedFactor;

        if (reload_time <= 0) then
        begin
            inv_place := -1;

            inv_place := FindInventory(weapon[current_gun].ammo_type);

    if (inv_place > -1) then
            ammo_remaining := current_profile.inventory[inv_place].params[0];

            amount2 := weapon[current_gun].bullet_capacity - weapon[current_gun].bullets_loaded;

    if (ammo_remaining < amount2) then amount2 := ammo_remaining;

            weapon[current_gun].bullets_loaded := weapon[current_gun].bullets_loaded + amount2;

            ammo_remaining := ammo_remaining - amount2;

    if (inv_place > -1) then
            current_profile.inventory[inv_place].params[0]:= ammo_remaining;

    if (current_profile.inventory[inv_place].params[0]= 0) then
            ClearInventory(inv_place);

            reload_time := 0;
        end; // end if
    end; // end if


    current_shot_time := current_shot_time + speedFactor;
    if current_shot_time>100 then current_shot_time:=100;

    if (current_shot_time >= weapon[current_gun].shot_time) and (Keys[MouseLB]) then
        FireGun;

    if (Keys[82]) then ReloadGun(true);

    if (Keys[32]) and (cycled = false) then
    begin
        CycleWeapon;
        cycled := true;
    end; // end if

    if (Keys[13]) then
    begin
      Keys[13]:=false;

    for i:=0 to 3 do
    if RectInRect(_x-w2,
                  _y-h2,
                   w,
                   h,mymap.Kompas[i].x,mymap.Kompas[i].y,mymap.Kompas[i].w,mymap.Kompas[i].h) then
    if mymap.Kompas[i].level>0 then
    begin
       mymap.CreateLevel(mymap.Kompas[i].level);
       break;
    end;

    end; // end if

    if (not Keys[32]) then cycled := false;

    if (Keys[49])and (cycled = false) then
    begin
        if (weapon[1].types <>'') then
        begin
            current_gun := 0;
            CycleWeapon;
            cycled := true;
        end; // end if
    end; // end if
    if (Keys[50])and (cycled = false) then
    begin
      if (weapon[2].types <>'') then
        begin
            current_gun := 1;
            CycleWeapon;
            cycled := true;
        end; // end if
    end; // end if
    if (Keys[51])and (cycled = false) then
    begin
         if (weapon[3].types <>'') then
        begin
            current_gun := 2;
            CycleWeapon;
            cycled := true;
        end; // end if
    end; // end if
    if (Keys[52])and (cycled = false) then
    begin
        if (weapon[4].types <>'') then
        begin
            current_gun := 3;
            CycleWeapon;
            cycled := true;
        end; // end if
    end; // end if
    if (Keys[53])and (cycled = false) then
    begin
        if (weapon[5].types <>'') then
        begin
            current_gun := 4;
            CycleWeapon;
            cycled := true;
        end; // end if
    end; // end if
    if (Keys[54])and (cycled = false) then
    begin
        if (weapon[6].types <>'') then
        begin
            current_gun := 5;
            CycleWeapon;
            cycled := true;
        end; // end if
    end; // end if


    torso_target_rotation:= GetAngle(_x, _y, MousePos.X , MousePos.Y );

    moving := false;
    if ((Keys[37] or Keys[65]) and not (Keys[38] or Keys[87]) and not(Keys[40] or Keys[83]) and not (Keys[39] or Keys[68])) then
    MovePlayer(-1, 0);

    if ((Keys[39] or Keys[68]) and not(Keys[38] or Keys[87]) and not(Keys[40] or Keys[83]) and not (Keys[37] or Keys[65])) then
    MovePlayer( 1, 0);

    if ((Keys[38] or Keys[87]) and not(Keys[39] or Keys[68]) and not(Keys[37] or Keys[65]) and not(Keys[40] or Keys[83])) then
    MovePlayer(0, -1);

    if ((Keys[40] or Keys[83]) and not(Keys[39] or Keys[68]) and not(Keys[37] or Keys[65]) and not(Keys[38] or Keys[87])) then
    MovePlayer(0, 1);

    amount := sqrt(walk_speed * walk_speed / 2);

    if ((Keys[40] or Keys[83]) and (Keys[39] or Keys[68]) and not(Keys[37] or Keys[65]) and not(Keys[38] or Keys[87])) then
    MovePlayer(1, 1);

    if ((Keys[40] or Keys[83]) and (Keys[37] or Keys[65]) and not(Keys[39] or Keys[68]) and not(Keys[38] or Keys[87])) then
    MovePlayer(-1, 1);

    if ((Keys[38] or Keys[87]) and (Keys[39] or Keys[68]) and not(Keys[37] or Keys[65]) and not(Keys[40] or Keys[83])) then
    MovePlayer( 1, -1);

    if ((Keys[38] or Keys[87]) and (Keys[37] or Keys[65]) and not(Keys[40] or Keys[83]) and not(Keys[39] or Keys[68])) then
    MovePlayer(-1, -1);

    if (moving = false) then
    begin
        tempangle := 180 + torso_rotation;
        if (abs(tempangle - 0)   < 45) or (tempangle > 315) then legs_target_rotation := 0;
        if (abs(tempangle - 90)  < 45) then legs_target_rotation := 90;
        if (abs(tempangle - 180) < 45) then legs_target_rotation := 180;
        if (abs(tempangle - 270) < 45) then legs_target_rotation := 270;

        legs_target_rotation := legs_target_rotation - 180;

        if (legs_rotation <> legs_target_rotation) and (walk =false) then
        begin
            walk := true;
        end;

        if (legs_rotation = legs_target_rotation) and (walk) then
        begin
            walk := false;
            current_cadr_torse:=0;
        end;// end if
    end; // end if

    if (moving) and (walk = false) then
    begin
        walk := true;
    end; // end if


      if (walk) then
    begin
        inc(current_cadr_torse);
        if current_cadr_torse>17 then current_cadr_torse:=0;
        current_pause_ta:=0;
    end; // end if

    torso_rotation := ReachAngle(torso_rotation, torso_target_rotation, 10 * speedFactor, 1, 0);
    legs_rotation  := ReachAngle(legs_rotation, legs_target_rotation, 7 * speedFactor, 1, 0);

     if (current_profile.shots_fired > 0) then
    begin
         current_profile.score_accuracy := round(current_profile.shots_hit/current_profile.shots_fired * 100);
        if (current_profile.score_accuracy > 99) then current_profile.score_accuracy := 99;

        if (current_profile.score_accuracy < 0) then current_profile.score_accuracy := 0;
      end
    else
    current_profile.score_accuracy := 0;

  accuracy:=1;
end;

procedure OPlayer.Draw;
begin
   glblend(1);
  DrawTextureBox(trunc(_x),trunc(_y),64,64,MenTorsTexture[current_cadr_torse],true,legs_rotation);
  DrawTextureBox(trunc(_x),trunc(_y),64,64,MenTexture,true,torso_rotation);
end;

procedure OPlayer.Init(dx,dy:integer);
var
i:integer;
begin
   _x := dx;
   _y := dy;

   w:=32;
   h:=32;
   w2:=w div 2;
   h2:=h div 2;


   moving := false;
   walk := false;
   walk_speed := current_profile.walk_speed;
   diag_speed := sqrt(walk_speed * walk_speed / 2);
   legs_rotation:=0;
   torso_rotation:=0;
   torso_target_rotation:=0;

   base_accuracy := current_profile.base_accuracy;
   accuracy := base_accuracy;
   target_accuracy:=base_accuracy;

  dying:=false;
  cycled:=false;

  max_guns:=0;
  current_shot_time := 0;
  base_critical:=0;
  gun_limit := current_profile.gun_limit;
  current_shot_time:=0;
  reload_time := 0;
  reload_multi := 0.670000;
  current_gun := 0;

  max_health := current_profile.max_health;
  health := max_health;

  armour_protect := current_profile.armour_protect;
  armour_max_health := current_profile.armour_max_health;
  armour_health := armour_max_health;

  current_cadr_torse:=0;
  current_pause_ta:=0;
  bloodspeed:=0;

  if high(weapon)>-1 then
  zeromemory(weapon,sizeof(weapon));
  setlength(weapon,21);

   for i:= 0 to high(current_profile.inventory) do
   if (current_profile.inventory[i].params[1]  > 0)then
    AddWeapon(current_profile.inventory[i].name, current_profile.inventory[i].params[0], i);


end;

function OPlayer.MovePlayer(dx, dy:integer):boolean;
var
speed,backx,backy:real;
l3,l4:integer;
diag:boolean;
begin
    if (GamePaused)then
    begin
        result:=false;
        exit;
    end; // end if

     l4 := dx;
     l3 := dy;
     diag:=false;

    if (dx <> 0) or (dy <> 0) then
    begin
        speed := walk_speed * speedFactor;
        diag := false;

        if (dx <> 0) and (dy <> 0) then
        begin
            speed := diag_speed * speedFactor;
            diag := true;
        end;

        backx := _x;
        backy := _y;
        _y := _y + dy * speed * 1;
        _x := _x + dx * speed * 1;
        moving := true;
        speed := walk_speed * speedFactor;


        if (SceneCollide(0,0,false, false)>0) then
        begin
            _x := backx;
            _y := backy;

            if (diag = true) then
            begin
                _y := _y + dy * speed * 1;

                if (SceneCollide(0,0,false, false)>0) then
                begin
                    l3 := 0;
                    _y := backy;
                end; // end if

                if (l3 = 0) then
                begin
                    _x := _x + dx * speed * 1;
                    if (SceneCollide(0,0,false, false)>0) then
                    begin
                        l4 := 0;
                        _x := backx;
                    end; // end if
                end
                else
                l4 := 0;

            end
            else
            begin
                l4 := 0;
                l3 := 0;
            end; // end if
        end; // end if

        if (l4 = 0) and (l3 = 0) then moving := false;
        if (l4 > 0) and (l3 = 0) then legs_target_rotation := 270;
        if (l4 < 0) and (l3 = 0) then legs_target_rotation := 90;
        if (l4 = 0) and (l3 > 0) then legs_target_rotation := 0;
        if (l4 = 0) and (l3 < 0) then legs_target_rotation := 180;
        if (l4 > 0) and (l3 > 0) then legs_target_rotation := 315;
        if (l4 > 0) and (l3 < 0) then legs_target_rotation := 225;
        if (l4 < 0) and (l3 > 0) then legs_target_rotation := 45;
        if (l4 < 0) and (l3 < 0) then legs_target_rotation := 135;
        if (_x > scrw) then _x := scrw;
        if (_x < 0)   then _x := 0;
        if (_y > scrh) then _y := scrh;
        if (_y < 0)   then _y := 0;
        legs_target_rotation := legs_target_rotation - 180;
    end; // end if
    
end; // End of the function


procedure DrawHSprite(x,y:real;id:integer;Color:integer=$FFFFFF; Alpha : byte=255);
  begin
  glColor3f(1,1,1);
  glPushMatrix();
if Alpha<>255 then glEnable(GL_BLEND);

 glcolor4ub(GetRValue(Color),GetGValue(Color),GetBValue(Color),Alpha);
  glTranslatef(X,Y,0);
                glBindTexture(GL_TEXTURE_2D, AnimationBox[id].GFXfileId); // use floor
                glBegin(GL_QUADS);

                glTexCoord2f(AnimationBox[id].x1,1-AnimationBox[id].y1); glVertex2f(0, 0);
                glTexCoord2f(AnimationBox[id].x2,1-AnimationBox[id].y1); glVertex2f(AnimationBox[id].w,0);
       	        glTexCoord2f(AnimationBox[id].x2,1-AnimationBox[id].y2); glVertex2f(AnimationBox[id].w, AnimationBox[id].h);
                glTexCoord2f(AnimationBox[id].x1,1-AnimationBox[id].y2); glVertex2f(0,AnimationBox[id].h);

                glEnd();
  glPopMatrix();
if Alpha<>255 then glDisable(GL_BLEND);

  end;


procedure Tmap.ScreenShake(amount:integer=0);
var
t:integer;
begin
    t:=amount;
    if ((10 + t) < abs(screen_shake)) then exit;

    screen_shake_speed := (10 + t) / 10;
    if (screen_shake > 4) then screen_shake_speed:=0.400000;
    screen_shake := 10 + t ;
end;

procedure Tmap.Draw;
var
i,j,n,tx,ty:integer;
 begin
glEnable( GL_TEXTURE_2D );
 for i:=0 to w do
 for j:=0 to h do
 if RectInRect(0,0,scrw,scrh,cells[i,j].x,cells[i,j].y,512,512) then
 begin
 DrawTextureBox(cells[i,j].x,cells[i,j].y,512,512,cells[i,j].id,false,0,true);
 end;
 glDisable( GL_TEXTURE_2D );
 glblend(2);
 if ShowBlok then
 for i:=0 to high(MapObjects) do
 begin
 DrawRectangle2D(MapObjects[i].x,MapObjects[i].y,MapObjects[i].w,MapObjects[i].h,$FF0000);
 end;

 glblend(1);
 DrawBloods;

  for i:=0 to 3 do
 if RectInRect(0,0,scrw,scrh,Kompas[i].x,Kompas[i].y,Kompas[i].w,Kompas[i].h) then
 if Kompas[i].level>0 then
 begin
 DrawRectangle2D(Kompas[i].x,Kompas[i].y,Kompas[i].w,Kompas[i].h,$FF0000,200,0,true);

 end;


 if EditMode then
 begin
 glblend(1);
   for i:=0 to high(Script) do
   if Script[i].active=1 then
   if RectInRect(0,0,scrw,scrh,Script[i].x+MyMap.SmeshX,Script[i].y+MyMap.SmeshY,Script[i].w,Script[i].h) then
   begin             
   tx:=0;
   if n=  SelectedBlok then tx:=50;
       if Script[i].types=0 then
        DrawRectangle2D(Script[i].x+MyMap.SmeshX,
                        Script[i].y+MyMap.SmeshY,
                        Script[i].w,Script[i].h,$FF0000+tx,200,0,true);
       if Script[i].types=2 then
        DrawRectangle2D(Script[i].x+MyMap.SmeshX,
                        Script[i].y+MyMap.SmeshY,
                        Script[i].w,Script[i].h,$0000FF+tx,200,0,false);

   end;

 end;


end;

function FindInventory(find_item:string):integer;
var
i:integer;
begin
    result:= -1;
    for i:= 0 to high(current_profile.inventory) do
    begin
        if (current_profile.inventory[i].name = find_item) then
        begin
            result:= i;
        end;
        end;
end;

procedure CreateProfile;
var
i:integer;
begin
    //zeromemory(current_profile.inventory,sizeof(current_profile.inventory));
    setlength(current_profile.inventory,52);
    for i:= 0 to high(current_profile.inventory) do
    begin
        current_profile.inventory[i].name := '';
        current_profile.inventory[i].params[0] := 0;
        current_profile.inventory[i].params[1] := 0;
        current_profile.inventory[i].params[2] := 0;
        current_profile.inventory[i].params[3] := 0;
    end; // end of for
end;


procedure ResetProfile;
var
i:integer;
begin
    zeromemory(current_profile.inventory,sizeof(current_profile.inventory));
    setlength(current_profile.inventory,52);
    current_profile.enemies_killed := 0;
    current_profile.shots_fired := 0;
    current_profile.shots_hit := 0;
    current_profile.score_accuracy := 0;
    current_profile.survived := 0;
    current_profile.survived_time := 0;
    current_profile.rank := 'F';
    current_profile.damage_taken := 0;
    
    for i:= 0 to  high(current_profile.inventory) do
    begin
        current_profile.inventory[i].name := '';
        current_profile.inventory[i].params[0] := 0;
        current_profile.inventory[i].params[1] := 0;
        current_profile.inventory[i].params[2] := 0;
        current_profile.inventory[i].params[3] := 0;
    end; // end of for

    current_profile.inventory[41].name := 'Dubinka';
    current_profile.inventory[41].params[0] := 0;
    current_profile.inventory[41].params[1] := 1;
    
    current_profile.inventory[42].name := 'glock19c';
    current_profile.inventory[42].params[0] := 15;
    current_profile.inventory[42].params[1] := 1;

    current_profile.inventory[1].name := '35_ammo';
    current_profile.inventory[1].params[0] := 30;

    current_profile.score := 0;
    current_profile.max_inventory_slots := 20;
    current_profile.max_health := 100;
    current_profile.armour_max_health := 50;
    current_profile.armour_protect := 35;
    current_profile.gender := 1;
    current_profile.gun_limit := 6;
    current_profile.walk_speed := 3.300000;
    current_profile.base_accuracy := 0;

end;



function SceneCollide(Objects:byte;Id:integer; noenemy, nogood:boolean):byte;
var
i:integer;
rads :real;
stepx :real;
stepy :real;
begin
    noenemy := false;
result:=0;

 if  Objects=1 then
 begin
 if Enemies[id].Alive=false then exit;
 for i:=0 to high(mymap.MapObjects) do
  if RectInRect(Enemies[id]._x-Enemies[id].w2,
                  Enemies[id]._y-Enemies[id].h2,
                  Enemies[id].w,
                  Enemies[id].h,
                  mymap.MapObjects[i].x,
                  mymap.MapObjects[i].y,
                  mymap.MapObjects[i].w,
                  mymap.MapObjects[i].h ) then
    begin
    result:=1;
    exit;
    end; // end if

   end;

   if  Objects=0 then
   begin
 for i:=0 to high(mymap.MapObjects) do
  if RectInRect(MyHero._x-MyHero.w2,
                  MyHero._y-MyHero.h2,
                  MyHero.w,
                  MyHero.h,
                  mymap.MapObjects[i].x,
                  mymap.MapObjects[i].y,
                  mymap.MapObjects[i].w,
                  mymap.MapObjects[i].h ) then
    begin
    result:=1;
    exit;
    end; // end if

   end;

    if (nogood = false) then
    if  Objects=1 then     //Player 0, Monster 1,...
    if RectInRect(MyHero._x-MyHero.w2,
                  MyHero._y-MyHero.h2,
                  MyHero.w,
                  MyHero.h,
                  Enemies[id]._x-Enemies[id].w2,
                  Enemies[id]._y-Enemies[id].h2,
                  Enemies[id].w,
                  Enemies[id].h ) then
    begin
    result:=2;
    exit;
    end; // end if


    for i:= 0 to high(Enemies) do
    if Enemies[i].Alive then
   begin
   if  Objects=0 then     //Player 0, Monster 1,...
     if RectInRect(MyHero._x-MyHero.w2,
                  MyHero._y-MyHero.h2,
                  MyHero.w,
                  MyHero.h,
                  Enemies[i]._x-Enemies[i].w2,
                  Enemies[i]._y-Enemies[i].h2,
                  Enemies[i].w,
                  Enemies[i].h ) then
    begin

    result:=2;
    exit;
    end; // end if

     if  (Objects=1) and (id<>i) then     //Player 0, Monster 1,...
     if RectInRect(Enemies[id]._x -Enemies[id].w2,
                   Enemies[id]._y -Enemies[id].h2,
                   Enemies[id].w,
                   Enemies[id].h,
                   Enemies[i]._x  -Enemies[i].w2,
                   Enemies[i]._y  -Enemies[i].h2,
                   Enemies[i].w,
                   Enemies[i].h ) then
    begin
    result:=2;
    exit;
    end; // end if
   end;


end;




function same_sign(a, b:real):boolean;
begin
    result:=((a * b) >= 0);
end;


function intersect(x1, y1, x2, y2, x3, y3, x4, y4:real):integer;
var
    _l9,
    _l7,
    _l8,
    _l5,
    _l6,
    _l4,
    _l13,
    _l12,
    _l11,
    _l10:real;
    _l1,
    _l3,
    _l2:real;
    x,y:real;
begin
    _l9 := y2 - y1;
    _l8 := x1 - x2;
    _l6 := x2 * y1 - x1 * y2;
    _l11 := _l9 * x3 + _l8 * y3 + _l6;
    _l10 := _l9 * x4 + _l8 * y4 + _l6;
    if (_l11 <> 0) and (_l10 <> 0) and same_sign(_l11, _l10) then
   begin
   result:=0;
   exit;
   end;
    _l7 := y4 - y3;
    _l5 := x3 - x4;
    _l4 := x4 * y3 - x3 * y4;
    _l13 := _l7 * x1 + _l5 * y1 + _l4;
    _l12 := _l7 * x2 + _l5 * y2 + _l4;
    if (_l13 <> 0) and (_l12 <> 0) and same_sign(_l13, _l12) then
   begin
   result:=0;
   exit;
   end;

    _l1 := _l9 * _l5 - _l7 * _l8;
    if (_l1 = 0) then
   begin
   result:=1;
   exit;
   end;

    if (_l1 < 0) then
    _l3 :=-(_l1 / 2)
    else
    _l3 := (_l1 / 2);

    _l2 := _l8 * _l4 - _l5 * _l6;
    if (_l2 < 0) then x := (_l2 - _l3) / _l1
    else
    x := (_l2 + _l3) / _l1;

    _l2 := _l7 * _l6 - _l9 * _l4;
    if (_l2 < 0) then
    y := (_l2 - _l3) / _l1
    else
    y := (_l2 + _l3) / _l1;

    intersectXY.x:=trunc(x);
    intersectXY.y:=trunc(y);
    result:=2;
end; // End of the function


procedure OPlayer.CalculateScore;
begin

    current_profile.total_score := 0;
    current_profile.total_score := current_profile.total_score + current_profile.score_accuracy * 50;
    current_profile.total_score := current_profile.total_score + current_profile.enemies_killed * 50;
    current_profile.total_score := current_profile.total_score + current_profile.survived_time / 6;
    current_profile.total_score := current_profile.total_score - current_profile.damage_taken * 7;
    if (current_profile.total_score < 0) then current_profile.total_score := 0;
    current_profile.total_score := round(current_profile.total_score);
    current_profile.rank := 'Супермен';
    if (current_profile.total_score < 20250) then current_profile.rank := 'Рэмбо';
    if (current_profile.total_score < 18000) then current_profile.rank := 'Спецназовец';
    if (current_profile.total_score < 16000) then current_profile.rank := 'Охотник на зомби';
    if (current_profile.total_score < 12000) then current_profile.rank := 'Солдат';
    if (current_profile.total_score < 8000)  then current_profile.rank := 'Обычный человек';
    if (current_profile.total_score < 4000)  then current_profile.rank := 'Зомби';
     mymap.Total := round(current_profile.total_score);

end;


function OPlayer.AddInventory(types:string; ammo, isweapon:integer):integer;
var
foundspace,foundblankspace:integer;
k,m:integer;
begin
    foundspace := 0;
    foundblankspace := 0;
    m:=-1;
    if (isweapon > 0) then
    begin
        for k:= 41 to 50 do
        begin
           if (current_profile.inventory[k].name=types) then m:=1;
            if (current_profile.inventory[k].name = '') then
            begin
                foundspace := k;
                break;
            end;
        end;

      if (m>-1) then foundspace := 0;

        if (foundspace = 0) then foundspace := -10
        else
        begin
            current_profile.inventory[foundspace].name := types;
            if (AddWeapon(types, ammo, foundspace) = false) then
            begin
                current_profile.inventory[foundspace].name := '';
                foundspace := -10;
            end; // end if
        end // end if
    end
    else
    begin
        for k:=0 to current_profile.max_inventory_slots do
        begin
            if (current_profile.inventory[k].name = '') then foundblankspace := k;
            if (current_profile.inventory[k].name = types) and
               (ammo > 0) and (isweapon = 0) then foundspace := k;
        end; // end of for

        if (foundspace < 1) then foundspace := foundblankspace;

    end; // end if

    if (foundspace > 0) then
    begin
        current_profile.inventory[foundspace].name := types;
        current_profile.inventory[foundspace].params[0] := current_profile.inventory[foundspace].params[0] + ammo;
        current_profile.inventory[foundspace].params[1] := isweapon;
    end; // end if
    result:=foundspace;
end;

procedure MakeBonusText(msg:string);
begin
bonustext.text:=msg;
bonustext.alpha:=255;
end;

function CollectBonus(types:string):boolean;
var
inv:integer;
picked:boolean;
begin
    dec(bonuses_inplay);

    picked := false;

     if (types = 'BonusColt45') then
     begin
        inv := MyHero.AddInventory('colt45', 6, 1);
        if (inv > 0) then
        begin
            picked := true;
            MakeBonusText('Colt 45');
            PlayEffect('AddWeapon.mp3');

        end
        else if (inv = -10) then
        begin
            MakeBonusText('Уже есть!');
            picked := true;
        end
        else
        MakeBonusText('Рюкзак переполнен!');

    end // end if
    else
    if (types = 'BonusGM94Launcher') then
    begin
        inv := MyHero.AddInventory('gm94launcher', 3, 1);
        if (inv > 0) then
        begin
            picked := true;
            MakeBonusText('GM94 Launcher');
      PlayEffect('AddWeapon.mp3');
        end
        else if (inv = -10) then
        begin
          MakeBonusText('Уже есть!');
          picked := true;
        end
        else
        MakeBonusText('Рюкзак переполнен!');

    end // end if
    else
    if (types = 'BonusGlock19C') then
    begin
        inv := MyHero.AddInventory('glock19c', 15, 1);
        if (inv > 0) then
        begin
            picked := true;
            MakeBonusText('Glock 19C');
            PlayEffect('AddWeapon.mp3');
        end
        else
        if (inv = -10) then
        begin
           MakeBonusText('Уже есть!');
           picked := true;
        end
        else
        MakeBonusText('Рюкзак переполнен!');
    end;

    if (types = 'BonusMossberg500') then
    begin
        inv := MyHero.AddInventory('mossberg500', 7, 1);
        if (inv > 0) then
        begin
            picked := true;
            MakeBonusText('Mossberg 500');
            PlayEffect('AddWeapon.mp3');
        end
        else
        if (inv = -10) then
        begin
           MakeBonusText('Уже есть!');
           picked := true;
        end
        else
          MakeBonusText('Рюкзак переполнен!');

    end; // end if
    if (types = 'BonusSteyrTMP') then
    begin
        inv := MyHero.AddInventory('steyrtmp', 30, 1);
        if (inv > 0) then
        begin
            picked := true;
            MakeBonusText('Steyr TMP');
     PlayEffect('AddWeapon.mp3');
        end
        else
        if (inv = -10) then
        begin
          MakeBonusText('Уже есть!');
          picked := true;
        end
        else
        MakeBonusText('Рюкзак переполнен!');
    end; // end if


    if (types = 'Bonus12GaugeShells') then
    begin
        if (MyHero.AddInventory('12gauge_ammo', 12, 0) > 0) then
        begin
         picked := true;
         MakeBonusText('Патроны .12мм');
         PlayEffect('AddWeapon.mp3');
        end
        else
        MakeBonusText('Рюкзак переполнен!');

    end; // end if

    if (types = 'Bonus35Bullets') then
    begin
        if (MyHero.AddInventory('35_ammo', 30, 0) > 0) then
        begin
            picked := true;
            MakeBonusText('Патроны .35мм');
      PlayEffect('AddWeapon.mp3');
        end
        else
         MakeBonusText('Рюкзак переполнен!');
         // end if
    end; // end if

       if (types = 'Bonus45Bullets') then
    begin
        if (MyHero.AddInventory('45_ammo', 8, 0) > 0) then
        begin
            picked := true;
            MakeBonusText('Патроны .45мм');
        PlayEffect('AddWeapon.mp3');
        end
        else
         MakeBonusText('Рюкзак переполнен!');
         // end if
    end; // end if

   if (types = 'BonusGrenadeAmmo') then
    begin
        if (MyHero.AddInventory('grenade_ammo', 3, 0) > 0) then
        begin
            picked := true;
            MakeBonusText('Заряд .94мм');
         PlayEffect('AddWeapon.mp3');
        end
        else
         MakeBonusText('Рюкзак переполнен!');
         // end if
    end; // end if



    if (types = 'BonusHealth') then
    begin
        picked := true;
        MakeBonusText('+25 к Здоровью');
        MyHero.health := MyHero.health + 25;
        if (MyHero.health > MyHero.max_health) then
            MyHero.health := MyHero.max_health;

    end; // end if

    if (types = 'BonusArmour') then
    begin
        if (MyHero.armour_health < MyHero.armour_max_health) then
        begin
            picked := true;
            MakeBonusText('+25 к Броне');
            MyHero.armour_health := MyHero.armour_health + 25;
            if (MyHero.armour_health > MyHero.armour_max_health) then
            MyHero.armour_health := MyHero.armour_max_health;

        end
        else
            MakeBonusText('Броня на максимуме!');

    end; // end if

    result:=picked;
end;


procedure CreateBonus(types:string; x, y:integer;nocollide:boolean);
var
i:integer;
k:integer;
begin
  k:=-1;

   for i:=0 to high(Bonus) do
   if Bonus[i].alive=false then
   begin
   k:=i;
   break;
   end;

   if k=-1 then
   begin
   k:=high(Bonus)+1;
   setlength(Bonus,k+1);
   end;

   Bonus[k].w:=10;
   Bonus[k].h:=10;

   if types='Bonus45Bullets' then
   begin
    Bonus[k].w:=32;
    Bonus[k].h:=32;
    Bonus[k].Tid:= AmmoPic[2];
   end;

   if types='Bonus35Bullets' then
   begin
    Bonus[k].w:=32;
    Bonus[k].h:=32;
    Bonus[k].Tid:= AmmoPic[1];
   end;

   if types='Bonus12GaugeShells' then
   begin
    Bonus[k].w:=32;
    Bonus[k].h:=32;
    Bonus[k].Tid:= AmmoPic[0];
   end;

   if types='BonusGrenadeAmmo' then
   begin
    Bonus[k].w:=32;
    Bonus[k].h:=32;
    Bonus[k].Tid:= AmmoPic[3];
   end;

   //
   if types='BonusGM94Launcher' then
   begin
    Bonus[k].w:=64;
    Bonus[k].h:=32;
    Bonus[k].Tid:= sWeaponPic[5];
   end;

   if types='BonusSteyrTMP' then
   begin
    Bonus[k].w:=64;
    Bonus[k].h:=32;
    Bonus[k].Tid:= sWeaponPic[3];
   end;

    if types='BonusMossberg500' then
   begin
    Bonus[k].w:=64;
    Bonus[k].h:=32;
    Bonus[k].Tid:= sWeaponPic[4];
   end;

   if types='BonusGlock19C' then
   begin
    Bonus[k].w:=64;
    Bonus[k].h:=32;
    Bonus[k].Tid:= sWeaponPic[1];
   end;

    if types='BonusColt45' then
   begin
    Bonus[k].w:=64;
    Bonus[k].h:=32;
    Bonus[k].Tid:= sWeaponPic[2];
   end;
 //
     if types='BonusHealth' then
   begin
    Bonus[k].w:=32;
    Bonus[k].h:=32;
    Bonus[k].Tid:= HealthPic;
   end;

     if types='BonusArmour' then
   begin
    Bonus[k].w:=32;
    Bonus[k].h:=32;
    Bonus[k].Tid:= ArmorPic;
   end;

   Bonus[k].x := x;
   Bonus[k].y := y;
   Bonus[k].alive := true;
   Bonus[k].btype := types;
   inc(bonuses_inplay);

end;

procedure DrawBonus;
var
i:integer;
x,y,w,h,Tid:integer;
begin
 glblend(1);
   for i:=0 to high(Bonus) do
   if Bonus[i].alive then
        begin

   x:=Bonus[i].x;
   y:=Bonus[i].y;
   w:=Bonus[i].w;
   h:=Bonus[i].h;
   Tid:=Bonus[i].Tid;

  if RectInRect(0,0,scrw,scrh,x-(w div 2),y-(h div 2),w,h) then
   DrawTextureBox(x-(w div 2),y-(h div 2),w,h,Tid,true);

   end;


end;


procedure DrawEnemy;
var
i:integer;
begin
DrawObj:=0;
   for i:=0 to high(Enemies) do
   if Enemies[i].alive then Enemies[i].Draw(0,0);
end;

procedure DoBonus;
var
i:integer;
begin
    if (gamepaused) then exit;

   for i:=0 to high(bonus) do
   begin

    if (bonus[i].alive=false) then continue;

     if RectInRect(myhero._x-myhero.w2,
                   myhero._y-myhero.h2,
                   myhero.w,
                   myhero.h,
                  bonus[i].x-(bonus[i].w div 2),
                  bonus[i].y-(bonus[i].h div 2),
                  bonus[i].w,bonus[i].h )
   then
    if (CollectBonus(bonus[i].btype)) then
        begin
            bonus[i].alive:= false;

        end; // end if
    end;
end;


procedure Tmap.ActionLoop;
begin
end;

procedure Tmap.StartGame;
begin
    game_started := 1;
    game_time := 0;
    had_steyr := false;
    had_mossberg := false;
    had_boss := 0;
end;

procedure InitWeapon;
begin
    WeaponData[1].shot_time:= 40;
    WeaponData[1].types:= 'revolver';
    WeaponData[1].shots_fired:= 1;
    WeaponData[1].spread:= 0;
    WeaponData[1].shot_size:= 20;
    WeaponData[1].calliber_type:= 6;
    WeaponData[1].ammo_type:= '45_ammo';
    WeaponData[1].bullet_capacity:= 6;
    WeaponData[1].reload_time:= 180;
    WeaponData[1].code := 'colt45';
    WeaponData[1].name := 'Colt 45';
    WeaponData[1].pic := 1;
    WeaponData[1].melee:= false;
    WeaponData[1].chainsaw := false;
    WeaponData[1].explosive:= 0;
    WeaponData[1].flamethrower:= false;
    WeaponData[1].preference := 20;
    WeaponData[1].critical:= 1.750000;

    WeaponData[2].shot_time:= 30;
    WeaponData[2].types:= 'autopistol';
    WeaponData[2].shots_fired:= 1;
    WeaponData[2].spread:= 0;
    WeaponData[2].shot_size:= 20;
    WeaponData[2].calliber_type:= 2;
    WeaponData[2].ammo_type:= '35_ammo';
    WeaponData[2].bullet_capacity:= 15;
    WeaponData[2].reload_time:= 180;
    WeaponData[2].code := 'glock19c';
    WeaponData[2].name := 'Glock 19C';
    WeaponData[2].pic := 1;
    WeaponData[2].melee:= false;
    WeaponData[2].chainsaw := false;
    WeaponData[2].explosive:= 0;
    WeaponData[2].flamethrower:= false;
    WeaponData[2].preference := 5;
    WeaponData[2].critical:= 1;

    WeaponData[3].shot_time:= 60;
    WeaponData[3].types:= 'shotgun';
    WeaponData[3].shots_fired:= 5;
    WeaponData[3].spread:= 12;
    WeaponData[3].shot_size:= 20;
    WeaponData[3].calliber_type:= 3;
    WeaponData[3].ammo_type:= '12gauge_ammo';
    WeaponData[3].bullet_capacity:= 7;
    WeaponData[3].reload_time:= 180;
    WeaponData[3].code := 'mossberg500';
    WeaponData[3].name := 'Mossberg 500';
    WeaponData[3].pic := 1;
    WeaponData[3].melee:= false;
    WeaponData[3].chainsaw := false;
    WeaponData[3].explosive:= 0;
    WeaponData[3].flamethrower:= false;
    WeaponData[3].preference := 50;
    WeaponData[3].critical:= 0;

    WeaponData[4].shot_time:= 7;
    WeaponData[4].types:= 'machinegun';
    WeaponData[4].shots_fired:= 1;
    WeaponData[4].spread:= 0;
    WeaponData[4].shot_size:= 20;
    WeaponData[4].calliber_type:= 2;
    WeaponData[4].ammo_type:= '35_ammo';
    WeaponData[4].bullet_capacity:= 30;
    WeaponData[4].reload_time:= 120;
    WeaponData[4].code := 'steyrtmp';
    WeaponData[4].name := 'Steyr TMP';
    WeaponData[4].pic := 1;
    WeaponData[4].melee:= false;
    WeaponData[4].chainsaw := false;
    WeaponData[4].explosive:= 0;
    WeaponData[4].flamethrower:= false;
    WeaponData[4].preference := 40;
    WeaponData[4].critical:= 0.500000;

    WeaponData[5].shot_time:= 40;
    WeaponData[5].types:= 'Dubinka';
    WeaponData[5].shots_fired:= 0;
    WeaponData[5].spread:= 0;
    WeaponData[5].shot_size:= 20;
    WeaponData[5].calliber_type:= 1;
    WeaponData[5].ammo_type:= 'nonammo';
    WeaponData[5].bullet_capacity:= 0;
    WeaponData[5].reload_time:= 0;
    WeaponData[5].code := 'Dubinka';
    WeaponData[5].name := 'Дубинка';
    WeaponData[5].pic := 1;
    WeaponData[5].melee:= true;
    WeaponData[5].chainsaw := false;
    WeaponData[5].explosive:= 0;
    WeaponData[5].flamethrower:= false;
    WeaponData[5].preference := 1;
    WeaponData[5].critical:= 2.500000;

    WeaponData[6].shot_time:= 60;
    WeaponData[6].types:= 'grenadelauncher';
    WeaponData[6].shots_fired:= 1;
    WeaponData[6].spread:= 0;
    WeaponData[6].shot_size:= 100;
    WeaponData[6].calliber_type:= 18;
    WeaponData[6].ammo_type:= 'grenade_ammo';
    WeaponData[6].bullet_capacity:= 3;
    WeaponData[6].reload_time:= 180;
    WeaponData[6].code := 'gm94launcher';
    WeaponData[6].name := 'GM94 Launcher';
    WeaponData[6].pic := 1;
    WeaponData[6].melee:= false;
    WeaponData[6].chainsaw := false;
    WeaponData[6].explosive:= 30;
    WeaponData[6].flamethrower:= false;
    WeaponData[6].preference := 99;
    WeaponData[6].critical:= 0;
end;


procedure Tmap.DoLevel;
begin
    if (game_time > 0) then
    begin
        next_zombietime := 600;
        zombie_types[1] := 'Zombie';
        zombie_types[2] := 'Zombie';
        zombie_types[3] := 'Zombie';
        zombie_types[4] := 'ZombieCrawler';
        zombie_types[5] := 'ZombieCrawler';
    end; // end if
    if (game_time > 2000) then
    begin
        next_zombietime := 400;
        zombie_types[1] := 'Zombie';
        zombie_types[2] := 'Zombie';
        zombie_types[3] := 'ZombieDogWalk';
        zombie_types[4] := 'ZombieCrawler';
        zombie_types[5] := 'ZombieCrawler';
    end; // end if
    if (game_time > 4000) then
    begin
        next_zombietime := 300;
        zombie_types[1] := 'Zombie';
        zombie_types[2] := 'ZombieDogWalk';
        zombie_types[3] := 'ZombieDogWalk';
        zombie_types[4] := 'Zombie';
        zombie_types[5] := 'Zombie';
    end; // end if
    if (game_time > 6000) then
    begin
        next_zombietime := 300;
        zombie_types[1] := 'ZombieSlowRunner';
        zombie_types[2] := 'ZombieSlowRunner';
        zombie_types[3] := 'Zombie';
        zombie_types[4] := 'Zombie';
        zombie_types[5] := 'Zombie';
    end; // end if
    if (game_time > 8000) then
    begin
        next_zombietime := 250;
        zombie_types[1] := 'ZombieDogWalk';
        zombie_types[2] := 'ZombieDogWalk';
        zombie_types[3] := 'ZombieSlowRunner';
        zombie_types[4] := 'ZombieSlowRunner';
        zombie_types[5] := 'ZombieSlowRunner';

        if (had_steyr = false) then
        begin
            force_next_bonus := 'BonusSteyrTMP';
            had_steyr := true;
        end; // end if
    end; // end if
    if (game_time > 10000) then
    begin
        next_zombietime := 50;
        zombie_types[1] := 'Zombie';
        zombie_types[2] := 'Zombie';
        zombie_types[3] := 'Zombie';
        zombie_types[4] := 'Zombie';
        zombie_types[5] := 'Zombie';
    end; // end if
    if (game_time > 12000) then
    begin
        next_zombietime := 100;
        zombie_types[1] := 'ZombieSlowRunner';
        zombie_types[2] := 'ZombieDogWalk';
        zombie_types[3] := 'ZombieCrawler';
        zombie_types[4] := 'ZombieCrawler';
        zombie_types[5] := 'ZombieCrawler';
    end; // end if
    if (game_time > 14000) then
    begin
        next_zombietime := 50;
        zombie_types[1] := 'Zombie';
        zombie_types[2] := 'ZombieCralwer';
        zombie_types[3] := 'ZombieDogWalk';
        zombie_types[4] := 'ZombieDogWalk';
        zombie_types[5] := 'Zombie';
    end; // end if
    if (game_time > 16000) then
    begin
        next_zombietime := 150;
        zombie_types[1] := 'ZombieRunner';
        zombie_types[2] := 'ZombieDogWalk';
        zombie_types[3] := 'ZombieSlowRunner';
        zombie_types[4] := 'ZombieSlowRunner';
        zombie_types[5] := 'ZombieDogWalk';
    end; // end if
    if (game_time > 18000) then
    begin
        next_zombietime := 250;
        zombie_types[1] := 'ZombieRunner';
        zombie_types[2] := 'ZombieRunner';
        zombie_types[3] := 'ZombieRunner';
        zombie_types[4] := 'ZombieRunner';
        zombie_types[5] := 'ZombieDogWalk';

        if (had_gm94launcher =false) then
        begin
            force_next_bonus := 'BonusGM94Launcher';
            had_gm94launcher := true;
        end; // end if
    end; // end if
    if (game_time > 20000) then
    begin
        next_zombietime := 150;
        zombie_types[1] := 'ZombieDogRun';
        zombie_types[2] := 'ZombieDogRun';
        zombie_types[3] := 'ZombieDogRun';
        zombie_types[4] := 'ZombieDogWalk';
        zombie_types[5] := 'ZombieDogWalk';
    end; // end if
    if (game_time > 22000) then
    begin
        next_zombietime := 200;
        zombie_types[1] := 'ZombieDogRun';
        zombie_types[2] := 'ZombieDogRun';
        zombie_types[3] := 'ZombieRunner';
        zombie_types[4] := 'ZombieRunner';
        zombie_types[5] := 'ZombieSlowRunner';
    end; // end if
    if (game_time > 24000) then
    begin
        next_zombietime := 250;
        zombie_types[1] := 'ZombieRunner';
        zombie_types[2] := 'ZombieGiant';
        zombie_types[3] := 'ZombieRunner';
        zombie_types[4] := 'ZombieGiant';
        zombie_types[5] := 'ZombieRunner';
    end; // end if
    if (game_time > 26000) then
    begin
        next_zombietime := 20;
        zombie_types[1] := 'ZombieDogWalk';
        zombie_types[2] := 'ZombieDogWalk';
        zombie_types[3] := 'ZombieDogWalk';
        zombie_types[4] := 'Zombie';
        zombie_types[5] := 'Zombie';
    end; // end if
    if (game_time > 29000) then
    begin
        next_zombietime := 200;
        zombie_types[1] := 'ZombieRunner';
        zombie_types[2] := 'ZombieRunner';
        zombie_types[3] := 'ZombieDogRun';
        zombie_types[4] := 'ZombieDogRun';
        zombie_types[5] := 'ZombieDogRun';
        if (had_mossberg =false) then
        begin
            force_next_bonus := 'BonusMossberg500';
            had_mossberg := true;
        end; // end if
    end; // end if
    if (game_time > 32000) then
    begin
        next_zombietime := 400;
        zombie_types[1] := 'ZombieGiant';
        zombie_types[2] := 'ZombieGiant';
        zombie_types[3] := 'ZombieRunner';
        zombie_types[4] := 'ZombieRunner';
        zombie_types[5] := 'ZombieRunner';
    end; // end if
    if (game_time > 35000)  then
    begin
        next_zombietime := 150;
        zombie_types[1] := 'ZombieDogRun';
        zombie_types[2] := 'ZombieDogRun';
        zombie_types[3] := 'ZombieDogRun';
        zombie_types[4] := 'ZombieDogRun';
        zombie_types[5] := 'ZombieDogRun';
    end; // end if
    max_game_time := 38000;

    if (game_time > 38000) then
    begin
        next_zombietime := 200;
        zombie_types[1] := 'ZombieDogRun';
        zombie_types[2] := 'ZombieDogRun';
        zombie_types[3] := 'ZombieRunner';
        zombie_types[4] := 'ZombieRunner';
        zombie_types[5] := 'ZombieRunner';
        if (had_boss < 2) then
        begin
           ExteriorEnemySpawn('ZombieBigDog', true, 0, false);
           had_boss := had_boss + 1;
         end; // end if
    end; // end if
    if (exterior) then next_zombietime := next_zombietime / 1.500000;

end; // End of the function


procedure Tmap.DoScreenShake;
begin
    if (screen_shake < 0) then
    begin
        screen_shake := screen_shake + speedFactor * 0.300000;
        if (screen_shake > 0) then screen_shake := 0;
    end;

    if (screen_shake > 0) then
    begin
        screen_shake := screen_shake - speedFactor * screen_shake_speed;
        if (screen_shake < 0) then screen_shake := 0;
    end;
    screen_shake := screen_shake * -1;
end;


procedure Tmap.DoBackground(var player:OPlayer);
var
oldbkgx,oldbkgy,i,j,diff:integer;
 begin
 if GamePaused then exit;

  oldbkgx := SmeshX;
  oldbkgy := SmeshY;

     if (player._x > scr2w) and (SmeshX > -(Width - scrw)) then
       begin
       SmeshX := SmeshX - trunc(player._x - scr2w);
        diff := 0;
         if (SmeshX < -(width - scrw)) then
        begin
            diff := -(width - scrw) - SmeshX;
            SmeshX := -(width - scrw);
        end; // end if
        player._x := scr2w + diff;
    end; // end if

    if (player._x < scr2w) and ( SmeshX < 0) then
   begin
        diff := 0;
        SmeshX := SmeshX - trunc(player._x - scr2w);
        if (SmeshX > 0) then
        begin
            diff := -SmeshX;
            SmeshX := 0;
        end;
        player._x := scr2w + diff;
    end;

    if (player._y > scr2h) and ( SmeshY > -(height - scrh)) then
   begin
        diff := 0;
        SmeshY := SmeshY - trunc(player._y - scr2h);
        if (SmeshY< -(height - scrh)) then
        begin
            diff := -(height - scrh) - SmeshY;
            SmeshY := -(height - scrh);
        end;
        player._y := scr2h + diff;
    end;
    if (player._y < scr2h) and (SmeshY < 0) then
    begin
        diff := 0;
        SmeshY:= SmeshY - trunc(player._y - scr2h);
        if (SmeshY > 0) then
        begin
            diff := -SmeshY;
            SmeshY := 0;
        end;
        player._y := scr2h + diff;
    end;

    bkgXmove:= SmeshX - oldbkgx;
    bkgYmove:= SmeshY - oldbkgy;

 for i:=0 to high(Enemies) do
 if Enemies[i].Alive then
 begin
 Enemies[i]._x:=Enemies[i]._x+bkgXmove;
 Enemies[i]._y:=Enemies[i]._y+bkgYmove;
 end;

 for i:=0 to high(Bonus) do
 begin
 Bonus[i].x :=Bonus[i].x+bkgXmove;
 Bonus[i].y :=Bonus[i].y+bkgYmove;
 end;

 for i:=0 to high(Effects) do
 begin
 Effects[i].x :=Effects[i].x+bkgXmove;
 Effects[i].y :=Effects[i].y+bkgYmove;
 end;

 for i:=0 to w do
 for j:=0 to h do
 begin
 cells[i,j].x:=cells[i,j].x+bkgXmove;
 cells[i,j].y:=cells[i,j].y+bkgYmove;
 end;

 for j:=0 to 3 do
 if Kompas[j].level>0 then
 begin
 Kompas[j].x:=Kompas[j].x+bkgXmove;
 Kompas[j].y:=Kompas[j].y+bkgYmove;
 end;

 for i:=0 to high(MapObjects) do
 begin
 MapObjects[i].x:=MapObjects[i].x+bkgXmove;
 MapObjects[i].y:=MapObjects[i].y+bkgYmove;
 end;

end;

procedure Tmap.CreateLevel(Level:integer);
var
i,j,oldLevel:integer;
begin

oldLevel:=ActiveLevel;
ActiveLevel:=Level;

for i:=0 to mymap.w do
for j:=0 to mymap.h do
if cells[i,j].id>0 then glDeleteTextures(1, @mymap.cells[i,j].id);
zeromemory(@Kompas,sizeof(Kompas));

for i:=0 to 20 do
 for j:=0 to 20 do
 begin
 cells[i,j].x:=i*512;
 cells[i,j].y:=j*512;
 end;

 SmeshX:=0;
 SmeshY:=0;

 if ActiveLevel=1 then
  begin

 W:=3;
 H:=2;

 Width  :=W*512 +512;
 Height :=H*512 +512;

 loadtexture('data\maps\1M4.jpg',cells[0,0].id);
 loadtexture('data\maps\1M5.jpg',cells[1,0].id);
 loadtexture('data\maps\1M6.jpg',cells[2,0].id);
 loadtexture('data\maps\1M7.jpg',cells[3,0].id);

 loadtexture('data\maps\1M11.jpg',cells[0,1].id);
 loadtexture('data\maps\1M12.jpg',cells[1,1].id);
 loadtexture('data\maps\1M13.jpg',cells[2,1].id);
 loadtexture('data\maps\1M14.jpg',cells[3,1].id);

 loadtexture('data\maps\1M18.jpg',cells[0,2].id);
 loadtexture('data\maps\1M19.jpg',cells[1,2].id);
 loadtexture('data\maps\1M20.jpg',cells[2,2].id);
 loadtexture('data\maps\1M21.jpg',cells[3,2].id);

 Kompas[3].x:=0;
 Kompas[3].y:=512*2+50;
 Kompas[3].w:=64;
 Kompas[3].h:=128;
 Kompas[3].level:=2;


 MyHero._x:= 64;
 MyHero._y:= 512*2+100;

 DoBackground(MyHero);
 StopMusic;
PlayMusic('streamsound5.mp3');
 end;

 if ActiveLevel=2 then
  begin

 W:=2;
 H:=1;

 Width  :=W*512 +512;
 Height :=H*512 +512;

 loadtexture('data\maps\1M8.jpg',cells[0,0].id);
 loadtexture('data\maps\1M9.jpg',cells[1,0].id);
 loadtexture('data\maps\1M10.jpg',cells[2,0].id);

 loadtexture('data\maps\1M15.jpg',cells[0,1].id);
 loadtexture('data\maps\1M16.jpg',cells[1,1].id);
 loadtexture('data\maps\1M17.jpg',cells[2,1].id);

 Kompas[1].x:=width+SmeshX-64;
 Kompas[1].y:=512+80;
 Kompas[1].w:=64;
 Kompas[1].h:=128;
 Kompas[1].level:=1;

 Kompas[3].x:=0;
 Kompas[3].y:=512+30;
 Kompas[3].w:=64;
 Kompas[3].h:=256;
 Kompas[3].level:=3;

 if oldLevel=1 then
 begin
 MyHero._x:= Width-100;
 MyHero._y:= 512+128;
 end;

 if oldLevel=3 then
 begin
 MyHero._x:= 64;
 MyHero._y:= 512+160;
 end;

  DoBackground(MyHero);

  end;

 if ActiveLevel=3 then
  begin

 W:=4;
 H:=2;

 Width  :=W*512 +512;
 Height :=H*512 +512;

 loadtexture('data\maps\2M1.jpg',cells[0,0].id);
 loadtexture('data\maps\2M2.jpg',cells[1,0].id);
 loadtexture('data\maps\2M3.jpg',cells[2,0].id);
 loadtexture('data\maps\2M4.jpg',cells[3,0].id);
 loadtexture('data\maps\2M5.jpg',cells[4,0].id);

 loadtexture('data\maps\2M6.jpg',cells[0,1].id);
 loadtexture('data\maps\2M7.jpg',cells[1,1].id);
 loadtexture('data\maps\2M8.jpg',cells[2,1].id);
 loadtexture('data\maps\2M9.jpg',cells[3,1].id);
 loadtexture('data\maps\2M10.jpg',cells[4,1].id);

 loadtexture('data\maps\2M11.jpg',cells[0,2].id);
 loadtexture('data\maps\2M12.jpg',cells[1,2].id);
 loadtexture('data\maps\2M13.jpg',cells[2,2].id);
 loadtexture('data\maps\2M14.jpg',cells[3,2].id);
 loadtexture('data\maps\2M15.jpg',cells[4,2].id);

 Kompas[1].x:=width+SmeshX-256;
 Kompas[1].y:=1024+280;
 Kompas[1].w:=256;
 Kompas[1].h:=230;
 Kompas[1].level:=2;

 MyHero._x:= width+SmeshX-256;
 MyHero._y:= 1024+280;

 DoBackground(MyHero);

 end;

end;

procedure Tmap.Init;
 var
F1: TextFile;
  s: string;
  i,j,id,n:integer;
 begin

 ShowBlok:=false;
 
 for i:=0 to 20 do
 for j:=0 to 20 do
 begin
 cells[i,j].x:=i*512;
 cells[i,j].y:=j*512;
 end;

SmeshX:=0;
SmeshY:=0;

Total:= 0;
Winner:= 0;

CreateLevel(1);

 end;

procedure Tmap.Load;
 begin
 end;

procedure Tmap.Close;
 begin
 end;

Procedure InitGame;
var
i,k:integer;
begin
 OpenLog;
 InitSoundEngine;

 randomize;

 game_time:=0;

 Mymap.Init;
 InitWeapon;
 CreateProfile;
 ResetProfile;


 loadtexture('data\Men_Pistol.png',MenTexture);
 loadtexture('data\Cursor.png',CursorTexture);

  loadtexture('data\Boch1.png',Bochka1);
  loadtexture('data\Boch2.png',Bochka2);

  loadtexture('data\Armor.png',ArmorPic);
  loadtexture('data\Health.png',HealthPic);
  loadtexture('data\blood.png',BloodPic);

  loadtexture('data\Weapon\Dubina.png', WeaponPic[0]);
  loadtexture('data\Weapon\Glock19C.png',WeaponPic[1]);
  loadtexture('data\Weapon\Colt45.png', WeaponPic[2]);
  loadtexture('data\Weapon\Machinegun.png',WeaponPic[3]);
  loadtexture('data\Weapon\ShotGun.png', WeaponPic[4]);
  loadtexture('data\Weapon\Basuka.png',WeaponPic[5]);

  loadtexture('data\Weapon\sGlock19C.png',sWeaponPic[1]);
  loadtexture('data\Weapon\sColt45.png', sWeaponPic[2]);
  loadtexture('data\Weapon\sMachinegun.png',sWeaponPic[3]);
  loadtexture('data\Weapon\sShotGun.png', sWeaponPic[4]);
  loadtexture('data\Weapon\sBasuka.png',sWeaponPic[5]);

  loadtexture('data\Weapon\12Ammo.png',AmmoPic[0]);
  loadtexture('data\Weapon\35Ammo.png', AmmoPic[1]);
  loadtexture('data\Weapon\45Ammo.png',AmmoPic[2]);
  loadtexture('data\Weapon\94Ammo.png', AmmoPic[3]);

for i:=1 to 18 do
 loadtexture('data\Nogi\N'+inttostr(i)+'.png',MenTorsTexture[i-1]);

    setlength(Animation,8);
    Animation[0].MaxFrame:=18;
    Animation[0].MaxFrameDelay:=2;
    Animation[0].FrameW:=256;
    Animation[0].FrameH:=256;
    setlength(Animation[0].Frames,Animation[0].MaxFrame+1);
for i:=1 to 19 do
 loadtexture('data\Boom\image8'+inttostr(43+i)+'.jpg',Animation[0].Frames[i-1]);


    Animation[1].MaxFrame:=6;
    Animation[1].MaxFrameDelay:=2;
    Animation[1].FrameW:=128;
    Animation[1].FrameH:=128;
    setlength(Animation[1].Frames,Animation[1].MaxFrame+1);
for i:=1 to 7 do
 loadtexture('data\Blood\image'+inttostr(27+i)+'.png',Animation[1].Frames[i-1]);


    Animation[2].MaxFrame:=15;
    Animation[2].MaxFrameDelay:=2;
    Animation[2].FrameW:=64;
    Animation[2].FrameH:=128;
    setlength(Animation[2].Frames,Animation[2].MaxFrame+1);
for i:=1 to 16 do
 loadtexture('data\Monsters\Dm1-'+inttostr(i)+'.png',Animation[2].Frames[i-1]);

    k:=3;
    Animation[k].MaxFrame:=20;
    Animation[k].MaxFrameDelay:=2;
    Animation[k].FrameW:=75;
    Animation[k].FrameH:=150;
    setlength(Animation[k].Frames,Animation[k].MaxFrame+1);
for i:=1 to 21 do
 loadtexture('data\Monsters\Dm2-'+inttostr(i)+'.png',Animation[k].Frames[i-1]);

  k:=4;
    Animation[k].MaxFrame:=20;
    Animation[k].MaxFrameDelay:=2;
    Animation[k].FrameW:=75;
    Animation[k].FrameH:=150;
    setlength(Animation[k].Frames,Animation[k].MaxFrame+1);
for i:=1 to 21 do
 loadtexture('data\Monsters\Dm3-'+inttostr(i)+'.png',Animation[k].Frames[i-1]);

  k:=5;
    Animation[k].MaxFrame:=26;
    Animation[k].MaxFrameDelay:=2;
    Animation[k].FrameW:=75;
    Animation[k].FrameH:=150;
    setlength(Animation[k].Frames,Animation[k].MaxFrame+1);
for i:=1 to 27 do
 loadtexture('data\Monsters\Dm4-'+inttostr(i)+'.png',Animation[k].Frames[i-1]);

 k:=6;
    Animation[k].MaxFrame:=20;
    Animation[k].MaxFrameDelay:=2;
    Animation[k].FrameW:=75;
    Animation[k].FrameH:=150;
    setlength(Animation[k].Frames,Animation[3].MaxFrame+1);
for i:=1 to 21 do
 loadtexture('data\Monsters\Dm5-'+inttostr(i)+'.png',Animation[k].Frames[i-1]);

  k:=7;
    Animation[k].MaxFrame:=25;
    Animation[k].MaxFrameDelay:=2;
    Animation[k].FrameW:=120;
    Animation[k].FrameH:=240;
    setlength(Animation[k].Frames,Animation[k].MaxFrame+1);
for i:=1 to 26 do
 loadtexture('data\Monsters\Dm6-'+inttostr(i)+'.png',Animation[k].Frames[i-1]);


     CreateEnemy(100,
                 100,
                random(360),
                'Barrel' + inttostr(random(3) + 1), false,true, 0);


  for i := 1 to 10 do
    CreateEnemy(100 + random(Mymap.width - 250),
                100 + random(Mymap.height - 250),
                random(360),
                'Barrel' + inttostr(random(3) + 1), false,true, 0);

 CreateBonus('BonusColt45', 400, 500, true);
 CreateBonus('Bonus45Bullets', 432, 500,  true);
 CreateBonus('Bonus45Bullets', 470, 500,  true);
 CreateBonus('Bonus35Bullets', 500, 500, true);
 CreateBonus('Bonus35Bullets', 540, 500, true);

 CreateBonus('BonusMossberg500', 600, 500, true);
 CreateBonus('BonusGM94Launcher', 650, 500, true);
 CreateBonus('BonusSteyrTMP', 700, 500, true);
 CreateBonus('BonusSteyrTMP', 700, 600, true);

 MyHero.Init(mymap.Width-512,512);

 end;

Procedure CloseGame;
var
i,j:integer;
begin
glDeleteTextures(1, @Bochka1);
glDeleteTextures(1, @Bochka2);

glDeleteTextures(1, @ArmorPic);
glDeleteTextures(1, @HealthPic);

for i:=0 to 5 do  glDeleteTextures(1, @WeaponPic[i]);
for i:=1 to 5 do  glDeleteTextures(1, @sWeaponPic[i]);
for i:=0 to 3 do  glDeleteTextures(1, @AmmoPic[i]);
for i:=0 to 18 do glDeleteTextures(1, @MenTorsTexture[i]);

glDeleteTextures(1, @MenTexture);
glDeleteTextures(1, @CursorTexture);

for i:=0 to high(Animation) do
for j:=0 to high(Animation[i].Frames) do
glDeleteTextures(1, @Animation[i].Frames[j]);

for i:=0 to mymap.w do
for j:=0 to mymap.h do
 glDeleteTextures(1, @mymap.cells[i,j].id);

FreeSoundEngine;
end;

procedure ProccesGame;
var
MoveForward:integer;
begin

 if Keys[VK_ESCAPE] then PostQuitMessage(0);

 ActionLoop;

  if Keys[MouseLB] then
 begin
  Keys[MouseLB]:=false;
  MakeBonusText('Бэнг бэнг');
 end;

   if Keys[MouseRB] then
 begin
  Keys[MouseRB]:=false;
  if CreateEnemy(100,100,45,'Zombie',false,false,100) then
  MakeBonusText('Монстрило креате')
  else
  MakeBonusText('Не могу содать монстра');

 end;


  end;



 procedure Render;
 Var
 s:string;
 i,k:integer;
 Pt: TPoint;
 ammo_remaining:integer;
 inv_place:integer;
 begin
  glClear(GL_COLOR_BUFFER_BIT or GL_DEPTH_BUFFER_BIT);
 glPushMatrix;


   glDisable( GL_TEXTURE_2D );
  Enable2d(true);

  Mymap.Draw;
  DrawBonus;
  DrawEnemy;
  MyHero.Draw;
  DrawEffect;

 glblend(1);
   DrawTextureBox(1,scrh-33,32,32,HealthPic);
   SText2D(MySysfont, inttostr(MyHero.health),1,scrh-5,$0,255);
   SText2D(MySysfont, inttostr(MyHero.health),2,scrh-6,$FFFFFF,255);

  DrawTextureBox(34,scrh-33,32,32,ArmorPic);
   SText2D(MySysfont, inttostr(MyHero.armour_health),34,scrh-5,$0,255);
   SText2D(MySysfont, inttostr(MyHero.armour_health),35,scrh-6,$ffffff,255);

   for i:=1 to high(MyHero.weapon) do
   if length(MyHero.weapon[i].name)>0 then
       SText2D(MySysfont,inttostr(i)+'. '+MyHero.weapon[i].name,10,scr2h+i*15,Rgb(255,0,0),255);

     SText2D(MySysfont,bonustext.text,scr2w,scrh-10,Rgb(255,0,0),bonustext.alpha);
     SText2D(MySysfont,inttostr(trunc(game_time)),scr2w,100,Rgb(255,0,0),255);

    ammo_remaining := 0;
    inv_place := -1;
    inv_place := MyHero.FindInventory(MyHero.weapon[MyHero.current_gun].ammo_type);

    if (inv_place > -1) then
     ammo_remaining := current_profile.inventory[inv_place].params[0];

   if MyHero.weapon[MyHero.current_gun].name='Dubinka' then k:=0;
   if MyHero.weapon[MyHero.current_gun].name='Glock 19C' then k:=1;
   if MyHero.weapon[MyHero.current_gun].name='Colt 45' then k:=2;
   if MyHero.weapon[MyHero.current_gun].name='Steyr TMP' then k:=3;
   if MyHero.weapon[MyHero.current_gun].name='Mossberg 500' then k:=4;
   if MyHero.weapon[MyHero.current_gun].name='GM94 Launcher' then k:=5;

  DrawRectangle2D(scrw-130,scrh-86,128,84,$FFFFFF,180,0,true,false);
  DrawRectangle2D(scrw-131,scrh-87,130,86,$000000,180,0,false,false);
  glblend(1);
   DrawTextureBox(scrw-130,scrh-66,128,64,WeaponPic[k]);

   s:='';

  if (MyHero.reload_time > 0) then
   SText2D(MySysfont,'Перезарядка',scrw-127,scrh-60,Rgb(255,0,0),255);

      SText2D(MySysfont,MyHero.weapon[MyHero.current_gun].name,scrw-127,scrh-74,Rgb(0,0,0),255);

  SText2D(MySysfont, inttostr(MyHero.weapon[MyHero.current_gun].bullets_loaded)+'/'+
                     inttostr(ammo_remaining),scrw-55,scrh-10,Rgb(0,0,0),255);

  glblend(2);
  DrawTextureBox(MousePos.X,MousePos.Y,16,16,CursorTexture,true);

 Enable2d(false);

 glPopMatrix;
 SwapBuffers(GWDC);

 end;

end.




