Prototype game engine for Heroes of Might & Magic, featuring a gameplay plot-twist...
Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.

530 wiersze
22KB

  1. -- Copyright (c) 2024 - Ognjen 'xolatile' Milan Robovic
  2. --
  3. -- GNU General Public Licence (version 3 or later)
  4. with ray;
  5. package body core is
  6. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  7. type terminal_colour is (
  8. grey, red, green, yellow, blue, pink,
  9. cyan, white
  10. );
  11. type terminal_effect is (
  12. normal, bold, italic, underline, blink, invert
  13. );
  14. ------------------------------------------------------------------------------------------
  15. type texture_data_array is array (natural range <>) of ray.texture;
  16. type sound_data_array is array (natural range <>) of ray.sound;
  17. type font_data_array is array (natural range <>) of ray.font;
  18. ------------------------------------------------------------------------------------------
  19. texture_count : integer := 0;
  20. sound_count : integer := 0;
  21. font_count : integer := 0;
  22. texture_array : access texture_data_array;
  23. sound_array : access sound_data_array;
  24. font_array : access font_data_array;
  25. game_icon : ray.image;
  26. ------------------------------------------------------------------------------------------
  27. procedure terminal (colour : in terminal_colour := white;
  28. effect : in terminal_effect := normal) is
  29. format : string := character'val (27) & "[" & character'val (terminal_effect'pos (effect) + 48) & ";3" & character'val (terminal_colour'pos (colour) + 48) & "m";
  30. begin
  31. put (format);
  32. end terminal;
  33. ------------------------------------------------------------------------------------------
  34. function "=" (a, b : in signal_code) return boolean is begin return natural (signal_code'pos (a)) = natural (signal_code'pos (b)); end "=";
  35. function "=" (a, b : in cursor_code) return boolean is begin return natural (cursor_code'pos (a)) = natural (cursor_code'pos (b)); end "=";
  36. function "/" (a, b : in signal_code) return boolean is begin return natural (signal_code'pos (a)) /= natural (signal_code'pos (b)); end "/";
  37. function "/" (a, b : in cursor_code) return boolean is begin return natural (cursor_code'pos (a)) /= natural (cursor_code'pos (b)); end "/";
  38. ------------------------------------------------------------------------------------------
  39. function "+" (data : in point; modifier : in natural) return point is
  40. this : point := data;
  41. begin
  42. this.value := (if (data.value + modifier) > data.limit then data.limit else (data.value + modifier));
  43. --
  44. return this;
  45. end "+";
  46. ------------------------------------------------------------------------------------------
  47. function "-" (data : in point; modifier : in natural) return point is
  48. this : point := data;
  49. begin
  50. this.value := (if (data.value - modifier) <= 0 then 0 else (data.value - modifier));
  51. --
  52. return this;
  53. end "-";
  54. ------------------------------------------------------------------------------------------
  55. function "*" (data : in point; modifier : in natural) return point is
  56. this : point := data;
  57. begin
  58. this.value := (if (data.value * modifier) > data.limit then data.limit else (data.value * modifier));
  59. --
  60. return this;
  61. end "*";
  62. ------------------------------------------------------------------------------------------
  63. function "/" (data : in point; modifier : in natural) return point is
  64. this : point := data;
  65. begin
  66. this.value := (if (data.value / modifier) <= 0 then 0 else (data.value / modifier));
  67. --
  68. return this;
  69. end "/";
  70. ------------------------------------------------------------------------------------------
  71. procedure echo (status : in echo_status;
  72. text : in string) is
  73. begin
  74. if not echo_mark (status) then
  75. return;
  76. end if;
  77. --
  78. put ("[");
  79. case status is
  80. when failure => terminal (red, bold); put ("Failure"); terminal;
  81. when warning => terminal (yellow, bold); put ("Warning"); terminal;
  82. when success => terminal (green, bold); put ("Success"); terminal;
  83. when comment => terminal (grey, bold); put ("Comment"); terminal;
  84. when import => terminal (cyan, bold); put (" <-- "); terminal;
  85. when export => terminal (blue, bold); put (" --> "); terminal;
  86. end case;
  87. put ("] ");
  88. --
  89. put_line (text);
  90. end echo;
  91. ------------------------------------------------------------------------------------------
  92. procedure echo_when (condition : in boolean; status : in echo_status; text : in string) is
  93. begin
  94. if condition then
  95. echo (status, text);
  96. end if;
  97. end echo_when;
  98. ------------------------------------------------------------------------------------------
  99. procedure dash is
  100. begin
  101. terminal (grey, bold);
  102. put ("------------------------------------------------------------------------------------------");
  103. put ("------------------------------------------------------------------------------------------");
  104. terminal;
  105. new_line;
  106. end dash;
  107. ------------------------------------------------------------------------------------------
  108. procedure semi_dash is
  109. begin
  110. terminal (grey, bold);
  111. put (" ");
  112. put ("------------------------------------------------------------------------------------------");
  113. terminal;
  114. new_line;
  115. end semi_dash;
  116. ------------------------------------------------------------------------------------------
  117. function c_string (ada_string : string) return string is
  118. begin
  119. return (ada_string & character'val (0));
  120. end c_string;
  121. ------------------------------------------------------------------------------------------
  122. function random (minimum, maximum : in integer) return integer is
  123. begin
  124. return ray.get_random (minimum, maximum);
  125. end random;
  126. ------------------------------------------------------------------------------------------
  127. function clip (value, minimum, maximum : in integer) return integer is
  128. begin
  129. if value < minimum then return minimum; end if;
  130. if value > maximum then return maximum; end if;
  131. --
  132. return value;
  133. end clip;
  134. ------------------------------------------------------------------------------------------
  135. function lowercase (text : in string) return string is
  136. result : string (1 .. text'length);
  137. begin
  138. for index in text'range loop
  139. if text (index) in 'A' .. 'Z' then
  140. result (index) := character'val (character'pos (text (index)) + 32);
  141. else
  142. result (index) := text (index);
  143. end if;
  144. end loop;
  145. --
  146. return result;
  147. end lowercase;
  148. ------------------------------------------------------------------------------------------
  149. function window_width return integer is begin return ray.get_screen_width; end window_width;
  150. function window_height return integer is begin return ray.get_screen_height; end window_height;
  151. ------------------------------------------------------------------------------------------
  152. function center_x (object : in integer) return integer is begin return (window_width - object) / 2; end center_x;
  153. function center_y (object : in integer) return integer is begin return (window_height - object) / 2; end center_y;
  154. ------------------------------------------------------------------------------------------
  155. function cursor_inside (x, y, width, height : in integer) return boolean is
  156. begin
  157. return cursor.x > x and cursor.x < x + width * zoom and cursor.y > y and cursor.y < y + height * zoom;
  158. end cursor_inside;
  159. ------------------------------------------------------------------------------------------
  160. function import_sprite (file_path : in string; frames, states : in integer) return sprite is
  161. this : sprite;
  162. begin
  163. texture_array (texture_count) := ray.load_texture (c_string (file_path));
  164. --
  165. texture_count := texture_count + 1;
  166. this.index := texture_count - 1;
  167. this.width := texture_array (this.index).width / frames;
  168. this.height := texture_array (this.index).height / states;
  169. this.frames := frames;
  170. this.states := states;
  171. --
  172. if this.width = 0 or this.height = 0 then
  173. echo (warning, "Sprite not imported: " & file_path);
  174. end if;
  175. --
  176. return this;
  177. end import_sprite;
  178. ------------------------------------------------------------------------------------------
  179. function import_font (file_path : in string; scale, space : in integer) return font is
  180. this : font;
  181. begin
  182. font_array (font_count) := ray.load_font (c_string (file_path));
  183. --
  184. font_count := font_count + 1;
  185. this.index := font_count - 1;
  186. this.scale := scale;
  187. this.space := space;
  188. --
  189. return this;
  190. end import_font;
  191. ------------------------------------------------------------------------------------------
  192. function import_song (file_path : in string) return song is
  193. this : song;
  194. begin
  195. sound_array (sound_count) := ray.load_sound (c_string (file_path));
  196. --
  197. sound_count := sound_count + 1;
  198. this.index := sound_count - 1;
  199. --
  200. return this;
  201. end import_song;
  202. ------------------------------------------------------------------------------------------
  203. procedure import_text (data : in out string_box_data; file_path : in string) is
  204. begin
  205. data.text := to_unbounded_string (to_ada (ray.load_text (c_string (file_path)))) & character'val (0);
  206. end import_text;
  207. ------------------------------------------------------------------------------------------
  208. procedure create_image (width, height : in integer) is
  209. begin
  210. global_mapshot := ray.image_colour (width * base, height * base, (0, 0, 0, 255));
  211. end create_image;
  212. ------------------------------------------------------------------------------------------
  213. procedure render_image (data : in sprite; x, y, u, v, width, height : in integer) is
  214. temporary : ray.image;
  215. begin
  216. temporary := ray.image_import (texture_array (data.index));
  217. --
  218. ray.image_render (data => global_mapshot,
  219. copy => temporary,
  220. from => (float (u), float (v), float (width), float (height)),
  221. to => (float (x), float (y), float (width), float (height)));
  222. --
  223. ray.image_delete (temporary);
  224. end render_image;
  225. ------------------------------------------------------------------------------------------
  226. procedure export_image (file_path : in string) is
  227. ignore : integer;
  228. begin
  229. ignore := ray.image_export (global_mapshot, c_string (file_path));
  230. --
  231. ray.image_delete (global_mapshot);
  232. end export_image;
  233. ------------------------------------------------------------------------------------------
  234. procedure draw (data : in sprite := (others => 0);
  235. x : in integer := 0;
  236. y : in integer := 0;
  237. u : in integer := 0;
  238. v : in integer := 0;
  239. width : in integer := 0;
  240. height : in integer := 0;
  241. state : in animation := idle;
  242. factor : in integer := zoom;
  243. tint : in colour := (others => 255)) is
  244. new_width : constant float := float ((if width = 0 then data.width else width));
  245. new_height : constant float := float ((if height = 0 then data.height else height));
  246. --
  247. new_tint : ray.colour := (ray.colour_range (tint.r), ray.colour_range (tint.g), ray.colour_range (tint.b), ray.colour_range (tint.a));
  248. begin
  249. ray.draw_texture (data => texture_array (data.index),
  250. uv => (x => float (if u > 0 then u else (animation_time mod data.frames) * data.width),
  251. y => float (if v > 0 then v else (animation'pos (state) mod data.states) * data.height),
  252. width => new_width,
  253. height => new_height),
  254. view => (x => float (x),
  255. y => float (y),
  256. width => new_width * float (factor),
  257. height => new_height * float (factor)),
  258. tint => new_tint);
  259. end draw;
  260. ------------------------------------------------------------------------------------------
  261. procedure draw_horizontally (data : in sprite; x, y, width, factor : in integer; tint : in colour := (others => 255)) is
  262. begin
  263. for move in 0 .. width / data.width - 1 loop
  264. draw (data, x + move * data.width, y, tint => tint, factor => factor);
  265. end loop;
  266. --
  267. if width mod data.width > 0 then
  268. draw (data, x + (width / data.width) * data.width, y, 0, 0, width mod data.width, data.height, tint => tint, factor => factor);
  269. end if;
  270. end draw_horizontally;
  271. ------------------------------------------------------------------------------------------
  272. procedure draw_vertically (data : in sprite; x, y, height, factor : in integer; tint : in colour := (others => 255)) is
  273. begin
  274. for move in 0 .. height / data.height - 1 loop
  275. draw (data, x, y + move * data.height, tint => tint, factor => factor);
  276. end loop;
  277. --
  278. if height mod data.height > 0 then
  279. draw (data, x, y + (height / data.height) * data.height, 0, 0, data.width, height mod data.height, tint => tint, factor => factor);
  280. end if;
  281. end draw_vertically;
  282. ------------------------------------------------------------------------------------------
  283. procedure write (text : in string := "";
  284. x : in integer := 0;
  285. y : in integer := 0;
  286. tint : in colour := (others => 255);
  287. size : in integer := 0;
  288. data : in font := (others => 0)) is
  289. new_tint : ray.colour := (ray.colour_range (tint.r), ray.colour_range (tint.g), ray.colour_range (tint.b), ray.colour_range (tint.a));
  290. begin
  291. ray.draw_text (data => font_array (data.index),
  292. text => c_string (text),
  293. view => (float (x), float (y)),
  294. scale => (if size = 0 then float (font_array (data.index).base) else float (size)),
  295. space => float (font_array (data.index).pad),
  296. tint => new_tint);
  297. end write;
  298. ------------------------------------------------------------------------------------------
  299. procedure play (index : in integer) is begin ray.play_sound (sound_array (index)); end play;
  300. procedure stop (index : in integer) is begin ray.stop_sound (sound_array (index)); end stop;
  301. ------------------------------------------------------------------------------------------
  302. procedure overlay is
  303. begin
  304. ray.draw_rectangle (0, 0, window_width, window_height, (0, 0, 0, 127));
  305. end overlay;
  306. ------------------------------------------------------------------------------------------
  307. function read_help_box return string is begin return to_string (help_box.text); end read_help_box;
  308. function read_text_box return string is begin return to_string (text_box.text); end read_text_box;
  309. ------------------------------------------------------------------------------------------
  310. procedure write_help_box (text : in string) is begin help_box.text := to_unbounded_string (text); end write_help_box;
  311. procedure write_text_box (text : in string) is begin text_box.text := to_unbounded_string (text); end write_text_box;
  312. ------------------------------------------------------------------------------------------
  313. procedure increment (value : in out integer) is begin value := value + 1; end increment;
  314. procedure decrement (value : in out integer) is begin value := value - 1; end decrement;
  315. ------------------------------------------------------------------------------------------
  316. procedure idle_skip is null;
  317. procedure move_camera_up is begin core.camera.y := core.camera.y - 1; end move_camera_up;
  318. procedure move_camera_down is begin core.camera.y := core.camera.y + 1; end move_camera_down;
  319. procedure move_camera_left is begin core.camera.x := core.camera.x - 1; end move_camera_left;
  320. procedure move_camera_right is begin core.camera.x := core.camera.x + 1; end move_camera_right;
  321. ------------------------------------------------------------------------------------------
  322. procedure toggle_fullscreen is
  323. begin
  324. ray.toggle_fullscreen;
  325. end toggle_fullscreen;
  326. ------------------------------------------------------------------------------------------
  327. procedure initialize is
  328. begin
  329. echo (comment, "Initializing core components...");
  330. --
  331. engine_active := true;
  332. texture_array := new texture_data_array (0 .. 1600);
  333. sound_array := new sound_data_array (0 .. 4);
  334. font_array := new font_data_array (0 .. 16);
  335. --
  336. echo (comment, "-- Setting trace log level to none (ignoring all default Raylib logs).");
  337. ray.set_trace_log_level (ray.log_none);
  338. --
  339. ray.set_window_flags (ray.flag_window_resizable);
  340. --
  341. echo (comment, "-- Initializing Raylib window data...");
  342. echo (comment, "-- -- Window title : Xorana");
  343. echo (comment, "-- -- Window width : 1800");
  344. echo (comment, "-- -- Window height : 900");
  345. ray.open_window (1800, 900, c_string ("Xorana"));
  346. --
  347. --~echo (comment, "-- Initializing Raylib audio device data...");
  348. --~ray.open_audio_device;
  349. --
  350. game_icon := ray.load_image (c_string (folder & "/ui/game_icon.png"));
  351. --
  352. ray.window_icon (game_icon);
  353. --
  354. --ray.randomization (19970725);
  355. ray.set_target_fps (60);
  356. --
  357. echo (success, "Initialized core components.");
  358. end initialize;
  359. ------------------------------------------------------------------------------------------
  360. procedure deinitialize is
  361. begin
  362. echo (comment, "Deinitializing core components...");
  363. --
  364. engine_active := false;
  365. --
  366. echo (comment, "-- -- Unloading Raylib" & texture_count'image & " textures.");
  367. echo (comment, "-- -- Unloading Raylib" & sound_count'image & " sounds.");
  368. echo (comment, "-- -- Unloading Raylib" & font_count'image & " fonts.");
  369. --
  370. for index in 0 .. texture_count - 1 loop ray.unload_texture (texture_array (index)); end loop;
  371. for index in 0 .. sound_count - 1 loop ray.unload_sound (sound_array (index)); end loop;
  372. for index in 0 .. font_count - 1 loop ray.unload_font (font_array (index)); end loop;
  373. --
  374. --~echo (comment, "-- Deinitializing Raylib audio device data...");
  375. --~ray.close_audio_device;
  376. --
  377. ray.unload_image (game_icon);
  378. --
  379. echo (comment, "-- Deinitializing Raylib window data...");
  380. ray.close_window;
  381. --
  382. echo (success, "Deinitialized core components.");
  383. end deinitialize;
  384. ------------------------------------------------------------------------------------------
  385. procedure synchronize is
  386. signal : integer := signal_code'pos (signal_none);
  387. begin
  388. global_time := global_time + 1;
  389. global_time := global_time mod (gameplay_framerate * animation_framerate);
  390. gameplay_time := global_time mod (gameplay_framerate);
  391. animation_time := global_time / (gameplay_framerate / animation_framerate);
  392. framerate := integer (ray.get_fps);
  393. signal := ray.get_key_pressed;
  394. cursor.x := ray.get_mouse_x;
  395. cursor.y := ray.get_mouse_y;
  396. wheel := wheel + ray.mouse_wheel_move;
  397. --
  398. ray.end_drawing;
  399. --
  400. if ray.exit_key_is_pressed then
  401. engine_active := false;
  402. end if;
  403. --
  404. if ray.mouse_button_is_pressed (ray.mouse_button_left) then cursor_mode := cursor_left; end if;
  405. if ray.mouse_button_is_pressed (ray.mouse_button_right) then cursor_mode := cursor_right; end if;
  406. if ray.mouse_button_is_pressed (ray.mouse_button_middle) then cursor_mode := cursor_middle; end if;
  407. if ray.mouse_button_is_released (ray.mouse_button_left) then cursor_mode := cursor_none; end if;
  408. if ray.mouse_button_is_released (ray.mouse_button_right) then cursor_mode := cursor_none; end if;
  409. if ray.mouse_button_is_released (ray.mouse_button_middle) then cursor_mode := cursor_none; end if;
  410. --
  411. case signal is
  412. when 48 .. 57 => signal_mode := signal_code'val (signal - 48 + signal_code'pos (signal_0));
  413. when 65 .. 90 => signal_mode := signal_code'val (signal - 65 + signal_code'pos (signal_a));
  414. when 320 .. 329 => signal_mode := signal_code'val (signal - 320 + signal_code'pos (signal_kp_0));
  415. --
  416. when 0 => signal_mode := signal_none;
  417. when 32 => signal_mode := signal_space;
  418. when 96 => signal_mode := signal_grave;
  419. when 340 => signal_mode := signal_left_shift;
  420. when 341 => signal_mode := signal_left_control;
  421. when 333 => signal_mode := signal_kp_subtract;
  422. when 334 => signal_mode := signal_kp_add;
  423. when 256 => signal_mode := signal_escape;
  424. when 257 => signal_mode := signal_enter;
  425. when 258 => signal_mode := signal_tab;
  426. when 259 => signal_mode := signal_backspace;
  427. when 262 => signal_mode := signal_right;
  428. when 263 => signal_mode := signal_left;
  429. when 264 => signal_mode := signal_down;
  430. when 265 => signal_mode := signal_up;
  431. when others => signal_mode := signal_none;
  432. end case;
  433. --
  434. ray.begin_drawing;
  435. --
  436. ray.clear_background ((0, 0, 0, 255));
  437. end synchronize;
  438. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  439. end core;