{
    This file is part of Chentrah,
    Copyright (C) 2004-2008 Anton Rzheshevski (chebmaster@mail.ru).

    This program is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see http://www.gnu.org/licenses/

 ********************************************************************** 

   This file contains the graphical console class implementation.

 **********************************************************************}


 { TConsole }

 procedure TConsole.Fade();
 begin
   f_vis:=False;
   if not(Assigned(Module) and (Module.BimLoaded))
     then f_lasttime:=Now()
     else f_lasttime:=Now() - 1; //1 day ago ;)
 end;

 procedure TConsole._SetVisible(b: boolean);
 begin
   if not b then f_sb:=0;
   if b = f_vis then exit;
   f_vis:=b;
  // f_lasttime:=Now();
 end;

 constructor TConsole.Create;
 begin
   inherited Create;
   f_Limit:=1000;
   f_vis:= MotherState.DeveloperMode or MotherState.DebugMode;
   Add('*');
 end;
 
 procedure TConsole.SetDefaultBg (bg: TDefaultBGs);
 begin
   //SetBg(BaseImagesPath + DefaultBgNames[bg, GetIsRussian()]);
   if MotherState.InstallPath = ''
     then begin
       SetBgPtr(@error_bg_img, sizeof(error_bg_img));
       _CgeErrorCursor;
     end
     else
       Case bg of
         dbTitle: begin
           SetBg(MotherState.InstallPath + ImagesDir + 'cl_background_default.jpg');
           CgeStandardCursor;
         end;
         dbError: begin
           SetBg(MotherState.InstallPath + ImagesDir + 'cl_background_error.jpg');
           _CgeErrorCursor;
         end;
         dbWarning: begin
           SetBg(MotherState.InstallPath + ImagesDir + 'cl_background_warning.jpg');
           CgeStandardCursor;
         end;
         dbInstalling: begin
           SetBg(MotherState.InstallPath + ImagesDir + 'cl_background_default.jpg');
           CgeHourglassCursor;
         end;
         dbShutdown: begin
           SetBg(MotherState.InstallPath + ImagesDir +'shutdown.jpg');
           CgeHourglassCursor;
         end;
       else
         Die(MI_ERROR_PROGRAMMER_NO_BAKA, ['FIXME: unknown constant ' + GetEnumName(typeinfo(TDefaultBgs), ord(bg)) + ' in TConsole.SetDefaultBg()']);
       end;
 end;
 
 
  procedure ResampleImg (var i: TImageData; newwidth, newheight: integer);
  var
    i2: TImageData;
  begin
    NewImage(newwidth, newheight, i.Format, i2);
    StretchResample(i, 0, 0, i.Width, i.Height, i2, 0, 0, i2.Width, i2.Height,
      CGE_RESAMPLE_FILTER, No);
    FreeImage(i);
    i:=i2;
  end;


 procedure TConsole._ApplyBg(var b: TImageData);
 var
   w, h: integer;
 begin
   if f_bgtex <> 0 then glDeleteTextures(1, @f_bgtex);
   glGenTextures(1, @f_bgtex);
   glBindTexture(GL_TEXTURE_2D, f_bgtex);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   if b.Format <> ifR8G8B8 then ConvertImage(b, ifR8G8B8);
   w:= GetHigherPowerOf2(b.Width) shr f_bgmip;
   h:= GetHigherPowerOf2(b.Height) shr f_bgmip;
