Subversion Repositories jumper

Compare Revisions

Regard whitespace Rev 11 → Rev 10

/trunk/Main.pas
68,7 → 68,6
LevelTotalStones: Integer;
LevelRemovedStones: Integer;
JumpHistory: TStringList;
Level: TLevel;
procedure LoadSettings;
procedure SaveSettings;
procedure RestartLevel;
225,8 → 224,6
MUndo.Enabled := false;
 
SetLength(LookupFieldCoordinateArray, 0);
 
if Assigned(Level) then FreeAndNil(Level);
end;
 
procedure TMainForm.LoadPictureForType(FieldType: TFieldType; Picture: TPicture);
301,8 → 298,8
begin
result := fsError;
case t of
ftFullSpace: result := fsLocked;
ftHalfSpace: result := fsLocked;
ftLocked: result := fsLocked;
ftLockedWithTab: result := fsLocked;
ftEmpty: result := fsAvailable;
ftGreen: result := fsStone;
ftYellow: result := fsStone;
373,7 → 370,7
if MayJump(x, y, x, y+2) then exit;
if MayJump(x, y, x, y-2) then exit;
 
if Level.GetGameMode = gmDiagonal then
if AllowDiagonalMoves then
begin
if MayJump(x, y, x-2, y-2) then exit;
if MayJump(x, y, x+2, y-2) then exit;
417,7 → 414,7
JumpHistory.Add(Format(LNG_JUMP_LOG, [SourceTag+1, s.x+1, s.y+1, DestTag+1, d.x+1, d.y+1]));
 
