unit u_game;

interface

uses OMEGA, omegaGUI, u_const, Graphics, SysUtils, IniFiles, Dialogs;

procedure GameInit;
procedure GameDraw;
procedure GameQuit;
procedure GameProcess;
procedure GameSlovProcess;

implementation

var
  txCursor,txShow,txGround,txGroundBack,txHero:PTexture;
  sndDeath, sndOo, sndWater, sndInWater, sndDow,
  sndTheGame, sndJump, sndHhh, sndEfforts, sndExplo:PSound;
  sndPong:array[1..4] of PSound;
  fntMain:PFont2D;
  Player:TPlayer;
  ScreenText:ShortString;
  EyeX,EyeY,pEyeX,pEyeY:Single;
  _EyeX,_EyeY:Integer;
  SysTimer:integer;
  Keys:array[1..4] of PSound;
  GameState:integer=0;
  LogoId,LogoTime,LastAnswId,AnswTimer,MemoryTimer,SelectedMemory,
  DeathTimer,WaterCounter,LastJ,HeroId,ExpCounter:integer;
  SelectMem:integer=-1;
  HeroTalk:string;
  boolOo:Boolean=false;
  PosIn:integer=-1;

function IniGet(FileAddr,Section,Key,Default:string):string;
var i:TIniFile;
begin
  try
    i:=TIniFile.Create(FileAddr);
    result:=i.ReadString(Section,Key,Default);
    i.Free;
  except
    result:=Default;
  end;
end;
procedure IniSet(FileAddr,Section,Key,Value:string);
var i:TIniFile;
begin
  try
    i:=TIniFile.Create(FileAddr);
    i.WriteString(Section,Key,Value);
    i.Free;
  except
    
  end;
end;

procedure PlaySoundPos(snd:PSound;X,Y:single);
var t:Single;
    i:Integer;
begin
  if Player.InWater then Exit;
  t:=M_Distance(Player.X,Player.Y,X,Y);
  if t<sX div draw_coef then
    Snd_Play(snd,0,VOLUME(Round((1-t/(sX div draw_coef))*100)));
end;


procedure GameQuit;
begin

end;

