Rev 21 | Rev 23 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
1 | daniel-mar | 1 | unit LevelFunctions; |
2 | |||
3 | interface |
||
4 | |||
5 | uses |
||
21 | daniel-mar | 6 | SysUtils, Dialogs, Functions, ExtCtrls, Classes, Math; |
1 | daniel-mar | 7 | |
8 | type |
||
19 | daniel-mar | 9 | TFieldType = (ftUndefined, ftFullSpace, ftEmpty, ftRed, ftYellow, ftGreen); |
1 | daniel-mar | 10 | |
11 | TFieldProperties = record |
||
12 | Typ: TFieldType; |
||
13 | Goal: Boolean; |
||
14 | end; |
||
15 | |||
11 | daniel-mar | 16 | TGameMode = (gmUndefined, gmNormal, gmDiagonal); |
1 | daniel-mar | 17 | |
19 | daniel-mar | 18 | TRow = record |
19 | Indent: integer; |
||
20 | Fields: array of TFieldProperties; |
||
21 | end; |
||
22 | TLevelArray = array of TRow; |
||
1 | daniel-mar | 23 | |
19 | daniel-mar | 24 | TLevelError = (leUndefined, leNone, leInvalidElement, leEmptyBoard, leRowInvalidLength, |
11 | daniel-mar | 25 | leUnsupportedVersion, leUnsupportedMode); |
1 | daniel-mar | 26 | |
11 | daniel-mar | 27 | TLevel = class(TObject) |
28 | private |
||
29 | FStringList: TStringList; |
||
30 | procedure Load(ABoardFile: string); |
||
22 | daniel-mar | 31 | function GetGameMode: TGameMode; |
11 | daniel-mar | 32 | public |
33 | constructor Create(ABoardFile: string); |
||
34 | destructor Destroy; override; |
||
35 | function LevelStringToLevelArray(ShowErrors: boolean): TLevelArray; |
||
36 | function CheckLevelIntegrity: TLevelError; overload; |
||
37 | function CheckLevelIntegrity(ShowErrors: boolean): TLevelError; overload; |
||
22 | daniel-mar | 38 | property GameMode: TGameMode read GetGameMode; |
11 | daniel-mar | 39 | end; |
40 | |||
21 | daniel-mar | 41 | TField = record |
42 | FieldType: TFieldType; |
||
43 | Goal: Boolean; |
||
44 | Panel: TPanel; |
||
45 | Stone: TImage; |
||
46 | end; |
||
47 | |||
48 | TGoalStatus = (gsUndefined, gsNoGoal, gsMultipleStonesRemaining, gsLastStoneInGoalRed, gsLastStoneInGoalYellow, gsLastStoneInGoalGreen, gsLastStoneOutsideGoal); |
||
49 | |||
50 | TFieldState = (fsUndefined, fsError, fsLocked, fsAvailable, fsStone); |
||
51 | |||
52 | TPlayGroundMatrix = record |
||
53 | Fields: array of array of TField; |
||
54 | public |
||
55 | function MatrixHasGoal: boolean; |
||
56 | function GoalFieldType: TFieldType; |
||
57 | function MatrixWorth: integer; |
||
58 | procedure ClearMatrix(FreeVCL: boolean); |
||
59 | function CloneMatrix: TPlayGroundMatrix; |
||
60 | function FieldState(t: TFieldType): TFieldState; overload; |
||
61 | function FieldState(f: TField): TFieldState; overload; |
||
62 | function FieldState(x, y: integer): TFieldState; overload; |
||
22 | daniel-mar | 63 | function CanJump(SourceX, SourceY, DestX, DestY: integer; DiagonalOK: boolean): boolean; overload; |
64 | function CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean; overload; |
||
65 | function CanJump(DiagonalOK: boolean): boolean; overload; |
||
21 | daniel-mar | 66 | end; |
67 | |||
8 | daniel-mar | 68 | function FieldTypeWorth(t: TFieldType): integer; |
1 | daniel-mar | 69 | |
70 | implementation |
||
71 | |||
21 | daniel-mar | 72 | function FieldTypeWorth(t: TFieldType): integer; |
73 | begin |
||
74 | if t = ftGreen then result := 10 |
||
75 | else if t = ftYellow then result := 20 |
||
76 | else if t = ftRed then result := 30 |
||
77 | else result := 0; |
||
78 | end; |
||
79 | |||
80 | { TPlayGroundMatrix } |
||
81 | |||
82 | function TPlayGroundMatrix.MatrixHasGoal: boolean; |
||
1 | daniel-mar | 83 | var |
22 | daniel-mar | 84 | x, y: integer; |
1 | daniel-mar | 85 | begin |
21 | daniel-mar | 86 | result := false; |
22 | daniel-mar | 87 | for x := Low(Fields) to High(Fields) do |
21 | daniel-mar | 88 | begin |
22 | daniel-mar | 89 | for y := Low(Fields[x]) to High(Fields[x]) do |
21 | daniel-mar | 90 | begin |
22 | daniel-mar | 91 | result := result or Fields[x][y].Goal; |
21 | daniel-mar | 92 | end; |
93 | end; |
||
94 | end; |
||
1 | daniel-mar | 95 | |
21 | daniel-mar | 96 | function TPlayGroundMatrix.GoalFieldType: TFieldType; |
97 | var |
||
22 | daniel-mar | 98 | x, y: integer; |
21 | daniel-mar | 99 | begin |
100 | result := ftEmpty; // Damit der Compiler nicht meckert |
||
22 | daniel-mar | 101 | for x := Low(Fields) to High(Fields) do |
21 | daniel-mar | 102 | begin |
22 | daniel-mar | 103 | for y := Low(Fields[x]) to High(Fields[x]) do |
21 | daniel-mar | 104 | begin |
22 | daniel-mar | 105 | if Fields[x][y].Goal then result := Fields[x][y].FieldType |
21 | daniel-mar | 106 | end; |
107 | end; |
||
108 | end; |
||
1 | daniel-mar | 109 | |
21 | daniel-mar | 110 | function TPlayGroundMatrix.MatrixWorth: integer; |
111 | var |
||
22 | daniel-mar | 112 | x, y: integer; |
21 | daniel-mar | 113 | begin |
114 | result := 0; |
||
22 | daniel-mar | 115 | for x := Low(Fields) to High(Fields) do |
21 | daniel-mar | 116 | begin |
22 | daniel-mar | 117 | for y := Low(Fields[x]) to High(Fields[x]) do |
21 | daniel-mar | 118 | begin |
22 | daniel-mar | 119 | Inc(result, FieldTypeWorth(Fields[x][y].FieldType)); |
21 | daniel-mar | 120 | end; |
121 | end; |
||
122 | end; |
||
1 | daniel-mar | 123 | |
21 | daniel-mar | 124 | procedure TPlayGroundMatrix.ClearMatrix(FreeVCL: boolean); |
125 | var |
||
22 | daniel-mar | 126 | x, y: integer; |
21 | daniel-mar | 127 | begin |
22 | daniel-mar | 128 | for x := Low(Fields) to High(Fields) do |
1 | daniel-mar | 129 | begin |
22 | daniel-mar | 130 | for y := Low(Fields[x]) to High(Fields[x]) do |
1 | daniel-mar | 131 | begin |
21 | daniel-mar | 132 | if FreeVCL then |
133 | begin |
||
22 | daniel-mar | 134 | if Assigned(Fields[x][y].Stone) then Fields[x][y].Stone.Free; |
135 | if Assigned(Fields[x][y].Panel) then Fields[x][y].Panel.Free; |
||
1 | daniel-mar | 136 | end; |
21 | daniel-mar | 137 | end; |
22 | daniel-mar | 138 | SetLength(Fields[x], 0); |
21 | daniel-mar | 139 | end; |
140 | SetLength(Fields, 0); |
||
141 | end; |
||
1 | daniel-mar | 142 | |
21 | daniel-mar | 143 | function TPlayGroundMatrix.CloneMatrix: TPlayGroundMatrix; |
144 | var |
||
22 | daniel-mar | 145 | x, y: integer; |
21 | daniel-mar | 146 | begin |
147 | SetLength(result.Fields, Length(Fields)); |
||
22 | daniel-mar | 148 | for x := Low(Fields) to High(Fields) do |
21 | daniel-mar | 149 | begin |
22 | daniel-mar | 150 | SetLength(result.Fields[x], Length(Fields[x])); |
151 | for y := Low(Fields[x]) to High(Fields[x]) do |
||
21 | daniel-mar | 152 | begin |
22 | daniel-mar | 153 | result.Fields[x][y].FieldType := Fields[x][y].FieldType; |
154 | result.Fields[x][y].Goal := Fields[x][y].Goal; |
||
155 | result.Fields[x][y].Panel := Fields[x][y].Panel; |
||
156 | result.Fields[x][y].Stone := Fields[x][y].Stone; |
||
1 | daniel-mar | 157 | end; |
158 | end; |
||
159 | end; |
||
160 | |||
21 | daniel-mar | 161 | function TPlayGroundMatrix.FieldState(t: TFieldType): TFieldState; |
1 | daniel-mar | 162 | begin |
21 | daniel-mar | 163 | result := fsError; |
164 | case t of |
||
165 | ftFullSpace: result := fsLocked; |
||
166 | ftEmpty: result := fsAvailable; |
||
167 | ftGreen: result := fsStone; |
||
168 | ftYellow: result := fsStone; |
||
169 | ftRed: result := fsStone; |
||
170 | end; |
||
1 | daniel-mar | 171 | end; |
172 | |||
21 | daniel-mar | 173 | function TPlayGroundMatrix.FieldState(f: TField): TFieldState; |
174 | begin |
||
175 | result := FieldState(f.FieldType); |
||
176 | end; |
||
177 | |||
178 | function TPlayGroundMatrix.FieldState(x, y: integer): TFieldState; |
||
179 | begin |
||
180 | result := fsError; |
||
181 | if (x < Low(Fields)) or (x > High(Fields)) then exit; |
||
182 | if (y < Low(Fields[x])) or (y > High(Fields[x])) then exit; |
||
183 | |||
184 | result := FieldState(Fields[x][y]); |
||
185 | end; |
||
186 | |||
22 | daniel-mar | 187 | function TPlayGroundMatrix.CanJump(SourceX, SourceY, DestX, DestY: integer; DiagonalOK: boolean): boolean; |
188 | begin |
||
189 | result := false; |
||
190 | |||
191 | // Check 1: Ist das Zielfeld überhaupt leer? |
||
192 | if FieldState(DestX, DestY) <> fsAvailable then exit; |
||
193 | |||
194 | // Check 2: Befindet sich ein Stein zwischen Source und Destination und ist der Abstand 2? |
||
195 | if DiagonalOK then |
||
196 | begin |
||
197 | if (SourceX-2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX-1, SourceY-1) = fsStone) then result := true; |
||
198 | if (SourceX-2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX-1, SourceY+1) = fsStone) then result := true; |
||
199 | if (SourceX+2 = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX+1, SourceY-1) = fsStone) then result := true; |
||
200 | if (SourceX+2 = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX+1, SourceY+1) = fsStone) then result := true; |
||
201 | end; |
||
202 | |||
203 | if (SourceX+2 = DestX) and (SourceY = DestY) and (FieldState(SourceX+1, SourceY ) = fsStone) then result := true; |
||
204 | if (SourceX-2 = DestX) and (SourceY = DestY) and (FieldState(SourceX-1, SourceY ) = fsStone) then result := true; |
||
205 | if (SourceX = DestX) and (SourceY+2 = DestY) and (FieldState(SourceX , SourceY+1) = fsStone) then result := true; |
||
206 | if (SourceX = DestX) and (SourceY-2 = DestY) and (FieldState(SourceX , SourceY-1) = fsStone) then result := true; |
||
207 | end; |
||
208 | |||
209 | function TPlayGroundMatrix.CanJump(SourceX, SourceY: integer; DiagonalOK: boolean): boolean; |
||
210 | begin |
||
211 | if FieldState(SourceX, SourceY) <> fsStone then |
||
212 | begin |
||
213 | result := false; |
||
214 | exit; |
||
215 | end; |
||
216 | |||
217 | result := true; |
||
218 | |||
219 | if CanJump(SourceX, SourceY, SourceX+2, SourceY, DiagonalOK) then exit; |
||
220 | if CanJump(SourceX, SourceY, SourceX-2, SourceY, DiagonalOK) then exit; |
||
221 | if CanJump(SourceX, SourceY, SourceX, SourceY+2, DiagonalOK) then exit; |
||
222 | if CanJump(SourceX, SourceY, SourceX, SourceY-2, DiagonalOK) then exit; |
||
223 | |||
224 | if DiagonalOK then |
||
225 | begin |
||
226 | if CanJump(SourceX, SourceY, SourceX-2, SourceY-2, DiagonalOK) then exit; |
||
227 | if CanJump(SourceX, SourceY, SourceX+2, SourceY-2, DiagonalOK) then exit; |
||
228 | if CanJump(SourceX, SourceY, SourceX-2, SourceY+2, DiagonalOK) then exit; |
||
229 | if CanJump(SourceX, SourceY, SourceX+2, SourceY+2, DiagonalOK) then exit; |
||
230 | end; |
||
231 | |||
232 | result := false; |
||
233 | end; |
||
234 | |||
235 | function TPlayGroundMatrix.CanJump(DiagonalOK: boolean): boolean; |
||
236 | var |
||
237 | x, y: integer; |
||
238 | begin |
||
239 | result := false; |
||
240 | for x := Low(Fields) to High(Fields) do |
||
241 | begin |
||
242 | for y := Low(Fields[x]) to High(Fields[x]) do |
||
243 | begin |
||
244 | if CanJump(x, y, DiagonalOK) then |
||
245 | begin |
||
246 | result := true; |
||
247 | break; |
||
248 | end; |
||
249 | if result then break; |
||
250 | end; |
||
251 | end; |
||
252 | end; |
||
253 | |||
11 | daniel-mar | 254 | { TLevel } |
255 | |||
256 | const NUM_HEADERS = 2; |
||
257 | |||
258 | constructor TLevel.Create(ABoardFile: string); |
||
1 | daniel-mar | 259 | begin |
11 | daniel-mar | 260 | inherited Create; |
261 | FStringList := TStringList.Create; |
||
262 | Load(ABoardFile); |
||
1 | daniel-mar | 263 | end; |
264 | |||
11 | daniel-mar | 265 | destructor TLevel.Destroy; |
1 | daniel-mar | 266 | begin |
11 | daniel-mar | 267 | FreeAndNil(FStringList); |
268 | |||
269 | inherited; |
||
1 | daniel-mar | 270 | end; |
271 | |||
11 | daniel-mar | 272 | function TLevel.GetGameMode: TGameMode; |
273 | begin |
||
274 | if LowerCase(FStringList.Strings[1]) = 'mode: normal' then |
||
275 | result := gmNormal |
||
276 | else if LowerCase(FStringList.Strings[1]) = 'mode: diagonal' then |
||
277 | result := gmDiagonal |
||
278 | else |
||
279 | result := gmUndefined; |
||
280 | end; |
||
281 | |||
282 | procedure TLevel.Load(ABoardFile: string); |
||
1 | daniel-mar | 283 | var |
11 | daniel-mar | 284 | i: Integer; |
1 | daniel-mar | 285 | begin |
11 | daniel-mar | 286 | FStringList.Clear; |
287 | FStringList.LoadFromFile(ABoardFile); |
||
1 | daniel-mar | 288 | |
11 | daniel-mar | 289 | // Remove whitespaces and empty lines |
290 | for i := FStringList.Count-1 downto NUM_HEADERS do |
||
1 | daniel-mar | 291 | begin |
11 | daniel-mar | 292 | FStringList.Strings[i] := StringReplace(FStringList.Strings[i], ' ', '', [rfReplaceAll]); |
293 | if FStringList.Strings[i] = '' then FStringList.Delete(i); |
||
1 | daniel-mar | 294 | end; |
11 | daniel-mar | 295 | end; |
1 | daniel-mar | 296 | |
11 | daniel-mar | 297 | function TLevel.LevelStringToLevelArray(ShowErrors: boolean): TLevelArray; |
298 | var |
||
299 | i: integer; |
||
300 | t: TFieldType; |
||
301 | err: TLevelError; |
||
302 | y: Integer; |
||
303 | x: Integer; |
||
304 | Line: string; |
||
305 | lch, uch: char; |
||
306 | ch: char; |
||
307 | begin |
||
308 | // Zuerst nach Fehlern suchen |
||
309 | err := CheckLevelIntegrity(ShowErrors); |
||
310 | if err <> leNone then exit; |
||
311 | |||
312 | // Nun Matrix aufbauen |
||
313 | SetLength(result, 0); |
||
314 | for i := NUM_HEADERS to FStringList.Count-1 do |
||
1 | daniel-mar | 315 | begin |
11 | daniel-mar | 316 | y := i - NUM_HEADERS; |
1 | daniel-mar | 317 | |
11 | daniel-mar | 318 | SetLength(result, Length(result)+1); // add line to matrix |
1 | daniel-mar | 319 | |
11 | daniel-mar | 320 | Line := FStringList.Strings[i]; |
19 | daniel-mar | 321 | result[y].Indent := DotsAtBeginning(Line) - DotsAtEnd(Line); |
322 | Line := StringReplace(Line, '.', '', [rfReplaceAll]); |
||
323 | SetLength(result[y].Fields, Length(Line)); |
||
1 | daniel-mar | 324 | |
19 | daniel-mar | 325 | for x := 0 to Length(Line)-1 do |
11 | daniel-mar | 326 | begin |
19 | daniel-mar | 327 | ch := Line[x+1]; |
11 | daniel-mar | 328 | lch := LowerCase(ch)[1]; |
329 | uch := UpperCase(ch)[1]; |
||
19 | daniel-mar | 330 | |
331 | t := ftUndefined; |
||
11 | daniel-mar | 332 | case lch of |
333 | '*': t := ftFullSpace; |
||
334 | 'e': t := ftEmpty; |
||
335 | 'r': t := ftRed; |
||
336 | 'y': t := ftYellow; |
||
337 | 'g': t := ftGreen; |
||
338 | end; |
||
1 | daniel-mar | 339 | |
19 | daniel-mar | 340 | result[y].Fields[x].Typ := t; |
341 | result[y].Fields[x].Goal := (ch = uch) and (ch <> lch); |
||
11 | daniel-mar | 342 | end; |
343 | end; |
||
344 | end; |
||
345 | |||
346 | function TLevel.CheckLevelIntegrity(ShowErrors: boolean): TLevelError; |
||
347 | resourcestring |
||
348 | 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 *.'; |
||
349 | LNG_LVL_UNSUPPORTED_VERSION = 'Level format invalid: Version not supported.'; |
||
350 | LNG_LVL_UNSUPPORTED_MODE = 'Level format invalid: Mode not supported.'; |
||
351 | LNG_LVL_EMPTY_BOARD = 'Level invalid: Board is empty.'; |
||
352 | LNG_LVL_INVALID_LENGTH = 'Level invalid: Lines don''t have an equal amount of elements.'; |
||
353 | begin |
||
354 | result := CheckLevelIntegrity; |
||
355 | if ShowErrors then |
||
1 | daniel-mar | 356 | begin |
11 | daniel-mar | 357 | case result of |
358 | leNone: ; |
||
359 | leInvalidElement: MessageDlg(LNG_LVL_INVALID_ELEMENT, mtError, [mbOk], 0); |
||
360 | leUnsupportedVersion: MessageDlg(LNG_LVL_UNSUPPORTED_VERSION, mtError, [mbOk], 0); |
||
361 | leUnsupportedMode: MessageDlg(LNG_LVL_UNSUPPORTED_MODE, mtError, [mbOk], 0); |
||
362 | leEmptyBoard: MessageDlg(LNG_LVL_EMPTY_BOARD, mtError, [mbOk], 0); |
||
363 | leRowInvalidLength: MessageDlg(LNG_LVL_INVALID_LENGTH, mtError, [mbOk], 0); |
||
1 | daniel-mar | 364 | end; |
365 | end; |
||
11 | daniel-mar | 366 | end; |
1 | daniel-mar | 367 | |
11 | daniel-mar | 368 | function TLevel.CheckLevelIntegrity: TLevelError; |
369 | var |
||
19 | daniel-mar | 370 | tmp: string; |
11 | daniel-mar | 371 | i: Integer; |
372 | Line: string; |
||
19 | daniel-mar | 373 | firstLine: string; |
374 | thisLine: string; |
||
11 | daniel-mar | 375 | begin |
376 | result := leNone; |
||
1 | daniel-mar | 377 | |
11 | daniel-mar | 378 | // Check 1: Ist der Header OK? |
1 | daniel-mar | 379 | |
11 | daniel-mar | 380 | if LowerCase(FStringList.Strings[0]) <> 'version 2' then |
1 | daniel-mar | 381 | begin |
11 | daniel-mar | 382 | result := leUnsupportedVersion; |
383 | exit; |
||
1 | daniel-mar | 384 | end; |
385 | |||
11 | daniel-mar | 386 | if ((LowerCase(FStringList.Strings[1]) <> 'mode: normal') and (LowerCase(FStringList.Strings[1]) <> 'mode: diagonal')) then |
1 | daniel-mar | 387 | begin |
11 | daniel-mar | 388 | result := leUnsupportedMode; |
389 | exit; |
||
1 | daniel-mar | 390 | end; |
391 | |||
11 | daniel-mar | 392 | // Check 2: Ist das Brett leer? |
1 | daniel-mar | 393 | |
19 | daniel-mar | 394 | tmp := ''; |
395 | for i := NUM_HEADERS to FStringList.Count-1 do tmp := tmp + FStringList.Strings[i]; |
||
396 | if Trim(StringReplace(tmp, '.', '', [rfReplaceAll])) = '' then |
||
1 | daniel-mar | 397 | begin |
11 | daniel-mar | 398 | result := leEmptyBoard; |
399 | exit; |
||
1 | daniel-mar | 400 | end; |
401 | |||
11 | daniel-mar | 402 | // Check 3: Geht das Level nicht in einem Quadrat oder Rechteck auf? |
1 | daniel-mar | 403 | |
19 | daniel-mar | 404 | firstLine := StringReplace(FStringList.Strings[NUM_HEADERS], '.', '', [rfReplaceAll]); |
11 | daniel-mar | 405 | for i := NUM_HEADERS to FStringList.Count-1 do |
1 | daniel-mar | 406 | begin |
19 | daniel-mar | 407 | thisLine := StringReplace(FStringList.Strings[i], '.', '', [rfReplaceAll]); |
408 | if Length(thisLine) <> Length(firstLine) then |
||
11 | daniel-mar | 409 | begin |
410 | result := leRowInvalidLength; // at row y-NUM_HEADERS |
||
411 | exit; |
||
412 | end; |
||
1 | daniel-mar | 413 | end; |
414 | |||
11 | daniel-mar | 415 | // Check 4: Gibt es ungültige Elemente in den Zeilen? |
1 | daniel-mar | 416 | |
11 | daniel-mar | 417 | for i := NUM_HEADERS to FStringList.Count-1 do |
418 | begin |
||
419 | Line := FStringList.Strings[i]; |
||
1 | daniel-mar | 420 | |
11 | daniel-mar | 421 | Line := StringReplace(Line, '.', '', [rfReplaceAll]); |
422 | Line := StringReplace(Line, '*', '', [rfReplaceAll]); |
||
423 | Line := StringReplace(Line, 'r', '', [rfReplaceAll, rfIgnoreCase]); |
||
424 | Line := StringReplace(Line, 'y', '', [rfReplaceAll, rfIgnoreCase]); |
||
425 | Line := StringReplace(Line, 'g', '', [rfReplaceAll, rfIgnoreCase]); |
||
426 | Line := StringReplace(Line, 'e', '', [rfReplaceAll, rfIgnoreCase]); |
||
1 | daniel-mar | 427 | |
11 | daniel-mar | 428 | if Length(Line) > 0 then |
1 | daniel-mar | 429 | begin |
11 | daniel-mar | 430 | result := leInvalidElement; // at row y-NUM_HEADERS |
431 | Exit; |
||
1 | daniel-mar | 432 | end; |
433 | end; |
||
434 | |||
22 | daniel-mar | 435 | // Check 5: Kann im Level gesprungen werden? |
11 | daniel-mar | 436 | |
437 | { Wird hier nicht abgeprüft, da dafür zuerst der PlayGround gebaut sein muss. |
||
438 | Es ist außerdem eher ein logischer Fehler, kein Fehler in der Levelstruktur! } |
||
8 | daniel-mar | 439 | end; |
440 | |||
1 | daniel-mar | 441 | end. |