Wing Commander 1, in Russian?

UnnamedCharacter

2nd Lieutenant
Has anyone seen this?

rus-ship1.png
rus2.png
rus3.png


By the way, this is not new, it's possibly quite old. I have seen an online reference to the Russian version of the game dating back to 2004, and the translated data files are timestamped as 1992.

A tiny sample of dialog in English:

Code:
Dialog  0: Bonjour, Lieutenant. You are called $C, no? I am called Angel.               | banzurlutanant3yuarcalddipstik2no2p8iamcaldanjl         | RA45,81,01,A35,81,01,A50,81,02,
Dialog  1: I am just reviewing some figures on our recent encounters with the Kilrathi. | iamjasrevuagsamfagursanowrresantankowntrswatzekalrate   | RA45,81,01,A35,81,01,A50,81,02,
Dialog  2: You would like to know what I have learned, perhaps?                         | yuwadliktunowatihavlrndprhaps                           | RA45,81,01,A35,81,01,A50,81,02,
Dialog  3: The Dralthi is the Kilrathi fighter seen most in this sector.                | tedralteastekalratefitrsenmosantassaktr                 | 425,R81,02,A45,81,01,A35,81,01,A50,
Dialog  4: These figures show that 1.4 missiles are required to destroy the Dralthi,    | tesfagurssotatwanpuntformaslsarrekwirdtudestroetedralte | R445,81,01,435,81,01,A50,81,02,
Dialog  5: while over seven direct laser hits are necessary to destroy the same vessel. | wilovrsavndiraklasrhatsarnasasaretudestrosamvasl        | R445,81,01,435,81,01,A50,81,02,
Dialog  6: I hope this information is useful to you, Lieutenant.                        | ihoptisanformasanasusfltuyu3lutanant                    | RA45,81,01,A35,81,01,A50,81,02,
And in Russian:

Code:
Dialog  0: Bonjour, лейтенант. Вас зовут $C, или нет ? Меня зовут Ангел.                | banzurlutanant3yuarcalddipstik2no2p8iamcaldanjl         | RA45,81,01,A35,81,01,A50,81,02,
Dialog  1: Я просматриваю схемы наших недавних столкновений с Кильрафи.                 | iamjasrevuagsamfagursanowrresantankowntrswatzekalrate   | RA45,81,01,A35,81,01,A50,81,02,
Dialog  2: Возможно, Вам будет интересно, чему я научилась ?                            | yuwadliktunowatihavlrndprhaps                           | RA45,81,01,A35,81,01,A50,81,02,
Dialog  3: В этом секторе больше всего замечено Dralthi.                                | tedralteastekalratefitrsenmosantassaktr                 | 425,R81,02,A45,81,01,A35,81,01,A50,
Dialog  4: Эти схемы показывают, что 1.4 ракеты разрушают Dralthi,                      | tesfagurssotatwanpuntformaslsarrekwirdtudestroetedralte | R445,81,01,435,81,01,A50,81,02,
Dialog  5: в то время как плазменными пушками необходимо семь прямых попаданий.         | wilovrsavndiraklasrhatsarnasasaretudestrosamvasl        | R445,81,01,435,81,01,A50,81,02,
Dialog  6: Я надеюсь, что эта информация поможет Вам, лейтенант.                        | ihoptisanformasanasusfltuyu3lutanant                    | RA45,81,01,A35,81,01,A50,81,02,
The fonts:

FONTS-ENG.png

FONTS-RUS.png


Using the above font file as an example of the work involved in doing this: they unpacked the data file, decompressed the individual packets, decoded the font, added Russian glyphs, re-encoded the font, re-compressed the packets, and re-packed the file. And according the file stamps, they did this in 1992. Wow. Whoever did this was years, decades ahead.
 

Jabberwocker

Spaceman
font editor source code (Turbo Pascal):
Code:
{.$DEFINE ALLCHARS}
{.$DEFINE CAPSONLY}
Var
    Scrn    : array [0..199,0..319] of byte absolute $A000:0000;
    palette : array [0.. $2FF] of byte;
    CurChar : byte;
    CurColor: byte;
    CurClrNo: byte;

