Subversion Repositories jumper

Compare Revisions

Regard whitespace Rev 23 → Rev 24

/trunk/Choice.pas
4,7 → 4,8
 
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,
Dialogs, StdCtrls, ImgList, ComCtrls, Menus, ExtCtrls, System.ImageList, LevelFunctions;
Dialogs, StdCtrls, ImgList, ComCtrls, Menus, ExtCtrls, ImageList,
LevelFunctions;
 
type
TLevelChoice = class(TForm)
44,9 → 45,8
 
procedure TLevelChoice.DrawLevelPreview(Level: TLevel);
var
LevelArray: TLevelArray;
PlaygroundMatrix: TPlayGroundMatrix;
y, x: integer;
t: TFieldType;
indent: Integer;
Image: TImage;
BackgroundColor: TColor;
57,21 → 57,17
Image := PreviewImage;
BackgroundColor := Self.Color;
 
LevelArray := nil;
 
ClearImage(Image, BackgroundColor);
 
LevelArray := Level.LevelStringToLevelArray(false);
 
for y := Low(LevelArray) to High(LevelArray) do
Level.FillPlaygroundMatrix(PlaygroundMatrix, false);
try
for x := Low(PlaygroundMatrix.Fields) to High(PlaygroundMatrix.Fields) do
begin
for x := Low(LevelArray[y].Fields) to High(LevelArray[y].Fields) do
for y := Low(PlaygroundMatrix.Fields[x]) to High(PlaygroundMatrix.Fields[x]) do
begin
t := LevelArray[y].Fields[x].Typ;
indent := LevelArray[y].Indent;
 
case t of
ftFullSpace: Image.Canvas.Brush.Color := BackgroundColor;
// Rectange filling
case PlaygroundMatrix.Fields[x,y].FieldType of
ftFullSpace: Image.Canvas.Brush.Color := BackgroundColor; // invisible
ftEmpty: Image.Canvas.Brush.Color := clWhite;
ftGreen: Image.Canvas.Brush.Color := clLime;
ftYellow: Image.Canvas.Brush.Color := clYellow;
78,11 → 74,19
ftRed: Image.Canvas.Brush.Color := clRed;
end;
 
if LevelArray[y].Fields[x].Goal then
// Rectangle border
if PlaygroundMatrix.Fields[x,y].Goal then
Image.Canvas.Pen.Color := clBlack
else
Image.Canvas.Pen.Color := BackgroundColor;
begin
if PlaygroundMatrix.Fields[x,y].FieldType = ftFullSpace then
Image.Canvas.Pen.Color := BackgroundColor // invisible
else
Image.Canvas.Pen.Color := clLtGray;
end;
 
// Draw the rectangle
indent := PlaygroundMatrix.Fields[x,y].Indent;
Image.Canvas.Rectangle(x*PREVIEW_BLOCK_SIZE + indent*PREVIEW_TAB_SIZE,
y*PREVIEW_BLOCK_SIZE,
x*PREVIEW_BLOCK_SIZE + indent*PREVIEW_TAB_SIZE + PREVIEW_BLOCK_SIZE,
89,7 → 93,10
y*PREVIEW_BLOCK_SIZE + PREVIEW_BLOCK_SIZE);
end;
end;
finally
PlaygroundMatrix.ClearMatrix(true);
end;
end;
 
function TLevelChoice.SelectedLevel: string;
begin
/trunk/LevelFunctions.pas
13,37 → 13,13
 
TFieldType = (ftUndefined, ftFullSpace, ftEmpty, ftRed, ftYellow, ftGreen);
 
TFieldProperties = record
Typ: TFieldType;
Goal: Boolean;
end;
 
TGameMode = (gmUndefined, gmNormal, gmDiagonal);
 
TRow = record
Indent: integer;
Fields: array of TFieldProperties;
end;
TLevelArray = array of TRow;
 
TLevelError = (leUndefined, leNone, leInvalidElement, leEmptyBoard, leRowInvalidLength,
leUnsupportedVersion, leUnsupportedMode);
 
