Prototype game engine for Heroes of Might & Magic, featuring a gameplay plot-twist...
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.

430 rindas
21KB

  1. -- Copyright (c) 2024 - Ognjen 'xolatile' Milan Robovic
  2. --
  3. -- GNU General Public Licence (version 3 or later)
  4. with core, ui, resource, equipment, unit, construction, chad, effect;
  5. use type core.cursor_code;
  6. package body world is
  7. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  8. view_reach : constant integer := 96;
  9. landmark_limit : constant integer := 90;
  10. location_limit : constant integer := 30;
  11. construction_limit : constant natural := 60;
  12. equipment_limit : constant natural := 600;
  13. unit_limit : constant natural := 60;
  14. earth : core.sprite;
  15. dark : core.sprite;
  16. border_upper : core.sprite;
  17. border_lower : core.sprite;
  18. border_left : core.sprite;
  19. border_right : core.sprite;
  20. corner_upper_left : core.sprite;
  21. corner_upper_right : core.sprite;
  22. corner_lower_left : core.sprite;
  23. corner_lower_right : core.sprite;
  24. ------------------------------------------------------------------------------------------
  25. procedure configure is
  26. begin
  27. core.echo (core.comment, "Configuring world components...");
  28. --
  29. earth := core.import_sprite (core.folder & "/game/world/terrain/earth.png", 1, 1);
  30. dark := core.import_sprite (core.folder & "/game/world/dark.png", 1, 1);
  31. border_upper := core.import_sprite (core.folder & "/game/world/frame/border_upper.png", 1, 1);
  32. border_lower := core.import_sprite (core.folder & "/game/world/frame/border_lower.png", 1, 1);
  33. border_left := core.import_sprite (core.folder & "/game/world/frame/border_left.png", 1, 1);
  34. border_right := core.import_sprite (core.folder & "/game/world/frame/border_right.png", 1, 1);
  35. corner_upper_left := core.import_sprite (core.folder & "/game/world/frame/corner_upper_left.png", 1, 1);
  36. corner_upper_right := core.import_sprite (core.folder & "/game/world/frame/corner_upper_right.png", 1, 1);
  37. corner_lower_left := core.import_sprite (core.folder & "/game/world/frame/corner_lower_left.png", 1, 1);
  38. corner_lower_right := core.import_sprite (core.folder & "/game/world/frame/corner_lower_right.png", 1, 1);
  39. --
  40. for index in landmark_index loop
  41. landmarks (index) := core.import_sprite (file_path => core.folder & "/game/world/landmark/" & core.lowercase (index'image) & ".png",
  42. frames => landmark_trait (index).frames,
  43. states => 1);
  44. end loop;
  45. --
  46. for index in location_index loop
  47. locations (index) := core.import_sprite (file_path => core.folder & "/game/world/location/" & core.lowercase (index'image) & ".png",
  48. frames => location_trait (index).frames,
  49. states => location_trait (index).states);
  50. end loop;
  51. end configure;
  52. ------------------------------------------------------------------------------------------
  53. procedure make (index : in biome; width, height, chad_limit : in natural) is
  54. begin
  55. core.echo (core.comment, "-- Procedurally generating new map...");
  56. --
  57. core.echo (core.comment, "-- -- Map type : " & index'image);
  58. core.echo (core.comment, "-- -- Map width :" & width'image);
  59. core.echo (core.comment, "-- -- Map height :" & height'image);
  60. core.echo (core.comment, "-- -- Landmark count :" & landmark_limit'image);
  61. --
  62. map.kind := index;
  63. map.width := width;
  64. map.height := height;
  65. map.chad_limit := chad_limit;
  66. map.chad_count := 0;
  67. --
  68. map.earth := new integer_matrix (0 .. map.width - 1, 0 .. map.height - 1);
  69. map.clips := new boolean_matrix (0 .. map.width - 1, 0 .. map.height - 1);
  70. map.views := new boolean_matrix (0 .. map.width - 1, 0 .. map.height - 1);
  71. map.landmarks := new entity_array (1 .. landmark_limit);
  72. map.locations := new entity_array (1 .. location_limit);
  73. map.constructions := new entity_array (1 .. construction_limit);
  74. map.equipments := new entity_array (1 .. equipment_limit);
  75. map.units := new entity_array (1 .. unit_limit);
  76. map.chads := new chad.value_array (1 .. map.chad_limit);
  77. --
  78. for x in 0 .. width - 1 loop
  79. for y in 0 .. height - 1 loop
  80. map.earth (x, y) := (if core.random (0, 23) < 19 then core.random (0, 11) else core.random (0, 23));
  81. map.clips (x, y) := false;
  82. map.views (x, y) := false;
  83. end loop;
  84. end loop;
  85. --
  86. for index in 1 .. landmark_limit loop
  87. map.landmarks (index).index := core.random (0, landmark_count - 1);
  88. map.landmarks (index).state := 0;
  89. map.landmarks (index).x := core.random (6, map.width - 6);
  90. map.landmarks (index).y := core.random (6, map.height - 6);
  91. --
  92. if landmark_trait (landmark_index'val (map.landmarks (index).index)).clip then
  93. declare reach_x : constant natural := landmarks (landmark_index'val (map.landmarks (index).index)).width / core.base;
  94. reach_y : constant natural := landmarks (landmark_index'val (map.landmarks (index).index)).height / core.base;
  95. begin
  96. for x in 0 .. reach_x - 1 loop
  97. for y in 0 .. reach_y - 1 loop
  98. map.clips (map.landmarks (index).x + x, map.landmarks (index).y + y) := true;
  99. end loop;
  100. end loop;
  101. end;
  102. end if;
  103. end loop;
  104. --
  105. for index in 1 .. location_limit loop
  106. map.locations (index).index := core.random (0, location_count - 1);
  107. map.locations (index).state := 0;
  108. map.locations (index).x := core.random (6, map.width - 6);
  109. map.locations (index).y := core.random (6, map.height - 6);
  110. --
  111. if location_trait (location_index'val (map.locations (index).index)).clip then
  112. declare reach_x : constant natural := locations (location_index'val (map.locations (index).index)).width / core.base;
  113. reach_y : constant natural := locations (location_index'val (map.locations (index).index)).height / core.base;
  114. begin
  115. for x in 0 .. reach_x - 1 loop
  116. for y in 0 .. reach_y - 1 loop
  117. map.clips (map.locations (index).x + x, map.locations (index).y + y) := true;
  118. end loop;
  119. end loop;
  120. end;
  121. end if;
  122. end loop;
  123. --
  124. for index in 1 .. construction_limit loop
  125. map.constructions (index).index := core.random (0, construction.count - 1);
  126. map.constructions (index).state := 0;
  127. map.constructions (index).x := core.random (6, map.width - 6);
  128. map.constructions (index).y := core.random (6, map.height - 6);
  129. --
  130. declare reach_x : constant natural := construction.sprite (construction.enumeration'val (map.constructions (index).index)).width / core.base;
  131. reach_y : constant natural := construction.sprite (construction.enumeration'val (map.constructions (index).index)).height / core.base;
  132. begin
  133. for x in 0 .. reach_x - 1 loop
  134. for y in 0 .. reach_y - 1 loop
  135. map.clips (map.constructions (index).x + x, map.constructions (index).y + y) := true;
  136. end loop;
  137. end loop;
  138. end;
  139. end loop;
  140. --
  141. for index in 1 .. equipment_limit loop
  142. map.equipments (index).index := core.random (0, equipment.count - 1);
  143. map.equipments (index).state := 0;
  144. map.equipments (index).x := core.random (0, map.width - 1);
  145. map.equipments (index).y := core.random (0, map.height - 1);
  146. end loop;
  147. --
  148. for index in 1 .. unit_limit loop
  149. map.units (index).index := core.random (0, unit.count - 1);
  150. map.units (index).state := 0;
  151. map.units (index).x := core.random (0, map.width - 1);
  152. map.units (index).y := core.random (0, map.height - 1);
  153. --
  154. map.clips (map.units (index).x, map.units (index).y) := true;
  155. end loop;
  156. --
  157. core.echo (core.success, "Finished procedurally generating new map.");
  158. end make;
  159. ------------------------------------------------------------------------------------------
  160. procedure draw is
  161. offset : core.vector := ((core.window_width - core.base) / 2,
  162. (core.window_height - core.base) / 2);
  163. begin
  164. for vertical in 0 .. map.height - 1 loop
  165. exit when offset.y + (vertical - core.camera.y) * core.base * core.zoom > core.window_height;
  166. --
  167. for horizontal in 0 .. map.width - 1 loop
  168. exit when offset.x + (horizontal - core.camera.x) * core.base * core.zoom > core.window_width;
  169. --
  170. if not ((horizontal - core.camera.x) ** 2 + (vertical - core.camera.y) ** 2 > view_reach * 2) then
  171. map.views (horizontal, vertical) := true;
  172. end if;
  173. end loop;
  174. end loop;
  175. --
  176. declare x : constant integer := core.base * core.zoom * (-1 - core.camera.x) + offset.x;
  177. y : constant integer := core.base * core.zoom * (-1 - core.camera.y) + offset.y;
  178. width : constant integer := core.base * core.zoom * (map.width + 2);
  179. height : constant integer := core.base * core.zoom * (map.height + 2);
  180. begin
  181. core.draw_horizontally (border_upper, x + core.base * core.zoom, y, width - 2 * core.base * core.zoom, core.zoom);
  182. core.draw_horizontally (border_lower, x + core.base * core.zoom, y - core.base * core.zoom + height, width - 2 * core.base * core.zoom, core.zoom);
  183. core.draw_vertically (border_left, x, y + core.base * core.zoom, height - 2 * core.base * core.zoom, core.zoom);
  184. core.draw_vertically (border_right, x - core.base * core.zoom + width, y + core.base * core.zoom, height - 2 * core.base * core.zoom, core.zoom);
  185. --
  186. core.draw (corner_upper_left, x, y, factor => core.zoom);
  187. core.draw (corner_upper_right, x - core.base * core.zoom + width, y, factor => core.zoom);
  188. core.draw (corner_lower_left, x, y - core.base * core.zoom + height, factor => core.zoom);
  189. core.draw (corner_lower_right, x - core.base * core.zoom + width, y - core.base * core.zoom + height, factor => core.zoom);
  190. end;
  191. --
  192. for vertical in 0 .. map.height - 1 loop
  193. exit when offset.y + (vertical - core.camera.y) * core.base * core.zoom > core.window_height;
  194. --
  195. for horizontal in 0 .. map.width - 1 loop
  196. exit when offset.x + (horizontal - core.camera.x) * core.base * core.zoom > core.window_width;
  197. --
  198. if map.views (horizontal, vertical) then
  199. core.draw (data => earth,
  200. x => offset.x + (horizontal - core.camera.x) * core.base * core.zoom,
  201. y => offset.y + (vertical - core.camera.y) * core.base * core.zoom,
  202. u => core.base * biome'pos (map.kind) * 4,
  203. v => core.base * map.earth (horizontal, vertical),
  204. width => core.base,
  205. height => core.base);
  206. --~--
  207. if core.cursor.x > offset.x + (horizontal - core.camera.x ) * core.base * core.zoom - 6
  208. and core.cursor.x < offset.x + (horizontal - core.camera.x + 1) * core.base * core.zoom + 6
  209. and core.cursor.y > offset.y + (vertical - core.camera.y ) * core.base * core.zoom - 6
  210. and core.cursor.y < offset.y + (vertical - core.camera.y + 1) * core.base * core.zoom + 6
  211. and core.cursor_mode = core.cursor_left
  212. and not ui.prioritize then
  213. map.chads (1).x := horizontal;
  214. map.chads (1).y := vertical;
  215. core.cursor_mode := core.cursor_none;
  216. end if;
  217. end if;
  218. end loop;
  219. end loop;
  220. --
  221. for index in 1 .. landmark_limit loop
  222. if map.views (map.landmarks (index).x, map.landmarks (index).y) then
  223. core.draw (data => landmarks (landmark_index'val (map.landmarks (index).index)),
  224. x => offset.x + (map.landmarks (index).x - core.camera.x) * core.base * core.zoom,
  225. y => offset.y + (map.landmarks (index).y - core.camera.y) * core.base * core.zoom);
  226. if core.cursor_inside (x => offset.x + (map.landmarks (index).x - core.camera.x) * core.base * core.zoom,
  227. y => offset.y + (map.landmarks (index).y - core.camera.y) * core.base * core.zoom,
  228. width => landmarks (landmark_index'val (map.landmarks (index).index)).width,
  229. height => landmarks (landmark_index'val (map.landmarks (index).index)).height)
  230. and core.cursor_mode = core.cursor_right
  231. and not ui.prioritize then
  232. core.write_text_box (landmark_trait (landmark_index'val (map.landmarks (index).index)).name);
  233. end if;
  234. end if;
  235. end loop;
  236. --
  237. for index in 1 .. location_limit loop
  238. if map.views (map.locations (index).x, map.locations (index).y) then
  239. core.draw (data => locations (location_index'val (map.locations (index).index)),
  240. x => offset.x + (map.locations (index).x - core.camera.x) * core.base * core.zoom,
  241. y => offset.y + (map.locations (index).y - core.camera.y) * core.base * core.zoom,
  242. v => locations (location_index'val (map.locations (index).index)).height * map.locations (index).state,
  243. width => locations (location_index'val (map.locations (index).index)).width,
  244. height => locations (location_index'val (map.locations (index).index)).height);
  245. if core.cursor_inside (x => offset.x + (map.locations (index).x - core.camera.x) * core.base * core.zoom,
  246. y => offset.y + (map.locations (index).y - core.camera.y) * core.base * core.zoom,
  247. width => locations (location_index'val (map.locations (index).index)).width,
  248. height => locations (location_index'val (map.locations (index).index)).height)
  249. and core.cursor_mode = core.cursor_right
  250. and not ui.prioritize then
  251. core.write_text_box (location_trait (location_index'val (map.locations (index).index)).name);
  252. end if;
  253. end if;
  254. --
  255. if map.locations (index).state = 1 and core.animation_time = 0 then
  256. map.locations (index).state := 2;
  257. end if;
  258. --
  259. if core.camera.x > map.locations (index).x - 2
  260. and core.camera.x < map.locations (index).x + 1 + locations (location_index'val (map.locations (index).index)).width / core.base
  261. and core.camera.y > map.locations (index).y - 2
  262. and core.camera.y < map.locations (index).y + 1 + locations (location_index'val (map.locations (index).index)).height / core.base
  263. and map.locations (index).state = 0
  264. and core.signal_code'pos (core.signal_mode) = core.signal_code'pos (core.signal_e)
  265. and not ui.prioritize then
  266. effect.apply (location_trait (location_index'val (map.locations (index).index)).evoke);
  267. --
  268. map.locations (index).state := 1;
  269. end if;
  270. end loop;
  271. --
  272. for index in 1 .. construction_limit loop
  273. if map.views (map.constructions (index).x, map.constructions (index).y) then
  274. construction.draw_plus (construction.enumeration'val (map.constructions (index).index),
  275. offset.x + (map.constructions (index).x - core.camera.x) * core.base * core.zoom,
  276. offset.y + (map.constructions (index).y - core.camera.y) * core.base * core.zoom);
  277. end if;
  278. end loop;
  279. --
  280. for index in 1 .. equipment_limit loop
  281. if map.views (map.equipments (index).x, map.equipments (index).y) then
  282. equipment.draw_plus (equipment.enumeration'val (map.equipments (index).index),
  283. core.idle,
  284. offset.x + (map.equipments (index).x - core.camera.x) * core.base * core.zoom,
  285. offset.y + (map.equipments (index).y - core.camera.y) * core.base * core.zoom);
  286. end if;
  287. --
  288. if map.equipments (index).x = core.camera.x
  289. and map.equipments (index).y = core.camera.y
  290. and core.signal_code'pos (core.signal_mode) = core.signal_code'pos (core.signal_e) then
  291. if chad.take_equipment_item (map.chads (1), equipment.enumeration'val (map.equipments (index).index)) then
  292. map.equipments (index).index := equipment.enumeration'pos (equipment.none);
  293. end if;
  294. end if;
  295. end loop;
  296. --
  297. for index in 1 .. unit_limit loop
  298. if map.views (map.units (index).x, map.units (index).y) then
  299. unit.draw_full (map.units (index).index,
  300. offset.x + (map.units (index).x - core.camera.x) * core.base * core.zoom,
  301. offset.y + (map.units (index).y - core.camera.y) * core.base * core.zoom);
  302. end if;
  303. end loop;
  304. --
  305. for index in 1 .. map.chad_count loop
  306. if map.views (map.chads (index).x, map.chads (index).y) then
  307. chad.draw (map.chads (index),
  308. offset.x + (map.chads (index).x - core.camera.x) * core.base * core.zoom,
  309. offset.y + (map.chads (index).y - core.camera.y) * core.base * core.zoom);
  310. end if;
  311. end loop;
  312. --
  313. for vertical in 0 .. map.height - 1 loop
  314. exit when offset.y + (vertical - core.camera.y) * core.base * core.zoom > core.window_height;
  315. --
  316. for horizontal in 0 .. map.width - 1 loop
  317. exit when offset.x + (horizontal - core.camera.x) * core.base * core.zoom > core.window_width;
  318. --
  319. if (horizontal - core.camera.x) ** 2 + (vertical - core.camera.y) ** 2 > view_reach then
  320. core.draw (data => dark,
  321. x => offset.x + (horizontal - core.camera.x) * core.base * core.zoom,
  322. y => offset.y + (vertical - core.camera.y) * core.base * core.zoom);
  323. end if;
  324. end loop;
  325. end loop;
  326. end draw;
  327. ------------------------------------------------------------------------------------------
  328. procedure mapshot (file_path : in string) is
  329. begin
  330. core.create_image (map.width, map.height);
  331. --
  332. for vertical in 0 .. map.height - 1 loop
  333. for horizontal in 0 .. map.width - 1 loop
  334. core.render_image (data => earth,
  335. x => horizontal * core.base,
  336. y => vertical * core.base,
  337. u => core.base * biome'pos (map.kind) * 4,
  338. v => core.base * map.earth (horizontal, vertical),
  339. width => core.base,
  340. height => core.base);
  341. end loop;
  342. end loop;
  343. --
  344. for index in 1 .. landmark_limit loop
  345. core.render_image (data => landmarks (landmark_index'val (map.landmarks (index).index)),
  346. x => map.landmarks (index).x * core.base,
  347. y => map.landmarks (index).y * core.base,
  348. u => 0,
  349. v => 0,
  350. width => landmarks (landmark_index'val (map.landmarks (index).index)).width,
  351. height => landmarks (landmark_index'val (map.landmarks (index).index)).height);
  352. end loop;
  353. --
  354. for index in 1 .. location_limit loop
  355. core.render_image (data => locations (location_index'val (map.locations (index).index)),
  356. x => map.locations (index).x * core.base,
  357. y => map.locations (index).y * core.base,
  358. u => 0,
  359. v => 0,
  360. width => locations (location_index'val (map.locations (index).index)).width,
  361. height => locations (location_index'val (map.locations (index).index)).height);
  362. end loop;
  363. --
  364. for index in 1 .. construction_limit loop
  365. core.render_image (data => construction.sprite (construction.enumeration'val (map.constructions (index).index)),
  366. x => map.constructions (index).x * core.base,
  367. y => map.constructions (index).y * core.base,
  368. u => 0,
  369. v => 0,
  370. width => construction.sprite (construction.enumeration'val (map.constructions (index).index)).width,
  371. height => construction.sprite (construction.enumeration'val (map.constructions (index).index)).height);
  372. end loop;
  373. --
  374. for index in 1 .. equipment_limit loop
  375. core.render_image (data => equipment.sprite (equipment.enumeration'val (map.equipments (index).index)),
  376. x => map.equipments (index).x * core.base,
  377. y => map.equipments (index).y * core.base,
  378. u => 0,
  379. v => 0,
  380. width => equipment.sprite (equipment.enumeration'val (map.equipments (index).index)).width,
  381. height => equipment.sprite (equipment.enumeration'val (map.equipments (index).index)).height);
  382. end loop;
  383. --
  384. core.export_image (file_path);
  385. --
  386. core.echo (core.success, "Exported current world mapshot.");
  387. --
  388. core.dash;
  389. end mapshot;
  390. ------------------------------------------------------------------------------------------
  391. procedure reveal_map is
  392. begin
  393. for x in 0 .. map.width - 1 loop
  394. for y in 0 .. map.height - 1 loop
  395. map.views (x, y) := true;
  396. end loop;
  397. end loop;
  398. end reveal_map;
  399. ------------------------------------------------------------------------------------------
  400. procedure add_chad (data : in chad.value) is
  401. begin
  402. core.echo_when (map.chad_count = map.chad_limit, core.failure, "Can't add new chad, limit reached.");
  403. core.increment (map.chad_count);
  404. --
  405. map.chads (map.chad_count) := data;
  406. end add_chad;
  407. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  408. end world;