2
0

GameEngine.Mod 6.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231
  1. MODULE GameEngine;
  2. IMPORT G := Graph, Random, Out, Strings;
  3. CONST
  4. maxMapW* = 128;
  5. maxMapH* = maxMapW;
  6. cellW* = 16;
  7. cellH* = cellW;
  8. tilesInRow* = 8;
  9. (** Direction set elements **)
  10. up = 0;
  11. right = 1;
  12. down = 2;
  13. left = 3;
  14. upRight = 4;
  15. upLeft = 5;
  16. downRight = 6;
  17. downLeft = 7;
  18. TYPE
  19. Cell* = RECORD (** A single cell of the map *)
  20. kind*: INTEGER; (** What is saved in a file *)
  21. tile*: INTEGER; (** What is displayed on screen *)
  22. corners*: SET (** Set of upRight, upLeft, downRight, downLeft *)
  23. END;
  24. Map* = RECORD
  25. w*, h*: INTEGER;
  26. cells*: ARRAY maxMapH, maxMapW OF Cell
  27. END;
  28. Game* = RECORD
  29. map*: Map
  30. END;
  31. VAR
  32. tiles*: G.Bitmap;
  33. PROCEDURE DrawCell*(cell: Cell; x, y, toX, toY: INTEGER);
  34. VAR kx, ky: INTEGER;
  35. PROCEDURE DrawCorner(tile, offX, offY, toX, toY: INTEGER);
  36. BEGIN G.DrawPart(tiles,
  37. tile MOD tilesInRow * cellW + offX,
  38. tile DIV tilesInRow * cellH + offY,
  39. cellW DIV 2, cellH DIV 2, toX + offX, toY + offY)
  40. END DrawCorner;
  41. BEGIN
  42. kx := cell.tile MOD tilesInRow * cellW;
  43. ky := cell.tile DIV tilesInRow * cellH;
  44. G.DrawPart(tiles, kx, ky, cellW, cellH, toX, toY);
  45. IF cell.corners # {} THEN
  46. IF upLeft IN cell.corners THEN
  47. DrawCorner(cell.kind + tilesInRow + 5, 0, 0, toX, toY)
  48. END;
  49. IF upRight IN cell.corners THEN
  50. DrawCorner(cell.kind + tilesInRow + 4, cellW DIV 2, 0, toX, toY)
  51. END;
  52. IF downLeft IN cell.corners THEN
  53. DrawCorner(cell.kind + 5, 0, cellH DIV 2, toX, toY)
  54. END;
  55. IF downRight IN cell.corners THEN
  56. DrawCorner(cell.kind + 4, cellW DIV 2, cellH DIV 2, toX, toY)
  57. END
  58. END
  59. END DrawCell;
  60. PROCEDURE CheckNeighbours(VAR map: Map; x, y, kind: INTEGER): SET;
  61. VAR s: SET;
  62. PROCEDURE P(VAR map: Map; x, y, dir: INTEGER; VAR s: SET);
  63. BEGIN
  64. IF (0 <= x) & (x < map.w) & (0 <= y) & (y < map.h) &
  65. ((map.cells[y, x].kind = kind) OR
  66. (kind = 64) & (map.cells[y, x].kind = 96))
  67. THEN INCL(s, dir)
  68. END
  69. END P;
  70. BEGIN
  71. s := {};
  72. P(map, x , y - 1, up , s);
  73. P(map, x + 1, y , right , s);
  74. P(map, x , y + 1, down , s);
  75. P(map, x - 1, y , left , s);
  76. P(map, x - 1, y - 1, upLeft , s);
  77. P(map, x + 1, y - 1, upRight , s);
  78. P(map, x - 1, y + 1, downLeft , s);
  79. P(map, x + 1, y + 1, downRight, s)
  80. RETURN s END CheckNeighbours;
  81. PROCEDURE UpdateMapTile*(VAR map: Map; x, y: INTEGER);
  82. VAR kind, tile, xx, yy: INTEGER;
  83. dirs: SET; (* Set of directions of neighbours where kind is the same *)
  84. corners: SET;
  85. BEGIN
  86. kind := map.cells[y, x].kind;
  87. tile := kind;
  88. corners := {};
  89. IF (kind >= 32) & (kind MOD 32 = 0) THEN
  90. dirs := CheckNeighbours(map, x, y, kind);
  91. xx := 3; yy := 3;
  92. IF up IN dirs THEN
  93. IF {left, right, down} - dirs = {} THEN
  94. IF ~(upLeft IN dirs) THEN xx := 5; yy := 1
  95. ELSIF ~(upRight IN dirs) THEN xx := 4; yy := 1
  96. ELSIF ~(downLeft IN dirs) THEN xx := 5; yy := 0
  97. ELSIF ~(downRight IN dirs) THEN xx := 4; yy := 0
  98. ELSE xx := 1; yy := 1
  99. END
  100. ELSIF {left , right} - dirs = {} THEN xx := 1; yy := 2
  101. ELSIF {left , down } - dirs = {} THEN xx := 2; yy := 1
  102. ELSIF {right, down } - dirs = {} THEN xx := 0; yy := 1
  103. ELSIF left IN dirs THEN xx := 2; yy := 2
  104. ELSIF right IN dirs THEN xx := 0; yy := 2
  105. ELSIF down IN dirs THEN xx := 3; yy := 1
  106. ELSE xx := 3; yy := 2
  107. END
  108. ELSIF down IN dirs THEN
  109. IF {left, right} - dirs = {} THEN xx := 1; yy := 0
  110. ELSIF left IN dirs THEN xx := 2; yy := 0
  111. ELSIF right IN dirs THEN xx := 0; yy := 0
  112. ELSE xx := 3; yy := 0
  113. END
  114. ELSIF left IN dirs THEN
  115. IF right IN dirs THEN xx := 1; yy := 3
  116. ELSE xx := 2; yy := 3
  117. END
  118. ELSIF right IN dirs THEN xx := 0; yy := 3
  119. END;
  120. tile := kind + xx + yy * tilesInRow;
  121. IF {up, left, upLeft} - dirs = {upLeft} THEN INCL(corners, upLeft) END;
  122. IF {up, right, upRight} - dirs = {upRight} THEN INCL(corners, upRight) END;
  123. IF {down, left, downLeft} - dirs = {downLeft} THEN INCL(corners, downLeft) END;
  124. IF {down, right, downRight} - dirs = {downRight} THEN INCL(corners, downRight) END
  125. END;
  126. map.cells[y, x].tile := tile;
  127. map.cells[y, x].corners := corners
  128. END UpdateMapTile;
  129. PROCEDURE UpdateMapTiles*(VAR map: Map);
  130. VAR x, y: INTEGER;
  131. BEGIN
  132. FOR y := 0 TO map.h - 1 DO
  133. FOR x := 0 TO map.w - 1 DO
  134. UpdateMapTile(map, x, y)
  135. END
  136. END
  137. END UpdateMapTiles;
  138. PROCEDURE UpdateMapTileAround*(VAR map: Map; x, y: INTEGER);
  139. BEGIN
  140. UpdateMapTile(map, x, y);
  141. IF x > 0 THEN
  142. UpdateMapTile(map, x - 1, y);
  143. IF y > 0 THEN UpdateMapTile(map, x - 1, y - 1) END;
  144. IF y < map.h - 1 THEN UpdateMapTile(map, x - 1, y + 1) END
  145. END;
  146. IF x < map.w - 1 THEN
  147. UpdateMapTile(map, x + 1, y);
  148. IF y > 0 THEN UpdateMapTile(map, x + 1, y - 1) END;
  149. IF y < map.h - 1 THEN UpdateMapTile(map, x + 1, y + 1) END
  150. END;
  151. IF y > 0 THEN UpdateMapTile(map, x, y - 1) END;
  152. IF y < map.h - 1 THEN UpdateMapTile(map, x, y + 1) END
  153. END UpdateMapTileAround;
  154. PROCEDURE SetCell*(VAR map: Map; x, y, kind: INTEGER);
  155. PROCEDURE P(VAR cell: Cell; kind: INTEGER);
  156. BEGIN
  157. IF cell.kind # kind THEN
  158. cell.kind := kind;
  159. UpdateMapTileAround(map, x, y)
  160. END
  161. END P;
  162. BEGIN
  163. P(map.cells[y, x], kind)
  164. END SetCell;
  165. PROCEDURE MakeRandomMap*(VAR map: Map; w, h: INTEGER);
  166. VAR x, y: INTEGER;
  167. BEGIN
  168. map.w := w; map.h := h;
  169. FOR y := 0 TO h - 1 DO
  170. FOR x := 0 TO w - 1 DO
  171. map.cells[y, x].kind := 0 (*Random.Int(4)*)
  172. END
  173. END;
  174. UpdateMapTiles(map)
  175. END MakeRandomMap;
  176. PROCEDURE LoadMap*(VAR map: Map; fname: ARRAY OF CHAR): BOOLEAN;
  177. BEGIN
  178. RETURN TRUE END LoadMap;
  179. PROCEDURE SaveMap*(VAR map: Map; fname: ARRAY OF CHAR);
  180. BEGIN
  181. END SaveMap;
  182. (** Returns a bitmap with the given name (appends strings to make a file name).
  183. On error sets ok to FALSE and ouputs an error message.
  184. Never sets ok to TRUE. *)
  185. PROCEDURE LoadBitmap(name: ARRAY OF CHAR; VAR ok: BOOLEAN): G.Bitmap;
  186. VAR bmp: G.Bitmap;
  187. s: ARRAY 256 OF CHAR;
  188. BEGIN
  189. s := 'Data/Graph/';
  190. Strings.Append(name, s);
  191. Strings.Append('.png', s);
  192. bmp := G.LoadBitmap(s);
  193. IF bmp = NIL THEN
  194. ok := FALSE;
  195. Out.String('Error: Could not load bitmap "');
  196. Out.String(s); Out.String('".'); Out.Ln
  197. END
  198. RETURN bmp END LoadBitmap;
  199. PROCEDURE InitGame*(VAR game: Game);
  200. BEGIN
  201. MakeRandomMap(game.map, 128, 128)
  202. END InitGame;
  203. PROCEDURE Init*(): BOOLEAN;
  204. VAR ok: BOOLEAN;
  205. BEGIN ok := TRUE;
  206. tiles := LoadBitmap('tiles', ok)
  207. RETURN ok END Init;
  208. END GameEngine.