Const
    Scale   = 5;
    LoX     = 100;
    LoY     = 100-8*Scale;

    X_Color = 5;
    Y_Color = 180;
    Xs_Clr  = 5;
    Ys_Clr  = 10;
    Xi_Clr  = 10;
    Yi_Clr  = 0;

    ColorLim= 32;
    BoxColor= 80;

    LeftOfs = 5;
    UpOfs   = 5;
    Y_il    = 13;
    X_il    = 16;
{$IFDEF  ALLCHARS}
    MaxRow  = 13;
    Rows    : array [0..MaxRow] of byte = (  $20, $30,
                                   $40, $50, $60, $70,
                                   $80, $90, $A0, $B0,
                                   $C0, $D0, $E0, $F0 );
{$ELSE}
  {$IFDEF CAPSONLY}
    MaxRow  = 5;
    Rows    : array [0..MaxRow] of byte = (  $20, $30,
                                             $40, $50,
                                             $80, $90 );
  {$ELSE}
    MaxRow  = 9;
    Rows    : array [0..MaxRow] of byte = (  $20, $30,
                                   $40, $50, $60, $70,
                                   $80, $90, $A0, $E0 );
  {$ENDIF}
{$ENDIF}

Type
    ba = array [0..60000]    of byte;
    sm = array [0..15,0..15] of byte;

Var
    f         : file;
    q         : longint;
    p         : array [0..255] of ^sm;
    w         : array [0..255] of byte;
    Colors    : array [0..ColorLim] of byte;
    MaxColors : word;
    b         : ^ba;
    h         : byte;
    d         : byte;
    g         : byte;
    i, j, k, t: word;
    s         : string;
    row, col  : byte;
    TempChar  : sm;
    ClipChar  : sm;
    TempW     : byte;
    ClipW     : byte;

function GetKey: word; assembler;
asm
  xor  ax, ax
  int  $16
end;

procedure LoadFont;
begin
  if ParamCount = 1 then
    s := ParamStr(1)
  else begin
    Write('File to edit:'); ReadLn(s);
    if s[0] = #0 then Halt(1);
  end;
  Assign(f,s);
  ReSet(f,1);
  q := FileSize(f);
  GetMem(b, q);
  BlockRead(f,b^,q);
  Close(f);
  (*------------------------------*)
  h := b^[0];
  d := b^[2];
  g := b^[3];
  Move(b^[4],w,256);
  for i := 0 to 255 do begin
    GetMem( p[i],SizeOf(sm) );
    FillChar( p[i]^, SizeOf(sm), g );
    t := b^[i+$104] + b^[i+$204]*256;
    if i <> 32 then
      for j := 0 to h-1 do
        Move( b^[t+j*w[i]], p[i]^[j,0], w[i] )
    else
      w[32] := 4;
  end;
  FreeMem(b,q);
  (*------------------------------*)
  MaxColors := 1;
  Colors[0] := g;
  Colors[1] := d;
  for i := 0 to 255 do
    for j := 0 to h do
      for k := 0 to w[i] do begin
        t := 0;
        while (t <= MaxColors) and (Colors[t] <> p[i]^[j,k]) do Inc(t);
        if t > MaxColors then begin
          if MaxColors >= ColorLim then begin
            WriteLn('Too many colors - exiting.');
            Halt(5);
          end;
          Inc(MaxColors);
          Colors[MaxColors] := p[i]^[j,k];
        end;
      end;
  {--- sorting (except backgroung) ---}
  for i := 1 to pred(MaxColors) do begin
    k := i;
    for j := succ(i) to MaxColors do
      if Colors[j] < Colors[k] then k := j;
    t         := Colors[i];
    Colors[i] := Colors[k];
    Colors[k] := t;
  end;
  (*------------------------------*)
end;