//AddLog('%0', [f_bgmip]);
   if (b.Width <> w) or (b.Height <> h)
     then ResampleImg(b, w, h);
   glTexImage2D (GL_TEXTURE_2D, 0, GL_RGB, w, h, 0, GL_BGR, GL_UNSIGNED_BYTE, b.Bits);
   FreeImage(b);
 end;


 procedure TConsole.SetBg (name: string);
 var
   b: TImageData;
 begin
   if (name = f_bgname) and (f_bgmip = _RequiredBgmip()) then exit;
   try
     fillchar(b, sizeof(b), 0);
     f_bgname:=CgePath(name);
     f_bgmip:= _RequiredBgmip();
     LoadImageFromFile(f_bgname, b);
     _ApplyBg(b);
   except end;
   f_bgptr:= nil;
 end;

 function TConsole._RequiredBgmip(): integer;
  //with high QF, background will be oversized even for small window sizes
  // with low 1f, background will be low-res
 var
   wr, hr : integer;
   delta: float;
 begin
   Result:= 0;
   //assumed background image size is 2048x1024
{
   FUCK THIS!

   wr:= 2048 shr f_bgmip;
   hr:= 1024 shr f_bgmip;
   with MotherState
     do delta:= math.min(DisplayWidth / wr , DisplayHeight / hr ) * (QF / 100);
   if delta > 0.9 then Result:= math.max(0, f_bgmip - 1);
   if delta < (0.9 / 2.6) then Result:= math.min(3, f_bgmip + 1);
}
 end;

 procedure TConsole.SetBgPtr (p: pointer; size: integer);
 var
   b: TImageData;
 begin
   if p = f_bgptr then exit;
   try
     LoadImageFromMemory(p, size, b);
     _ApplyBg(b);
   except end;
   f_bgname:='';
 end;


 procedure TConsole.InitGL;
 var
   name: integer;
   p: pointer;
   i: TImageData;
   x, y: integer;
   file_name: string = 'consolefont.png';

 begin
   Try
     f_limit:=Config.IntChk['console','MaxLines',150,10000];
     f_hidetime:=Config['console','MessageDisplayTime'];
     f_fadetime:=Config['console','MessageFadeOutTime'];
     if f_hidetime = 0 then f_hidetime:=1; //division by zero is bad
     if f_fadetime = 0 then f_fadetime:=1;
     f_tostretch:= Config.IntChk['console','DoubleSizeIfResolutionHighetThan', 1024, 2048];
     ConsoleUseCondensedFont:= Config.Bool['console', 'UseCondensedFont'];
     if ConsoleUseCondensedFont then file_name:= 'consolefont-half.png';
     glGenTextures(1, @f_texture);
     glBindTexture(GL_TEXTURE_2D, f_texture);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
     if (MotherState.InstallPath = '') or not FileExists(MotherState.InstallPath + ImagesDir + file_name)
     then begin
       fillchar(i, sizeof(i), 0);
       LoadImageFromMemory(@iim_console[0], sizeof(iim_console), i);
       ConvertImage(i, ifA8Gray8);

       //create a shadow:
       for x:=0 to 254 do
         for y:= 32 to 254 do
           byte((i.bits + x*2 + 3 + (y + 1)*512)^):=
             byte((i.bits + x*2 + y*512)^) or byte((i.bits + x*2 + 2 + (y + 1)*512)^);

       glTexImage2D (GL_TEXTURE_2D, 0, GL_RGBA, i.Width, i.height, 0, GL_LUMINANCE_ALPHA, GL_UNSIGNED_BYTE, i.bits);
     end
     else begin
       if ConsoleUseCondensedFont then begin
         ConsoleCharWidth:= 4;
         ConsoleCharXstep:= 128 div 16;
         ConsoleImageWidth:= 128;
         ConsoleCharOffsetS:= 2;
       end;
       p:=LoadPic(PChar(MotherState.InstallPath + ImagesDir + file_name));
       CheckForGuardedException;
       glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE_ALPHA{GL_RGBA}, GetPicWidth(p), GetPicHeight(p), 0, GetPicFmt(p), GL_UNSIGNED_BYTE, GetPicPixels(p));
       DeletePic(p);
       CheckForGuardedException;
     end;

     if MotherState.InstallPath <> '' then begin
       p:= LoadPic(PChar(MotherState.InstallPath + ImagesDir + 'bsod.jpg'));
       CheckForGuardedException;
       glGenTextures(1, @f_bsodtexture);
       glBindTexture(GL_TEXTURE_2D, f_bsodtexture);
       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, GetPicWidth(p), GetPicHeight(p), 0, GetPicFmt(p), GL_UNSIGNED_BYTE, GetPicPixels(p));
       CheckForGuardedException;
       DeletePic(p);
       CheckForGuardedException;
     end;
     glGenTextures(1, @f_noisetexture);

     SetDefaultBg(dbTitle);

     InitAnimatedLogo;

   Except
     Die(MI_DIED_INITIALIZING, [RuEn('консоли','console')]);
   End;
 end;
 
 procedure SetGlStates2d;
 begin
   SwitchToFixedPipeline;
   glEnable(GL_TEXTURE_2D);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
   glEnable(GL_ALPHA_TEST);
   glEnable(GL_BLEND);
   glDisable(GL_SCISSOR_TEST);
   glAlphaFunc(GL_GREATER, 0);
   glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
   glDisable(GL_CULL_FACE);
   glDisable(GL_DEPTH_TEST);
   glDepthMask(GL_TRUE);
   glViewport(0, 0, MotherState.DisplayWidth, MotherState.DisplayHeight);
   glMatrixMode(GL_PROJECTION);
   glLoadIdentity();
   glMatrixMode(GL_MODELVIEW);
   glLoadIdentity();
   //origin in the upper left corner!
   glOrtho(0, MotherState.DisplayWidth, MotherState.DisplayHeight, 0, 0 ,1);