TLevel = class(TObject)
private
FStringList: TStringList;
procedure Load(ABoardFile: string);
function GetGameMode: TGameMode;
public
constructor Create(ABoardFile: string);
destructor Destroy; override;
function LevelStringToLevelArray(ShowErrors: boolean): TLevelArray;
function CheckLevelIntegrity: TLevelError; overload;
function CheckLevelIntegrity(ShowErrors: boolean): TLevelError; overload;
property GameMode: TGameMode read GetGameMode;
end;
 
TField = record
Indent: integer;
FieldType: TFieldType;
Goal: Boolean;
Panel: TPanel;
52,7 → 28,7
 
TGoalStatus = (gsUndefined, gsNoGoal, gsMultipleStonesRemaining, gsLastStoneInGoalRed, gsLastStoneInGoalYellow, gsLastStoneInGoalGreen, gsLastStoneOutsideGoal);
 
TFieldState = (fsUndefined, fsError, fsLocked, fsAvailable, fsStone);
TFieldState = (fsUndefined, fsLocked, fsAvailable, fsOccupied);
 
TPlayGroundMatrix = record
Fields: array of array of TField;
67,7 → 43,9
function FieldState(f: TField): TFieldState; overload;
function FieldState(x, y: integer): TFieldState; overload;
function CanJump(SourceX, SourceY, DestX, DestY: integer; DiagonalOK: boolean): boolean; overload;
function CanJump(Source, Dest: TCoord; DiagonalOK: boolean): boolean; overload;
function CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean; overload;
function CanJump(Source: TCoord; DiagonalOK: boolean): boolean; overload;
function CanJump(DiagonalOK: boolean): boolean; overload;
function IndexToCoord(index: integer): TCoord;
function CoordToIndex(coord: TCoord): integer; overload;
76,6 → 54,20
function Height: integer;
end;
 
TLevel = class(TObject)
private
FStringList: TStringList;
procedure Load(ABoardFile: string);
function GetGameMode: TGameMode;
public
constructor Create(ABoardFile: string);
destructor Destroy; override;
procedure FillPlaygroundMatrix(var matrix: TPlayGroundMatrix; ShowErrors: boolean);
function CheckLevelIntegrity: TLevelError; overload;
function CheckLevelIntegrity(ShowErrors: boolean): TLevelError; overload;
property GameMode: TGameMode read GetGameMode;
end;
 
function FieldTypeWorth(t: TFieldType): integer;
 
implementation
141,7 → 133,7
begin
for y := Low(Fields[x]) to High(Fields[x]) do
begin
Fields[x,y].FieldType := ftUndefined;
Fields[x,y].FieldType := ftUndefined
end;
end;
end;
165,16 → 157,28
result := Length(Fields);
end;
 
function TPlayGroundMatrix.CanJump(Source: TCoord;
DiagonalOK: boolean): boolean;
begin
result := CanJump(Source.X, Source.Y, DiagonalOK);
end;
 
function TPlayGroundMatrix.CanJump(Source, Dest: TCoord;
DiagonalOK: boolean): boolean;
begin
result := CanJump(Source.X, Source.Y, Dest.X, Dest.Y, DiagonalOK);
end;
 
procedure TPlayGroundMatrix.ClearMatrix(FreeVCL: boolean);
var
x, y: integer;
begin
if FreeVCL then
begin
for x := Low(Fields) to High(Fields) do
begin
for y := Low(Fields[x]) to High(Fields[x]) do
begin
if FreeVCL then
begin
if Assigned(Fields[x,y].Stone) then Fields[x,y].Stone.Free;
if Assigned(Fields[x,y].Panel) then Fields[x,y].Panel.Free;
end;
202,28 → 206,24
end;
 
function TPlayGroundMatrix.CoordToIndex(x, y: integer): integer;
var
c: TCoord;
begin
c.X := x;
c.Y := y;
result := CoordToIndex(c);
result := x + y * Width;
end;
 
function TPlayGroundMatrix.CoordToIndex(coord: TCoord): integer;
begin
result := coord.X + coord.Y * Width;
result := CoordToIndex(coord.X, coord.Y);
end;
 
class function TPlayGroundMatrix.FieldState(t: TFieldType): TFieldState;
begin
result := fsError;
result := fsUndefined;
case t of
ftFullSpace: result := fsLocked;
ftEmpty: result := fsAvailable;
ftGreen: result := fsStone;
ftYellow: result := fsStone;
ftRed: result := fsStone;
ftGreen: result := fsOccupied;
ftYellow: result := fsOccupied;
ftRed: result := fsOccupied;
end;
end;
 