procedure SaveFont;
var Key: char;
begin
  GetMem(b, 32*1024);
  b^[0] := h; b^[1] := 0; b^[2] := d; b^[3] := g;
  Move( w, b^[4], 256 );
  q := $304;
  for i := 0 to 255 do begin
    b^[$104+i] := byte(q and $FF);
    b^[$204+i] := byte( (q shr 8) and $FF);
    for j := 0 to h-1 do begin
      Move(p[i]^[j,0], b^[q], w[i]);
      Inc(q, w[i]);
    end;
  end;
  Write('Save font (Y/n)? ');
  Key := chr(GetKey);
  if (Key = #13) or (Key = 'y') or (Key = 'Y') then begin
    WriteLn('Yes');
    Assign(f,s);
    ReWrite(f,1);
    BlockWrite( f, b^, q );
    Close(f);
  end else begin
    WriteLn('No');
  end;
  FreeMem(b, 32*1024);
end;

procedure LoadPalette;
begin
  Assign(f,'DAC.REG');
  Reset(f,1);
  BlockRead(f,palette,$300);
  Close(f);
end;

procedure SetPalette;
begin
  ASM
    mov  ax, $1012
    xor  bx, bx
    push ds
    pop  es
    mov  dx, offset palette
    mov  cx, $100
    int  $10
  end;
end;

procedure Pixel( x,y: word; color: byte );
begin
  Scrn[y,x] := color;
end;

procedure SetupGraph;
begin
  asm
    mov  ax, $0013
    int  $10
  end;
  LoadPalette;
  SetPalette;
end;

procedure CleanGraph;
begin
  asm
    mov  ax, 0003
    int  $10
  end;
end;

procedure ShowFont;
Var i, j, k: word;
begin
  FillChar( Scrn, SizeOf(Scrn), Colors[0] );
  for i := 0 to MaxRow do begin
    for j := 0 to 15 do begin
      for k := 0 to pred(h) do begin
        Move( p[Rows[i]+j]^[k,0], Scrn[k+UpOfs+i*Y_il, LeftOfs+j*X_il], w[Rows[i]+j]);
      end;
    end;
  end;
end;

procedure Box( y1, x1, y2, x2: word; col: byte );
begin
  FillChar( Scrn[ y1, x1], succ(x2-x1), col);
  FillChar( Scrn[ y2, x1], succ(x2-x1), col);
  for i := y1 to y2 do begin
    Scrn[i, x1] := col;
    Scrn[i, x2] := col;
  end;
end;

procedure BoxC( color: byte );
var i, j: word;
begin
  i := pred(CurClrNo)*Yi_Clr+Y_Color;
  j := pred(CurClrNo)*Xi_Clr+X_Color;
  Box( i-2, j-2, i+Ys_Clr+1, j+Xs_Clr+1, color );
end;

procedure ShowColors;
var i, j: word;
begin
  CurClrNo := 1;
  CurColor := Colors[CurClrNo];
  for i := 1 to MaxColors do
    for j := 0 to pred(Ys_Clr) do
      FillChar( Scrn[ pred(i)*Yi_Clr+j+Y_Color, pred(i)*Xi_Clr+X_Color ], Xs_Clr, Colors[i]);
end;

procedure SetupScreen;
begin
  ShowFont;
  Row := 0;
  Col := 0;
end;

function ChoiseChar: boolean;
var Key: word; Process: boolean; i, j: word;
begin
  Process := True;
  while Process do begin
    CurChar := Rows[Row] + Col;
    i := UpOfs   + Y_il * Row - 2;
    j := LeftOfs + X_il * Col - 2;
    Box( i, j, i+h+2, j+w[CurChar]+3, BoxColor );
    Key := GetKey;
    Box( i, j, i+h+2, j+w[CurChar]+3, Colors[0] );
    case Key of
      $1C0D: { Enter    }
             begin Process := False; ChoiseChar := True end;
      $011B: { Escape   }
             begin Process := False; ChoiseChar := False end;
  (*    $0F09: { Tab      } ; **
  **    $0F00: { Shft-Tab } ; *)
      $5000: { Down     }
             if Row >= MaxRow then Row := 0 else Inc(Row);
      $4B00: { Left     }
             if Col = 0 then Col := 15 else Dec(Col);
      $4D00: { Right    }
             if Col >= 15 then Col := 0 else Inc(Col);
      $4800: { Up       }
             if Row = 0 then Row := MaxRow else Dec(Row);
      $2E00: { Alt-C    }
             begin
               ClipChar := p[CurChar]^;
               ClipW    := w[CurChar];
             end;
      $1700: { Alt-I    }
             begin
               TempChar    := p[CurChar]^;
               TempW       := w[CurChar];
               p[CurChar]^ := ClipChar;
               w[CurChar]  := ClipW;
               ShowFont;
             end;
      $1600: { Alt-U    }
             begin
               p[CurChar]^ := TempChar;
               w[CurChar]  := TempW;
               ShowFont;
             end;
      $1200: { Alt-E    }
             begin
               TempChar    := p[CurChar]^;
               TempW       := w[CurChar];
               FillChar( p[CurChar]^, SizeOf(sm), Colors[0] );
               w[CurChar]  := 1;
               ShowFont;
             end;
    end;
  end;
end;

procedure ShowChar;
begin
  for i := 0 to 15 do Move( TempChar[i,0], Scrn[80+i,50], 16 );
  for i := 0 to 15 do
    for j := 0 to 15 do
      for k := 0 to Pred(Scale) do
        FillChar( Scrn[LoY+i*Scale+k,LoX+j*Scale], Scale, TempChar[i,j] );
  Box( LoY-1, LoX-1, LoY+succ(h)*Scale+1, LoX+16*Scale+1, BoxColor );
end;

procedure EditChar;
Var Key: word; Done: boolean; row, col: word;
begin
  FillChar( Scrn, SizeOf(Scrn), Colors[0] );
  ShowColors;
  BoxC( CurColor );
  TempChar := p[CurChar]^;
  ShowChar;
  Done     := False;
  row      := 0;
  col      := 0;
  repeat
    Scrn[LoY+row*Scale+(Scale div 2), LoX+col*Scale+(Scale div 2)] := BoxColor;
    Key := GetKey;
    Scrn[LoY+row*Scale+(Scale div 2), LoX+col*Scale+(Scale div 2)] := TempChar[row,col];
    case Key of
    $1C0D: { Enter    }
            begin
              Done := True;
              k := 1;
              for i := 0 to pred(h) do
                for j := k to 15 do
                  if TempChar[i,j] <> Colors[0] then k := succ(j);
              TempW       := k;
              w[CurChar]  := TempW;
              p[CurChar]^ := TempChar;
            end;
    $011B: { Escape   }
            begin
              Done := True;
            end;
    $0F09: { Tab      }
            begin
              BoxC( Colors[0] );
              if CurClrNo >= MaxColors then CurClrNo := 1 else Inc(CurClrNo);
              CurColor := Colors[CurClrNo];
              BoxC( CurColor  );
            end;
    $0F00: { Shft-Tab }
            begin
              BoxC( Colors[0] );
              if CurClrNo = 1 then CurClrNo := MaxColors else Dec(CurClrNo);
              CurColor := Colors[CurClrNo];
              BoxC( CurColor  );
            end;
    $5000: { Down     }
            if Row >= h then Row := 0 else Inc(Row);
    $4B00: { Left     }
            if Col = 0 then Col := 15 else Dec(Col);
    $4D00: { Right    }
            if Col >= 15 then Col := 0 else Inc(Col);
    $4800: { Up       }
            if Row = 0 then Row := h else Dec(Row);
    $3920: { Space    }
            begin
              TempChar[row,col] := CurColor;
              ShowChar;
            end;
    $5300: { Del      }
            begin
              TempChar[row,col] := Colors[0];
              ShowChar;
            end;
    end;
  until Done;
  FillChar( Scrn, SizeOf(Scrn), Colors[0] );
  ShowFont;
end;

procedure EditFont;
begin
  SetupScreen;
  while ChoiseChar do EditChar;
end;

begin
  LoadFont;
  SetupGraph;
  EditFont;
  CleanGraph;
  SaveFont;
end.
 

UnnamedCharacter

2nd Lieutenant
Attached is the compiled executable; you will need DOSBox to run it.

If you want to give it a try, first you will need to unpack the FONTS.FNT file; you can use the WCToolbox to do this. Although the WC1 tooling is designed to work with pack files and not the individual packets, you can use the Priv1 tooling which will work just fine.

From the console:

Priv1ToolsCmd.exe unpack FONTS.FNT​

Afterwards, you may want to rename the packet files to a 8.3 file name format. Then using DOSBox, run FONTEDIT.EXE and specify a font packet.

fontedit_003.png
fontedit_004.png
 

Attachments

Top