function ReplaceBB(s:string):string;
begin
  result:=StringReplace(s,'|',#13,[rfReplaceAll])
end;

procedure SaveStory(name:string);
var i:Integer;
    fa:string;
begin
  fa:='Data/Other/'+name+'.ini';
  for i:=0 to Length(Memories)-1 do begin
    IniSet(fa,'I_'+inttostr(i+1),'X',IntToStr(Memories[i].X));
    IniSet(fa,'I_'+inttostr(i+1),'Y',IntToStr(Memories[i].Y));
  end;
end;

procedure LoadStory(name:string);
var c,q,i,j:integer;
    f:string;
    fa:string;
begin
  fa:='Data/Other/'+name+'.ini';
  c:=StrToIntDef(IniGet(fa,'Main','ItemsCount','0'),0);
  SetLength(Memories,c);
  for i:=0 to c-1 do begin
    with Memories[i] do begin
      Text:=ReplaceBB(IniGet(fa,'I_'+inttostr(i+1),'Text',''));
      X:=StrToIntDef(IniGet(fa,'I_'+inttostr(i+1),'X','0'),0);
      Y:=StrToIntDef(IniGet(fa,'I_'+inttostr(i+1),'Y','0'),0);
      Music:=IniGet(fa,'I_'+inttostr(i+1),'M','');
      q:=StrToIntDef(IniGet(fa,'I_'+inttostr(i+1),'Q','0'),0);
      answered:=false;
      SetLength(questions,q);
      for j:=0 to q-1 do begin
        questions[j].text:=ReplaceBB(IniGet(fa,'I_'+inttostr(i+1),'Q'+inttostr(j+1)+'T',''));
        questions[j].answerid:=StrToIntDef(IniGet(fa,'I_'+inttostr(i+1),'Q'+inttostr(j+1)+'I','1'),1)-1;
      end;
    end;
  end;
  c:=StrToIntDef(IniGet(fa,'Main','MemsCount','0'),0);
  SetLength(Mems,c);
  for i:=0 to c-1 do begin
    with Mems[i] do begin
      X1:=StrToIntDef(IniGet(fa,'Mem_'+inttostr(i+1),'X1','0'),0);
      Y1:=StrToIntDef(IniGet(fa,'Mem_'+inttostr(i+1),'Y1','0'),0);
      X2:=StrToIntDef(IniGet(fa,'Mem_'+inttostr(i+1),'X2','0'),0);
      Y2:=StrToIntDef(IniGet(fa,'Mem_'+inttostr(i+1),'Y2','0'),0);
      Id:=StrToIntDef(IniGet(fa,'Mem_'+inttostr(i+1),'Id','1'),1)-1;
      b:=IniGet(fa,'Mem_'+inttostr(i+1),'N','false')='true';
    end;
  end;
  c:=StrToIntDef(IniGet(fa,'Main','ACount','0'),0);
  SetLength(Anims,c);
  for i:=0 to c-1 do begin
    with Anims[i] do begin
      img:=Tex_LoadFromFile(PAnsiChar('Data/Textures/'+IniGet(fa,'A_'+inttostr(i+1),'N','')),$FF00FF,0);
      X:=StrToIntDef(IniGet(fa,'A_'+inttostr(i+1),'X','0'),0);
      Y:=StrToIntDef(IniGet(fa,'A_'+inttostr(i+1),'Y','0'),0);
      W:=StrToIntDef(IniGet(fa,'A_'+inttostr(i+1),'W','0'),0);
      H:=StrToIntDef(IniGet(fa,'A_'+inttostr(i+1),'H','0'),0);
      S:=StrToIntDef(IniGet(fa,'A_'+inttostr(i+1),'S','0'),0);
      Tex_SetFramesSize(img, W, H);
    end;

  end;
  c:=StrToIntDef(IniGet(fa,'Main','HeroesCount','0'),0);
  SetLength(Heroes,c);
  for i:=0 to c-1 do begin
    with Heroes[i] do begin
      X:=StrToIntDef(IniGet(fa,'Hero_'+inttostr(i+1),'X','0'),0);
      Y:=StrToIntDef(IniGet(fa,'Hero_'+inttostr(i+1),'Y','0'),0);
      Hello:=IniGet(fa,'Hero_'+inttostr(i+1),'Hello','');
      Name:=IniGet(fa,'Hero_'+inttostr(i+1),'Name','');
      h:=IniGet(fa,'Hero_'+inttostr(i+1),'H','')='true';
      Uniq:=StrToIntDef(IniGet(fa,'Hero_'+inttostr(i+1),'U','0'),0);;
      a:=true;
      q:=StrToIntDef(IniGet(fa,'Hero_'+inttostr(i+1),'C','0'),0);
      SetLength(Chat,q);
      for j:=0 to q-1 do begin
        Chat[j].Q:=ReplaceBB(IniGet(fa,'Hero_'+inttostr(i+1),'Q'+inttostr(j+1),''));
        Chat[j].A:=ReplaceBB(IniGet(fa,'Hero_'+inttostr(i+1),'A'+inttostr(j+1),''));
        Chat[j].Id:=StrToIntDef(IniGet(fa,'Hero_'+inttostr(i+1),'I'+inttostr(j+1),'0'),0)-1;
      end;
    end;
  end;
  c:=StrToIntDef(IniGet(fa,'Main','WaterRegs','0'),0);
  SetLength(WRegs,c);
  for i:=0 to c-1 do begin
    with WRegs[i] do begin
      X1:=StrToIntDef(IniGet(fa,'W_'+inttostr(i+1),'X1','0'),0);
      Y1:=StrToIntDef(IniGet(fa,'W_'+inttostr(i+1),'Y1','0'),0);
      X2:=StrToIntDef(IniGet(fa,'W_'+inttostr(i+1),'X2','0'),0);
      Y2:=StrToIntDef(IniGet(fa,'W_'+inttostr(i+1),'Y2','0'),0);
    end;
  end;
  LastAnswId:=-1; AnswTimer:=answ_time;
end;

procedure LoadLevel(name:string);
var bt:TBitmap;
    n,m:Integer;
begin
  txGroundBack:=Tex_LoadFromFile(PAnsiChar('Data/Levels/'+name+'_Mask.bmp'),$FF00FF,TEX_CLAMP);
  bt:=TBitmap.Create;
  bt.LoadFromFile('Data/Levels/'+name+'.bmp');
  txGround:=Tex_CreateZero(bt.Width,bt.Height,0);
  SetLength(Ground,bt.Width,bt.Height);
  Tex_BeginRenderIn(txGround,False,True,True);
  WaterCCount:=0; WBCount:=0; WaterDotsCount:=0;

  for m:=0 to bt.Height-1 do
    for n:=0 to bt.Width-1 do
      case bt.Canvas.Pixels[n,m] of
        $FF00FF: Ground[n,m]:=0;
        $FF0000: begin
          inc(WaterCCount);
          WaterC[WaterCCount].X:=n;
          WaterC[WaterCCount].Y:=m;
          WaterC[WaterCCount].Timer:=Random(water_time);
        end;
        $0000FF: begin
          Ground[n,m]:=0;
          Player.X:=n;
          Player.Y:=m;
        end;
        else begin
          Ground[n,m]:=1;
          Pr2D_Pixel(n,m,bt.Canvas.Pixels[n,m]);
        end;
      end;
  Tex_EndRenderIn;
  bt.Free;
  EyeX:=-round(Player.X)+(sX div draw_coef) div 2;
  EyeY:=-round(Player.Y)+(sY div draw_coef) div 2;
end;

procedure GameInit;
var n: Integer;
    s:string;
begin
  guiInit('Data/Gui');
  txCursor:=Tex_LoadFromFile('Data/Textures/Cursor.tga',-1,0);
  txShow:=Tex_LoadFromFile('Data/Textures/Show.gif',-1,0);
  txHero:=Tex_LoadFromFile('Data/Textures/Hero.gif',-1,0);
  fntMain:= Text_LoadFontFromFile('Data/Fonts/Font.tga','Data/Fonts/FontInfo.ofi');
  sndDeath := Snd_LoadFromFile('Data/Sound/death.wav',2);
  sndOo := Snd_LoadFromFile('Data/Sound/Oo.wav',2);
  sndDow := Snd_LoadFromFile('Data/Sound/Dow.wav',2);
  sndTheGame := Snd_LoadFromFile('Data/Sound/TheGame.wav',2);
  sndJump := Snd_LoadFromFile('Data/Sound/Jump.wav',2);
  sndHhh := Snd_LoadFromFile('Data/Sound/Hhh.wav',2);
  sndEfforts := Snd_LoadFromFile('Data/Sound/Efforts.wav',2);
  sndExplo := Snd_LoadFromFile('Data/Sound/Explo.wav',2);
  for n:=1 to 4 do
    sndPong[n] := Snd_LoadFromFile(PAnsiChar('Data/Sound/pong'+inttostr(n)+'.wav'),2);
  sndWater := Snd_LoadFromFile('Data/Sound/Water.wav',8);
  sndInWater := Snd_LoadFromFile('Data/Sound/inwater.wav',2);
  LoadStory('story');
  LoadLevel('level');
end;

procedure DrawText(X,Y:Single;s:string;size:Single;align:integer=align_left;trans:Byte=255;color:Integer=$FFFFFF);
begin
  if s='' then exit;
  case align of
    align_right:X:=X-Text_GetWidth(fntMain,PAnsiChar(S),size);
    align_center:X:=X-Text_GetWidth(fntMain,PAnsiChar(S),size)/2;
  end;
  Text_Draw(fntMain,X,Y,PAnsiChar(s),size,0,trans,color);
end;

procedure DrawHero(X,Y:Single; Color:Integer);
begin
  //X:=Round(X); Y:=Round(Y);
  Pr2D_Rect((EyeX+X-0.5)*draw_coef,
    (EyeY+Y+1)*draw_coef-hero_h*draw_coef,
    1*draw_coef-1,hero_h*draw_coef-1,$0088FF,255,PR_FILL);
  Pr2D_Rect((EyeX+X-0.5)*draw_coef,
    (EyeY+Y+1)*draw_coef-hero_h*draw_coef,
    1*draw_coef-1,1*draw_coef-1,Color,255,PR_FILL);
  {Pr2D_Rect((EyeX+X-0.5)*draw_coef,
    (EyeY+Y+1)*draw_coef-hero_h*draw_coef,
    1*draw_coef-1,hero_h*draw_coef-1,$FFFFFF); }
end;

procedure DrawMemory(id:Integer;trans:byte);
var i,t:integer;
    b:Boolean;
begin
  for i:=0 to Length(Memories[id].questions)-1 do begin
    b:=MouseInBorder(pEyeX+Memories[id].X-42,pEyeY+Memories[id].Y+33+i*21, Length(Memories[id].Questions[i].text)*symbolWidth+8, 20);
    if b then t:=255 else t:=128;
    Pr2D_Line(pEyeX+Memories[id].X-42+Length(Memories[id].Questions[i].text)*symbolWidth+8,
      pEyeY+Memories[id].Y+43+i*21,
      pEyeX+Memories[id].X-32+Length(Memories[id].Questions[i].text)*symbolWidth+8,
      pEyeY+Memories[id].Y+43+i*21,$FFFFFF,t);
    if Memories[Memories[id].Questions[i].answerid].answered then begin
      Pr2D_Line(pEyeX+Memories[id].X-32+Length(Memories[id].Questions[i].text)*symbolWidth+8,
        pEyeY+Memories[id].Y+43+i*21,
        pEyeX+Memories[Memories[id].Questions[i].answerid].X-50,
        pEyeY+Memories[Memories[id].Questions[i].answerid].Y, $FFFFFF);
      Pr2D_Circle(pEyeX+Memories[Memories[id].Questions[i].answerid].X-50,
        pEyeY+Memories[Memories[id].Questions[i].answerid].Y,4,$00FFFF,t,32,PR_FILL);
      Pr2D_Line(pEyeX+Memories[Memories[id].Questions[i].answerid].X-42,
        pEyeY+Memories[Memories[id].Questions[i].answerid].Y,
        pEyeX+Memories[Memories[id].Questions[i].answerid].X-50,
        pEyeY+Memories[Memories[id].Questions[i].answerid].Y, $FFFFFF);
      if b and guiMouseClick then begin
        SelectedMemory:=Memories[id].Questions[i].answerid;
        guiPlayClick;
        _EyeX:=sX div 2-Memories[Memories[id].Questions[i].answerid].X;
        _EyeY:=sY div 2-Memories[Memories[id].Questions[i].answerid].Y;
      end;
      DrawMemory(Memories[id].Questions[i].answerid,trans);
      Pr2D_Circle(pEyeX+Memories[id].X-32+Length(Memories[id].Questions[i].text)*symbolWidth+8,
        pEyeY+Memories[id].Y+43+i*21,4,$00FFFF,t,32,PR_FILL);
    end else begin
      DrawText(pEyeX+Memories[id].X-30+Length(Memories[id].Questions[i].text)*symbolWidth+8,
        pEyeY+Memories[id].Y+35+i*21,'?',0.5,align_left,t,$00FFFF);
    end;
    guiDrawMemoBorder(pEyeX+Memories[id].X-42,pEyeY+Memories[id].Y+33+i*21, Length(Memories[id].Questions[i].text)*symbolWidth-24, -12, t);
    guiDrawText(Memories[id].Questions[i].text,
      pEyeX+Memories[id].X-42,pEyeY+Memories[id].Y+34+i*21, False, False, t);
  end;
  b:=MouseInBorder(pEyeX+Memories[id].X-42,pEyeY+Memories[id].Y, 106, 32);
  if b then t:=255 else t:=128;
  guiDrawMemoBorder(pEyeX+Memories[id].X-42,pEyeY+Memories[id].Y, 84, 0, t);
  guiDrawText(Copy(Memories[id].text,1,13)+'...',pEyeX+Memories[id].X-42,pEyeY+Memories[id].Y, False, False, t);
  guiDrawText('...'+Copy(Memories[id].text,Length(Memories[id].text)-12,13),pEyeX+Memories[id].X-42,pEyeY+Memories[id].Y+13, False, False, t);
  if b and guiMouseClick then begin
   // SelectMem:=id;

    SelectedMemory:=id;
    guiPlayClick;
    _EyeX:=sX div 2-Memories[id].X;
    _EyeY:=sY div 2-Memories[id].Y;
  end;
end;

procedure GameDraw;
var n,trans,l,i,m: Integer;
    s:string;
    r:oeRect;
    X,Y,p,z:single;
begin

  guiFocus;
    case GameState of
      gs_died:begin
        DrawHero(sX div (draw_coef*2),sY div (draw_coef*2),$004488);
        if (ExpCounter<180) and (ExpCounter>90) then begin
          DrawText(sX/2,sY/2+64,'К сожалению это ваша судьба.',1,align_center);
        end;
        if (ExpCounter<=90) and (ExpCounter>0) then begin
          DrawText(sX/2,sY/2+68,'WELCOME TO THE HELL',0.6,align_center,128);
        end;
        if (ExpCounter=0) then begin
          DrawText(sX/2,sY/2+68,'Чувствуйте себя как дома. ESC',0.6,align_center,128);
        end;
        if Key_Down(K_ESCAPE) then begin
          OE_Quit;
        end;
      end;
      gs_explosion:begin
        if ExpCounter mod 2=0 then i:=$FFFFFF else i:=$000000;
        Pr2D_Rect(0,0,sX,sY,i,255,PR_FILL);
      end;
      gs_talk:begin
        guiDrawForm('Разговор с: '+Heroes[HeroId].Name,10,10,sX-20,sY-20);
        DrawText(20,40,HeroTalk,0.8);
        s:='Ответить:';
        for i:=0 to Length(Heroes[HeroId].Chat)-1 do begin
          s:=s+#13+inttostr(i+1)+'. '+Heroes[HeroId].Chat[i].Q;
          if Key_Press(K_1+i) then begin
            HeroTalk:=' - '+Heroes[HeroId].Chat[i].Q+#13' - '+Heroes[HeroId].Chat[i].A;
            if Heroes[HeroId].Chat[i].id>=0 then begin
              Memories[Heroes[HeroId].Chat[i].id].answered:=True;
            end;
          end;
        end;
        DrawText(20,sY/2,s,0.5);
        if Key_Down(K_ESCAPE) then begin
          GameState:=gs_game;
          case Heroes[HeroId].Uniq of
            1:Heroes[HeroId].X:=Heroes[HeroId].X+1;
            2:begin
                ExpCounter:=20;
              end;
          end;

        end;
      end;
      gs_memory:begin
      {  if SelectMem>=0 then begin
          Memories[SelectMem].X:=Mouse_X-round(pEyeX);
          Memories[SelectMem].Y:=Mouse_Y-round(pEyeY);
          if guiMouseClick then SelectMem:=-1;
        end;     }
        p:=M_Cos(round((MemoryTimer/memory_time)*90));
        for n:=-2 to 0 do
          for m:=-2 to 0 do
        SSprite_Draw(txShow,(sX-sX*p)/2+(Round(pEyeX) mod sX)+(n+0.5)*sX*p,(sY-sY*p)/2+(Round(pEyeY) mod sY)+(m+0.5)*sY*p,sX*p,sY*p);//,Round((p-0.5)*255));
        DrawMemory(0,Round(p*255));
        if SelectedMemory>=0 then begin
          guiDrawMemoBorder(pEyeX+Memories[SelectedMemory].X-128,pEyeY+Memories[SelectedMemory].Y-64, 256, 128);
          DrawText(pEyeX+Memories[SelectedMemory].X-120,pEyeY+Memories[SelectedMemory].Y-56,Memories[SelectedMemory].text,0.6);
          if guiDrawButton('Закрыть',pEyeX+Memories[SelectedMemory].X+58,pEyeY+Memories[SelectedMemory].Y+66, 96)=button_click then begin
            SelectedMemory:=-1;
          end;
        end;
        DrawText(8,8,'[ESC] - выход',0.4, align_left, Round(p*255), $00FFFF);
      end;
      gs_logos:begin
        l:=Logos[LogoId].t;
        if LogoTime<l*0.25 then begin
          p:=LogoTime/(l*0.25);
        end else
        if LogoTime>l*0.75 then begin
          p:=1-(LogoTime-l*0.75)/(l*0.25);
        end else
          p:=1;
        z:=p/10+1.1;
        if LogoId=logos_count-4 then
          SSprite_Draw(txShow,0,0,sX,sY,Round(p*255));
        DrawText(sX div 2, sY div 2, Logos[LogoId].n2, Logos[LogoId].s*z*1.2, align_center, Round(p*255));

        DrawText(sX div 2, sY div 2-16, Logos[LogoId].n1, 0.7, align_center,Round(p*255),$404040);
        DrawText(sX div 2, sY div 2+36, Logos[LogoId].n3, 0.7, align_center,Round(p*255),$002C70);
      end;
      gs_death:begin
        DrawText(sX/2,sY/2-4,'Нет, это не мои воспоминания, я решил другое...',0.6,align_center,255, $444444);
      end;
      gs_game:begin
        if EyeX>0 then EyeX:=0; if EyeY>0 then EyeY:=0;
        if EyeX<-txGround.Width+(sX div draw_coef) then EyeX:=-txGround.Width+(sX div draw_coef);
        if EyeY<-txGround.Height+(sY div draw_coef) then EyeY:=-txGround.Height+(sY div draw_coef);
        r.X:=-EyeX;
        r.Y:=-EyeY;
        r.Width:=sX div draw_coef;
        r.Height:=sY div draw_coef;
        CSprite_Draw(txGroundBack,0,0,sX,sY,@r);
        for i:=1 to WaterCCount do begin
          Pr2D_Rect((EyeX+WaterC[i].X-0.5)*draw_coef+2,
            (EyeY+WaterC[i].Y-0.5-WaterC[i].Timer/water_time)*draw_coef,
            draw_coef-5,draw_coef-5,$FF0000,128,PR_FILL);
        end;
        for i:=1 to WaterDotsCount do begin
          Pr2D_Rect((EyeX+WaterDots[i].X-0.5)*draw_coef+2,
            (EyeY+WaterDots[i].Y+0.5)*draw_coef,
            draw_coef-5,draw_coef-5,$FF0000,128,PR_FILL);
        end;
        DrawHero(Player.X,Player.Y,$004488);
        for i:=1 to WBCount do begin
          Pr2D_Circle(EyeX*draw_coef+WB[i].X,
            EyeY*draw_coef+WB[i].Y,WB[i].size,$FFFFFF);
        end;
        for i:=0 to Length(WRegs)-1 do begin
          Pr2D_Rect((EyeX+WRegs[i].X1-0.5)*draw_coef,(EyeY+WRegs[i].Y1-0.5)*draw_coef,
           (WRegs[i].X2-WRegs[i].X1)*draw_coef,(WRegs[i].Y2-WRegs[i].Y1)*draw_coef,
           $FF0000,64,PR_FILL);
        end;
        CSprite_Draw(txGround,0,0,sX,sY,@r);
        for i:=0 to Length(Anims)-1 do begin
          ASprite_Draw(Anims[i].img,
            (EyeX+Anims[i].X-0.5)*draw_coef,
            (EyeY+Anims[i].Y+1)*draw_coef,
            Anims[i].W*draw_coef,Anims[i].H*draw_coef,Anims[i].Id);
        end;
        {SSprite_Draw(txGround,(EyeX+0.5)*draw_coef,(EyeY-0.5)*draw_coef,
          txGround.Width*draw_coef,txGround.Height*draw_coef); }
        for n:=0 to Length(Heroes)-1 do
        if Heroes[n].a then begin
          if not Heroes[n].h then
             DrawHero(Heroes[n].X,Heroes[n].Y-0.5,$222222);
          if M_Distance(Player.X,Player.Y,Heroes[n].X,Heroes[n].Y)<=16 then begin
            guiDrawMemoBorder(sX/2+4,sY-36,sX/2-40,0,200);
            DrawText(sX/2+32,sY-34,'Поговорить с: '#13+Heroes[n].NAme,0.5);
            DrawText(sX/2+12-1*M_Cos(AnswTimer),sY-33-1*M_Cos(AnswTimer),'T',0.8+0.1*M_Cos(AnswTimer),align_left,255,$00FFFF);
            if Key_Down(K_T) then begin
              GameState:=gs_talk;
              HeroId:=n;
              HeroTalk:=Heroes[n].Hello;
            end;
          end;
        end;
        if (AnswTimer>0) and (LastAnswId>=0) then begin
          guiDrawMemoBorder(4,sY-36,sX/2-40,0,200);
          DrawText(32,sY-34,Copy(Memories[LastAnswId].text,1,41)+'...',0.5);
          DrawText(12-1*M_Cos(AnswTimer),sY-33-1*M_Cos(AnswTimer),'E',0.8+0.1*M_Cos(AnswTimer),align_left,255,$00FFFF);
        end;
      end;
    end;
  guiDraw;
  SSprite_Draw(txCursor,Mouse_X-32,Mouse_Y-32,64,64);
end;

procedure GameSlovProcess;
var i,j,x,y: integer;
    b:Boolean;
begin
  case GameState of
    gs_memory:begin
      if Key_Down(K_ESCAPE) then begin
        GameState:=gs_game;
        AnswTimer:=0;
      end;
      if Key_Press(K_S) then begin
        //   SaveStory ;
      end;
    end;
    gs_died:begin
      if ExpCounter>0 then begin
        Dec(ExpCounter);
      end;
    end;
    gs_afex:begin
      if ExpCounter>0 then begin
        Dec(ExpCounter);
        if ExpCounter=0 then begin
          ExpCounter:=200;
          EyeX:=0; EyeY:=0;
          GameState:=gs_died;
        end;
      end;
    end;
    gs_explosion:begin
      if ExpCounter>0 then begin
        Dec(ExpCounter);
        if ExpCounter=0 then begin
          GameState:=gs_afex;

          ExpCounter:=100;
          Media_Play('Data/Sound/choses.mp3', true);
        end;
      end;
    end;
    gs_game:begin
      if ExpCounter>0 then begin
        Dec(ExpCounter);
        if ExpCounter=0 then begin
          Snd_Play(sndExplo);
          ExpCounter:=10;
          GameState:=gs_explosion;
        end;
      end;
      for i:=0 to Length(Anims)-1 do begin
        Inc(Anims[i].SubI);
        if Anims[i].SubI>Anims[i].S then begin
          Anims[i].SubI:=0;
          Inc(Anims[i].Id);
        end;
      end;
      i:=0;
      while i<=Length(Heroes)-1 do begin
        if Heroes[i].a then begin
          if Heroes[i].d=False then begin
            if Ground[Heroes[i].X,Heroes[i].Y+1]=0 then begin
              Snd_Play(sndOo);
              LastAnswId:=18;
              AnswTimer:=answ_time;
              Heroes[i].d:=True;
            end;
          end else begin
            Inc(Heroes[i].Y,2);
            if Ground[Heroes[i].X,Heroes[i].Y+1]=1 then begin
              Heroes[i].a:=False;

            end;
          end;
        end;
        Inc(i);
      end;
      x:=round(Player.X);
      y:=round(Player.Y);
      b:=True;
      for i:=0 to Length(Mems)-1 do begin
        if (Memories[Mems[i].id].answered=False) then begin
          if (Player.X>=Mems[i].X1) and (Player.Y>=Mems[i].Y1) and
             (Player.X<=Mems[i].X2) and (Player.Y<=Mems[i].Y2) then begin
            Memories[Mems[i].id].answered:=True;
            LastAnswId:=Mems[i].id;
            AnswTimer:=answ_time;
            if not Mems[i].b then begin
              PosIn:=i;
              Mems[i].PosInX:=round(Player.X);
              Mems[i].PosInY:=round(Player.Y);
            end;
            if Memories[Mems[i].id].Music<>'' then begin
              LastM:=Memories[Mems[i].id].Music;
              Media_Play(PAnsiChar('Data/Sound/'+LastM),true);
            end;

          end;
        end;
      end;

      if (Key_Down(K_Down) or Key_Down(K_S)) then begin
        if Ground[x,y+1]=0 then begin
          Player.Ysp:=Player.Ysp+map_down
        end else Player.Ysp:=0;
      end;
      if Key_Down(K_E) then begin
        GameState:=gs_memory;
        MemoryTimer:=memory_time;
        _EyeX:=sX div 2-Memories[LastAnswId].X;
        _EyeY:=sY div 2-Memories[LastAnswId].Y;
        pEyeX:=Round(_EyeX);
        pEyeY:=Round(_EyeY);
        SelectedMemory:=LastAnswId;
      end;
      if Key_Down(K_R) and (PosIn>=0) then begin
        GameState:=gs_death;
        DeathTimer:=death_time;
      end;
      if (Player.CanJump=0) and (not Player.InWater) and (Ground[x,y+1]=1) and (Key_Down(K_UP) or Key_Down(K_W)) and (Player.Ysp=0) and (Ground[x,y-hero_h]=0) then begin
        Player.Ysp:=map_jump;
        Player.CanJump:=jump_time;
        Snd_Play(sndHhh);
      end;
      if Player.InWater and (Key_Down(K_UP) or Key_Down(K_W)) then begin
        Player.Ysp:=Player.Ysp-map_down;
      end;
      if Player.CanJump>0 then Dec(Player.CanJump);
      for i:=1 to WaterCCount do begin
        Dec(WaterC[i].Timer);
        if WaterC[i].Timer<=0 then begin
          WaterC[i].Timer:=water_time;
          Inc(WaterDotsCount);
          WaterDots[WaterDotsCount].X:= WaterC[i].X;
          WaterDots[WaterDotsCount].Y:= WaterC[i].Y;
          WaterDots[WaterDotsCount].Ysp:=water_sg;
        end;
      end;
      i:=1;
      while i<=WaterDotsCount do begin
        //if WaterDots[i].Ysp<water_max then
          WaterDots[i].Ysp:=WaterDots[i].Ysp+map_gravity;
        WaterDots[i].Y:=WaterDots[i].Y+WaterDots[i].Ysp;
        b:=False;
        for j:=0 to Length(WRegs)-1 do
        if (WaterDots[i].X>=WRegs[j].X1) and (WaterDots[i].Y>=WRegs[j].Y1) and
         (WaterDots[i].X<=WRegs[j].X2) and (WaterDots[i].Y<=WRegs[j].Y2) then begin
           b:=true;
           inc(WBCount);
           WB[WBCount].X:=WaterDots[i].X*draw_coef;
           WB[WBCount].Y:=WaterDots[i].Y*draw_coef;
           WB[WBCount].Ysp:=Random(100)/200;
           WB[WBCount].Xsp:=(Random(100)-50)/200;
           WB[WBCount].id:=j;
           WB[WBCount].size:=Random(draw_coef div 4)+1;
           Break;
        end;
        if b or (Ground[Round(WaterDots[i].X),round(WaterDots[i].Y)]=1) then begin
          PlaySoundPos(sndPong[Random(4)+1],WaterDots[i].X,WaterDots[i].Y);
          WaterDots[i]:=WaterDots[WaterDotsCount];
          Dec(WaterDotsCount);
          Dec(i);
        end;
        Inc(i);
      end;
    end;
  end;
end;

procedure GameProcess;
var i,x,y,j: integer;
    b:Boolean;
    p:Single;
begin
  case GameState of
    gs_death:begin
      Dec(DeathTimer);
      if DeathTimer<=0 then begin
        GameState:=gs_game;
        Player.X:=Mems[PosIn].PosInX;
        Player.Y:=Mems[PosIn].PosInY;
        Media_Play(PAnsiChar('Data/Sound/'+LastM),true);
        Snd_Play(sndTheGame);
        //Media_Play('Data/Sound/thegame.mp3',false);
      end;
    end;

    gs_memory:begin
      if MemoryTimer>0 then begin
        Dec(MemoryTimer);
      end;
      if M_Distance(pEyeX,pEyeY,_EyeX,_EyeY)>4 then begin
        i:=M_FindAngle(Round(pEyeX),Round(pEyeY),_EyeX,_EyeY);
        pEyeX:=pEyeX-round(M_Cos(i)*4);
        pEyeY:=pEyeY-round(M_Sin(i)*4);
      end;
      if Mouse_X<=0 then Inc(_EyeX,4);
      if Mouse_Y<=0 then Inc(_EyeY,4);
      if Mouse_X>=sX-1 then Dec(_EyeX,4);
      if Mouse_Y>=sY-1 then Dec(_EyeY,4);
    end;
    gs_logos:begin
      Inc(LogoTime);
      if LogoTime>Logos[LogoId].t then begin
        LogoTime:=0;
        Inc(LogoId);
        if LogoId>=logos_count then begin
          GameState:=gs_game;
          Randomize;
        end else begin
          if Logos[LogoId].m<>'' then
            Media_Play(PAnsiChar('Data/Sound/'+Logos[LogoId].m),False);
        end;
      end;
    end;
    gs_game:begin
      x:=-round(Player.X)+(sX div draw_coef) div 2;
      y:=-round(Player.Y)+(sY div draw_coef) div 2;
      j:=Round(M_Distance(EyeX,EyeY,X,Y));
      if j>4 then begin
        if j>8 then p:=1 else p:=0.25;
        i:=M_FindAngle(Round(EyeX),Round(EyeY),X,Y);
        EyeX:=EyeX-M_Cos(i)*p;
        EyeY:=EyeY-M_Sin(i)*p;
      end;
      Player.X:=Player.X+Player.Xsp;
      Player.Y:=Player.Y+Player.Ysp;
      x:=round(Player.X);
      y:=round(Player.Y);
      if (boolOo=False) and (Player.Ysp>death_fly) then begin
        boolOo:=True;
        Snd_Play(sndOo,0,VOLUME(100));
      end;
      i:=1;
      while i<=WBCount do begin
        WB[i].Ysp:=WB[i].Ysp+water_gravity;
        WB[i].Y:=WB[i].Y+WB[i].Ysp;
        WB[i].X:=WB[i].X+WB[i].Xsp;
        if WB[i].Y<=WRegs[WB[i].id].Y1*draw_coef then begin
          WB[i]:=WB[WBCount];
          Dec(WBCount);
          Dec(i);
        end;
        inc(i);
      end;
      b:=False;
      for i:=0 to Length(WRegs)-1 do
        if (Player.X>=WRegs[i].X1) and (Player.Y>=WRegs[i].Y1) and
             (Player.X<=WRegs[i].X2) and (Player.Y<=WRegs[i].Y2) then begin
               b:=true;
               LastJ:=i;
               Break;
             end;

      if b<>Player.InWater then begin
        Player.InWater:=b;
        Snd_Play(sndWater);
        if Player.InWater then begin
          Snd_Play(sndInWater,0,0,0,true);
          Snd_ChangeParam(sndEfforts,0,0,VOLUME(0),0);
          Tex_Filter(txGround,TEX_FILTER_TRILINEAR);
          Tex_Filter(txGroundBack,TEX_FILTER_TRILINEAR);

        end else begin
          if WaterCounter>=water_livetime div 2 then
            Snd_Play(sndEfforts);
          WaterCounter:=0;

          Snd_Stop(sndInWater);
          Tex_Filter(txGround,TEX_FILTER_NEAREST);
          Tex_Filter(txGroundBack,TEX_FILTER_NEAREST);
        end;
        for i:=1 to 10 do begin
          inc(WBCount);
          WB[WBCount].X:=Player.X*draw_coef;
          WB[WBCount].Y:=(Player.Y+1)*draw_coef;
          WB[WBCount].Ysp:=Random(100)/200;
          WB[WBCount].Xsp:=(Random(100)-50)/200;
          WB[WBCount].id:=LastJ;
          WB[WBCount].size:=Random(draw_coef div 4)+1;
        end;
      end;
      if Player.InWater then begin
        if Player.Y>=WRegs[LastJ].Y1+hero_h then
          Player.Ysp:=Player.Ysp+water_gravity else
        Player.Ysp:=Player.Ysp/1.01;
        Inc(WaterCounter);

        if (WaterCounter mod water_dow = 0) and (WaterCounter>=water_livetime div 2) then begin
          Snd_Play(sndDow);
        end;
        if (WaterCounter mod water_boubles = 0) then begin
          inc(WBCount);
          WB[WBCount].X:=Player.X*draw_coef;
          WB[WBCount].Y:=(Player.Y-hero_h)*draw_coef;
          WB[WBCount].Ysp:=0;
          WB[WBCount].Xsp:=0;
          WB[WBCount].id:=LastJ;
          WB[WBCount].size:=Random(draw_coef div 4)+1;
        end;
        if WaterCounter>=water_livetime then begin
          WaterCounter:=0;
          Snd_Stop(sndInWater);
          Player.InWater:=false;
          GameState:=gs_death;
          DeathTimer:=death_time;
          Snd_Play(sndDeath);
          Snd_Stop(sndInWater);
          Player.InWater:=False;
          Tex_Filter(txGround,TEX_FILTER_NEAREST);
          Tex_Filter(txGroundBack,TEX_FILTER_NEAREST);
          Media_Stop;
        end;
      end;
      b:=True;
      for i:=1 to hero_h-1 do begin
        if Ground[x-1,y-i]=1 then b:=False;
      end;
      if (Key_Down(K_Left) or Key_Down(K_A)) and (b) then begin
        Player.X:=Player.X-go_speed;
        x:=round(Player.X);
        if (Ground[x,y]=1) and b then Player.Y:=Player.Y-1;
      end;
      b:=True;
      for i:=1 to hero_h-1 do begin
        if Ground[x+1,y-i]=1 then b:=False;
      end;
      if (Key_Down(K_Right) or Key_Down(K_D)) and (b) then begin
        Player.X:=Player.X+go_speed;
        x:=round(Player.X);
        if (Ground[x,y]=1) and b then Player.Y:=Player.Y-1;
      end;
      if Ground[x,y+1]=1 then begin
        if Player.Ysp>0 then begin
          if (Player.Ysp>jump_fly) and (Player.Ysp<death_fly) then begin
            Snd_Play(sndJump);
          end;
          if Player.Ysp>death_fly then begin
            GameState:=gs_death;
            DeathTimer:=death_time;
            Snd_Play(sndDeath);
            if Player.InWater then begin
              Snd_Stop(sndInWater);
              Tex_Filter(txGround,TEX_FILTER_NEAREST);
              Tex_Filter(txGroundBack,TEX_FILTER_NEAREST);
              Player.InWater:=False;
            end;
            Snd_ChangeParam(sndOo,0,0,VOLUME(0),0);
            boolOo:=False;
            Media_Stop;
          end;
          Player.Ysp:=0;
        end;
      end else begin
        if Player.InWater=False then
          Player.Ysp:=Player.Ysp+map_gravity;
      end;
      if Ground[x,y-hero_h+1]=1 then begin
        if Player.Ysp<0 then begin
          Player.Ysp:=0;
        end;
      end;
      if AnswTimer>0 then begin
        dec(AnswTimer);
      end;
      if Player.Ysp>1 then Player.Ysp:=1;
      if Player.Ysp<-1 then Player.Ysp:=-1;
    end;
  end;
  if (GameState in [gs_logos]) and Key_Press(K_ESCAPE) then OE_Quit;
  guiProcess;
end;

end.