234,7 → 234,7
 
function TPlayGroundMatrix.FieldState(x, y: integer): TFieldState;
begin
result := fsError;
result := fsUndefined;
if (x < Low(Fields)) or (x > High(Fields)) then exit;
if (y < Low(Fields[x])) or (y > High(Fields[x])) then exit;
 
251,21 → 251,21
// Check 2: Befindet sich ein Stein zwischen Source und Destination und ist der Abstand 2?
if DiagonalOK then
begin
if (SourceX-2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX-1, SourceY-1) = fsStone) then result := true;
if (SourceX-2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX-1, SourceY+1) = fsStone) then result := true;
if (SourceX+2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX+1, SourceY-1) = fsStone) then result := true;
if (SourceX+2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX+1, SourceY+1) = fsStone) then result := true;
if (SourceX-2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX-1, SourceY-1) = fsOccupied) then result := true;
if (SourceX-2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX-1, SourceY+1) = fsOccupied) then result := true;
if (SourceX+2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX+1, SourceY-1) = fsOccupied) then result := true;
if (SourceX+2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX+1, SourceY+1) = fsOccupied) then result := true;
end;
 
if (SourceX+2 = DestX) and (SourceY = DestY) and (FieldState(SourceX+1, SourceY ) = fsStone) then result := true;
if (SourceX-2 = DestX) and (SourceY = DestY) and (FieldState(SourceX-1, SourceY ) = fsStone) then result := true;
if (SourceX = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX , SourceY+1) = fsStone) then result := true;
if (SourceX = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX , SourceY-1) = fsStone) then result := true;
if (SourceX+2 = DestX) and (SourceY = DestY) and (FieldState(SourceX+1, SourceY ) = fsOccupied) then result := true;
if (SourceX-2 = DestX) and (SourceY = DestY) and (FieldState(SourceX-1, SourceY ) = fsOccupied) then result := true;
if (SourceX = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX , SourceY+1) = fsOccupied) then result := true;
if (SourceX = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX , SourceY-1) = fsOccupied) then result := true;
end;
 
function TPlayGroundMatrix.CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean;
begin
if FieldState(SourceX, SourceY) <> fsStone then
if FieldState(SourceX, SourceY) <> fsOccupied then
begin
result := false;
exit;
351,7 → 351,7
end;
end;
 
function TLevel.LevelStringToLevelArray(ShowErrors: boolean): TLevelArray;
procedure TLevel.FillPlaygroundMatrix(var matrix: TPlayGroundMatrix; ShowErrors: boolean);
var
i: integer;
t: TFieldType;
361,23 → 361,36
Line: string;
lch, uch: char;
ch: char;
width: Integer;
height: Integer;
lineIndent: Integer;
begin
// Zuerst nach Fehlern suchen
err := CheckLevelIntegrity(ShowErrors);
if err <> leNone then exit;
 
// Breite feststellen
if FStringList.Count > NUM_HEADERS then
begin
Line := FStringList.Strings[NUM_HEADERS];
Line := StringReplace(Line, '.', '', [rfReplaceAll]);
width := Length(Line);
end
else width := 0;
 
// Höhe feststellen
height := FStringList.Count - NUM_HEADERS;
 
// Nun Matrix aufbauen
SetLength(result, 0);
matrix.ClearMatrix(true);
matrix.InitFieldArray(width, height);
for i := NUM_HEADERS to FStringList.Count-1 do
begin
y := i - NUM_HEADERS;
 
SetLength(result, Length(result)+1); // add line to matrix
 
Line := FStringList.Strings[i];
result[y].Indent := DotsAtBeginning(Line) - DotsAtEnd(Line);
lineIndent := DotsAtBeginning(Line) - DotsAtEnd(Line);
Line := StringReplace(Line, '.', '', [rfReplaceAll]);
SetLength(result[y].Fields, Length(Line));
 
for x := 0 to Length(Line)-1 do
begin
394,8 → 407,9
'g': t := ftGreen;
end;
 