//   gluOrtho2d(0, WindowManager.DisplayWidth, 0, WindowManager.DisplayHeight);
 end;



 function CCLd(a: glFloat; b: integer): glFloat;
 begin
   Case b of
     1: if a < 0 then Result:=1.0 else Result:=sqr(1.0 - a);
     2: if a < 0 then Result:=1.0 else Result:=sqr(1.0 - a);
     3: if a < 0
          then Result:=1.0
          else
            if a < 1.0 then Result:=sqrt(1.0 - a)
                       else Result:=0;
     4: if a < 0 then Result:=1.0 else Result:=(1.0 - a);
   end;
 end;

   function SLines(s:string; _m: integer): integer;
   begin
     Result:=1 + ((Length(s) - 1) div (_m - 1));
   end;

 procedure randoby(var b: byte); inline;
 var c: integer;
 begin
   c:=Random(101) - 50;
   if (integer (b) + c < 0) or (integer(b) + c > 255)
     then dec(b, c)
     else inc(b, c);
 end;

 procedure TConsole.Draw(Clearbackground, DrawBg: boolean);
 var
   zoom, bsodvoffs: glFloat;
   cuE, y0, lCo, rdh, c, ymax, xmax, Sdh, Swd,  cc, x, y, zms: integer;
   xp, yp, ts, tt, liT: glFloat;
   ntdx, ntdy: glFloat;
 begin
   zms:= Round((Now() - f_lasttime) * 86400000.0);
   WindowManager.UpdateWindowSize;
   SetGlStates2d;

   LastHeartbeatMoment:=Now();
   If not (Clearbackground
           or f_vis
           or (zms < (f_hidetime + f_fadetime))
           or DrawBg)
   then begin
     f_fadeline:= -1;
     f_fade:= 1.0;
     Exit;
   end;
   if ClearBackground or DrawBg then begin
