GameEngine.Mod 9.2 KB

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