result[y].Fields[x].Typ := t;
result[y].Fields[x].Goal := (ch = uch) and (ch <> lch);
matrix.Fields[x,y].Indent := lineIndent;
matrix.Fields[x,y].FieldType := t;
matrix.Fields[x,y].Goal := (ch = uch) and (ch <> lch);
end;
end;
end;
440,7 → 454,8
exit;
end;
 
if ((LowerCase(FStringList.Strings[1]) <> 'mode: normal') and (LowerCase(FStringList.Strings[1]) <> 'mode: diagonal')) then
if ((LowerCase(FStringList.Strings[1]) <> 'mode: normal') and
(LowerCase(FStringList.Strings[1]) <> 'mode: diagonal')) then
begin
result := leUnsupportedMode;
exit;
464,7 → 479,7
thisLine := StringReplace(FStringList.Strings[i], '.', '', [rfReplaceAll]);
if Length(thisLine) <> Length(firstLine) then
begin
result := leRowInvalidLength; // at row y-NUM_HEADERS
result := leRowInvalidLength; // at row y = i-NUM_HEADERS
exit;
end;
end;
484,7 → 499,7
 
if Length(Line) > 0 then
begin
result := leInvalidElement; // at row y-NUM_HEADERS
result := leInvalidElement; // at row y = i-NUM_HEADERS
Exit;
end;
end;
/trunk/Main.pas
75,10 → 75,9
function MayJump(SourceTag, DestTag: integer): boolean; overload;
procedure StoneDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
procedure StoneDragDrop(Sender, Source: TObject; X, Y: Integer);
function DrawField(x, y: integer; t: TFieldProperties; indent: integer): TField;
procedure DrawField(x, y: integer; var f: TField);
function DrawStone(fieldtype: TFieldType; panel: TPanel): TImage;
function DrawStoneBox(x, y, tag, halftabs: integer; isGoal: boolean): TPanel;
procedure BuildPlayground(LevelArray: TLevelArray);
procedure LoadPictureForType(FieldType: TFieldType; Picture: TPicture);
function GoalStatus: TGoalStatus;
end;
103,10 → 102,10
begin
for y := Low(Matrix.Fields[x]) to High(Matrix.Fields[x]) do
begin
if Assigned(Matrix.Fields[x][y].Stone) then
if Assigned(Matrix.Fields[x,y].Stone) then
begin
LoadPictureForType(Matrix.Fields[x][y].FieldType, Matrix.Fields[x][y].Stone.Picture);
StoneDraggingAllow(Matrix.Fields[x][y].Stone, Matrix.FieldState(Matrix.Fields[x][y].FieldType) <> fsAvailable);
LoadPictureForType(Matrix.Fields[x,y].FieldType, Matrix.Fields[x,y].Stone.Picture);
StoneDraggingAllow(Matrix.Fields[x,y].Stone, Matrix.FieldState(Matrix.Fields[x,y].FieldType) <> fsAvailable);
end;
end;
end;
277,7 → 276,7
 
procedure TMainForm.DoJump(SourceTag, DestTag: integer);
resourcestring
LNG_JUMP_LOG = '%d [%d, %d] -> %d [%d, %d];';
LNG_JUMP_LOG = '[%d, %d] -> [%d, %d];';
var
d, s: TCoord;
old_fieldtype: TFieldType;
288,21 → 287,21
s := PlaygroundMatrix.IndexToCoord(SourceTag);
d := PlaygroundMatrix.IndexToCoord(DestTag);
 
JumpHistory.Add(Format(LNG_JUMP_LOG, [SourceTag+1, s.x+1, s.y+1, DestTag+1, d.x+1, d.y+1]));
JumpHistory.Add(Format(LNG_JUMP_LOG, [s.x+1, s.y+1, d.x+1, d.y+1]));
 