//     f_vis:=Yes;
//     WindowManager.UpdateWindowSize;
   end;
   if ClearBackground then f_vis:=Yes;
   
   if f_sb < 0 then f_sb:=0;
   if not f_vis then f_sb:=0;

   {---------------- RENDER THE BLUE SCREEN OF DEATH ------------------}
   If Clearbackground then begin //Big red banner "no modules loaded"
     f_fade:= 1.0;
     glColor3f(0, 0, MotherState.FadeIn);
     if MessageContainer.CurrentLanguage = 0
     { Russian has hard-coded index 0, English - 1.
       One half of the texture is Russian "blue screen of death",
         another half is Latin "BSOD"}
       then bsodvoffs:= 0.5
       else bsodvoffs:= 0;
     glBindTexture(GL_TEXTURE_2D, f_bsodtexture);
     glBegin(GL_QUADS);
       glTexCoord2f(0, 0.5 + bsodvoffs);
       glVertex2f(0, MotherState.DisplayHeight); //bottom left corner
       glTexCoord2f(0, 0 + bsodvoffs);
       glVertex2f(0, 0);
       glTexCoord2f(1, 0 + bsodvoffs);
       glVertex2f(MotherState.DisplayWidth, 0);
       glTexCoord2f(1, 0.5 + bsodvoffs);
       glVertex2f(MotherState.DisplayWidth, MotherState.DisplayHeight);
     glEnd;


     glBindTexture(GL_TEXTURE_2D, f_noisetexture);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
     glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

    //procedural noise texture
     for y:=0 to (ntz div 4) - 1 do
       for x:=0 to ntz - 1 do
         f_noisearray[y,x]:= random(256);
        // randoby(f_noisearray[x, y]);
     ntdx:= 0;
     ntdy:= random();
     glTexImage2D (GL_TEXTURE_2D, 0, GL_LUMINANCE, ntz, ntz div 4, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, @f_noisearray[0,0]);
     glNormal3f( 0.0, 0.0, 1.0);
    // glColor3f(0.5, 0.5, 0.35 + 0.35 * sin(Now * 100000.0) / 2);
     glColor4f(1 * MotherState.FadeIn, 1 * MotherState.FadeIn, 1 * MotherState.FadeIn, 0.3);
     glBegin(GL_QUADS);
       glTexCoord2f(0 + ntdx, 5 + ntdy);
       glVertex2f(0, 0); //bottom left corner
       glTexCoord2f(0 + ntdx, 0 + ntdy);
       glVertex2f(0, MotherState.DisplayHeight);
       glTexCoord2f(1 + ntdx, 0 + ntdy);
       glVertex2f(MotherState.DisplayWidth, MotherState.DisplayHeight);
       glTexCoord2f(1 + ntdx, 5 + ntdy);
       glVertex2f(MotherState.DisplayWidth, 0);
     glEnd;

   end
   {----------------------- end BSOD ---------------------------------------}
   else
     if DrawBg then DrawBackground
               else begin
                 f_fade:= 1.0;
                 SetGlStates2d;
               end;

   glBindTexture(GL_TEXTURE_2D, f_texture);
   zoom:=1.0;
   Sdh:=MotherState.DisplayHeight;
   Rdh:=Sdh;
   Swd:=MotherState.DisplayWidth;

   if MotherState.DisplayWidth > f_tostretch then zoom:=2.0;// WindowManager.DisplayWidth / f_tostretch;
   xmax :=Trunc( ( (MotherState.DisplayWidth / zoom) - 2 * ConsoleBorders) / ConsoleCharWidth);
   ymax :=Trunc( ( (MotherState.DisplayHeight / zoom) - 2 * ConsoleBorders) / ConsoleCharHeight);
//VerboseLog ('xmax=%0, ymax=%1, zoom=%2', [xmax, ymax, zoom]);
   
   if zoom <> 1.0 then begin
     Sdh:=trunc (Sdh / zoom);
     Swd:=trunc (Swd/ zoom);
   end;

   cuE:=Count - 1;
   lCo:=-f_sb;
   while (cuE >= 0)
     and (f_vis or (cuE >= (f_fadeline - 1)))
     and (lCo < ymax)
   do begin
      inc(lCo, SLines(Self.Strings[cuE], xmax));
      dec(cuE);
   end;
   //if CuE < 0 then CuE:=0;
//VerboseLog('cuE=%0, lCo=%1', [cuE, lCo]);
   
   if lCo = 0 then Exit;
   
   if lCo > (ymax{ + f_sb}) then y0:= ymax{ + f_sb} - lCo else y0:=0;

   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
   glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);

   y:=y0;
   while (cuE < Count - 1) and (y <= ymax) do begin
     x:=0;
     c:=1;
     inc (cuE);

     if f_vis then liT:=0
     else begin
       if zms < f_hidetime then liT:= - (f_hidetime - zms) / f_hidetime
                           else liT:=(zms - f_hidetime) / f_fadetime;
     end;
     glColor4f(CCLd(liT, 1), CCLd(liT, 2), CCLd(liT, 3), CCLd(liT, 4) * MotherState.FadeIn);
     
     While c < (Length(Self.Strings[cuE]) - 1) do begin
       if y > 0 then begin
         //draw character;
         xp:=(ConsoleBorders + (x * ConsoleCharWidth)) * zoom;
         yp:=(ConsoleBorders + (y * ConsoleCharHeight)) * zoom;
         cc:=Ord(Self.Strings[cuE][c]);
         if cc >=32 then begin //ignore special characters
           ts:=((cc mod 16) * ConsoleCharXstep + ConsoleCharOffsetS) / ConsoleImageWidth;
           tt:=((cc div 16) * 16 + ConsoleCharOffsetT) / 256.0;
