GameEngine.Mod 8.9 KB

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