{$REGION 'Stein entfernen und Punkte vergeben'}
if Level.GameMode = gmDiagonal then
begin
if (s.X-2 = d.X) and (s.Y-2 = d.Y) and (PlayGroundMatrix.FieldState(s.X-1, s.Y-1) = fsStone) then RemoveStone(s.X-1, s.Y-1, true);
if (s.X-2 = d.X) and (s.Y+2 = d.Y) and (PlayGroundMatrix.FieldState(s.X-1, s.Y+1) = fsStone) then RemoveStone(s.X-1, s.Y+1, true);
if (s.X+2 = d.X) and (s.Y-2 = d.Y) and (PlayGroundMatrix.FieldState(s.X+1, s.Y-1) = fsStone) then RemoveStone(s.X+1, s.Y-1, true);
if (s.X+2 = d.X) and (s.Y+2 = d.Y) and (PlayGroundMatrix.FieldState(s.X+1, s.Y+1) = fsStone) then RemoveStone(s.X+1, s.Y+1, true);
if (s.X-2 = d.X) and (s.Y-2 = d.Y) and (PlayGroundMatrix.FieldState(s.X-1, s.Y-1) = fsOccupied) then RemoveStone(s.X-1, s.Y-1, true);
if (s.X-2 = d.X) and (s.Y+2 = d.Y) and (PlayGroundMatrix.FieldState(s.X-1, s.Y+1) = fsOccupied) then RemoveStone(s.X-1, s.Y+1, true);
if (s.X+2 = d.X) and (s.Y-2 = d.Y) and (PlayGroundMatrix.FieldState(s.X+1, s.Y-1) = fsOccupied) then RemoveStone(s.X+1, s.Y-1, true);
if (s.X+2 = d.X) and (s.Y+2 = d.Y) and (PlayGroundMatrix.FieldState(s.X+1, s.Y+1) = fsOccupied) then RemoveStone(s.X+1, s.Y+1, true);
end;
 
if (s.X+2 = d.X) and (s.Y = d.Y) and (PlayGroundMatrix.FieldState(s.X+1, s.Y ) = fsStone) then RemoveStone(s.X+1, s.Y, true);
if (s.X-2 = d.X) and (s.Y = d.Y) and (PlayGroundMatrix.FieldState(s.X-1, s.Y ) = fsStone) then RemoveStone(s.X-1, s.Y, true);
if (s.X = d.X) and (s.Y+2 = d.Y) and (PlayGroundMatrix.FieldState(s.X , s.Y+1) = fsStone) then RemoveStone(s.X, s.Y+1, true);
if (s.X = d.X) and (s.Y-2 = d.Y) and (PlayGroundMatrix.FieldState(s.X , s.Y-1) = fsStone) then RemoveStone(s.X, s.Y-1, true);
if (s.X+2 = d.X) and (s.Y = d.Y) and (PlayGroundMatrix.FieldState(s.X+1, s.Y ) = fsOccupied) then RemoveStone(s.X+1, s.Y, true);
if (s.X-2 = d.X) and (s.Y = d.Y) and (PlayGroundMatrix.FieldState(s.X-1, s.Y ) = fsOccupied) then RemoveStone(s.X-1, s.Y, true);
if (s.X = d.X) and (s.Y+2 = d.Y) and (PlayGroundMatrix.FieldState(s.X , s.Y+1) = fsOccupied) then RemoveStone(s.X, s.Y+1, true);
if (s.X = d.X) and (s.Y-2 = d.Y) and (PlayGroundMatrix.FieldState(s.X , s.Y-1) = fsOccupied) then RemoveStone(s.X, s.Y-1, true);
{$ENDREGION}
 
// Den Timer erst nach dem ersten Zug starten
358,7 → 357,7
s := PlayGroundMatrix.IndexToCoord(SourceTag);
d := PlayGroundMatrix.IndexToCoord(DestTag);
 
result := PlaygroundMatrix.CanJump(s.X, s.Y, d.X, d.Y, Level.GameMode = gmDiagonal);
result := PlaygroundMatrix.CanJump(s, d, Level.GameMode = gmDiagonal);
end;
 
procedure TMainForm.StoneDragDrop(Sender, Source: TObject; X, Y: Integer);
372,48 → 371,63
Accept := MayJump(TComponent(Source).Tag, TComponent(Sender).Tag);
end;
 
function TMainForm.DrawField(x, y: integer; t: TFieldProperties; indent: integer): TField;
procedure TMainForm.DrawField(x, y: integer; var f: TField);
var
newField: TField;
index: integer;
begin
ZeroMemory(@result, SizeOf(result));
if t.Typ = ftFullSpace then exit;
if f.FieldType = ftFullSpace then exit;
 
index := PlaygroundMatrix.CoordToIndex(x, y);
 