//VerboseLog(chr(c));
           glBegin(GL_QUADS);
             glTexCoord2f(ts, tt); //top left
             glVertex2f(xp, MotherState.DisplayHeight - (Rdh - yp));
             glTexCoord2f(ts + (ConsoleCharWidth + 1) / ConsoleImageWidth, tt); //top right
             glVertex2f(xp + (ConsoleCharWidth + 1) * zoom, MotherState.DisplayHeight - (Rdh - yp));
             glTexCoord2f(ts + (ConsoleCharWidth + 1) / ConsoleImageWidth, tt + ConsoleCharHeight / 256.0); //bottom right
             glVertex2f(xp + (ConsoleCharWidth + 1) * zoom, MotherState.DisplayHeight - (Rdh - yp - ConsoleCharHeight * zoom));
             glTexCoord2f(ts, tt + ConsoleCharHeight / 256.0); //bottom left
             glVertex2f(xp, MotherState.DisplayHeight - (Rdh - yp - ConsoleCharHeight * zoom));
           glEnd;
         end;
       end;
       inc (c);
       inc (x);
       if x > xmax then begin
         x:=1;
         inc(y);
       end;
     end;
     inc (y);
   end;

   
 end;
 
 procedure TConsole.DrawBackground();
 var f: glFloat;
 begin
   if f_bgmip <> _RequiredBgmip() then SetBg(f_bgname);
   SetGlStates2d;
   glDisable(GL_ALPHA_TEST);
   glDisable(GL_BLEND);
   f:=f_fade;
   glColor4f(f * MotherState.FadeIn, f * MotherState.FadeIn, f * MotherState.FadeIn, 1);
   glBindTexture(GL_TEXTURE_2D, f_bgtex);
   glBegin(GL_QUADS);
     glTexCoord2f(0, 0);
     glVertex2f(0, 0); //bottom left corner
     glTexCoord2f(0, 1);
     glVertex2f(0, MotherState.DisplayHeight);
     glTexCoord2f(1, 1);
     glVertex2f(MotherState.DisplayWidth, MotherState.DisplayHeight);
     glTexCoord2f(1, 0);
     glVertex2f(MotherState.DisplayWidth, 0);
   glEnd;
   glEnable(GL_ALPHA_TEST);
   glEnable(GL_BLEND);
 end;
 
 procedure TConsole.SetFadeIn(f: GLfloat);
 begin
   f_fade:=f;
 end;

 procedure TConsole.DrawLogo();
 var
   f: integer;
   s, a, n: glFloat;
   cx, cy: glFloat;
   phase, animphase: glFloat;
 begin
   phase:= (Now() - MotherState.LogoAnimationStart) * SecondsPerDay / LOGO_ANIMATION_LENGTH;
   if phase > 1.0 then MotherState.LogoAnimationPlaying:= No;
   if not MotherState.LogoAnimationPlaying then Exit;

   animphase:= (phase - logo_fadein) / (1.0 - logo_fadeout - logo_fadein);
   f:= round(animphase * length(f_logotex));
   f:= min (f,  high(f_logotex));
   f:= max (0, f);

   if phase < logo_fadein then begin
     //fade in
     n:= max(0.0, 1 - (phase / logo_fadein));
     s:= logo_size + 3500.0 * n;
     a:= sqr(sqr( 1 - n));
   end
   else
     if phase < (1.0 - logo_fadeout) then begin
       //animate
       s:=logo_size;
       a:=1;
     end
     else begin
       //fade out
       s:= logo_size;
       a:= sqr((1.0 - phase) / logo_fadeout);
     end;

   SetGlStates2d;

   glColor4f(a*2, a*3, 1, sqr(a));
