/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) |