newField.FieldType := t.Typ;
newField.Goal := t.Goal;
newField.Panel := DrawStoneBox(x, y, index, indent, t.Goal);
newField.Stone := DrawStone(t.Typ, newField.Panel);
f.Panel := DrawStoneBox(x, y, index, f.indent, f.Goal);
f.Stone := DrawStone(f.FieldType, f.Panel);
end;
 
result := newField;
procedure TMainForm.TimerTimer(Sender: TObject);
begin
if MPauseTime.Checked then exit;
if mainform.Focused then Inc(CountedSeconds);
RefreshTime;
end;
 
procedure TMainForm.BuildPlayground(LevelArray: TLevelArray);
function TMainForm.LevelTime: String;
begin
result := FormatDateTime('hh:nn:ss', CountedSeconds / SecsPerDay)
end;
 
procedure TMainForm.NewGame(Filename: string);
resourcestring
LNG_LVL_INVALID_NO_JUMP = 'Warning! The level is not playable. There are no jumps possible.';
var
y, x: integer;
max_x, max_y: integer;
p: TPanel;
newField: TField;
begin
DestroyLevel;
 
MPauseTime.Checked := true;
MPauseTime.Enabled := true;
Timer.Enabled := true;
MRestartGame.Enabled := true;
 
LevelFile := Filename;
Level := TLevel.Create(LevelFile);
 
Level.FillPlaygroundMatrix(PlaygroundMatrix, true);
if Length(PlaygroundMatrix.Fields) = 0 then Exit;
 
PlayGround.Visible := false;
 
// Attention: PlaygroundMatrix is indexed [x,y] while LevelArray is indexed [y,x]
// TODO: PlaygroundMatrix and LevelArray are redundant. Can't we just replace one with the other?
PlaygroundMatrix.InitFieldArray(Length(LevelArray[0].Fields), Length(LevelArray));
 
max_x := 0;
max_y := 0;
for y := Low(LevelArray) to High(LevelArray) do
for x := Low(PlaygroundMatrix.Fields) to High(PlaygroundMatrix.Fields) do
begin
for x := Low(LevelArray[y].Fields) to High(LevelArray[y].Fields) do
for y := Low(PlaygroundMatrix.Fields[x]) to High(PlaygroundMatrix.Fields[x]) do
begin
if TPlayGroundMatrix.FieldState(LevelArray[y].Fields[x].Typ) = fsStone then
if TPlayGroundMatrix.FieldState(PlaygroundMatrix.Fields[x,y].FieldType) = fsOccupied then
Inc(LevelTotalStones);
newField := DrawField(x, y, LevelArray[y].Fields[x], LevelArray[y].Indent);
PlaygroundMatrix.Fields[x, y] := newField;
p := newField.Panel;
DrawField(x, y, PlaygroundMatrix.Fields[x,y]);
p := PlaygroundMatrix.Fields[x,y].Panel;
if Assigned(p) then
begin
max_x := Max(max_x, p.Left + p.Width);
443,38 → 457,7
SetLength(PrevPlaygroundMatrixes,1);
PrevPlaygroundMatrixes[0] := PlayGroundMatrix.CloneMatrix;
MUndo.Enabled := false;
end;
 
procedure TMainForm.TimerTimer(Sender: TObject);
begin
if MPauseTime.Checked then exit;
if mainform.Focused then Inc(CountedSeconds);
RefreshTime;
end;
 
function TMainForm.LevelTime: String;
begin
result := FormatDateTime('hh:nn:ss', CountedSeconds / SecsPerDay)
end;
 
procedure TMainForm.NewGame(Filename: string);
resourcestring
LNG_LVL_INVALID_NO_JUMP = 'Warning! The level is not playable. There are no jumps possible.';
var
LevelArray: TLevelArray;
begin
DestroyLevel;
 
MPauseTime.Checked := true;
MPauseTime.Enabled := true;
Timer.Enabled := true;
MRestartGame.Enabled := true;
 
LevelFile := Filename;
Level := TLevel.Create(LevelFile);
LevelArray := Level.LevelStringToLevelArray(true);
if Length(LevelArray) = 0 then Exit;
BuildPlayground(LevelArray);
if not PlayGroundMatrix.CanJump(Level.GameMode = gmDiagonal) then
begin
MessageDlg(LNG_LVL_INVALID_NO_JUMP, mtError, [mbOk], 0);