{$REGION 'Stein entfernen und Punkte vergeben'}
if Level.GetGameMode = gmDiagonal then
if AllowDiagonalMoves then
begin
if (s.X-2 = d.X) and (s.Y-2 = d.Y) and (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 (FieldState(s.X-1, s.Y+1) = fsStone) then RemoveStone(s.X-1, s.Y+1, true);
488,7 → 485,7
if FieldState(DestX, DestY) <> fsAvailable then exit;
 
// Check 2: Befindet sich ein Stein zwischen Source und Destination und ist der Abstand 2?
if Level.GetGameMode = gmDiagonal then
if AllowDiagonalMoves 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;
528,7 → 525,7
newField: TField;
index: integer;
begin
if (t.Typ = ftFullSpace) or (t.Typ = ftHalfSpace) then exit;
if (t.Typ = ftLocked) or (t.Typ = ftLockedWithTab) then exit;
 
index := Length(LookupFieldCoordinateArray);
 
579,7 → 576,7
halftabs := 0;
for j := Low(LevelArray[i]) to High(LevelArray[i]) do
begin
if LevelArray[i][j].Typ = ftHalfSpace then inc(halftabs);
if LevelArray[i][j].Typ = ftLockedWithTab then inc(halftabs);
DrawField(j, i, LevelArray[i][j], halftabs);
end;
cur_x := High(LevelArray[i]) + 1;
632,12 → 629,13
 
procedure TMainForm.NewGame(Filename: string);
var
LevelString: String;
LevelArray: TLevelArray;
begin
DestroyLevel;
LevelFile := Filename;
Level := TLevel.Create(LevelFile);
LevelArray := Level.LevelStringToLevelArray(true);
LevelString := ReadFile(LevelFile);
LevelArray := LevelStringToLevelArray(LevelString, true);
if Length(LevelArray) = 0 then Exit;
BuildPlayground(LevelArray);
if not AreJumpsPossible then
714,7 → 712,6
 
procedure TMainForm.FormDestroy(Sender: TObject);
begin
DestroyLevel;
JumpHistory.Free;
end;
 
/trunk/Choice.pas
50,22 → 50,19
 
procedure TLevelChoice.PlayBtnClick(Sender: TObject);
var
Level: TLevel;
LevelString: string;
begin
if Assigned(LevelList.Selected) then
begin
if LevelList.Selected.ImageIndex = 2 then
begin
Level := TLevel.Create(Format(LVL_FILE, [LevelList.Selected.Caption]));
try
if Level.CheckLevelIntegrity(true) <> leNone then
LevelString := Functions.ReadFile(Format(LVL_FILE, [LevelList.Selected.Caption]));
// leNone könnte auftreten, wenn das Level z.B. repariert wurde...
if CheckLevelIntegrity(LevelString, true) <> leNone then
begin
exit;
end;
finally
FreeAndNil(Level);
end;
end;
ModalResult := mrOk;
end;
end;
83,7 → 80,6
procedure TLevelChoice.LevelListClick(Sender: TObject);
var
LevelFile, LevelString: string;
Level: TLevel;
begin
PlayBtn.Enabled := Assigned(LevelList.Selected);
PLoadLevel.Enabled := Assigned(LevelList.Selected);
91,12 → 87,8
if Assigned(LevelList.Selected) then
begin
LevelFile := Format(LVL_FILE, [LevelList.Selected.Caption]);
Level := TLevel.Create(LevelFile);
try
DrawLevelPreview(Level, PreviewImage, Color);
finally
FreeAndNil(Level);
end;
LevelString := Functions.ReadFile(LevelFile);
DrawLevelPreview(LevelString, PreviewImage, Color);
end
else
begin
118,7 → 110,7
procedure TLevelChoice.RefreshList;
var
s: TSearchRec;
Level: TLevel;
LevelString: string;
begin
LevelList.Clear;
 
129,11 → 121,11
with LevelList.Items.Add do
begin
Caption := Copy(s.Name, 1, Length(s.Name)-Length(LVL_EXT));
Level := TLevel.Create(LVL_PATH + s.Name);
case Level.GetGameMode of
gmNormal: ImageIndex := 0;
gmDiagonal: ImageIndex := 1;
gmUndefined: ImageIndex := 2;
LevelString := Functions.ReadFile(LVL_PATH + s.Name);
case GetLevelType(LevelString) of
ltStandard: ImageIndex := 0;
ltDiagonal: ImageIndex := 1;
ltError: ImageIndex := 2;
end;
end;
until FindNext(s) <> 0;
/trunk/Functions.pas
12,6 → 12,7
function Explode(Separator, Text: String): TStringList;
function Position(FullString, Search: String): Integer;
function ReadFile(InputFile: string): string;
function RemoveLineBreaks(inp: string): string;
 
implementation
 
128,5 → 129,12
CloseFile(f);
end;
 
function RemoveLineBreaks(inp: string): string;
begin
inp := StringReplace(inp, #13, '', [rfReplaceAll]);
inp := StringReplace(inp, #10, '', [rfReplaceAll]);
result := inp;
end;
 
end.
/trunk/LevelFunctions.pas
3,10 → 3,10
interface
 
uses
SysUtils, Dialogs, Functions, ExtCtrls, Graphics, Classes, Math;
SysUtils, Dialogs, Functions, ExtCtrls, Graphics;
 
type
TFieldType = (ftFullSpace, ftHalfSpace, ftEmpty, ftRed, ftYellow, ftGreen);
TFieldType = (ftLocked, ftLockedWithTab, ftEmpty, ftGreen, ftYellow, ftRed);
 
TFieldProperties = record
Typ: TFieldType;
13,57 → 13,71
Goal: Boolean;
end;
 
TGameMode = (gmUndefined, gmNormal, gmDiagonal);
TLevelType = (ltStandard, ltDiagonal, ltError);
 
TLevelArray = array of array of TFieldProperties;
 
TLevelError = (leNone, leInvalidElement, leEmptyBoard, leRowInvalidLength,
leUnsupportedVersion, leUnsupportedMode);
TLevelError = (leNone, leInvalidElement, leNoIndicator, leMultipleIndicator,
leLevelIncomplete, leHeaderError, leInvalidGoal);
 
TLevel = class(TObject)
private
FStringList: TStringList;
procedure Load(ABoardFile: string);
public
constructor Create(ABoardFile: string);
destructor Destroy; override;
function LevelStringToLevelArray(ShowErrors: boolean): TLevelArray;
function CheckLevelIntegrity: TLevelError; overload;
function CheckLevelIntegrity(ShowErrors: boolean): TLevelError; overload;
function GetGameMode: TGameMode;
end;
 
procedure DrawLevelPreview(Level: TLevel; Image: TImage; BackgroundColor: TColor);
procedure DrawLevelPreview(LevelString: string; Image: TImage; BackgroundColor: TColor);
function GetLevelType(LevelString: string): TLevelType;
function CheckLevelIntegrity(LevelString: string; ShowErrors: boolean): TLevelError; overload;
function CheckLevelIntegrity(LevelString: string): TLevelError; overload;
function LevelStringToLevelArray(LevelString: string; ShowErrors: boolean): TLevelArray;
function FieldTypeWorth(t: TFieldType): integer;
 
var
AllowDiagonalMoves: boolean;
 
implementation
 
procedure DrawLevelPreview(Level: TLevel; Image: TImage; BackgroundColor: TColor);
const
PREVIEW_BLOCK_SIZE = 10; // Enthält Field und Abstand
PREVIEW_TAB_SIZE = PREVIEW_BLOCK_SIZE div 2; // 5
HEADER_SIZE = 3;
ERED = '3';
EYEL = '2';
EGRE = '1';
ELOC = 'X';
EEMP = 'E';
EIND = '!';
ETAR = '>';
ESPE = '*';
TY_DIA = 'D';
TY_NOR = 'N';
 
resourcestring
LNG_LVL_INVALID_ELEMENT = 'Level invalid: There are invalid elements in the file.'+#13#10#13#10+'Valid elements are "1", "2", "3", "X", "*", "E" and ">" as goal prefix.';
LNG_LVL_INVALID_WIDTH = 'Level invalid: No width indicator ("!") found.';
LNG_LVL_INVALID_HEIGHT_MUTLIPLE = 'Level invalid: The level''s actual length is not a multiple of the width.';
LNG_LVL_INVALID_MULTIPLE_WIND = 'Level invalid: There are multiple width indicators ("!").';
LNG_LVL_INVALID_HEADER = 'Level invalid: The header is invalid. It does not match the structure "1(D|N)~".';
LNG_INVALID_GOAL = 'Level invalid: A goal does not point to a valid accessable element ("3", "2", "1" or "E").';
 
procedure DrawLevelPreview(LevelString: string; Image: TImage; BackgroundColor: TColor);
var
LevelArray: TLevelArray;
y, x: integer;
i, j: integer;
t: TFieldType;
halftabs: integer;
const
PREVIEW_BLOCK_SIZE = 10; // Enthält Field und Abstand
PREVIEW_TAB_SIZE = PREVIEW_BLOCK_SIZE div 2; // 5
begin
LevelArray := nil;
 
ClearImage(Image, BackgroundColor);
 
LevelArray := Level.LevelStringToLevelArray(false);
LevelArray := LevelStringToLevelArray(LevelString, false);
 
for y := Low(LevelArray) to High(LevelArray) do
for i := Low(LevelArray) to High(LevelArray) do
begin
halftabs := 0;
for x := Low(LevelArray[y]) to High(LevelArray[y]) do
for j := Low(LevelArray[i]) to High(LevelArray[i]) do
begin
t := LevelArray[y][x].Typ;
t := LevelArray[i][j].Typ;
 
case t of
ftFullSpace: Image.Canvas.Brush.Color := BackgroundColor;
ftHalfSpace: begin
ftLocked: Image.Canvas.Brush.Color := BackgroundColor;
ftLockedWithTab: begin
Image.Canvas.Brush.Color := BackgroundColor;
inc(halftabs);
end;
73,215 → 87,231
ftRed: Image.Canvas.Brush.Color := clRed;
end;
 
if LevelArray[y][x].Goal then
if LevelArray[i][j].Goal then
Image.Canvas.Pen.Color := clBlack
else
Image.Canvas.Pen.Color := BackgroundColor;
 
Image.Canvas.Rectangle((x-halftabs)*PREVIEW_BLOCK_SIZE + halftabs*PREVIEW_TAB_SIZE,
y*PREVIEW_BLOCK_SIZE,
(x-halftabs)*PREVIEW_BLOCK_SIZE + halftabs*PREVIEW_TAB_SIZE + PREVIEW_BLOCK_SIZE,
y*PREVIEW_BLOCK_SIZE + PREVIEW_BLOCK_SIZE);
Image.Canvas.Rectangle(j*PREVIEW_BLOCK_SIZE - halftabs*PREVIEW_TAB_SIZE, i*PREVIEW_BLOCK_SIZE, j*PREVIEW_BLOCK_SIZE - halftabs*PREVIEW_TAB_SIZE+PREVIEW_BLOCK_SIZE, i*PREVIEW_BLOCK_SIZE+PREVIEW_BLOCK_SIZE);
end;
end;
end;
 
function FieldTypeWorth(t: TFieldType): integer;
function GetLevelType(LevelString: string): TLevelType;
begin
if t = ftGreen then result := 10
else if t = ftYellow then result := 20
else if t = ftRed then result := 30
else result := 0;
if CheckLevelIntegrity(LevelString) = leNone then
begin
if Copy(LevelString, 2, 1) = TY_DIA then
begin
result := ltDiagonal;
end
else // if Copy(LevelString, 2, 1) = TY_NOR
begin
result := ltStandard;
end;
 
{ TLevel }
 
const NUM_HEADERS = 2;
 
constructor TLevel.Create(ABoardFile: string);
end
else
begin
inherited Create;
FStringList := TStringList.Create;
Load(ABoardFile);
result := ltError;
end;
end;
 
destructor TLevel.Destroy;
procedure ShowErrorMessage(error: TLevelError);
begin
FreeAndNil(FStringList);
 
inherited;
case error of
leNone: ;
leInvalidElement: MessageDlg(LNG_LVL_INVALID_ELEMENT, mtError, [mbOk], 0);
leNoIndicator: MessageDlg(LNG_LVL_INVALID_WIDTH, mtError, [mbOk], 0);
leMultipleIndicator: MessageDlg(LNG_LVL_INVALID_MULTIPLE_WIND, mtError, [mbOk], 0);
leLevelIncomplete: MessageDlg(LNG_LVL_INVALID_HEIGHT_MUTLIPLE, mtError, [mbOk], 0);
leHeaderError: MessageDlg(LNG_LVL_INVALID_HEADER, mtError, [mbOk], 0);
leInvalidGoal: MessageDlg(LNG_INVALID_GOAL, mtError, [mbOk], 0);
end;
end;
 
function TLevel.GetGameMode: TGameMode;
function CheckLevelIntegrity(LevelString: string; ShowErrors: boolean): TLevelError;
begin
if LowerCase(FStringList.Strings[1]) = 'mode: normal' then
result := gmNormal
else if LowerCase(FStringList.Strings[1]) = 'mode: diagonal' then
result := gmDiagonal
else
result := gmUndefined;
result := CheckLevelIntegrity(LevelString);
if ShowErrors then ShowErrorMessage(result);
end;
 
procedure TLevel.Load(ABoardFile: string);
function CheckLevelIntegrity(LevelString: string): TLevelError;
var
i: Integer;
W: integer;
H: extended;
header, h_ver, h_dia, h_del, tmp: string;
p: integer;
begin
FStringList.Clear;
FStringList.LoadFromFile(ABoardFile);
result := leNone;
 
// Remove whitespaces and empty lines
for i := FStringList.Count-1 downto NUM_HEADERS do
// Entfernt die Zeilenumbrüche
 
LevelString := RemoveLineBreaks(LevelString);
 
// Check 1: Ist der Header OK?
 
header := copy(LevelString, 1, HEADER_SIZE);
 
h_ver := copy(header, 1, 1);
if h_ver <> '1' then
begin
FStringList.Strings[i] := StringReplace(FStringList.Strings[i], ' ', '', [rfReplaceAll]);
if FStringList.Strings[i] = '' then FStringList.Delete(i);
result := leHeaderError;
Exit;
end;
end;
 
function TLevel.LevelStringToLevelArray(ShowErrors: boolean): TLevelArray;
var
i: integer;
t: TFieldType;
err: TLevelError;
longestLine: Integer;
thisLine: Integer;
y: Integer;
x: Integer;
Line: string;
lch, uch: char;
ch: char;
h_dia := copy(header, 2, 1);
if (h_dia <> TY_DIA) and (h_dia <> TY_NOR) then
begin
// Zuerst nach Fehlern suchen
err := CheckLevelIntegrity(ShowErrors);
if err <> leNone then exit;
result := leHeaderError;
Exit;
end;
 
// Längste Zeile finden
longestLine := 0;
for i := NUM_HEADERS to FStringList.Count-1 do
h_del := copy(header, 3, 1);
if h_del <> '~' then
begin
longestLine := Max(longestLine, Length(FStringList.Strings[i]));
result := leHeaderError;
Exit;
end;
 
// Nun Matrix aufbauen
SetLength(result, 0);
for i := NUM_HEADERS to FStringList.Count-1 do
begin
y := i - NUM_HEADERS;
LevelString := copy(LevelString, HEADER_SIZE+1, Length(LevelString)-HEADER_SIZE);
 
SetLength(result, Length(result)+1); // add line to matrix
SetLength(result[y], longestLine);
// Check 2: Steht das ggf. vorhandenen ">" vor einem gültigen Feld 1, 2, 3, E?
 
Line := FStringList.Strings[i];
p := Position(LevelString, ETAR);
 
for x := 0 to LongestLine-1 do
while (p <> -1) do
begin
ch := Copy(Line,x+1,1)[1];
lch := LowerCase(ch)[1];
uch := UpperCase(ch)[1];
case lch of
'*': t := ftFullSpace;
'.': t := ftHalfSpace;
'e': t := ftEmpty;
'r': t := ftRed;
'y': t := ftYellow;
'g': t := ftGreen;
tmp := copy(LevelString, p+1, 1);
 
if (tmp <> EEMP) and (tmp <> EGRE) and (tmp <> EYEL) and (tmp <> ERED) then
begin
result := leInvalidGoal;
Exit;
end;
 
result[y][x].Typ := t;
result[y][x].Goal := (ch = uch) and (ch <> lch);
LevelString := StringReplace(LevelString, ETAR, '', []); // Dieses Ziel entfernen
 
p := Position(LevelString, ETAR);
end;
end;
end;
 
function TLevel.CheckLevelIntegrity(ShowErrors: boolean): TLevelError;
resourcestring
LNG_LVL_INVALID_ELEMENT = 'Level invalid: There are invalid elements in the file.'+#13#10#13#10+'Valid elements are r/R, y/Y, g/G, e/E, . and *.';
LNG_LVL_UNSUPPORTED_VERSION = 'Level format invalid: Version not supported.';
LNG_LVL_UNSUPPORTED_MODE = 'Level format invalid: Mode not supported.';
LNG_LVL_EMPTY_BOARD = 'Level invalid: Board is empty.';
LNG_LVL_INVALID_LENGTH = 'Level invalid: Lines don''t have an equal amount of elements.';
// Check 3: Kommt überhaupt ein "!" vor?
 
W := Position(LevelString, EIND);
 
if W = -1 then
begin
result := CheckLevelIntegrity;
if ShowErrors then
begin
case result of
leNone: ;
leInvalidElement: MessageDlg(LNG_LVL_INVALID_ELEMENT, mtError, [mbOk], 0);
leUnsupportedVersion: MessageDlg(LNG_LVL_UNSUPPORTED_VERSION, mtError, [mbOk], 0);
leUnsupportedMode: MessageDlg(LNG_LVL_UNSUPPORTED_MODE, mtError, [mbOk], 0);
leEmptyBoard: MessageDlg(LNG_LVL_EMPTY_BOARD, mtError, [mbOk], 0);
leRowInvalidLength: MessageDlg(LNG_LVL_INVALID_LENGTH, mtError, [mbOk], 0);
result := leNoIndicator;
Exit;
end;
end;
end;
 
function TLevel.CheckLevelIntegrity: TLevelError;
var
W: integer;
H: extended;
header, h_ver, h_dia, h_del, tmp: string;
p: integer;
i: Integer;
Line: string;
begin
result := leNone;
// Check 4: Kam das "!" mehrmals vor?
 
// Check 1: Ist der Header OK?
LevelString := StringReplace(LevelString, EIND, '', []); // Das Erste entfernen
 
if LowerCase(FStringList.Strings[0]) <> 'version 2' then
if Position(LevelString, EIND) <> -1 then // gibt es ein Zweites?
begin
result := leUnsupportedVersion;
exit;
result := leMultipleIndicator;
Exit;
end;
 
if ((LowerCase(FStringList.Strings[1]) <> 'mode: normal') and (LowerCase(FStringList.Strings[1]) <> 'mode: diagonal')) then
// Check 5: Geht das Level nicht in einem Quadrat oder Rechteck auf?
 
H := (Length(LevelString) - 1) / W;
 
if not Ganzzahlig(H) then
begin
result := leUnsupportedMode;
exit;
result := leLevelIncomplete;
Exit;
end;
 
// Check 2: Ist das Brett leer?
// Check 6: Gibt es ungültige Elemente im LevelString?
 
if FStringList.Count - NUM_HEADERS = 0 then
LevelString := StringReplace(LevelString, ESPE, '', [rfReplaceAll]);
LevelString := StringReplace(LevelString, ELOC, '', [rfReplaceAll]);
LevelString := StringReplace(LevelString, EEMP, '', [rfReplaceAll]);
LevelString := StringReplace(LevelString, EGRE, '', [rfReplaceAll]);
LevelString := StringReplace(LevelString, EYEL, '', [rfReplaceAll]);
LevelString := StringReplace(LevelString, ERED, '', [rfReplaceAll]);
 
if Length(LevelString) > 0 then
begin
result := leEmptyBoard;
exit;
result := leInvalidElement;
Exit;
end;
 
// Check 3: Geht das Level nicht in einem Quadrat oder Rechteck auf?
// Check 7: Kann im Level gesprungen werden
 
for i := NUM_HEADERS to FStringList.Count-1 do
begin
if Length(FStringList.Strings[i]) <> Length(FStringList.Strings[NUM_HEADERS]) then
begin
result := leRowInvalidLength; // at row y-NUM_HEADERS
exit;
{ Wird hier nicht abgeprüft, da dafür zuerst der PlayGround gebaut sein muss.
Es ist außerdem eher ein logischer Fehler, kein Fehler in der Levelstruktur! }
end;
end;
 
// Check 4: Gibt es ungültige Elemente in den Zeilen?
 
for i := NUM_HEADERS to FStringList.Count-1 do
function LevelStringToLevelArray(LevelString: string; ShowErrors: boolean): TLevelArray;
var
i, j, j_dec, c: integer;
m: string;
t: TFieldType;
W, H: integer;
err: TLevelError;
NextIsGoal: boolean;
begin
Line := FStringList.Strings[i];
// Zuerst nach Fehlern suchen
err := CheckLevelIntegrity(LevelString, ShowErrors);
if err <> leNone then exit;
 
Line := StringReplace(Line, '.', '', [rfReplaceAll]);
Line := StringReplace(Line, '*', '', [rfReplaceAll]);
Line := StringReplace(Line, 'r', '', [rfReplaceAll, rfIgnoreCase]);
Line := StringReplace(Line, 'y', '', [rfReplaceAll, rfIgnoreCase]);
Line := StringReplace(Line, 'g', '', [rfReplaceAll, rfIgnoreCase]);
Line := StringReplace(Line, 'e', '', [rfReplaceAll, rfIgnoreCase]);
// Headerinformationen auslesen
AllowDiagonalMoves := copy(LevelString, 2, 1) = TY_DIA;
 
if Length(Line) > 0 then
// Header entfernen
LevelString := copy(LevelString, HEADER_SIZE+1, Length(LevelString)-HEADER_SIZE);
 
// Entfernt die Zeilenumbrüche
LevelString := RemoveLineBreaks(LevelString);
 
// Dimensionen abmessen
W := Position(StringReplace(LevelString, ETAR, '', [rfReplaceAll]), EIND) - 1;
LevelString := StringReplace(LevelString, EIND, '', [rfReplaceAll]);
H := Length(LevelString) div W;
 
c := 1;
NextIsGoal := false;
 
SetLength(result, round(H));
for i := Low(result) to High(result) do
begin
result := leInvalidElement; // at row y-NUM_HEADERS
Exit;
j_dec := 0;
SetLength(result[i], round(W));
for j := Low(result[i]) to High(result[i])+1 do // +1 wegen dem möglichen zusätzlichem ">"
begin
if (j = High(result[i])+1) and (j_dec = 0) then break;
m := Copy(LevelString, c, 1);
if m = ETAR then
begin
NextIsGoal := true;
inc(j_dec);
end
else
begin
if m = EEMP then t := ftEmpty
else if m = EGRE then t := ftGreen
else if m = EYEL then t := ftYellow
else if m = ERED then t := ftRed
else if m = ESPE then t := ftLockedWithTab
else t := ftLocked;
result[i][j-j_dec].Typ := t;
result[i][j-j_dec].Goal := NextIsGoal;
if NextIsGoal then NextIsGoal := false;
end;
inc(c);
end;
end;
end;
 
// Check 5: Kann im Level gesprungen werden
 
{ Wird hier nicht abgeprüft, da dafür zuerst der PlayGround gebaut sein muss.
Es ist außerdem eher ein logischer Fehler, kein Fehler in der Levelstruktur! }
function FieldTypeWorth(t: TFieldType): integer;
begin
if t = ftGreen then result := 10
else if t = ftYellow then result := 20
else if t = ftRed then result := 30
else result := 0;
end;
 
end.
/trunk/Private/Konzept.txt
28,4 → 28,3
 
Fragen
- Sollte es möglich sein, dass es mehrere Ziele gibt? z.B. 2 Ziele für 2 Steine?
- Sollte "Triangle" ein eigener Gamemode sein? (Ist genau so wie Diagonal, aber anderes Icon)
/trunk/Choice.dfm
2,7 → 2,7
Left = 257
Top = 146
Caption = 'ViaThinkSoft Peg Solitaire - Board choice'
ClientHeight = 415
ClientHeight = 406
ClientWidth = 656
Color = clBtnFace
Font.Charset = DEFAULT_CHARSET
82,7 → 82,7
Left = 24
Top = 32
Bitmap = {
494C010103001800340020002000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
494C010103001800200020002000FFFFFFFFFF10FFFFFFFFFFFFFFFF424D3600
0000000000003600000028000000800000002000000001002000000000000040
0000000000000000000000000000000000000000000000000000000000000000
0000800000008000000080000000800000008000000080000000800000008000
/trunk/HighScore.dfm
26,10 → 26,6
object PPMTab: TTabSheet
Caption = 'Highest Points per Minute'
ImageIndex = 3
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
object PPMList: TListView
Left = 8
Top = 8
59,10 → 55,6
end
object RemainingTab: TTabSheet
Caption = 'Lowest remaining stones'
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
object RemainingList: TListView
Left = 8
Top = 8
93,10 → 85,6
object TimeTab: TTabSheet
Caption = 'Shortest time'
ImageIndex = 1
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
object TimeList: TListView
Left = 8
Top = 8
127,10 → 115,6
object ScoreTab: TTabSheet
Caption = 'Highest score'
ImageIndex = 2
ExplicitLeft = 0
ExplicitTop = 0
ExplicitWidth = 0
ExplicitHeight = 0
object ScoreList: TListView
Left = 8
Top = 8
/trunk/Boards/Drag-n-Drop Board Variant B.brd
1,9 → 1,8
Version 2
Mode: Normal
* * e r r * *
* r y y y r *
r y g g g y r
r y g g g y r
r y g g g y r
* r y y y r *
* * r r r * *
1N~
XXE33XX!
X32223X
3211123
3211123
3211123
X32223X
XX333XX
/trunk/Boards/Drag-n-Drop Board Variant A with diagonal moves.brd
1,9 → 1,8
Version 2
Mode: Diagonal
* * r r r * *
* r y y y r *
r y g g g y r
r y g e g y r
r y g g g y r
* r y y y r *
* * r r r * *
1D~
XX333XX!
X32223X
3211123
321E123
3211123
X32223X
XX333XX
/trunk/Boards/Drag-n-Drop Board Variant B with diagonal moves.brd
1,9 → 1,8
Version 2
Mode: Diagonal
* * e r r * *
* r y y y r *
r y g g g y r
r y g g g y r
r y g g g y r
* r y y y r *
* * r r r * *
1D~
XXE33XX!
X32223X
3211123
3211123
3211123
X32223X
XX333XX
/trunk/Boards/German Wiegleb Board.brd
1,11 → 1,10
Version 2
Mode: Normal
* * * y y y * * *
* * * y y y * * *
* * * y y y * * *
y y y y y y y y y
y y y y E y y y y
y y y y y y y y y
* * * y y y * * *
* * * y y y * * *
* * * y y y * * *
1N~
XXX222XXX!
XXX222XXX
XXX222XXX
222222222
2222>E2222
222222222
XXX222XXX
XXX222XXX
XXX222XXX
/trunk/Boards/French Solitaire.brd
1,9 → 1,8
Version 2
Mode: Normal
* * y y y * *
* y y y y y *
y y y e y y y
y y y y y y y
y y y Y y y y
* y y y y y *
* * y y y * *
1N~
XX222XX!
X22222X
222E222
2222222
222>2222
X22222X
XX222XX
/trunk/Boards/English Standard Board.brd
1,9 → 1,8
Version 2
Mode: Normal
* * y y y * *
* * y y y * *
y y y y y y y
y y y E y y y
y y y y y y y
* * y y y * *
* * y y y * *
1N~
XX222XX!
XX222XX
2222222
222>E222
2222222
XX222XX
XX222XX
/trunk/Boards/Diamond Board.brd
1,11 → 1,10
Version 2
Mode: Normal
* * * * y * * * *
* * * y y y * * *
* * y y y y y * *
* y y y y y y y *
y y y y E y y y y
* y y y y y y y *
* * y y y y y * *
* * * y y y * * *
* * * * y * * * *
1N~
XXXX2XXXX!
XXX222XXX
XX22222XX
X2222222X
2222>E2222
X2222222X
XX22222XX
XXX222XXX
XXXX2XXXX
/trunk/Boards/German Wiegleb Board with diagonal moves.brd
1,11 → 1,10
Version 2
Mode: Diagonal
* * * y y y * * *
* * * y y y * * *
* * * y y y * * *
y y y y y y y y y
y y y y E y y y y
y y y y y y y y y
* * * y y y * * *
* * * y y y * * *
* * * y y y * * *
1D~
XXX222XXX!
XXX222XXX
XXX222XXX
222222222
2222>E2222
222222222
XXX222XXX
XXX222XXX
XXX222XXX
/trunk/Boards/French Solitaire with diagonal moves.brd
1,9 → 1,8
Version 2
Mode: Diagonal
* * y y y * *
* y y y y y *
y y y e y y y
y y y y y y y
y y y Y y y y
* y y y y y *
* * y y y * *
1D~
XX222XX!
X22222X
222E222
2222222
222>2222
X22222X
XX222XX
/trunk/Boards/English Standard Board with diagonal moves.brd
1,9 → 1,8
Version 2
Mode: Diagonal
* * y y y * *
* * y y y * *
y y y y y y y
y y y E y y y
y y y y y y y
* * y y y * *
* * y y y * *
1D~
XX222XX!
XX222XX
2222222
222>E222
2222222
XX222XX
XX222XX
/trunk/Boards/Diamond Board with diagonal moves.brd
1,11 → 1,10
Version 2
Mode: Diagonal
* * * * y * * * *
* * * y y y * * *
* * y y y y y * *
* y y y y y y y *
y y y y E y y y y
* y y y y y y y *
* * y y y y y * *
* * * y y y * * *
* * * * y * * * *
1D~
XXXX2XXXX!
XXX222XXX
XX22222XX
X2222222X
2222>E2222
X2222222X
XX22222XX
XXX222XXX
XXXX2XXXX
/trunk/Boards/Asymetric 3-3-2-2 Board.brd
1,10 → 1,9
Version 2
Mode: Normal
* * y y y * * *
* * y y y * * *
* * y y y * * *
y y y y y y y y
y y y E y y y y
y y y y y y y y
* * y y y * * *
* * y y y * * *
1N~
XX222XXX!
XX222XXX
XX222XXX
22222222
222>E2222
22222222
XX222XXX
XX222XXX
/trunk/Boards/Asymetric 3-3-2-2 Board with diagonal moves.brd
1,10 → 1,9
Version 2
Mode: Diagonal
* * y y y * * *
* * y y y * * *
* * y y y * * *
y y y y y y y y
y y y E y y y y
y y y y y y y y
* * y y y * * *
* * y y y * * *
1D~
XX222XXX!
XX222XXX
XX222XXX
22222222
222>E2222
22222222
XX222XXX
XX222XXX
/trunk/Boards/FunCircus.brd
1,11 → 1,10
Version 2
Mode: Normal
y g r y r g y r y
g y r g y r g y r
g y r g y y r g r
g y r g r g y y r
g y r y e r y g r
g y r y g r g y y
g g y r g y r g y
g y y r y g y r y
g y r y r y g r y
1N~
213231232!
123123123
123122313
123131223
1232E3213
123213122
112312312
122321232
123232132
/trunk/Boards/How to develop levels.txt
3,24 → 3,35
 
Path and name: Boards\*.brd
Author: Daniel Marschall
Revision: 11 November 2018
Revision: March, 7th 2009
 
== Header sequence ==
 
line 1: version 2
line 2: mode: normal
or
mode: diagonal
1 Version/Variant 1
D|N Are diagonal moves allowed or not allowed?
~ End of header
 
== The elements ==
 
* This is a locked field. You cannot place a stone there.
. This is a locked field with the width of a half block. Use it for aligning triangle shaped boards.
r Slot with a red (30 pts) stone.
y Slot with a yellow (20 pts) stone.
g Slot filled with a green (10 pts) stone.
e Empty slot
X This is a locked field. You cannot place a stone there
3 This is a space with a red (30) stone.
2 This is a space with a yellow (20) stone.
1 This is a space with a green (10) stone.
E This is a space.
* This is handled like a locked field (X), but it has only the half width.
This is necessary if you want to have a playground in a triangle shape.
 
Uppercase means the slot is a target (where the last stone has to go).
== Special chars between the elements ==
 
Whitespaces and extra line breaks are ignored.
> The next element (which may not be X, * or a line end) is the area,
where the last stone has to go to.
! Between the first and the second line of the matrix, there has to
be an "!". This is neccessary that the width can be detected.
There has to be one "!" in the file. Also, the level has to be complete.
If there are 9 elements before "!", then the level is only valid,
if there are 0, 9, 18, 27, 36, ... elements after the "!".
 
== Hints ==
 
Carriage-Return (CR) and Line-feeds (LF) are optional, but they are recommended because
of a better overview.
/trunk/Boards/Triangle Board Variant A.brd
1,7 → 1,6
Version 2
Mode: Diagonal
....e
...y y
..y y y
.y y y y
y y Y y y
1D~
****E!
***22
**222
*2222
22>222
/trunk/Boards/Triangle Board Variant B.brd
1,7 → 1,6
Version 2
Mode: Diagonal
....E
...y y
..y y y
.y y y y
y y y y y
1D~
****>E!
***22
**222
*2222
22222
/trunk/Boards/FunCircus with diagonal moves.brd
1,11 → 1,10
Version 2
Mode: Diagonal
y g r y r g y r y
g y r g y r g y r
g y r g y y r g r
g y r g r g y y r
g y r y e r y g r
g y r y g r g y y
g g y r g y r g y
g y y r y g y r y
g y r y r y g r y
1D~
213231232!
123123123
123122313
123131223
1232E3213
123213122
112312312
122321232
123232132
/trunk/Boards/Drag-n-Drop Board Variant A.brd
1,9 → 1,8
Version 2
Mode: Normal
* * r r r * *
* r y y y r *
r y g g g y r
r y g e g y r
r y g g g y r
* r y y y r *
* * r r r * *
1N~
XX333XX!
X32223X
3211123
321E123
3211123
X32223X
XX333XX