//   glBlendFunc(GL_DST_COLOR, GL_SRC_COLOR);
   s:=s/2;
   cx:= Trunc(MotherState.DisplayWidth /2);
   cy:= Trunc(MotherState.DisplayHeight /2);
   if Assigned(f_logotex) then begin
     glEnable(GL_TEXTURE_2D);
     glBindTexture(GL_TEXTURE_2D, f_logotex[high(f_logotex) - f]);
     glBegin(GL_QUADS);
       glTexCoord2f(0, 1);
       glVertex2f(cx - s, cy + s); //bottom left corner
       glTexCoord2f(0, 0);
       glVertex2f(cx - s, cy - s);
       glTexCoord2f(1, 0);
       glVertex2f(cx + s, cy - s);
       glTexCoord2f(1, 1);
       glVertex2f(cx + s, cy + s);
     glEnd;
   end;
 end;

 
 procedure TConsole.InitAnimatedLogo;
 var
   i: integer;
   logo: TDynImageDataArray;
   f: string;
   {$ifdef win32} msg:TMSG;{$endif}
 begin
   if NowRestarting or (MotherState.InstallPath = '') then Exit;
   Try
     LoadMultiImageFromFile(MotherState.InstallPath + ImagesDir + 'chentrah-logo.mng', logo);
     
     SetLength(f_logotex, Length(logo));
//addlog('==== %0 logo frames',[length(logo)]);
     glEnable(GL_TEXTURE_2D);
     glGenTextures(length(logo), @f_logotex[0]);
     For i:=0 to high(logo) do begin
       if logo[i].Format <> ifGray8 then ConvertImage(logo[i], ifGray8);
       glBindTexture(GL_TEXTURE_2D, f_logotex[i]);
       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
       glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
       glTexImage2D (GL_TEXTURE_2D, 0, GL_ALPHA, 256, 256, 0, GL_ALPHA, GL_UNSIGNED_BYTE, logo[i].Bits);
     end;
     FreeImagesInArray(logo);
   except
     AddLog(RuEn('Не удалось загрузить логотип!'#10#13'%0','Unable to load the logo!'#10#13'%0'), [StopDying()])
   end;
 end;

 procedure TConsole.Add(s: AnsiString);
 var
   i: integer;
 begin
   //recursion. Scary.
   i:=Pos(#13, s);
   if (i > 0) and (i < Length(s)) then begin
     if i <= 2 then s:= Copy(s, i + 1, Length(s) - i)
     else begin
       s[i]:=#0;//don't draw it
       Add(Copy(s, 1, i));
       Add(Copy(s, i, Length(s) - i + 1));
       Exit;
     end;
   end;
   if (s <> '') and (s[1]<>#0) then s:=#127 + s;
   inherited Add(s);
   if f_fadeline < 0 then f_fadeline:=Count - 1;
   if Count > f_limit then begin
     if f_fadeline > 0 then dec(f_fadeline);
     Delete(0);
   end;
     if (Assigned(Module) and (Module.BimLoaded))
      or not (MotherState.DeveloperMode or MotherState.DebugMode)
       then f_lasttime:=Now() - 1 //a day ago
       else f_lasttime:=Now();
 end;
 
 procedure TConsole.AddComment(S: AnsiString);
 var
   i: integer;
 begin
   if Count = 0 then Add(S)
   else begin
     i:=Pos(#13, s);
     if (i > 0) and (i < Length(s)) then begin
       s[i]:=#0;//don't draw it
       if i <= 2
       then Add(Copy(s, i + 1, Length(s) - i))
       else begin
         AddComment(Copy(s, 1, i));
         Add(Copy(s, i, Length(s) - i + 1));
       end;
       Exit;
     end;
     Strings[Count - 1] := Strings[Count - 1] + S;
     if (Assigned(Module) and (Module.BimLoaded))
      or not (MotherState.DeveloperMode or MotherState.DebugMode)
       then f_lasttime:=Now() - 1 //a day ago
       else f_lasttime:=Now();
   end;
 end;

 procedure TConsole.Delete(i: integer);
 begin
   inherited Delete(i);
 end;

