Prototype game engine for Heroes of Might & Magic, featuring a gameplay plot-twist...
25개 이상의 토픽을 선택하실 수 없습니다. Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

353 lines
13KB

  1. -- Copyright (c) 2024 - Ognjen 'xolatile' Milan Robovic
  2. --
  3. -- GNU General Public Licence (version 3 or later)
  4. pragma ada_2012;
  5. --~with core, ui, effect, attribute, skill, resource, faction, might, magic, equipment, unit, construction, chad, deity, world, ai;
  6. with core, ui, effect, attribute, skill, resource, faction, deity, material, magic, equipment, unit, construction, chad, world;
  7. with ada.strings.unbounded;
  8. use ada.strings.unbounded;
  9. use core;
  10. procedure main is
  11. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  12. side_panel : integer := 0;
  13. preview_width : integer := 0;
  14. preview_height : integer := 0;
  15. text_box_height : integer := 0;
  16. player : chad.value := (
  17. index => chad.ada,
  18. state => core.idle,
  19. x => 0,
  20. y => 0,
  21. health => (30, 40),
  22. mana => (20, 30),
  23. stamina => (10, 20),
  24. attributes => (1, 2, 3, 4, 5, 6),
  25. skills => (1, 2, 3, 4, 5, 6, 7, 8, 9, others => 0),
  26. resources => (101, 103, 107, 109, 113, 127),
  27. equipments => (equipment.chest => equipment.elven_armour,
  28. --~equipment.head => equipment.elven_helmet,
  29. equipment.hands => equipment.leather_gauntlets,
  30. equipment.feet => equipment.leather_greaves,
  31. equipment.main_hand => equipment.jade_sword,
  32. others => equipment.none),
  33. item_count => 0,
  34. items => (others => equipment.none)
  35. );
  36. ------------------------------------------------------------------------------------------
  37. type view is (
  38. map_preview_panel, status_preview_panel, text_box_panel
  39. );
  40. view_icon : array (view) of sprite := (others => (others => 0));
  41. view_list : array (view) of boolean := (others => true);
  42. view_text : array (view) of long_string := (
  43. "Toggle map preview panel. ",
  44. "Toggle status preview panel. ",
  45. "Toggle text box panel. "
  46. );
  47. procedure swap_map_preview_panel is begin view_list (map_preview_panel) := not view_list (map_preview_panel); end swap_map_preview_panel;
  48. procedure swap_status_preview_panel is begin view_list (status_preview_panel) := not view_list (status_preview_panel); end swap_status_preview_panel;
  49. procedure swap_text_box_panel is begin view_list (text_box_panel) := not view_list (text_box_panel); end swap_text_box_panel;
  50. view_show : array (view) of access procedure := (
  51. swap_map_preview_panel'access,
  52. swap_status_preview_panel'access,
  53. swap_text_box_panel'access
  54. );
  55. game_title : sprite;
  56. game_preview : array (world.biome) of sprite;
  57. switch : natural := 0;
  58. choose : world.biome := world.grass;
  59. ------------------------------------------------------------------------------------------
  60. procedure check_move_camera_up is
  61. begin
  62. decrement (world.map.chads (1).y);
  63. world.map.chads (1).y := clip (world.map.chads (1).y, 0, world.map.height - 1);
  64. if world.map.clips (world.map.chads (1).x, world.map.chads (1).y) then
  65. increment (world.map.chads (1).y);
  66. end if;
  67. end check_move_camera_up;
  68. procedure check_move_camera_down is
  69. begin
  70. increment (world.map.chads (1).y);
  71. world.map.chads (1).y := clip (world.map.chads (1).y, 0, world.map.height - 1);
  72. if world.map.clips (world.map.chads (1).x, world.map.chads (1).y) then
  73. decrement (world.map.chads (1).y);
  74. end if;
  75. end check_move_camera_down;
  76. procedure check_move_camera_left is
  77. begin
  78. decrement (world.map.chads (1).x);
  79. world.map.chads (1).x := clip (world.map.chads (1).x, 0, world.map.width - 1);
  80. if world.map.clips (world.map.chads (1).x, world.map.chads (1).y) then
  81. increment (world.map.chads (1).x);
  82. end if;
  83. end check_move_camera_left;
  84. procedure check_move_camera_right is
  85. begin
  86. increment (world.map.chads (1).x);
  87. world.map.chads (1).x := clip (world.map.chads (1).x, 0, world.map.width - 1);
  88. if world.map.clips (world.map.chads (1).x, world.map.chads (1).y) then
  89. decrement (world.map.chads (1).x);
  90. end if;
  91. end check_move_camera_right;
  92. procedure ui_main_style is
  93. begin
  94. ui.active := ui.style'val ((ui.style'pos (ui.active) + 1) mod ui.style_count);
  95. end ui_main_style;
  96. procedure zoom_in is begin zoom := 2; end zoom_in;
  97. procedure zoom_out is begin zoom := 1; end zoom_out;
  98. signal_list : constant array (signal_code) of access procedure := (
  99. signal_up => check_move_camera_up'access,
  100. signal_down => check_move_camera_down'access,
  101. signal_left => check_move_camera_left'access,
  102. signal_right => check_move_camera_right'access,
  103. signal_v => ui_main_style'access,
  104. signal_kp_add => zoom_in'access,
  105. signal_kp_subtract => zoom_out'access,
  106. signal_m => world.reveal_map'access,
  107. signal_f => toggle_fullscreen'access,
  108. others => idle_skip'access
  109. );
  110. ------------------------------------------------------------------------------------------
  111. procedure main_menu is
  112. begin
  113. draw (game_preview (world.ash), center_x (game_preview (world.ash).width * 2), center_y (game_preview (world.ash).height * 2), factor => 2);
  114. draw (game_title, center_x (game_title.width * 2), center_y (game_title.height * 2), factor => 2);
  115. --
  116. ui.write ("Main Menu", 0, 0);
  117. --
  118. ui.draw_check_box (0, 32, view_list (map_preview_panel), "map_preview_panel");
  119. ui.draw_check_box (0, 64, view_list (status_preview_panel), "status_preview_panel");
  120. ui.draw_check_box (0, 96, view_list (text_box_panel), "text_box_panel");
  121. end main_menu;
  122. view_source_code : natural := 25;
  123. source_code : array (0 .. 35) of unbounded_string := (
  124. to_unbounded_string (folder & "/source/ai.adb"),
  125. to_unbounded_string (folder & "/source/ai.ads"),
  126. to_unbounded_string (folder & "/source/attribute.adb"),
  127. to_unbounded_string (folder & "/source/attribute.ads"),
  128. to_unbounded_string (folder & "/source/chad.adb"),
  129. to_unbounded_string (folder & "/source/chad.ads"),
  130. to_unbounded_string (folder & "/source/construction.adb"),
  131. to_unbounded_string (folder & "/source/construction.ads"),
  132. to_unbounded_string (folder & "/source/core.adb"),
  133. to_unbounded_string (folder & "/source/core.ads"),
  134. to_unbounded_string (folder & "/source/deity.adb"),
  135. to_unbounded_string (folder & "/source/deity.ads"),
  136. to_unbounded_string (folder & "/source/effect.adb"),
  137. to_unbounded_string (folder & "/source/effect.ads"),
  138. to_unbounded_string (folder & "/source/equipment.adb"),
  139. to_unbounded_string (folder & "/source/equipment.ads"),
  140. to_unbounded_string (folder & "/source/faction.adb"),
  141. to_unbounded_string (folder & "/source/faction.ads"),
  142. to_unbounded_string (folder & "/source/magic.adb"),
  143. to_unbounded_string (folder & "/source/magic.ads"),
  144. to_unbounded_string (folder & "/source/main.adb"),
  145. to_unbounded_string (folder & "/source/material.adb"),
  146. to_unbounded_string (folder & "/source/material.ads"),
  147. to_unbounded_string (folder & "/source/might.adb"),
  148. to_unbounded_string (folder & "/source/might.ads"),
  149. to_unbounded_string (folder & "/source/ray.ads"),
  150. to_unbounded_string (folder & "/source/resource.adb"),
  151. to_unbounded_string (folder & "/source/resource.ads"),
  152. to_unbounded_string (folder & "/source/skill.adb"),
  153. to_unbounded_string (folder & "/source/skill.ads"),
  154. to_unbounded_string (folder & "/source/ui.adb"),
  155. to_unbounded_string (folder & "/source/ui.ads"),
  156. to_unbounded_string (folder & "/source/unit.adb"),
  157. to_unbounded_string (folder & "/source/unit.ads"),
  158. to_unbounded_string (folder & "/source/world.adb"),
  159. to_unbounded_string (folder & "/source/world.ads")
  160. );
  161. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  162. begin
  163. dash;
  164. echo (comment, "Copyright (C) 2024 -- Ognjen 'xolatile' Milan Robovic");
  165. echo (comment, "Version -- 1.0.0");
  166. echo (comment, "License -- GNU/GPLv3+");
  167. echo (comment, "Xhads is free software, you can redistribute it and modify it under the terms of the GNU General Public License by Free Software Foundation.");
  168. dash;
  169. initialize;
  170. ui.active := ui.main;
  171. ui.configure;
  172. --~play (import_song (c_string (core.folder & "/song/main_menu.ogg")).index);
  173. attribute.configure;
  174. skill.configure;
  175. resource.configure;
  176. --~might.configure;
  177. magic.configure;
  178. material.configure;
  179. equipment.configure;
  180. unit.configure;
  181. deity.configure;
  182. construction.configure;
  183. chad.configure;
  184. world.configure;
  185. --~ai.configure;
  186. world.make (world.swamp, 240, 180, 8);
  187. world.add_chad (player);
  188. dash;
  189. echo (success, "Successfully initialized game data, entering main gameplay loop.");
  190. dash;
  191. for index in view loop
  192. view_icon (index) := import_sprite (core.folder & "/icon/engine/" & lowercase (view'image (index)) & ".png", 1, 1);
  193. end loop;
  194. game_title := import_sprite (core.folder & "/ui/game_title.png", 1, 1);
  195. for index in world.biome loop
  196. game_preview (index) := import_sprite (core.folder & "/ui/preview/" & lowercase (world.biome'image (index)) & "land.png", 1, 1);
  197. end loop;
  198. ------------------------------------------------------------------------------------------
  199. introduction_loop: loop
  200. synchronize;
  201. --
  202. exit when signal_mode = signal_space or cursor_mode = cursor_right;
  203. --
  204. case signal_mode is
  205. when signal_none => null;
  206. when signal_space => null;
  207. when others => switch := (switch + 1) mod world.biome_count;
  208. choose := world.biome'val (switch);
  209. end case;
  210. --
  211. draw (game_preview (choose), center_x (game_preview (choose).width * 2), center_y (game_preview (choose).height * 2), factor => 2);
  212. draw (game_title, center_x (game_title.width * 2), center_y (game_title.height * 2), factor => 2);
  213. --
  214. ui.write ("[-- Press Spacebar or RMB to continue]", 0, center_y (24), (102, 102, 102, 255));
  215. end loop introduction_loop;
  216. cursor_mode := cursor_none;
  217. main_menu_loop: loop
  218. synchronize;
  219. --
  220. exit when signal_mode = signal_space or cursor_mode = cursor_right;
  221. --
  222. --~main_menu;
  223. --
  224. declare source_code_data : string_box_data;
  225. begin
  226. import_text (source_code_data, to_string (source_code (view_source_code)));
  227. --
  228. if cursor_mode = cursor_left then
  229. view_source_code := (view_source_code + 1) mod 36;
  230. cursor_mode := cursor_none;
  231. wheel := 0.0;
  232. end if;
  233. --
  234. ui.write_ada_code (source_code_data, 0, integer (wheel) * 30);
  235. end;
  236. end loop main_menu_loop;
  237. cursor_mode := cursor_none;
  238. ui.active := ui.style'val (faction.enumeration'pos (chad.trait (player.index).kind) + 1);
  239. gameplay_loop: loop
  240. synchronize;
  241. --
  242. exit when engine_active = false;
  243. --
  244. if not view_list (status_preview_panel) then
  245. side_panel := 0;
  246. else
  247. side_panel := 376 + 2 * 32;
  248. end if;
  249. --
  250. preview_width := window_width - side_panel;
  251. preview_height := window_height - text_box_height;
  252. text_box_height := 32;
  253. --
  254. world.draw;
  255. --
  256. if view_list (map_preview_panel) then
  257. ui.draw_menu (0, 0, preview_width, preview_height);
  258. end if;
  259. --
  260. if view_list (status_preview_panel) then
  261. ui.draw_tiny_menu (preview_width, 0, side_panel, preview_height);
  262. chad.draw_data (world.map.chads (1), preview_width + 32, 32);
  263. --~ui.draw_state_box (preview_width + 32, 32);
  264. end if;
  265. --
  266. if view_list (text_box_panel) then
  267. ui.draw_help_box (0, window_height - text_box_height, window_width - icon * (view'pos (view'last) + 1), text_box_height);
  268. end if;
  269. --
  270. for index in view loop
  271. ui.draw_icon (view_icon (index), view_text (index),
  272. window_width - icon * (view'pos (view'last) + 1) + icon * view'pos (index),
  273. window_height - text_box_height,
  274. view_show (index));
  275. end loop;
  276. --
  277. resource.draw_points (player.resources, (preview_width - 4 * icon * resource.count) / 2, (if view_list (map_preview_panel) then icon else 0));
  278. --
  279. signal_list (signal_mode).all;
  280. --
  281. --~magic.menu (0, 0, true);
  282. --~might.menu (0, 0, true);
  283. --
  284. --~chad.draw_alice;
  285. --
  286. --~deity.draw (deity.AEZORA, 300, 300);
  287. --~deity.draw (deity.ULDRAE, 500, 300);
  288. --
  289. ui.write (framerate'image, window_width - 5 * core.icon + 3, window_height - 27);
  290. --
  291. camera.x := world.map.chads (1).x;
  292. camera.y := world.map.chads (1).y;
  293. --
  294. ui.synchronize;
  295. end loop gameplay_loop;
  296. --~world.mapshot (folder & "/test.png");
  297. ------------------------------------------------------------------------------------------
  298. deinitialize;
  299. dash;
  300. end main;