Rev 9 | Rev 21 | Go to most recent revision | Show entire file | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed
Rev 9 | Rev 11 | ||
---|---|---|---|
Line 1... | Line 1... | ||
1 | unit LevelFunctions; |
1 | unit LevelFunctions; |
2 | 2 | ||
3 | interface |
3 | interface |
4 | 4 | ||
5 | uses |
5 | uses |
6 | SysUtils, Dialogs, Functions, ExtCtrls, Graphics; |
6 | SysUtils, Dialogs, Functions, ExtCtrls, Graphics, Classes, Math; |
7 | 7 | ||
8 | type |
8 | type |
9 | TFieldType = (ftLocked, ftLockedWithTab, ftEmpty, ftGreen, ftYellow, ftRed); |
9 | TFieldType = (ftFullSpace, ftHalfSpace, ftEmpty, ftRed, ftYellow, ftGreen); |
10 | 10 | ||
11 | TFieldProperties = record |
11 | TFieldProperties = record |
12 | Typ: TFieldType; |
12 | Typ: TFieldType; |
13 | Goal: Boolean; |
13 | Goal: Boolean; |
14 | end; |
14 | end; |
15 | 15 | ||
16 | TLevelType = (ltStandard, ltDiagonal, ltError); |
16 | TGameMode = (gmUndefined, gmNormal, gmDiagonal); |
17 | 17 | ||
18 | TLevelArray = array of array of TFieldProperties; |
18 | TLevelArray = array of array of TFieldProperties; |
19 | 19 | ||
20 | TLevelError = (leNone, leInvalidElement, leNoIndicator, leMultipleIndicator, |
20 | TLevelError = (leNone, leInvalidElement, leEmptyBoard, leRowInvalidLength, |
21 | leLevelIncomplete, leHeaderError, leInvalidGoal); |
21 | leUnsupportedVersion, leUnsupportedMode); |
22 | 22 | ||
- | 23 | TLevel = class(TObject) |
|
- | 24 | private |
|
- | 25 | FStringList: TStringList; |
|
23 | procedure DrawLevelPreview(LevelString: string; Image: TImage; BackgroundColor: TColor); |
26 | procedure Load(ABoardFile: string); |
- | 27 | public |
|
24 | function GetLevelType(LevelString: string): TLevelType; |
28 | constructor Create(ABoardFile: string); |
- | 29 | destructor Destroy; override; |
|
25 | function CheckLevelIntegrity(LevelString: string; ShowErrors: boolean): TLevelError; overload; |
30 | function LevelStringToLevelArray(ShowErrors: boolean): TLevelArray; |
26 | function CheckLevelIntegrity(LevelString: string): TLevelError; overload; |
31 | function CheckLevelIntegrity: TLevelError; overload; |
27 | function LevelStringToLevelArray(LevelString: string; ShowErrors: boolean): TLevelArray; |
32 | function CheckLevelIntegrity(ShowErrors: boolean): TLevelError; overload; |
28 | function FieldTypeWorth(t: TFieldType): integer; |
33 | function GetGameMode: TGameMode; |
- | 34 | end; |
|
29 | 35 | ||
30 | var |
- | |
- | 36 | procedure DrawLevelPreview(Level: TLevel; Image: TImage; BackgroundColor: TColor); |
|
31 | AllowDiagonalMoves: boolean; |
37 | function FieldTypeWorth(t: TFieldType): integer; |
32 | 38 | ||
33 | implementation |
39 | implementation |
34 | 40 | ||
35 | const |
- | |
36 | PREVIEW_BLOCK_SIZE = 10; // Enthält Field und Abstand |
- | |
37 | PREVIEW_TAB_SIZE = PREVIEW_BLOCK_SIZE div 2; // 5 |
- | |
38 | HEADER_SIZE = 3; |
- | |
39 | ERED = '3'; |
- | |
40 | EYEL = '2'; |
- | |
41 | EGRE = '1'; |
- | |
42 | ELOC = 'X'; |
- | |
43 | EEMP = 'E'; |
- | |
44 | EIND = '!'; |
- | |
45 | ETAR = '>'; |
- | |
46 | ESPE = '*'; |
- | |
47 | TY_DIA = 'D'; |
- | |
48 | TY_NOR = 'N'; |
- | |
49 | - | ||
50 | resourcestring |
- | |
51 | 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.'; |
- | |
52 | LNG_LVL_INVALID_WIDTH = 'Level invalid: No width indicator ("!") found.'; |
- | |
53 | LNG_LVL_INVALID_HEIGHT_MUTLIPLE = 'Level invalid: The level''s actual length is not a multiple of the width.'; |
- | |
54 | LNG_LVL_INVALID_MULTIPLE_WIND = 'Level invalid: There are multiple width indicators ("!").'; |
- | |
55 | LNG_LVL_INVALID_HEADER = 'Level invalid: The header is invalid. It does not match the structure "1(D|N)~".'; |
- | |
56 | LNG_INVALID_GOAL = 'Level invalid: A goal does not point to a valid accessable element ("3", "2", "1" or "E").'; |
- | |
57 | - | ||
58 | procedure DrawLevelPreview(LevelString: string; Image: TImage; BackgroundColor: TColor); |
41 | procedure DrawLevelPreview(Level: TLevel; Image: TImage; BackgroundColor: TColor); |
59 | var |
42 | var |
60 | LevelArray: TLevelArray; |
43 | LevelArray: TLevelArray; |
61 | i, j: integer; |
44 | y, x: integer; |
62 | t: TFieldType; |
45 | t: TFieldType; |
63 | halftabs: integer; |
46 | halftabs: integer; |
- | 47 | const |
|
- | 48 | PREVIEW_BLOCK_SIZE = 10; // Enthält Field und Abstand |
|
- | 49 | PREVIEW_TAB_SIZE = PREVIEW_BLOCK_SIZE div 2; // 5 |
|
64 | begin |
50 | begin |
65 | LevelArray := nil; |
51 | LevelArray := nil; |
66 | 52 | ||
67 | ClearImage(Image, BackgroundColor); |
53 | ClearImage(Image, BackgroundColor); |
68 | 54 | ||
69 | LevelArray := LevelStringToLevelArray(LevelString, false); |
55 | LevelArray := Level.LevelStringToLevelArray(false); |
70 | 56 | ||
71 | for i := Low(LevelArray) to High(LevelArray) do |
57 | for y := Low(LevelArray) to High(LevelArray) do |
72 | begin |
58 | begin |
73 | halftabs := 0; |
59 | halftabs := 0; |
74 | for j := Low(LevelArray[i]) to High(LevelArray[i]) do |
60 | for x := Low(LevelArray[y]) to High(LevelArray[y]) do |
75 | begin |
61 | begin |
76 | t := LevelArray[i][j].Typ; |
62 | t := LevelArray[y][x].Typ; |
77 | 63 | ||
78 | case t of |
64 | case t of |
79 | ftLocked: Image.Canvas.Brush.Color := BackgroundColor; |
65 | ftFullSpace: Image.Canvas.Brush.Color := BackgroundColor; |
80 | ftLockedWithTab: begin |
66 | ftHalfSpace: begin |
81 | Image.Canvas.Brush.Color := BackgroundColor; |
67 | Image.Canvas.Brush.Color := BackgroundColor; |
82 | inc(halftabs); |
68 | inc(halftabs); |
83 | end; |
69 | end; |
84 | ftEmpty: Image.Canvas.Brush.Color := clWhite; |
70 | ftEmpty: Image.Canvas.Brush.Color := clWhite; |
85 | ftGreen: Image.Canvas.Brush.Color := clLime; |
71 | ftGreen: Image.Canvas.Brush.Color := clLime; |
86 | ftYellow: Image.Canvas.Brush.Color := clYellow; |
72 | ftYellow: Image.Canvas.Brush.Color := clYellow; |
87 | ftRed: Image.Canvas.Brush.Color := clRed; |
73 | ftRed: Image.Canvas.Brush.Color := clRed; |
88 | end; |
74 | end; |
89 | 75 | ||
90 | if LevelArray[i][j].Goal then |
76 | if LevelArray[y][x].Goal then |
91 | Image.Canvas.Pen.Color := clBlack |
77 | Image.Canvas.Pen.Color := clBlack |
92 | else |
78 | else |
93 | Image.Canvas.Pen.Color := BackgroundColor; |
79 | Image.Canvas.Pen.Color := BackgroundColor; |
94 | 80 | ||
- | 81 | Image.Canvas.Rectangle((x-halftabs)*PREVIEW_BLOCK_SIZE + halftabs*PREVIEW_TAB_SIZE, |
|
- | 82 | y*PREVIEW_BLOCK_SIZE, |
|
95 | 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); |
83 | (x-halftabs)*PREVIEW_BLOCK_SIZE + halftabs*PREVIEW_TAB_SIZE + PREVIEW_BLOCK_SIZE, |
- | 84 | y*PREVIEW_BLOCK_SIZE + PREVIEW_BLOCK_SIZE); |
|
96 | end; |
85 | end; |
97 | end; |
86 | end; |
98 | end; |
87 | end; |
99 | 88 | ||
100 | function GetLevelType(LevelString: string): TLevelType; |
89 | function FieldTypeWorth(t: TFieldType): integer; |
101 | begin |
- | |
102 | if CheckLevelIntegrity(LevelString) = leNone then |
- | |
103 | begin |
- | |
104 | if Copy(LevelString, 2, 1) = TY_DIA then |
- | |
105 | begin |
- | |
106 | result := ltDiagonal; |
- | |
107 | end |
- | |
108 | else // if Copy(LevelString, 2, 1) = TY_NOR |
- | |
109 | begin |
90 | begin |
- | 91 | if t = ftGreen then result := 10 |
|
- | 92 | else if t = ftYellow then result := 20 |
|
- | 93 | else if t = ftRed then result := 30 |
|
110 | result := ltStandard; |
94 | else result := 0; |
111 | end; |
95 | end; |
112 | end |
96 | |
113 | else |
97 | { TLevel } |
- | 98 | ||
- | 99 | const NUM_HEADERS = 2; |
|
- | 100 | ||
- | 101 | constructor TLevel.Create(ABoardFile: string); |
|
114 | begin |
102 | begin |
115 | result := ltError; |
103 | inherited Create; |
- | 104 | FStringList := TStringList.Create; |
|
116 | end; |
105 | Load(ABoardFile); |
117 | end; |
106 | end; |
118 | 107 | ||
119 | procedure ShowErrorMessage(error: TLevelError); |
108 | destructor TLevel.Destroy; |
120 | begin |
109 | begin |
121 | case error of |
110 | FreeAndNil(FStringList); |
- | 111 | ||
122 | leNone: ; |
112 | inherited; |
123 | leInvalidElement: MessageDlg(LNG_LVL_INVALID_ELEMENT, mtError, [mbOk], 0); |
- | |
124 | leNoIndicator: MessageDlg(LNG_LVL_INVALID_WIDTH, mtError, [mbOk], 0); |
- | |
125 | leMultipleIndicator: MessageDlg(LNG_LVL_INVALID_MULTIPLE_WIND, mtError, [mbOk], 0); |
- | |
126 | leLevelIncomplete: MessageDlg(LNG_LVL_INVALID_HEIGHT_MUTLIPLE, mtError, [mbOk], 0); |
- | |
127 | leHeaderError: MessageDlg(LNG_LVL_INVALID_HEADER, mtError, [mbOk], 0); |
- | |
128 | leInvalidGoal: MessageDlg(LNG_INVALID_GOAL, mtError, [mbOk], 0); |
- | |
129 | end; |
- | |
130 | end; |
113 | end; |
131 | 114 | ||
132 | function CheckLevelIntegrity(LevelString: string; ShowErrors: boolean): TLevelError; |
115 | function TLevel.GetGameMode: TGameMode; |
133 | begin |
116 | begin |
- | 117 | if LowerCase(FStringList.Strings[1]) = 'mode: normal' then |
|
134 | result := CheckLevelIntegrity(LevelString); |
118 | result := gmNormal |
135 | if ShowErrors then ShowErrorMessage(result); |
119 | else if LowerCase(FStringList.Strings[1]) = 'mode: diagonal' then |
- | 120 | result := gmDiagonal |
|
- | 121 | else |
|
- | 122 | result := gmUndefined; |
|
136 | end; |
123 | end; |
137 | 124 | ||
138 | function CheckLevelIntegrity(LevelString: string): TLevelError; |
125 | procedure TLevel.Load(ABoardFile: string); |
139 | var |
126 | var |
140 | W: integer; |
127 | i: Integer; |
141 | H: extended; |
- | |
142 | header, h_ver, h_dia, h_del, tmp: string; |
- | |
143 | p: integer; |
- | |
144 | begin |
128 | begin |
145 | result := leNone; |
129 | FStringList.Clear; |
146 | - | ||
147 | // Entfernt die Zeilenumbrüche |
130 | FStringList.LoadFromFile(ABoardFile); |
148 | 131 | ||
149 | LevelString := RemoveLineBreaks(LevelString); |
- | |
150 | - | ||
151 | // Check 1: Ist der Header OK? |
132 | // Remove whitespaces and empty lines |
152 | - | ||
153 | header := copy(LevelString, 1, HEADER_SIZE); |
133 | for i := FStringList.Count-1 downto NUM_HEADERS do |
154 | - | ||
155 | h_ver := copy(header, 1, 1); |
- | |
156 | if h_ver <> '1' then |
- | |
157 | begin |
134 | begin |
- | 135 | FStringList.Strings[i] := StringReplace(FStringList.Strings[i], ' ', '', [rfReplaceAll]); |
|
158 | result := leHeaderError; |
136 | if FStringList.Strings[i] = '' then FStringList.Delete(i); |
159 | Exit; |
137 | end; |
160 | end; |
138 | end; |
161 | 139 | ||
- | 140 | function TLevel.LevelStringToLevelArray(ShowErrors: boolean): TLevelArray; |
|
- | 141 | var |
|
- | 142 | i: integer; |
|
- | 143 | t: TFieldType; |
|
- | 144 | err: TLevelError; |
|
- | 145 | longestLine: Integer; |
|
162 | h_dia := copy(header, 2, 1); |
146 | thisLine: Integer; |
- | 147 | y: Integer; |
|
- | 148 | x: Integer; |
|
- | 149 | Line: string; |
|
163 | if (h_dia <> TY_DIA) and (h_dia <> TY_NOR) then |
150 | lch, uch: char; |
- | 151 | ch: char; |
|
164 | begin |
152 | begin |
165 | result := leHeaderError; |
153 | // Zuerst nach Fehlern suchen |
166 | Exit; |
154 | err := CheckLevelIntegrity(ShowErrors); |
167 | end; |
155 | if err <> leNone then exit; |
168 | 156 | ||
169 | h_del := copy(header, 3, 1); |
157 | // Längste Zeile finden |
170 | if h_del <> '~' then |
158 | longestLine := 0; |
- | 159 | for i := NUM_HEADERS to FStringList.Count-1 do |
|
171 | begin |
160 | begin |
172 | result := leHeaderError; |
161 | longestLine := Max(longestLine, Length(FStringList.Strings[i])); |
173 | Exit; |
- | |
174 | end; |
162 | end; |
175 | 163 | ||
- | 164 | // Nun Matrix aufbauen |
|
- | 165 | SetLength(result, 0); |
|
176 | LevelString := copy(LevelString, HEADER_SIZE+1, Length(LevelString)-HEADER_SIZE); |
166 | for i := NUM_HEADERS to FStringList.Count-1 do |
- | 167 | begin |
|
- | 168 | y := i - NUM_HEADERS; |
|
177 | 169 | ||
178 | // Check 2: Steht das ggf. vorhandenen ">" vor einem gültigen Feld 1, 2, 3, E? |
170 | SetLength(result, Length(result)+1); // add line to matrix |
- | 171 | SetLength(result[y], longestLine); |
|
179 | 172 | ||
180 | p := Position(LevelString, ETAR); |
173 | Line := FStringList.Strings[i]; |
181 | 174 | ||
182 | while (p <> -1) do |
175 | for x := 0 to LongestLine-1 do |
183 | begin |
176 | begin |
184 | tmp := copy(LevelString, p+1, 1); |
177 | ch := Copy(Line,x+1,1)[1]; |
185 | - | ||
- | 178 | lch := LowerCase(ch)[1]; |
|
186 | if (tmp <> EEMP) and (tmp <> EGRE) and (tmp <> EYEL) and (tmp <> ERED) then |
179 | uch := UpperCase(ch)[1]; |
187 | begin |
180 | case lch of |
- | 181 | '*': t := ftFullSpace; |
|
188 | result := leInvalidGoal; |
182 | '.': t := ftHalfSpace; |
- | 183 | 'e': t := ftEmpty; |
|
189 | Exit; |
184 | 'r': t := ftRed; |
- | 185 | 'y': t := ftYellow; |
|
- | 186 | 'g': t := ftGreen; |
|
190 | end; |
187 | end; |
191 | 188 | ||
- | 189 | result[y][x].Typ := t; |
|
192 | LevelString := StringReplace(LevelString, ETAR, '', []); // Dieses Ziel entfernen |
190 | result[y][x].Goal := (ch = uch) and (ch <> lch); |
193 | 191 | end; |
|
194 | p := Position(LevelString, ETAR); |
192 | end; |
195 | end; |
193 | end; |
196 | 194 | ||
197 | // Check 3: Kommt überhaupt ein "!" vor? |
195 | function TLevel.CheckLevelIntegrity(ShowErrors: boolean): TLevelError; |
198 | - | ||
199 | W := Position(LevelString, EIND); |
196 | resourcestring |
200 | - | ||
- | 197 | 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 *.'; |
|
- | 198 | LNG_LVL_UNSUPPORTED_VERSION = 'Level format invalid: Version not supported.'; |
|
- | 199 | LNG_LVL_UNSUPPORTED_MODE = 'Level format invalid: Mode not supported.'; |
|
201 | if W = -1 then |
200 | LNG_LVL_EMPTY_BOARD = 'Level invalid: Board is empty.'; |
- | 201 | LNG_LVL_INVALID_LENGTH = 'Level invalid: Lines don''t have an equal amount of elements.'; |
|
202 | begin |
202 | begin |
203 | result := leNoIndicator; |
203 | result := CheckLevelIntegrity; |
- | 204 | if ShowErrors then |
|
- | 205 | begin |
|
- | 206 | case result of |
|
- | 207 | leNone: ; |
|
- | 208 | leInvalidElement: MessageDlg(LNG_LVL_INVALID_ELEMENT, mtError, [mbOk], 0); |
|
- | 209 | leUnsupportedVersion: MessageDlg(LNG_LVL_UNSUPPORTED_VERSION, mtError, [mbOk], 0); |
|
- | 210 | leUnsupportedMode: MessageDlg(LNG_LVL_UNSUPPORTED_MODE, mtError, [mbOk], 0); |
|
- | 211 | leEmptyBoard: MessageDlg(LNG_LVL_EMPTY_BOARD, mtError, [mbOk], 0); |
|
- | 212 | leRowInvalidLength: MessageDlg(LNG_LVL_INVALID_LENGTH, mtError, [mbOk], 0); |
|
204 | Exit; |
213 | end; |
- | 214 | end; |
|
205 | end; |
215 | end; |
206 | 216 | ||
- | 217 | function TLevel.CheckLevelIntegrity: TLevelError; |
|
- | 218 | var |
|
- | 219 | W: integer; |
|
- | 220 | H: extended; |
|
207 | // Check 4: Kam das "!" mehrmals vor? |
221 | header, h_ver, h_dia, h_del, tmp: string; |
- | 222 | p: integer; |
|
- | 223 | i: Integer; |
|
- | 224 | Line: string; |
|
- | 225 | begin |
|
- | 226 | result := leNone; |
|
208 | 227 | ||
209 | LevelString := StringReplace(LevelString, EIND, '', []); // Das Erste entfernen |
228 | // Check 1: Ist der Header OK? |
210 | 229 | ||
211 | if Position(LevelString, EIND) <> -1 then // gibt es ein Zweites? |
230 | if LowerCase(FStringList.Strings[0]) <> 'version 2' then |
212 | begin |
231 | begin |
213 | result := leMultipleIndicator; |
232 | result := leUnsupportedVersion; |
214 | Exit; |
233 | exit; |
215 | end; |
234 | end; |
216 | 235 | ||
217 | // Check 5: Geht das Level nicht in einem Quadrat oder Rechteck auf? |
236 | if ((LowerCase(FStringList.Strings[1]) <> 'mode: normal') and (LowerCase(FStringList.Strings[1]) <> 'mode: diagonal')) then |
218 | - | ||
219 | H := (Length(LevelString) - 1) / W; |
- | |
220 | - | ||
221 | if not Ganzzahlig(H) then |
- | |
222 | begin |
237 | begin |
223 | result := leLevelIncomplete; |
238 | result := leUnsupportedMode; |
224 | Exit; |
239 | exit; |
225 | end; |
240 | end; |
226 | 241 | ||
227 | // Check 6: Gibt es ungültige Elemente im LevelString? |
242 | // Check 2: Ist das Brett leer? |
228 | 243 | ||
229 | LevelString := StringReplace(LevelString, ESPE, '', [rfReplaceAll]); |
- | |
230 | LevelString := StringReplace(LevelString, ELOC, '', [rfReplaceAll]); |
- | |
231 | LevelString := StringReplace(LevelString, EEMP, '', [rfReplaceAll]); |
- | |
232 | LevelString := StringReplace(LevelString, EGRE, '', [rfReplaceAll]); |
- | |
233 | LevelString := StringReplace(LevelString, EYEL, '', [rfReplaceAll]); |
- | |
234 | LevelString := StringReplace(LevelString, ERED, '', [rfReplaceAll]); |
- | |
235 | - | ||
236 | if Length(LevelString) > 0 then |
244 | if FStringList.Count - NUM_HEADERS = 0 then |
237 | begin |
245 | begin |
238 | result := leInvalidElement; |
246 | result := leEmptyBoard; |
239 | Exit; |
247 | exit; |
240 | end; |
248 | end; |
241 | 249 | ||
242 | // Check 7: Kann im Level gesprungen werden |
250 | // Check 3: Geht das Level nicht in einem Quadrat oder Rechteck auf? |
243 | - | ||
244 | { Wird hier nicht abgeprüft, da dafür zuerst der PlayGround gebaut sein muss. |
- | |
245 | Es ist außerdem eher ein logischer Fehler, kein Fehler in der Levelstruktur! } |
- | |
246 | end; |
- | |
247 | 251 | ||
248 | function LevelStringToLevelArray(LevelString: string; ShowErrors: boolean): TLevelArray; |
- | |
249 | var |
- | |
250 | i, j, j_dec, c: integer; |
252 | for i := NUM_HEADERS to FStringList.Count-1 do |
251 | m: string; |
- | |
252 | t: TFieldType; |
- | |
253 | W, H: integer; |
- | |
254 | err: TLevelError; |
- | |
255 | NextIsGoal: boolean; |
- | |
256 | begin |
253 | begin |
- | 254 | if Length(FStringList.Strings[i]) <> Length(FStringList.Strings[NUM_HEADERS]) then |
|
257 | // Zuerst nach Fehlern suchen |
255 | begin |
258 | err := CheckLevelIntegrity(LevelString, ShowErrors); |
256 | result := leRowInvalidLength; // at row y-NUM_HEADERS |
259 | if err <> leNone then exit; |
257 | exit; |
260 | - | ||
261 | // Headerinformationen auslesen |
258 | end; |
262 | AllowDiagonalMoves := copy(LevelString, 2, 1) = TY_DIA; |
- | |
263 | - | ||
264 | // Header entfernen |
259 | end; |
265 | LevelString := copy(LevelString, HEADER_SIZE+1, Length(LevelString)-HEADER_SIZE); |
- | |
266 | 260 | ||
267 | // Entfernt die Zeilenumbrüche |
- | |
268 | LevelString := RemoveLineBreaks(LevelString); |
261 | // Check 4: Gibt es ungültige Elemente in den Zeilen? |
269 | 262 | ||
270 | // Dimensionen abmessen |
- | |
271 | W := Position(StringReplace(LevelString, ETAR, '', [rfReplaceAll]), EIND) - 1; |
- | |
272 | LevelString := StringReplace(LevelString, EIND, '', [rfReplaceAll]); |
263 | for i := NUM_HEADERS to FStringList.Count-1 do |
- | 264 | begin |
|
273 | H := Length(LevelString) div W; |
265 | Line := FStringList.Strings[i]; |
274 | 266 | ||
275 | c := 1; |
267 | Line := StringReplace(Line, '.', '', [rfReplaceAll]); |
276 | NextIsGoal := false; |
268 | Line := StringReplace(Line, '*', '', [rfReplaceAll]); |
- | 269 | Line := StringReplace(Line, 'r', '', [rfReplaceAll, rfIgnoreCase]); |
|
- | 270 | Line := StringReplace(Line, 'y', '', [rfReplaceAll, rfIgnoreCase]); |
|
- | 271 | Line := StringReplace(Line, 'g', '', [rfReplaceAll, rfIgnoreCase]); |
|
- | 272 | Line := StringReplace(Line, 'e', '', [rfReplaceAll, rfIgnoreCase]); |
|
277 | 273 | ||
278 | SetLength(result, round(H)); |
- | |
279 | for i := Low(result) to High(result) do |
- | |
280 | begin |
- | |
281 | j_dec := 0; |
- | |
282 | SetLength(result[i], round(W)); |
274 | if Length(Line) > 0 then |
283 | for j := Low(result[i]) to High(result[i])+1 do // +1 wegen dem möglichen zusätzlichem ">" |
- | |
284 | begin |
- | |
285 | if (j = High(result[i])+1) and (j_dec = 0) then break; |
- | |
286 | m := Copy(LevelString, c, 1); |
- | |
287 | if m = ETAR then |
- | |
288 | begin |
275 | begin |
289 | NextIsGoal := true; |
- | |
290 | inc(j_dec); |
- | |
291 | end |
- | |
292 | else |
- | |
293 | begin |
- | |
294 | if m = EEMP then t := ftEmpty |
- | |
295 | else if m = EGRE then t := ftGreen |
- | |
296 | else if m = EYEL then t := ftYellow |
- | |
297 | else if m = ERED then t := ftRed |
- | |
298 | else if m = ESPE then t := ftLockedWithTab |
276 | result := leInvalidElement; // at row y-NUM_HEADERS |
299 | else t := ftLocked; |
- | |
300 | result[i][j-j_dec].Typ := t; |
- | |
301 | result[i][j-j_dec].Goal := NextIsGoal; |
- | |
302 | if NextIsGoal then NextIsGoal := false; |
- | |
303 | end; |
277 | Exit; |
304 | inc(c); |
- | |
305 | end; |
- | |
306 | end; |
278 | end; |
307 | end; |
279 | end; |
308 | 280 | ||
309 | function FieldTypeWorth(t: TFieldType): integer; |
281 | // Check 5: Kann im Level gesprungen werden |
310 | begin |
282 | |
311 | if t = ftGreen then result := 10 |
- | |
312 | else if t = ftYellow then result := 20 |
283 | { Wird hier nicht abgeprüft, da dafür zuerst der PlayGround gebaut sein muss. |
313 | else if t = ftRed then result := 30 |
284 | Es ist außerdem eher ein logischer Fehler, kein Fehler in der Levelstruktur! } |
314 | else result := 0; |
- | |
315 | end; |
285 | end; |
316 | 286 | ||
317 | end. |
287 | end. |