Prototype game engine for Heroes of Might & Magic, featuring a gameplay plot-twist...
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

476 linhas
25KB

  1. -- Copyright (c) 2024 - Ognjen 'xolatile' Milan Robovic
  2. --
  3. -- GNU General Public Licence (version 3 or later)
  4. with core, ui;
  5. package body ui is
  6. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  7. type element is (
  8. none,
  9. main_background,
  10. --
  11. corner_upper_left, border_upper, corner_upper_right,
  12. border_left, border_right,
  13. corner_lower_left, border_lower, corner_lower_right,
  14. --
  15. tiny_corner_upper_left, tiny_border_upper, tiny_corner_upper_right,
  16. tiny_border_left, tiny_border_right,
  17. tiny_corner_lower_left, tiny_border_lower, tiny_corner_lower_right,
  18. --
  19. frame_upper_left, frame_upper, frame_upper_right,
  20. frame_left, frame_middle, frame_right,
  21. frame_lower_left, frame_lower, frame_lower_right,
  22. --
  23. icon_upper_left, icon_upper, icon_upper_right,
  24. icon_left, icon_right,
  25. icon_lower_left, icon_lower, icon_lower_right,
  26. --
  27. text_upper_left, text_upper, text_upper_right,
  28. text_left, text_middle, text_right,
  29. text_lower_left, text_lower, text_lower_right,
  30. --
  31. cursor, icon, overicon, icon_selected,
  32. --
  33. fill_bar_left, fill_bar_horizontal, fill_bar_right, fill_horizontal,
  34. --
  35. scroll_bar_lower, scroll_bar_middle, scroll_bar_upper,
  36. --
  37. title_bar_left, title_bar_middle, title_bar_right
  38. );
  39. ------------------------------------------------------------------------------------------
  40. structure_limit : constant natural := 12;
  41. sprite : array (style, element) of core.sprite;
  42. font : array (style) of core.font;
  43. structure_array : array (0 .. structure_limit) of structure;
  44. structure_count : natural := 0;
  45. ------------------------------------------------------------------------------------------
  46. function cursor_inside (x, y, width, height : in integer) return boolean is
  47. begin
  48. --~return (core.cursor.x > x and core.cursor.x < x + width and core.cursor.y > y and core.cursor.y < y + height);
  49. if core.cursor.x > x and core.cursor.x < x + width
  50. and core.cursor.y > y and core.cursor.y < y + height then
  51. return true;
  52. else
  53. return false;
  54. end if;
  55. end cursor_inside;
  56. ------------------------------------------------------------------------------------------
  57. procedure draw (index : in element := none;
  58. x : in integer := 0;
  59. y : in integer := 0;
  60. width : in integer := 0;
  61. height : in integer := 0) is
  62. save_zoom : natural := core.zoom;
  63. begin
  64. core.zoom := 1;
  65. core.draw (sprite (active, index), x, y, 0, 0, width, height);
  66. core.zoom := save_zoom;
  67. end draw;
  68. ------------------------------------------------------------------------------------------
  69. procedure draw_horizontally (index : in element; x, y, width : in integer; action : core.pointer := core.idle'access) is
  70. step : constant integer := sprite (active, index).width;
  71. begin
  72. for move in 0 .. width / step - 1 loop
  73. draw (index, x + move * step,y);
  74. end loop;
  75. --
  76. if width mod step > 0 then
  77. draw (index, x + (width / step) * step, y, width mod step, sprite (active, index).height);
  78. end if;
  79. --
  80. --~if core.cursor.x > x and core.cursor.x < x + width
  81. --~and core.cursor.y > y and core.cursor.y < y + sprite (active, index).height
  82. --~and core.cursor_mode = 1 then
  83. --~action.all;
  84. --~core.cursor_mode := 0;
  85. --~end if;
  86. end draw_horizontally;
  87. ------------------------------------------------------------------------------------------
  88. procedure draw_vertically (index : in element; x, y, height : in integer; action : core.pointer := core.idle'access) is
  89. step : constant integer := sprite (active, index).height;
  90. begin
  91. for move in 0 .. height / step - 1 loop
  92. draw (index, x, y + move * step);
  93. end loop;
  94. --
  95. if height mod step > 0 then
  96. draw (index, x, y + (height / step) * step, sprite (active, index).width, height mod step);
  97. end if;
  98. --
  99. --~if core.cursor.x > x and core.cursor.x < x + sprite (active, index).width
  100. --~and core.cursor.y > y and core.cursor.y < y + height
  101. --~and core.cursor_mode = 1 then
  102. --~action.all;
  103. --~core.cursor_mode := 0;
  104. --~end if;
  105. end draw_vertically;
  106. ------------------------------------------------------------------------------------------
  107. procedure draw_background (index : in element; x, y, width, height : in integer; action : core.pointer := core.idle'access) is
  108. base_width : integer := sprite (active, index).width;
  109. base_height : integer := sprite (active, index).height;
  110. crop_width : integer := width mod base_width;
  111. crop_height : integer := height mod base_height;
  112. begin
  113. for move_y in 0 .. height / base_height - 1 loop
  114. for move_x in 0 .. width / base_width - 1 loop
  115. draw (index, x + move_x * base_width, y + move_y * base_height);
  116. end loop;
  117. --
  118. if width mod base_width > 0 then
  119. draw (index, x + width - crop_width, y + move_y * base_height, crop_width, base_height);
  120. end if;
  121. end loop;
  122. --
  123. for move_x in 0 .. width / base_width - 1 loop
  124. if height mod base_height > 0 then
  125. draw (index, x + move_x * base_width, y + height - crop_height, base_width, crop_height);
  126. end if;
  127. end loop;
  128. --
  129. if width mod base_width > 0 and height mod base_height > 0 then
  130. draw (index, x + width - crop_width, y + height - crop_height, crop_width, crop_height);
  131. end if;
  132. end draw_background;
  133. ------------------------------------------------------------------------------------------
  134. procedure draw_structure (data : in structure) is
  135. offset : constant integer := core.icon;
  136. new_width : constant integer := (if data.resize then 320 else data.width);
  137. new_height : constant integer := (if data.resize then data.gui_n * (3 * core.icon / 2) + 2 * offset else data.height);
  138. new_x : constant integer := (if data.center then (core.window_width - new_width) / 2 else data.x);
  139. new_y : constant integer := (if data.center then (core.window_height - new_height) / 2 else data.y);
  140. --
  141. at_x : integer := new_x + offset;
  142. at_y : integer := new_y + offset;
  143. begin
  144. draw_tiny_menu (new_x, new_y, new_width, new_height);
  145. draw_title_bar (new_x, new_y, new_width, data.title);
  146. --
  147. for x in 0 .. data.gui_n - 1 loop
  148. case data.gui_list (x).kind is
  149. when gui_button =>
  150. draw_frame (data.gui_list (x).info, at_x, at_y, new_width - 2 * offset, 3 * core.icon / 2);
  151. draw_icon (data.gui_list (x).image, data.gui_list (x).info, at_x + core.icon / 4, at_y + core.icon / 4);
  152. write (data.gui_list (x).text, at_x + 5 * core.icon / 4, at_y + 2 + core.icon / 4);
  153. if cursor_inside (at_x, at_y, new_width - 2 * offset - core.icon - 2, 3 * core.icon / 2) then
  154. draw (cursor, at_x + new_width - 96, at_y);
  155. end if;
  156. at_y := at_y + 3 * core.icon / 2;
  157. when others => null;
  158. end case;
  159. end loop;
  160. end draw_structure;
  161. ------------------------------------------------------------------------------------------
  162. procedure configure is
  163. procedure load_ui (index : in style; folder_path : in string) is
  164. begin
  165. font (index) := core.import_font ("./sprite/ui/" & folder_path & "/font.png", 24, 0);
  166. --
  167. for this in element loop
  168. sprite (index, this) := core.import_sprite ("./sprite/ui/" & folder_path & "/" & core.lowercase (element'image (this)) & ".png", 1, 1);
  169. end loop;
  170. end load_ui;
  171. begin
  172. core.echo (core.comment, "Configuring UI components...");
  173. --
  174. for index in style loop
  175. load_ui (index, core.lowercase (style'image (index)));
  176. end loop;
  177. end configure;
  178. ------------------------------------------------------------------------------------------
  179. procedure synchronize is
  180. begin
  181. for index in 0 .. structure_count - 1 loop
  182. if core.signal_mode = core.signal_code'pos (structure_array (index).toggle) then
  183. structure_array (index).show := (if structure_array (index).show then false else true);
  184. end if;
  185. --
  186. if structure_array (index).show then
  187. draw_structure (structure_array (index));
  188. end if;
  189. end loop;
  190. end synchronize;
  191. ------------------------------------------------------------------------------------------
  192. procedure write (text : in string; x, y : in integer) is
  193. begin
  194. core.write (text, x, y, font (active));
  195. end write;
  196. ------------------------------------------------------------------------------------------
  197. procedure draw_icon (data : in core.sprite; description : in string; x, y : in integer; action : core.pointer := core.idle'access) is
  198. save_zoom : natural := core.zoom;
  199. begin
  200. draw (icon, x, y);
  201. --
  202. core.zoom := 1;
  203. core.draw (data, x, y);
  204. core.zoom := save_zoom;
  205. --
  206. if cursor_inside (x, y, core.icon, core.icon) then
  207. draw (icon_selected, x, y);
  208. --
  209. core.write_text_box (description);
  210. --
  211. if core.cursor_mode = 1 then
  212. action.all;
  213. core.cursor_mode := 0;
  214. end if;
  215. end if;
  216. end draw_icon;
  217. ------------------------------------------------------------------------------------------
  218. procedure draw_overicon (data : in core.sprite; description : in string; x, y : in integer; action : core.pointer := core.idle'access) is
  219. save_zoom : natural := core.zoom;
  220. begin
  221. core.zoom := 1;
  222. core.draw (data, x, y);
  223. core.zoom := save_zoom;
  224. --
  225. draw (overicon, x, y);
  226. end draw_overicon;
  227. ------------------------------------------------------------------------------------------
  228. procedure draw_text_box (text : in string) is
  229. width : constant integer := 144;
  230. height : constant integer := 72;
  231. x : constant integer := (core.window_width - width) / 2;
  232. y : constant integer := (core.window_height - height) / 2;
  233. offset : constant integer := sprite (active, text_middle).width;
  234. begin
  235. draw_background (text_middle, x + offset, y + offset, width - 2 * offset, height - 2 * offset);
  236. --
  237. draw_horizontally (text_upper, x + offset, y, width - 2 * offset);
  238. draw_horizontally (text_lower, x + offset, y + height - offset, width - 2 * offset);
  239. draw_vertically (text_left, x, y + offset, height - 2 * offset);
  240. draw_vertically (text_right, x + width - offset, y + offset, height - 2 * offset);
  241. --
  242. draw (text_upper_left, x, y);
  243. draw (text_upper_right, x + width - offset, y);
  244. draw (text_lower_left, x, y + height - offset);
  245. draw (text_lower_right, x + width - offset, y + height - offset);
  246. --
  247. write (text, x, y);
  248. end draw_text_box;
  249. ------------------------------------------------------------------------------------------
  250. --~procedure a is begin core.echo (core.warning, "Heyo world!"); end a;
  251. procedure draw_help_box (x, y, width, height : in integer; action : core.pointer := core.idle'access) is
  252. offset : constant integer := sprite (active, text_middle).width;
  253. begin
  254. draw_background (text_middle, x + offset, y + offset, width - 2 * offset, height - 2 * offset);
  255. --
  256. draw_horizontally (text_upper, x + offset, y, width - 2 * offset);
  257. draw_horizontally (text_lower, x + offset, y + height - offset, width - 2 * offset);
  258. draw_vertically (text_left, x, y + offset, height - 2 * offset);
  259. draw_vertically (text_right, x + width - offset, y + offset, height - 2 * offset);
  260. --
  261. draw (text_upper_left, x, y);
  262. draw (text_upper_right, x + width - offset, y);
  263. draw (text_lower_left, x, y + height - offset);
  264. draw (text_lower_right, x + width - offset, y + height - offset);
  265. --
  266. core.write (core.read_text_box, x, y, font (active));
  267. --
  268. --~core.block_queue ((x, y, width, height, 2, a'access));
  269. end draw_help_box;
  270. ------------------------------------------------------------------------------------------
  271. procedure draw_frame (description : in string; x, y, width, height : in integer; action : core.pointer := core.idle'access) is
  272. offset_x : constant integer := sprite (active, frame_middle).width;
  273. offset_y : constant integer := sprite (active, frame_middle).height;
  274. begin
  275. if height < core.icon or width < core.icon then
  276. return;
  277. end if;
  278. --
  279. draw_background (frame_middle, x + offset_x, y + offset_y, width - 2 * offset_x, height - 2 * offset_y);
  280. --
  281. draw_horizontally (frame_upper, x + offset_x, y, width - 2 * offset_x);
  282. draw_horizontally (frame_lower, x + offset_x, y + height - offset_y, width - 2 * offset_x);
  283. draw_vertically (frame_left, x, y + offset_y, height - 2 * offset_y);
  284. draw_vertically (frame_right, x + width - offset_x, y + offset_y, height - 2 * offset_y);
  285. --
  286. draw (frame_upper_left, x, y);
  287. draw (frame_upper_right, x + width - sprite (active, frame_upper_right).width, y);
  288. draw (frame_lower_left, x, y + height - sprite (active, frame_lower_left).height);
  289. draw (frame_lower_right, x + width - sprite (active, frame_lower_right).width, y + height - sprite (active, frame_lower_right).height);
  290. end draw_frame;
  291. ------------------------------------------------------------------------------------------
  292. procedure draw_title_bar (x, y, width : in integer; title : in string) is
  293. middle_width : constant integer := width - sprite (active, title_bar_left).width - sprite (active, title_bar_right).width;
  294. begin
  295. draw (title_bar_left, x, y - sprite (active, title_bar_left).height);
  296. draw (title_bar_right, x + middle_width + sprite (active, title_bar_left).width, y - sprite (active, title_bar_right).height);
  297. --
  298. draw_horizontally (title_bar_middle, x + sprite (active, title_bar_left).width, y - sprite (active, title_bar_middle).height, middle_width);
  299. --
  300. core.write (title, x + sprite (active, title_bar_left).width / 2 + 20, y - sprite (active, title_bar_middle).height / 2 - 6, font (active));
  301. end draw_title_bar;
  302. ------------------------------------------------------------------------------------------
  303. procedure draw_fill_bar (x, y, width : in integer; fill : in float) is
  304. middle_width : constant integer := width - sprite (active, fill_bar_left).width - sprite (active, fill_bar_right).width;
  305. fill_width : constant integer := integer (float (middle_width) * fill);
  306. begin
  307. draw (fill_bar_left, x, y - sprite (active, fill_bar_left).height);
  308. draw (fill_bar_right, x + middle_width + sprite (active, fill_bar_left).width, y - sprite (active, fill_bar_right).height);
  309. --
  310. draw_horizontally (fill_bar_horizontal, x + sprite (active, fill_bar_left).width, y - sprite (active, fill_bar_horizontal).height, middle_width);
  311. draw_horizontally (fill_horizontal, x + sprite (active, fill_bar_left).width, y - sprite (active, fill_bar_horizontal).height, fill_width);
  312. end draw_fill_bar;
  313. ------------------------------------------------------------------------------------------
  314. procedure draw_scroll_bar (x, y, height : in integer; offset : in integer) is
  315. middle_height : constant integer := height - sprite (active, scroll_bar_upper).height - sprite (active, scroll_bar_lower).height;
  316. begin
  317. draw (scroll_bar_upper, x, y);
  318. draw (scroll_bar_lower, x, y + middle_height + sprite (active, scroll_bar_upper).height);
  319. --
  320. draw_vertically (scroll_bar_middle, x, y + sprite (active, scroll_bar_upper).height, middle_height);
  321. end draw_scroll_bar;
  322. ------------------------------------------------------------------------------------------
  323. procedure draw_menu (x, y, width, height : in integer) is
  324. offset : constant integer := sprite (active, none).width;
  325. begin
  326. declare upper : constant integer := width - sprite (active, corner_upper_left).width - sprite (active, corner_upper_right).width;
  327. lower : constant integer := width - sprite (active, corner_lower_left).width - sprite (active, corner_lower_right).width;
  328. left : constant integer := height - sprite (active, corner_upper_left).height - sprite (active, corner_lower_left).height;
  329. right : constant integer := height - sprite (active, corner_upper_right).height - sprite (active, corner_lower_right).height;
  330. begin
  331. draw_horizontally (border_upper, x + sprite (active, corner_upper_left).width, y, upper, action => core.move_camera_up'access);
  332. draw_horizontally (border_lower, x + sprite (active, corner_lower_left).width, y + height - sprite (active, border_lower).height, lower, action => core.move_camera_down'access);
  333. draw_vertically (border_left, x, y + sprite (active, corner_upper_left).height, left, action => core.move_camera_left'access);
  334. draw_vertically (border_right, x + width - sprite (active, border_right).width, y + sprite (active, corner_upper_right).height, right, action => core.move_camera_right'access);
  335. end;
  336. --
  337. draw (corner_upper_left, x, y);
  338. draw (corner_upper_right, x + width - sprite (active, corner_upper_right).width, y);
  339. draw (corner_lower_left, x, y + height - sprite (active, corner_lower_left).height);
  340. draw (corner_lower_right, x + width - sprite (active, corner_lower_right).width, y + height - sprite (active, corner_lower_right).height);
  341. end draw_menu;
  342. ------------------------------------------------------------------------------------------
  343. procedure draw_tiny_menu (x, y, width, height : in integer) is
  344. offset : constant integer := sprite (active, none).width;
  345. begin
  346. draw_background (main_background, x + offset, y + offset, width - 2 * offset, height - 2 * offset);
  347. --
  348. declare upper : constant integer := width - sprite (active, tiny_corner_upper_left).width - sprite (active, tiny_corner_upper_right).width;
  349. lower : constant integer := width - sprite (active, tiny_corner_lower_left).width - sprite (active, tiny_corner_lower_right).width;
  350. left : constant integer := height - sprite (active, tiny_corner_upper_left).height - sprite (active, tiny_corner_lower_left).height;
  351. right : constant integer := height - sprite (active, tiny_corner_upper_right).height - sprite (active, tiny_corner_lower_right).height;
  352. begin
  353. draw_horizontally (tiny_border_upper, x + sprite (active, tiny_corner_upper_left).width, y, upper);
  354. draw_horizontally (tiny_border_lower, x + sprite (active, tiny_corner_lower_left).width, y + height - sprite (active, tiny_border_lower).height, lower);
  355. draw_vertically (tiny_border_left, x, y + sprite (active, tiny_corner_upper_left).height, left);
  356. draw_vertically (tiny_border_right, x + width - sprite (active, tiny_border_right).width, y + sprite (active, tiny_corner_upper_right).height, right);
  357. end;
  358. --
  359. draw (tiny_corner_upper_left, x, y);
  360. draw (tiny_corner_upper_right, x + width - sprite (active, tiny_corner_upper_right).width, y);
  361. draw (tiny_corner_lower_left, x, y + height - sprite (active, tiny_corner_lower_left).height);
  362. draw (tiny_corner_lower_right, x + width - sprite (active, tiny_corner_lower_right).width, y + height - sprite (active, tiny_corner_lower_right).height);
  363. end draw_tiny_menu;
  364. ------------------------------------------------------------------------------------------
  365. procedure draw_icon_menu (description : in string; x, y, width, height : in integer; action : core.pointer := core.idle'access) is
  366. offset_x : constant integer := sprite (active, icon_upper_left).width;
  367. offset_y : constant integer := sprite (active, icon_upper_left).height;
  368. begin
  369. if height < 2 * sprite (active, icon_upper_left).height
  370. or width < 2 * sprite (active, icon_upper_left).width then
  371. return;
  372. end if;
  373. --
  374. draw_horizontally (icon_upper, x + offset_x, y, width - 2 * offset_x);
  375. draw_horizontally (icon_lower, x + offset_x, y + height - offset_y, width - 2 * offset_x);
  376. draw_vertically (icon_left, x, y + offset_y, height - 2 * offset_y);
  377. draw_vertically (icon_right, x + width - offset_x, y + offset_y, height - 2 * offset_y);
  378. --
  379. draw (icon_upper_left, x, y);
  380. draw (icon_upper_right, x + width - sprite (active, icon_upper_right).width, y);
  381. draw (icon_lower_left, x, y + height - sprite (active, icon_lower_left).height);
  382. draw (icon_lower_right, x + width - sprite (active, icon_lower_right).width, y + height - sprite (active, icon_lower_right).height);
  383. end draw_icon_menu;
  384. ------------------------------------------------------------------------------------------
  385. procedure draw_state_box (x, y : in integer) is
  386. begin
  387. ui.write ("Cursor X:" & core.cursor.x'image, x, y + 0);
  388. ui.write ("Cursor Y:" & core.cursor.y'image, x, y + 32);
  389. ui.write ("Cursor Mode:" & core.cursor_mode'image, x, y + 64);
  390. ui.write ("Camera X:" & core.camera.x'image, x, y + 96);
  391. ui.write ("Camera Y:" & core.camera.y'image, x, y + 128);
  392. ui.write ("Global Time:" & core.global_time'image, x, y + 160);
  393. ui.write ("Gameplay Time:" & core.gameplay_time'image, x, y + 192);
  394. ui.write ("Animation Time:" & core.animation_time'image, x, y + 224);
  395. ui.write ("Framerate:" & core.framerate'image, x, y + 256);
  396. end draw_state_box;
  397. ------------------------------------------------------------------------------------------
  398. procedure add_structure (data : in structure) is
  399. begin
  400. structure_array (structure_count) := data;
  401. structure_array (structure_count).gui_list := new gui_array (0 .. structure_array (structure_count).gui_n - 1);
  402. structure_array (structure_count).gui_n := 0;
  403. --
  404. core.increment (structure_count);
  405. end add_structure;
  406. ------------------------------------------------------------------------------------------
  407. procedure add_structure_button (icon : in core.sprite; text : in core.short_string; description : in core.long_string := "") is
  408. begin
  409. structure_array (structure_count - 1).gui_list (structure_array (structure_count - 1).gui_n).kind := gui_button;
  410. structure_array (structure_count - 1).gui_list (structure_array (structure_count - 1).gui_n).text := text;
  411. structure_array (structure_count - 1).gui_list (structure_array (structure_count - 1).gui_n).info := description;
  412. structure_array (structure_count - 1).gui_list (structure_array (structure_count - 1).gui_n).number := 0;
  413. structure_array (structure_count - 1).gui_list (structure_array (structure_count - 1).gui_n).image := icon;
  414. --
  415. core.increment (structure_array (structure_count - 1).gui_n);
  416. end add_structure_button;
  417. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  418. end ui;