Subversion Repositories jumper

Compare Revisions

Regard whitespace Rev 18 → Rev 19

/trunk/Boards/Diamond Board.brd
File deleted
/trunk/Boards/Drag-n-Drop Board Variant A.brd
File deleted
/trunk/Boards/Diamond Board with diagonal moves.brd
File deleted
/trunk/Boards/6x6 Square with diagonal moves.brd
0,0 → 1,8
Version 2
Mode: Diagonal
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
/trunk/Boards/6x6 Square.brd
0,0 → 1,8
Version 2
Mode: Normal
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
/trunk/Boards/Arrow.brd
0,0 → 1,9
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
/trunk/Boards/D.brd
0,0 → 1,9
Version 2
Mode: Diagonal
e e y y y * *
e e y y y * *
y y * * y y y
y y * * y y y
y y * * y y y
e e y y y * *
e e y y y * *
/trunk/Boards/Diamond Board Variant A.brd
0,0 → 1,11
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 * * * *
/trunk/Boards/Diamond Board Variant B.brd
0,0 → 1,11
Version 2
Mode: Diagonal
* * * * 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 *
* * y y y y y * *
* * * y y y * * *
* * * * y * * * *
/trunk/Boards/Drag-n-Drop Board Variant A.brd
0,0 → 1,9
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 * *
/trunk/Boards/Heart Diagonal.brd
0,0 → 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 e y y y y y
* y y y y y y y *
* * y y y y y * *
* * * y y y * * *
* * * * y * * * *
/trunk/Boards/Heart.brd
0,0 → 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 e y y y y y
* y y y y y y y *
* * y y y y y * *
* * * y y y * * *
* * * * y * * * *
/trunk/Boards/Hexagonal.brd
0,0 → 1,11
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 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 * * *
....y y y y y * * * *
/trunk/Boards/How to develop levels.txt
3,7 → 3,7
 
Path and name: Boards\*.brd
Author: Daniel Marschall
Revision: 11 November 2018
Revision: 12 November 2018
 
== Header sequence ==
 
15,7 → 15,6
== 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.
23,4 → 22,7
 
Uppercase means the slot is a target (where the last stone has to go).
 
Whitespaces and extra line breaks are ignored.
Dots (.) at the beginning of a line shift the line to the right by a half block size (optical only).
Dots (.) at the end of a line shift the line to the left by a half block size (optical only).
 
Whitespaces between elements and empty lines are ignored.
/trunk/Boards/Rhombus.brd
0,0 → 1,7
Version 2
Mode: Diagonal
....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
/trunk/Boards/Snowflake.brd
0,0 → 1,11
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 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 * y y * * * *
/trunk/Boards/Star.brd
0,0 → 1,7
Version 2
Mode: Diagonal
* * * e * ...
* y y y y ..
* y y y * .
y y y y *
. * y * * *
/trunk/Boards/Trapeze.brd
0,0 → 1,6
Version 2
Mode: Diagonal
...y y y y * * *
..e y y y y * *
.y y y y y y *
y y y y y y y
/trunk/Boards/Triangle Board Variant A.brd
1,7 → 1,7
Version 2
Mode: Diagonal
....e
...y y
..y y y
.y y y y
....e * * * *
...y y * * *
..y y y * *
.y y y y *
y y Y y y
/trunk/Boards/Triangle Board Variant B.brd
1,7 → 1,7
Version 2
Mode: Diagonal
....E
...y y
..y y y
.y y y y
....E * * * *
...y y * * *
..y y y * *
.y y y y *
y y y y y
/trunk/Boards/Triangle Board Variant C.brd
0,0 → 1,10
Version 2
Mode: Diagonal
* * * * * * 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 *
/trunk/LevelFunctions.pas
6,7 → 6,7
SysUtils, Dialogs, Functions, ExtCtrls, Graphics, Classes, Math;
 
