20 |
20 |
21 unit uLand; |
21 unit uLand; |
22 interface |
22 interface |
23 uses SDLh, uLandTemplates, uFloat, uConsts, GLunit, uTypes; |
23 uses SDLh, uLandTemplates, uFloat, uConsts, GLunit, uTypes; |
24 |
24 |
25 type direction = record x, y: LongInt; end; |
|
26 const DIR_N: direction = (x: 0; y: -1); |
|
27 DIR_E: direction = (x: 1; y: 0); |
|
28 DIR_S: direction = (x: 0; y: 1); |
|
29 DIR_W: direction = (x: -1; y: 0); |
|
30 |
|
31 procedure initModule; |
25 procedure initModule; |
32 procedure freeModule; |
26 procedure freeModule; |
33 procedure DrawBottomBorder; |
27 procedure DrawBottomBorder; |
34 procedure GenMap; |
28 procedure GenMap; |
35 function GenPreview: TPreview; |
29 function GenPreview: TPreview; |
36 |
30 |
37 implementation |
31 implementation |
38 uses uConsole, uStore, uRandom, uLandObjects, uIO, uLandTexture, sysutils, |
32 uses uConsole, uStore, uRandom, uLandObjects, uIO, uLandTexture, sysutils, |
39 uVariables, uUtils, uCommands, Adler32, uDebug, uLandPainted, uTextures; |
33 uVariables, uUtils, uCommands, Adler32, uDebug, uLandPainted, uTextures, |
40 |
34 uLandGraphics, uLandGenMaze, uLandOutline; |
41 operator = (const a, b: direction) c: Boolean; |
35 |
42 begin |
|
43 c := (a.x = b.x) and (a.y = b.y); |
|
44 end; |
|
45 |
|
46 type TPixAr = record |
|
47 Count: Longword; |
|
48 ar: array[0..Pred(cMaxEdgePoints)] of TPoint; |
|
49 end; |
|
50 |
|
51 procedure DrawLine(X1, Y1, X2, Y2: LongInt; Color: Longword); |
|
52 var |
|
53 eX, eY, dX, dY: LongInt; |
|
54 i, sX, sY, x, y, d: LongInt; |
|
55 begin |
|
56 eX:= 0; |
|
57 eY:= 0; |
|
58 dX:= X2 - X1; |
|
59 dY:= Y2 - Y1; |
|
60 |
|
61 if (dX > 0) then sX:= 1 |
|
62 else |
|
63 if (dX < 0) then |
|
64 begin |
|
65 sX:= -1; |
|
66 dX:= -dX |
|
67 end else sX:= dX; |
|
68 |
|
69 if (dY > 0) then sY:= 1 |
|
70 else |
|
71 if (dY < 0) then |
|
72 begin |
|
73 sY:= -1; |
|
74 dY:= -dY |
|
75 end else sY:= dY; |
|
76 |
|
77 if (dX > dY) then d:= dX |
|
78 else d:= dY; |
|
79 |
|
80 x:= X1; |
|
81 y:= Y1; |
|
82 |
|
83 for i:= 0 to d do |
|
84 begin |
|
85 inc(eX, dX); |
|
86 inc(eY, dY); |
|
87 if (eX > d) then |
|
88 begin |
|
89 dec(eX, d); |
|
90 inc(x, sX); |
|
91 end; |
|
92 if (eY > d) then |
|
93 begin |
|
94 dec(eY, d); |
|
95 inc(y, sY); |
|
96 end; |
|
97 |
|
98 if ((x and LAND_WIDTH_MASK) = 0) and ((y and LAND_HEIGHT_MASK) = 0) then |
|
99 Land[y, x]:= Color; |
|
100 end |
|
101 end; |
|
102 |
|
103 procedure DrawEdge(var pa: TPixAr; Color: Longword); |
|
104 var i: LongInt; |
|
105 begin |
|
106 i:= 0; |
|
107 with pa do |
|
108 while i < LongInt(Count) - 1 do |
|
109 if (ar[i + 1].X = NTPX) then inc(i, 2) |
|
110 else begin |
|
111 DrawLine(ar[i].x, ar[i].y, ar[i + 1].x, ar[i + 1].y, Color); |
|
112 inc(i) |
|
113 end |
|
114 end; |
|
115 |
|
116 procedure Vector(p1, p2, p3: TPoint; var Vx, Vy: hwFloat); |
|
117 var d1, d2, d: hwFloat; |
|
118 begin |
|
119 Vx:= int2hwFloat(p1.X - p3.X); |
|
120 Vy:= int2hwFloat(p1.Y - p3.Y); |
|
121 d:= DistanceI(p2.X - p1.X, p2.Y - p1.Y); |
|
122 d1:= DistanceI(p2.X - p3.X, p2.Y - p3.Y); |
|
123 d2:= Distance(Vx, Vy); |
|
124 if d1 < d then d:= d1; |
|
125 if d2 < d then d:= d2; |
|
126 d:= d * _1div3; |
|
127 if d2.QWordValue = 0 then |
|
128 begin |
|
129 Vx:= _0; |
|
130 Vy:= _0 |
|
131 end else |
|
132 begin |
|
133 d2:= _1 / d2; |
|
134 Vx:= Vx * d2; |
|
135 Vy:= Vy * d2; |
|
136 |
|
137 Vx:= Vx * d; |
|
138 Vy:= Vy * d |
|
139 end |
|
140 end; |
|
141 |
|
142 procedure AddLoopPoints(var pa, opa: TPixAr; StartI, EndI: LongInt; Delta: hwFloat); |
|
143 var i, pi, ni: LongInt; |
|
144 NVx, NVy, PVx, PVy: hwFloat; |
|
145 x1, x2, y1, y2: LongInt; |
|
146 tsq, tcb, t, r1, r2, r3, cx1, cx2, cy1, cy2: hwFloat; |
|
147 X, Y: LongInt; |
|
148 begin |
|
149 pi:= EndI; |
|
150 i:= StartI; |
|
151 ni:= Succ(StartI); |
|
152 {$HINTS OFF} |
|
153 Vector(opa.ar[pi], opa.ar[i], opa.ar[ni], NVx, NVy); |
|
154 {$HINTS ON} |
|
155 repeat |
|
156 inc(pi); |
|
157 if pi > EndI then pi:= StartI; |
|
158 inc(i); |
|
159 if i > EndI then i:= StartI; |
|
160 inc(ni); |
|
161 if ni > EndI then ni:= StartI; |
|
162 PVx:= NVx; |
|
163 PVy:= NVy; |
|
164 Vector(opa.ar[pi], opa.ar[i], opa.ar[ni], NVx, NVy); |
|
165 |
|
166 x1:= opa.ar[pi].x; |
|
167 y1:= opa.ar[pi].y; |
|
168 x2:= opa.ar[i].x; |
|
169 y2:= opa.ar[i].y; |
|
170 cx1:= int2hwFloat(x1) - PVx; |
|
171 cy1:= int2hwFloat(y1) - PVy; |
|
172 cx2:= int2hwFloat(x2) + NVx; |
|
173 cy2:= int2hwFloat(y2) + NVy; |
|
174 t:= _0; |
|
175 while t.Round = 0 do |
|
176 begin |
|
177 tsq:= t * t; |
|
178 tcb:= tsq * t; |
|
179 r1:= (_1 - t*3 + tsq*3 - tcb); |
|
180 r2:= ( t*3 - tsq*6 + tcb*3); |
|
181 r3:= ( tsq*3 - tcb*3); |
|
182 X:= hwRound(r1 * x1 + r2 * cx1 + r3 * cx2 + tcb * x2); |
|
183 Y:= hwRound(r1 * y1 + r2 * cy1 + r3 * cy2 + tcb * y2); |
|
184 t:= t + Delta; |
|
185 pa.ar[pa.Count].x:= X; |
|
186 pa.ar[pa.Count].y:= Y; |
|
187 inc(pa.Count); |
|
188 TryDo(pa.Count <= cMaxEdgePoints, 'Edge points overflow', true) |
|
189 end; |
|
190 until i = StartI; |
|
191 pa.ar[pa.Count].x:= opa.ar[StartI].X; |
|
192 pa.ar[pa.Count].y:= opa.ar[StartI].Y; |
|
193 inc(pa.Count) |
|
194 end; |
|
195 |
|
196 procedure BezierizeEdge(var pa: TPixAr; Delta: hwFloat); |
|
197 var i, StartLoop: LongInt; |
|
198 opa: TPixAr; |
|
199 begin |
|
200 opa:= pa; |
|
201 pa.Count:= 0; |
|
202 i:= 0; |
|
203 StartLoop:= 0; |
|
204 while i < LongInt(opa.Count) do |
|
205 if (opa.ar[i + 1].X = NTPX) then |
|
206 begin |
|
207 AddLoopPoints(pa, opa, StartLoop, i, Delta); |
|
208 inc(i, 2); |
|
209 StartLoop:= i; |
|
210 pa.ar[pa.Count].X:= NTPX; |
|
211 pa.ar[pa.Count].Y:= 0; |
|
212 inc(pa.Count); |
|
213 end else inc(i) |
|
214 end; |
|
215 |
|
216 procedure FillLand(x, y: LongInt); |
|
217 var Stack: record |
|
218 Count: Longword; |
|
219 points: array[0..8192] of record |
|
220 xl, xr, y, dir: LongInt; |
|
221 end |
|
222 end; |
|
223 |
|
224 procedure Push(_xl, _xr, _y, _dir: LongInt); |
|
225 begin |
|
226 TryDo(Stack.Count <= 8192, 'FillLand: stack overflow', true); |
|
227 _y:= _y + _dir; |
|
228 if (_y < 0) or (_y >= LAND_HEIGHT) then exit; |
|
229 with Stack.points[Stack.Count] do |
|
230 begin |
|
231 xl:= _xl; |
|
232 xr:= _xr; |
|
233 y:= _y; |
|
234 dir:= _dir |
|
235 end; |
|
236 inc(Stack.Count) |
|
237 end; |
|
238 |
|
239 procedure Pop(var _xl, _xr, _y, _dir: LongInt); |
|
240 begin |
|
241 dec(Stack.Count); |
|
242 with Stack.points[Stack.Count] do |
|
243 begin |
|
244 _xl:= xl; |
|
245 _xr:= xr; |
|
246 _y:= y; |
|
247 _dir:= dir |
|
248 end |
|
249 end; |
|
250 |
|
251 var xl, xr, dir: LongInt; |
|
252 begin |
|
253 Stack.Count:= 0; |
|
254 xl:= x - 1; |
|
255 xr:= x; |
|
256 Push(xl, xr, y, -1); |
|
257 Push(xl, xr, y, 1); |
|
258 dir:= 0; |
|
259 while Stack.Count > 0 do |
|
260 begin |
|
261 Pop(xl, xr, y, dir); |
|
262 while (xl > 0) and (Land[y, xl] <> 0) do dec(xl); |
|
263 while (xr < LAND_WIDTH - 1) and (Land[y, xr] <> 0) do inc(xr); |
|
264 while (xl < xr) do |
|
265 begin |
|
266 while (xl <= xr) and (Land[y, xl] = 0) do inc(xl); |
|
267 x:= xl; |
|
268 while (xl <= xr) and (Land[y, xl] <> 0) do |
|
269 begin |
|
270 Land[y, xl]:= 0; |
|
271 inc(xl) |
|
272 end; |
|
273 if x < xl then |
|
274 begin |
|
275 Push(x, Pred(xl), y, dir); |
|
276 Push(x, Pred(xl), y,-dir); |
|
277 end; |
|
278 end; |
|
279 end; |
|
280 end; |
|
281 |
36 |
282 procedure ColorizeLand(Surface: PSDL_Surface); |
37 procedure ColorizeLand(Surface: PSDL_Surface); |
283 var tmpsurf: PSDL_Surface; |
38 var tmpsurf: PSDL_Surface; |
284 r, rr: TSDL_Rect; |
39 r, rr: TSDL_Rect; |
285 x, yd, yu: LongInt; |
40 x, yd, yu: LongInt; |
415 FillPoints^[i].y:= LAND_HEIGHT - 1 - FillPoints^[i].y; |
170 FillPoints^[i].y:= LAND_HEIGHT - 1 - FillPoints^[i].y; |
416 end; |
171 end; |
417 end |
172 end |
418 end; |
173 end; |
419 |
174 |
420 function CheckIntersect(V1, V2, V3, V4: TPoint): boolean; |
|
421 var c1, c2, dm: LongInt; |
|
422 begin |
|
423 dm:= (V4.y - V3.y) * (V2.x - V1.x) - (V4.x - V3.x) * (V2.y - V1.y); |
|
424 c1:= (V4.x - V3.x) * (V1.y - V3.y) - (V4.y - V3.y) * (V1.x - V3.x); |
|
425 if dm = 0 then exit(false); |
|
426 |
|
427 c2:= (V2.x - V3.x) * (V1.y - V3.y) - (V2.y - V3.y) * (V1.x - V3.x); |
|
428 if dm > 0 then |
|
429 begin |
|
430 if (c1 < 0) or (c1 > dm) then exit(false); |
|
431 if (c2 < 0) or (c2 > dm) then exit(false) |
|
432 end else |
|
433 begin |
|
434 if (c1 > 0) or (c1 < dm) then exit(false); |
|
435 if (c2 > 0) or (c2 < dm) then exit(false) |
|
436 end; |
|
437 |
|
438 //AddFileLog('1 (' + inttostr(V1.x) + ',' + inttostr(V1.y) + ')x(' + inttostr(V2.x) + ',' + inttostr(V2.y) + ')'); |
|
439 //AddFileLog('2 (' + inttostr(V3.x) + ',' + inttostr(V3.y) + ')x(' + inttostr(V4.x) + ',' + inttostr(V4.y) + ')'); |
|
440 CheckIntersect:= true |
|
441 end; |
|
442 |
|
443 function CheckSelfIntersect(var pa: TPixAr; ind: Longword): boolean; |
|
444 var i: Longword; |
|
445 begin |
|
446 if (ind <= 0) or (ind >= Pred(pa.Count)) then exit(false); |
|
447 for i:= 1 to pa.Count - 3 do |
|
448 if (i <= ind - 1) or (i >= ind + 2) then |
|
449 begin |
|
450 if (i <> ind - 1) and |
|
451 CheckIntersect(pa.ar[ind], pa.ar[ind - 1], pa.ar[i], pa.ar[i - 1]) then exit(true); |
|
452 if (i <> ind + 2) and |
|
453 CheckIntersect(pa.ar[ind], pa.ar[ind + 1], pa.ar[i], pa.ar[i - 1]) then exit(true); |
|
454 end; |
|
455 CheckSelfIntersect:= false |
|
456 end; |
|
457 |
|
458 procedure RandomizePoints(var pa: TPixAr); |
|
459 const cEdge = 55; |
|
460 cMinDist = 8; |
|
461 var radz: array[0..Pred(cMaxEdgePoints)] of LongInt; |
|
462 i, k, dist, px, py: LongInt; |
|
463 begin |
|
464 for i:= 0 to Pred(pa.Count) do |
|
465 begin |
|
466 radz[i]:= 0; |
|
467 with pa.ar[i] do |
|
468 if x <> NTPX then |
|
469 begin |
|
470 radz[i]:= Min(Max(x - cEdge, 0), Max(LAND_WIDTH - cEdge - x, 0)); |
|
471 radz[i]:= Min(radz[i], Min(Max(y - cEdge, 0), Max(LAND_HEIGHT - cEdge - y, 0))); |
|
472 if radz[i] > 0 then |
|
473 for k:= 0 to Pred(i) do |
|
474 begin |
|
475 dist:= Max(abs(x - pa.ar[k].x), abs(y - pa.ar[k].y)); |
|
476 radz[k]:= Max(0, Min((dist - cMinDist) div 2, radz[k])); |
|
477 radz[i]:= Max(0, Min(dist - radz[k] - cMinDist, radz[i])) |
|
478 end |
|
479 end; |
|
480 end; |
|
481 |
|
482 for i:= 0 to Pred(pa.Count) do |
|
483 with pa.ar[i] do |
|
484 if ((x and LAND_WIDTH_MASK) = 0) and ((y and LAND_HEIGHT_MASK) = 0) then |
|
485 begin |
|
486 px:= x; |
|
487 py:= y; |
|
488 x:= x + LongInt(GetRandom(7) - 3) * (radz[i] * 5 div 7) div 3; |
|
489 y:= y + LongInt(GetRandom(7) - 3) * (radz[i] * 5 div 7) div 3; |
|
490 if CheckSelfIntersect(pa, i) then |
|
491 begin |
|
492 x:= px; |
|
493 y:= py |
|
494 end; |
|
495 end |
|
496 end; |
|
497 |
|
498 |
175 |
499 procedure GenBlank(var Template: TEdgeTemplate); |
176 procedure GenBlank(var Template: TEdgeTemplate); |
500 var pa: TPixAr; |
177 var pa: TPixAr; |
501 i: Longword; |
178 i: Longword; |
502 y, x: Longword; |
179 y, x: Longword; |
608 |
285 |
609 if SDL_MustLock(Surface) then |
286 if SDL_MustLock(Surface) then |
610 SDL_UnlockSurface(Surface); |
287 SDL_UnlockSurface(Surface); |
611 end; |
288 end; |
612 |
289 |
613 procedure GenMaze; |
|
614 const small_cell_size = 128; |
|
615 medium_cell_size = 192; |
|
616 large_cell_size = 256; |
|
617 braidness = 10; |
|
618 |
|
619 var x, y: LongInt; |
|
620 cellsize: LongInt; //selected by the user in the gui |
|
621 seen_cells_x, seen_cells_y: LongInt; //number of cells that can be visited by the generator, that is every second cell in x and y direction. the cells between there are walls that will be removed when we move from one cell to another |
|
622 num_edges_x, num_edges_y: LongInt; //number of resulting edges that need to be vertexificated |
|
623 num_cells_x, num_cells_y: LongInt; //actual number of cells, depending on cell size |
|
624 seen_list: array of array of LongInt; |
|
625 xwalls: array of array of Boolean; |
|
626 ywalls: array of array of Boolean; |
|
627 x_edge_list: array of array of Boolean; |
|
628 y_edge_list: array of array of Boolean; |
|
629 maze: array of array of Boolean; |
|
630 pa: TPixAr; |
|
631 num_vertices: LongInt; |
|
632 off_y: LongInt; |
|
633 num_steps: LongInt; |
|
634 current_step: LongInt; |
|
635 step_done: array of Boolean; |
|
636 done: Boolean; |
|
637 last_cell: array of record x, y: LongInt; end; |
|
638 came_from: array of array of record x, y: LongInt; end; |
|
639 came_from_pos: array of LongInt; |
|
640 maze_inverted: Boolean; |
|
641 |
|
642 function when_seen(x: LongInt; y: LongInt): LongInt; |
|
643 begin |
|
644 if (x < 0) or (x >= seen_cells_x) or (y < 0) or (y >= seen_cells_y) then |
|
645 when_seen := current_step |
|
646 else |
|
647 when_seen := seen_list[x, y]; |
|
648 end; |
|
649 |
|
650 function is_x_edge(x, y: LongInt): Boolean; |
|
651 begin |
|
652 if (x < 0) or (x > num_edges_x) or (y < 0) or (y > num_cells_y) then |
|
653 is_x_edge := false |
|
654 else |
|
655 is_x_edge := x_edge_list[x, y]; |
|
656 end; |
|
657 |
|
658 function is_y_edge(x, y: LongInt): Boolean; |
|
659 begin |
|
660 if (x < 0) or (x > num_cells_x) or (y < 0) or (y > num_edges_y) then |
|
661 is_y_edge := false |
|
662 else |
|
663 is_y_edge := y_edge_list[x, y]; |
|
664 end; |
|
665 |
|
666 procedure see_cell; |
|
667 var dir: direction; |
|
668 tries: LongInt; |
|
669 x, y: LongInt; |
|
670 found_cell: Boolean; |
|
671 next_dir_clockwise: Boolean; |
|
672 |
|
673 begin |
|
674 x := last_cell[current_step].x; |
|
675 y := last_cell[current_step].y; |
|
676 seen_list[x, y] := current_step; |
|
677 case GetRandom(4) of |
|
678 0: dir := DIR_N; |
|
679 1: dir := DIR_E; |
|
680 2: dir := DIR_S; |
|
681 3: dir := DIR_W; |
|
682 end; |
|
683 tries := 0; |
|
684 found_cell := false; |
|
685 if getrandom(2) = 1 then next_dir_clockwise := true |
|
686 else next_dir_clockwise := false; |
|
687 |
|
688 while (tries < 5) and (not found_cell) do |
|
689 begin |
|
690 if when_seen(x + dir.x, y + dir.y) = current_step then //we are seeing ourselves, try another direction |
|
691 begin |
|
692 //we have already seen the target cell, decide if we should remove the wall anyway |
|
693 //(or put a wall there if maze_inverted, but we are not doing that right now) |
|
694 if not maze_inverted and (GetRandom(braidness) = 0) then |
|
695 //or just warn that inverted+braid+indestructible terrain != good idea |
|
696 begin |
|
697 case dir.x of |
|
698 -1: if x > 0 then ywalls[x-1, y] := false; |
|
699 1: if x < seen_cells_x - 1 then ywalls[x, y] := false; |
|
700 end; |
|
701 case dir.y of |
|
702 -1: if y > 0 then xwalls[x, y-1] := false; |
|
703 1: if y < seen_cells_y - 1 then xwalls[x, y] := false; |
|
704 end; |
|
705 end; |
|
706 if next_dir_clockwise then |
|
707 begin |
|
708 if dir = DIR_N then |
|
709 dir := DIR_E |
|
710 else if dir = DIR_E then |
|
711 dir := DIR_S |
|
712 else if dir = DIR_S then |
|
713 dir := DIR_W |
|
714 else |
|
715 dir := DIR_N; |
|
716 end |
|
717 else |
|
718 begin |
|
719 if dir = DIR_N then |
|
720 dir := DIR_W |
|
721 else if dir = DIR_E then |
|
722 dir := DIR_N |
|
723 else if dir = DIR_S then |
|
724 dir := DIR_E |
|
725 else |
|
726 dir := DIR_S; |
|
727 end |
|
728 end |
|
729 else if when_seen(x + dir.x, y + dir.y) = -1 then //cell was not seen yet, go there |
|
730 begin |
|
731 case dir.y of |
|
732 -1: xwalls[x, y-1] := false; |
|
733 1: xwalls[x, y] := false; |
|
734 end; |
|
735 case dir.x of |
|
736 -1: ywalls[x-1, y] := false; |
|
737 1: ywalls[x, y] := false; |
|
738 end; |
|
739 last_cell[current_step].x := x+dir.x; |
|
740 last_cell[current_step].y := y+dir.y; |
|
741 came_from_pos[current_step] := came_from_pos[current_step] + 1; |
|
742 came_from[current_step, came_from_pos[current_step]].x := x; |
|
743 came_from[current_step, came_from_pos[current_step]].y := y; |
|
744 found_cell := true; |
|
745 end |
|
746 else //we are seeing someone else, quit |
|
747 begin |
|
748 step_done[current_step] := true; |
|
749 found_cell := true; |
|
750 end; |
|
751 |
|
752 tries := tries + 1; |
|
753 end; |
|
754 if not found_cell then |
|
755 begin |
|
756 last_cell[current_step].x := came_from[current_step, came_from_pos[current_step]].x; |
|
757 last_cell[current_step].y := came_from[current_step, came_from_pos[current_step]].y; |
|
758 came_from_pos[current_step] := came_from_pos[current_step] - 1; |
|
759 if came_from_pos[current_step] >= 0 then see_cell |
|
760 else step_done[current_step] := true; |
|
761 end; |
|
762 end; |
|
763 |
|
764 procedure add_vertex(x, y: LongInt); |
|
765 var tmp_x, tmp_y: LongInt; |
|
766 begin |
|
767 if x = NTPX then |
|
768 begin |
|
769 if pa.ar[num_vertices - 6].x = NTPX then |
|
770 begin |
|
771 num_vertices := num_vertices - 6; |
|
772 end |
|
773 else |
|
774 begin |
|
775 pa.ar[num_vertices].x := NTPX; |
|
776 pa.ar[num_vertices].y := 0; |
|
777 end |
|
778 end |
|
779 else |
|
780 begin |
|
781 if maze_inverted or (x mod 2 = 0) then tmp_x := cellsize |
|
782 else tmp_x := cellsize * 2 div 3; |
|
783 if maze_inverted or (y mod 2 = 0) then tmp_y := cellsize |
|
784 else tmp_y := cellsize * 2 div 3; |
|
785 |
|
786 pa.ar[num_vertices].x := (x-1)*cellsize + tmp_x; |
|
787 pa.ar[num_vertices].y := (y-1)*cellsize + tmp_y + off_y; |
|
788 end; |
|
789 num_vertices := num_vertices + 1; |
|
790 end; |
|
791 |
|
792 procedure add_edge(x, y: LongInt; dir: direction); |
|
793 var i: LongInt; |
|
794 begin |
|
795 if dir = DIR_N then |
|
796 begin |
|
797 dir := DIR_W |
|
798 end |
|
799 else if dir = DIR_E then |
|
800 begin |
|
801 dir := DIR_N |
|
802 end |
|
803 else if dir = DIR_S then |
|
804 begin |
|
805 dir := DIR_E |
|
806 end |
|
807 else |
|
808 begin |
|
809 dir := DIR_S; |
|
810 end; |
|
811 |
|
812 for i := 0 to 3 do |
|
813 begin |
|
814 if dir = DIR_N then |
|
815 dir := DIR_E |
|
816 else if dir = DIR_E then |
|
817 dir := DIR_S |
|
818 else if dir = DIR_S then |
|
819 dir := DIR_W |
|
820 else |
|
821 dir := DIR_N; |
|
822 |
|
823 if (dir = DIR_N) and is_x_edge(x, y) then |
|
824 begin |
|
825 x_edge_list[x, y] := false; |
|
826 add_vertex(x+1, y); |
|
827 add_edge(x, y-1, DIR_N); |
|
828 break; |
|
829 end; |
|
830 |
|
831 if (dir = DIR_E) and is_y_edge(x+1, y) then |
|
832 begin |
|
833 y_edge_list[x+1, y] := false; |
|
834 add_vertex(x+2, y+1); |
|
835 add_edge(x+1, y, DIR_E); |
|
836 break; |
|
837 end; |
|
838 |
|
839 if (dir = DIR_S) and is_x_edge(x, y+1) then |
|
840 begin |
|
841 x_edge_list[x, y+1] := false; |
|
842 add_vertex(x+1, y+2); |
|
843 add_edge(x, y+1, DIR_S); |
|
844 break; |
|
845 end; |
|
846 |
|
847 if (dir = DIR_W) and is_y_edge(x, y) then |
|
848 begin |
|
849 y_edge_list[x, y] := false; |
|
850 add_vertex(x, y+1); |
|
851 add_edge(x-1, y, DIR_W); |
|
852 break; |
|
853 end; |
|
854 end; |
|
855 |
|
856 end; |
|
857 |
|
858 begin |
|
859 case cTemplateFilter of |
|
860 0: begin |
|
861 cellsize := small_cell_size; |
|
862 maze_inverted := false; |
|
863 end; |
|
864 1: begin |
|
865 cellsize := medium_cell_size; |
|
866 maze_inverted := false; |
|
867 end; |
|
868 2: begin |
|
869 cellsize := large_cell_size; |
|
870 maze_inverted := false; |
|
871 end; |
|
872 3: begin |
|
873 cellsize := small_cell_size; |
|
874 maze_inverted := true; |
|
875 end; |
|
876 4: begin |
|
877 cellsize := medium_cell_size; |
|
878 maze_inverted := true; |
|
879 end; |
|
880 5: begin |
|
881 cellsize := large_cell_size; |
|
882 maze_inverted := true; |
|
883 end; |
|
884 end; |
|
885 |
|
886 num_cells_x := LAND_WIDTH div cellsize; |
|
887 if not odd(num_cells_x) then num_cells_x := num_cells_x - 1; //needs to be odd |
|
888 num_cells_y := LAND_HEIGHT div cellsize; |
|
889 if not odd(num_cells_y) then num_cells_y := num_cells_y - 1; |
|
890 num_edges_x := num_cells_x - 1; |
|
891 num_edges_y := num_cells_y - 1; |
|
892 seen_cells_x := num_cells_x div 2; |
|
893 seen_cells_y := num_cells_y div 2; |
|
894 |
|
895 if maze_inverted then |
|
896 num_steps := 3 //TODO randomize, between 3 and 5? |
|
897 else |
|
898 num_steps := 1; |
|
899 SetLength(step_done, num_steps); |
|
900 SetLength(last_cell, num_steps); |
|
901 SetLength(came_from_pos, num_steps); |
|
902 SetLength(came_from, num_steps, num_cells_x*num_cells_y); |
|
903 done := false; |
|
904 for current_step := 0 to num_steps - 1 do |
|
905 step_done[current_step] := false; |
|
906 came_from_pos[current_step] := 0; |
|
907 current_step := 0; |
|
908 |
|
909 SetLength(seen_list, seen_cells_x, seen_cells_y); |
|
910 SetLength(xwalls, seen_cells_x, seen_cells_y - 1); |
|
911 SetLength(ywalls, seen_cells_x - 1, seen_cells_y); |
|
912 SetLength(x_edge_list, num_edges_x, num_cells_y); |
|
913 SetLength(y_edge_list, num_cells_x, num_edges_y); |
|
914 SetLength(maze, num_cells_x, num_cells_y); |
|
915 |
|
916 num_vertices := 0; |
|
917 |
|
918 playHeight := num_cells_y * cellsize; |
|
919 playWidth := num_cells_x * cellsize; |
|
920 off_y := LAND_HEIGHT - playHeight; |
|
921 |
|
922 for x := 0 to playWidth do |
|
923 for y := 0 to off_y - 1 do |
|
924 Land[y, x] := 0; |
|
925 |
|
926 for x := 0 to playWidth do |
|
927 for y := off_y to LAND_HEIGHT - 1 do |
|
928 Land[y, x] := lfBasic; |
|
929 |
|
930 for y := 0 to num_cells_y - 1 do |
|
931 for x := 0 to num_cells_x - 1 do |
|
932 maze[x, y] := false; |
|
933 |
|
934 for x := 0 to seen_cells_x - 1 do |
|
935 for y := 0 to seen_cells_y - 2 do |
|
936 xwalls[x, y] := true; |
|
937 |
|
938 for x := 0 to seen_cells_x - 2 do |
|
939 for y := 0 to seen_cells_y - 1 do |
|
940 ywalls[x, y] := true; |
|
941 |
|
942 for x := 0 to seen_cells_x - 1 do |
|
943 for y := 0 to seen_cells_y - 1 do |
|
944 seen_list[x, y] := -1; |
|
945 |
|
946 for x := 0 to num_edges_x - 1 do |
|
947 for y := 0 to num_cells_y - 1 do |
|
948 x_edge_list[x, y] := false; |
|
949 |
|
950 for x := 0 to num_cells_x - 1 do |
|
951 for y := 0 to num_edges_y - 1 do |
|
952 y_edge_list[x, y] := false; |
|
953 |
|
954 for current_step := 0 to num_steps-1 do |
|
955 begin |
|
956 x := GetRandom(seen_cells_x - 1) div LongWord(num_steps); |
|
957 last_cell[current_step].x := x + current_step * seen_cells_x div num_steps; |
|
958 last_cell[current_step].y := GetRandom(seen_cells_y); |
|
959 end; |
|
960 |
|
961 while not done do |
|
962 begin |
|
963 done := true; |
|
964 for current_step := 0 to num_steps-1 do |
|
965 begin |
|
966 if not step_done[current_step] then |
|
967 begin |
|
968 see_cell; |
|
969 done := false; |
|
970 end; |
|
971 end; |
|
972 end; |
|
973 |
|
974 for x := 0 to seen_cells_x - 1 do |
|
975 for y := 0 to seen_cells_y - 1 do |
|
976 if seen_list[x, y] > -1 then |
|
977 maze[(x+1)*2-1, (y+1)*2-1] := true; |
|
978 |
|
979 for x := 0 to seen_cells_x - 1 do |
|
980 for y := 0 to seen_cells_y - 2 do |
|
981 if not xwalls[x, y] then |
|
982 maze[x*2 + 1, y*2 + 2] := true; |
|
983 |
|
984 |
|
985 for x := 0 to seen_cells_x - 2 do |
|
986 for y := 0 to seen_cells_y - 1 do |
|
987 if not ywalls[x, y] then |
|
988 maze[x*2 + 2, y*2 + 1] := true; |
|
989 |
|
990 for x := 0 to num_edges_x - 1 do |
|
991 for y := 0 to num_cells_y - 1 do |
|
992 if maze[x, y] xor maze[x+1, y] then |
|
993 x_edge_list[x, y] := true |
|
994 else |
|
995 x_edge_list[x, y] := false; |
|
996 |
|
997 for x := 0 to num_cells_x - 1 do |
|
998 for y := 0 to num_edges_y - 1 do |
|
999 if maze[x, y] xor maze[x, y+1] then |
|
1000 y_edge_list[x, y] := true |
|
1001 else |
|
1002 y_edge_list[x, y] := false; |
|
1003 |
|
1004 for x := 0 to num_edges_x - 1 do |
|
1005 for y := 0 to num_cells_y - 1 do |
|
1006 if x_edge_list[x, y] then |
|
1007 begin |
|
1008 x_edge_list[x, y] := false; |
|
1009 add_vertex(x+1, y+1); |
|
1010 add_vertex(x+1, y); |
|
1011 add_edge(x, y-1, DIR_N); |
|
1012 add_vertex(NTPX, 0); |
|
1013 end; |
|
1014 |
|
1015 pa.count := num_vertices; |
|
1016 |
|
1017 RandomizePoints(pa); |
|
1018 BezierizeEdge(pa, _0_25); |
|
1019 RandomizePoints(pa); |
|
1020 BezierizeEdge(pa, _0_25); |
|
1021 |
|
1022 DrawEdge(pa, 0); |
|
1023 |
|
1024 if maze_inverted then |
|
1025 FillLand(1, 1+off_y) |
|
1026 else |
|
1027 begin |
|
1028 x := 0; |
|
1029 while Land[cellsize div 2 + cellsize + off_y, x] = lfBasic do |
|
1030 x := x + 1; |
|
1031 while Land[cellsize div 2 + cellsize + off_y, x] = 0 do |
|
1032 x := x + 1; |
|
1033 FillLand(x+1, cellsize div 2 + cellsize + off_y); |
|
1034 end; |
|
1035 |
|
1036 MaxHedgehogs:= 32; |
|
1037 if (GameFlags and gfDisableGirders) <> 0 then hasGirders:= false |
|
1038 else hasGirders := true; |
|
1039 leftX:= 0; |
|
1040 rightX:= playWidth; |
|
1041 topY:= off_y; |
|
1042 hasBorder := false; |
|
1043 end; |
|
1044 |
290 |
1045 procedure GenLandSurface; |
291 procedure GenLandSurface; |
1046 var tmpsurf: PSDL_Surface; |
292 var tmpsurf: PSDL_Surface; |
1047 x,y: Longword; |
293 x,y: Longword; |
1048 begin |
294 begin |