type
TFieldType = (ftFullSpace, ftHalfSpace, ftEmpty, ftRed, ftYellow, ftGreen);
TFieldType = (ftUndefined, ftFullSpace, ftEmpty, ftRed, ftYellow, ftGreen);
 
TFieldProperties = record
Typ: TFieldType;
15,9 → 15,13
 
TGameMode = (gmUndefined, gmNormal, gmDiagonal);
 
TLevelArray = array of array of TFieldProperties;
TRow = record
Indent: integer;
Fields: array of TFieldProperties;
end;
TLevelArray = array of TRow;
 
TLevelError = (leNone, leInvalidElement, leEmptyBoard, leRowInvalidLength,
TLevelError = (leUndefined, leNone, leInvalidElement, leEmptyBoard, leRowInvalidLength,
leUnsupportedVersion, leUnsupportedMode);
 
TLevel = class(TObject)
43,7 → 47,7
LevelArray: TLevelArray;
y, x: integer;
t: TFieldType;
halftabs: integer;
indent: Integer;
const
PREVIEW_BLOCK_SIZE = 10; // Enthält Field und Abstand
PREVIEW_TAB_SIZE = PREVIEW_BLOCK_SIZE div 2; // 5
56,17 → 60,13
 
for y := Low(LevelArray) to High(LevelArray) do
begin
halftabs := 0;
for x := Low(LevelArray[y]) to High(LevelArray[y]) do
for x := Low(LevelArray[y].Fields) to High(LevelArray[y].Fields) do
begin
t := LevelArray[y][x].Typ;
t := LevelArray[y].Fields[x].Typ;
indent := LevelArray[y].Indent;
 
case t of
ftFullSpace: Image.Canvas.Brush.Color := BackgroundColor;
ftHalfSpace: begin
Image.Canvas.Brush.Color := BackgroundColor;
inc(halftabs);
end;
ftEmpty: Image.Canvas.Brush.Color := clWhite;
ftGreen: Image.Canvas.Brush.Color := clLime;
ftYellow: Image.Canvas.Brush.Color := clYellow;
73,14 → 73,14
ftRed: Image.Canvas.Brush.Color := clRed;
end;
 
if LevelArray[y][x].Goal then
if LevelArray[y].Fields[x].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,
Image.Canvas.Rectangle(x*PREVIEW_BLOCK_SIZE + indent*PREVIEW_TAB_SIZE,
y*PREVIEW_BLOCK_SIZE,
(x-halftabs)*PREVIEW_BLOCK_SIZE + halftabs*PREVIEW_TAB_SIZE + PREVIEW_BLOCK_SIZE,
x*PREVIEW_BLOCK_SIZE + indent*PREVIEW_TAB_SIZE + PREVIEW_BLOCK_SIZE,
y*PREVIEW_BLOCK_SIZE + PREVIEW_BLOCK_SIZE);
end;
end;
137,13 → 137,39
end;
end;
 
function DotsAtBeginning(s: string): integer;
var
i: integer;
begin
result := 0;
for i := 1 to Length(s) do
begin
if s[i] = '.' then
Inc(result)
else
Exit;
end;
end;
 
function DotsAtEnd(s: string): integer;
var
i: integer;
begin
result := 0;
for i := Length(s) downto 1 do
begin
if s[i] = '.' then
Inc(result)
else
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;
154,13 → 180,6
err := CheckLevelIntegrity(ShowErrors);
if err <> leNone then exit;
 
// Längste Zeile finden
longestLine := 0;
for i := NUM_HEADERS to FStringList.Count-1 do
begin
longestLine := Max(longestLine, Length(FStringList.Strings[i]));
end;
 
// Nun Matrix aufbauen
SetLength(result, 0);
for i := NUM_HEADERS to FStringList.Count-1 do
168,18 → 187,21
y := i - NUM_HEADERS;
 
SetLength(result, Length(result)+1); // add line to matrix
SetLength(result[y], longestLine);
 
Line := FStringList.Strings[i];
result[y].Indent := DotsAtBeginning(Line) - DotsAtEnd(Line);
Line := StringReplace(Line, '.', '', [rfReplaceAll]);
SetLength(result[y].Fields, Length(Line));
 
for x := 0 to LongestLine-1 do
for x := 0 to Length(Line)-1 do
begin
ch := Copy(Line,x+1,1)[1];
ch := Line[x+1];
lch := LowerCase(ch)[1];
uch := UpperCase(ch)[1];
 
t := ftUndefined;
case lch of
'*': t := ftFullSpace;
'.': t := ftHalfSpace;
'e': t := ftEmpty;
'r': t := ftRed;
'y': t := ftYellow;
186,8 → 208,8
'g': t := ftGreen;
end;
 
result[y][x].Typ := t;
result[y][x].Goal := (ch = uch) and (ch <> lch);
result[y].Fields[x].Typ := t;
result[y].Fields[x].Goal := (ch = uch) and (ch <> lch);
end;
end;
end;
216,12 → 238,11
 
function TLevel.CheckLevelIntegrity: TLevelError;
var
W: integer;
H: extended;
header, h_ver, h_dia, h_del, tmp: string;
p: integer;
tmp: string;
i: Integer;
Line: string;
firstLine: string;
thisLine: string;
begin
result := leNone;
 
241,7 → 262,9
 
// Check 2: Ist das Brett leer?
 
if FStringList.Count - NUM_HEADERS = 0 then
tmp := '';
for i := NUM_HEADERS to FStringList.Count-1 do tmp := tmp + FStringList.Strings[i];
if Trim(StringReplace(tmp, '.', '', [rfReplaceAll])) = '' then
begin
result := leEmptyBoard;
exit;
249,9 → 272,11
 
// Check 3: Geht das Level nicht in einem Quadrat oder Rechteck auf?
 
firstLine := StringReplace(FStringList.Strings[NUM_HEADERS], '.', '', [rfReplaceAll]);
for i := NUM_HEADERS to FStringList.Count-1 do
begin
if Length(FStringList.Strings[i]) <> Length(FStringList.Strings[NUM_HEADERS]) then
thisLine := StringReplace(FStringList.Strings[i], '.', '', [rfReplaceAll]);
if Length(thisLine) <> Length(firstLine) then
begin
result := leRowInvalidLength; // at row y-NUM_HEADERS
exit;
/trunk/Main.dfm
25,8 → 25,8
PixelsPerInch = 96
TextHeight = 13
object Playground: TPanel
Left = 8
Top = 8
Left = 0
Top = 0
Width = 313
Height = 289
BevelOuter = bvNone
/trunk/Main.pas
14,9 → 14,9
Stone: TImage;
end;
 
TGoalStatus = (gsNoGoal, gsMultipleStonesRemaining, gsLastStoneInGoalRed, gsLastStoneInGoalYellow, gsLastStoneInGoalGreen, gsLastStoneOutsideGoal);
TGoalStatus = (gsUndefined, gsNoGoal, gsMultipleStonesRemaining, gsLastStoneInGoalRed, gsLastStoneInGoalYellow, gsLastStoneInGoalGreen, gsLastStoneOutsideGoal);
 
TFieldState = (fsError, fsLocked, fsAvailable, fsStone);
TFieldState = (fsUndefined, fsError, fsLocked, fsAvailable, fsStone);
 
TPlayGroundMatrix = array of array of TField;
 
93,10 → 93,9
function CanJump(x, y: integer): boolean;
function MayJump(SourceX, SourceY, DestX, DestY: integer): boolean; overload;
function MayJump(SourceTag, DestTag: integer): boolean; overload;
procedure StoneDragOver(Sender, Source: TObject; X,
Y: Integer; State: TDragState; var Accept: Boolean);
procedure StoneDragOver(Sender, Source: TObject; X, Y: Integer; State: TDragState; var Accept: Boolean);
procedure StoneDragDrop(Sender, Source: TObject; X, Y: Integer);
procedure DrawField(x, y: integer; t: TFieldProperties; halftabs: integer);
function DrawField(x, y: integer; t: TFieldProperties; indent: integer): TField;
function DrawStone(fieldtype: TFieldType; panel: TPanel): TImage;
function DrawStoneBox(x, y, tag, halftabs: integer; isGoal: boolean): TPanel;
procedure BuildPlayground(LevelArray: TLevelArray);
118,7 → 117,7
implementation
 
uses
About, Finish, Choice, Functions, History, HighScore, Help, Constants;
About, Finish, Choice, Functions, History, HighScore, Help, Constants, Math;
 
{$R *.dfm}
 
140,6 → 139,7
var
i, j: integer;
begin
result := ftEmpty; // Damit der Compiler nicht meckert
for i := Low(Matrix) to High(Matrix) do
begin
for j := Low(Matrix[i]) to High(Matrix[i]) do
288,7 → 288,7
result.BevelOuter := bvLowered;
result.Width := MET_FIELD_SIZE;
result.Height := MET_FIELD_SIZE;
result.Left := x * (MET_FIELD_SIZE+MET_FIELD_SPACE) + MET_FIELD_SPACE - (halftabs*MET_HALFTAB_SIZE);
result.Left := x * (MET_FIELD_SIZE+MET_FIELD_SPACE) + MET_FIELD_SPACE + (halftabs*MET_HALFTAB_SIZE);
result.Top := y * (MET_FIELD_SIZE+MET_FIELD_SPACE) + MET_FIELD_SPACE;
 
result.Tag := tag;
306,7 → 306,6
result := fsError;
case t of
ftFullSpace: result := fsLocked;
ftHalfSpace: result := fsLocked;
ftEmpty: result := fsAvailable;
ftGreen: result := fsStone;
ftYellow: result := fsStone;
557,18 → 556,19
Accept := MayJump(TComponent(Source).Tag, TComponent(Sender).Tag);
end;
 
procedure TMainForm.DrawField(x, y: integer; t: TFieldProperties; halftabs: integer);
function TMainForm.DrawField(x, y: integer; t: TFieldProperties; indent: integer): TField;
var
newField: TField;
index: integer;
begin
if (t.Typ = ftFullSpace) or (t.Typ = ftHalfSpace) then exit;
ZeroMemory(@result, SizeOf(result));
if t.Typ = ftFullSpace then exit;
 
index := Length(LookupFieldCoordinateArray);
 
newField.FieldType := t.Typ;
newField.Goal := t.Goal;
newField.Panel := DrawStoneBox(x, y, index, halftabs, t.Goal);
newField.Panel := DrawStoneBox(x, y, index, indent, t.Goal);
newField.Stone := DrawStone(t.Typ, newField.Panel);
if FieldState(t.Typ) = fsStone then Inc(LevelTotalStones);
 
579,6 → 579,8
if Length(PlayGroundMatrix) < x+1 then SetLength(PlayGroundMatrix, x+1);
if Length(PlayGroundMatrix[x]) < y+1 then SetLength(PlayGroundMatrix[x], y+1);
PlaygroundMatrix[x, y] := newField;
 
result := newField;
end;
 
function TMainForm.CloneMatrix(Source: TPlayGroundMatrix): TPlayGroundMatrix;
601,53 → 603,46
 
procedure TMainForm.BuildPlayground(LevelArray: TLevelArray);
var
i, j, halftabs, cur_x: integer;
max_x, max_y, old_cw, old_ch: integer;
y, x: integer;
max_x, max_y: integer;
p: TPanel;
begin
PlayGround.Visible := false;
 
// Die Dimensionen ermitteln
max_x := 0;
for i := Low(LevelArray) to High(LevelArray) do
max_y := 0;
for y := Low(LevelArray) to High(LevelArray) do
begin
halftabs := 0;
for j := Low(LevelArray[i]) to High(LevelArray[i]) do
for x := Low(LevelArray[y].Fields) to High(LevelArray[y].Fields) do
begin
if LevelArray[i][j].Typ = ftHalfSpace then inc(halftabs);
DrawField(j, i, LevelArray[i][j], halftabs);
p := DrawField(x, y, LevelArray[y].Fields[x], LevelArray[y].Indent).Panel;
if Assigned(p) then
begin
max_x := Max(max_x, p.Left + p.Width);
max_y := Max(max_y, p.Top + p.Height);
end;
cur_x := High(LevelArray[i]) + 1;
if cur_x > max_x then max_x := cur_x;
end;
max_y := High(LevelArray) + 1;
end;
 
PlayGround.Visible := true;
 
// Die aktuellen Dimensionen merken
old_cw := ClientWidth;
old_ch := ClientHeight;
 
// Das Form an das Level anpassen
PlayGround.Width := MET_FIELD_SPACE + max_x * (MET_FIELD_SPACE + MET_FIELD_SIZE);
PlayGround.Height := MET_FIELD_SPACE + max_y * (MET_FIELD_SPACE + MET_FIELD_SIZE);
PlayGround.Top := MET_OUTER_MARGIN;
PlayGround.Left := MET_OUTER_MARGIN;
PlayGround.Width := max_x;
PlayGround.Height := max_y;
ClientWidth := 2 * MET_OUTER_MARGIN + PlayGround.Width;
ClientHeight := 2 * MET_OUTER_MARGIN + PlayGround.Height + Statistics.Height;
 
// If the board is too small, ClientWidth/ClientHeight will stop at a minimum value
// in this case, we make sure that the Playground is centered
PlayGround.Left := ClientWidth div 2 - Playground.Width div 2;
PlayGround.Top := (ClientHeight - Statistics.Height) div 2 - Playground.Height div 2;
 
Statistics.Panels.Items[0].Width := Round(ClientWidth*MET_PERCENT_PNL_TIME);
Statistics.Panels.Items[1].Width := Round(ClientWidth*MET_PERCENT_PNL_STONES);
 
// Wenn sich das Form vergrößert oder verkleinert hat, neu justieren
if (old_cw <> ClientWidth) or (old_ch <> ClientHeight) then
begin
Left := Screen.Width div 2 - Width div 2;
Top := Screen.Height div 2 - Height div 2;
// Playground mittig setzen, falls die Mindestgröße für die
// Punkteanzeige unterschritten wurde,
PlayGround.Left := ClientWidth div 2 - PlayGround.Width div 2;
PlayGround.Top := ClientHeight div 2 - PlayGround.Height div 2;
end;
 
SetLength(PrevPlaygroundMatrixes,1);
PrevPlaygroundMatrixes[0] := CloneMatrix(PlayGroundMatrix);
MUndo.Enabled := false;
740,7 → 735,9
else if ft = ftYellow then
result := gsLastStoneInGoalYellow
else if ft = ftGreen then
result := gsLastStoneInGoalGreen;
result := gsLastStoneInGoalGreen
else
result := gsUndefined;
end;
end;
 
/trunk/Private/Konzept.txt
5,6 → 5,7
 
ToDo:
- deutsche übersetzung prüfen, besonders hilfefenster
- prüfen, welche boards lösbar sind, und in welchen diagonale züge erlaubt werden sollen und in welchen nicht
 
Kleinigkeiten:
- standardbretter aus wikipedia als level entwickeln
15,7 → 16,7
- sollte das ziel-feld besser farblich hervorgehoben werden?
 
Zukunft:
- hervorheben von gültigen feldern (conf)
- hervorheben von gültigen feldern, wenn drag gestartet wird (+ deaktivierbar machen)
- Leveleditor designen
- 9 Steinsorten?
- Panels durch Grafiken ersetzen, Grafik-Templates mit Tile-Background erlauben
26,4 → 27,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)