Prototype game engine for Heroes of Might & Magic, featuring a gameplay plot-twist...
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

398 lines
16KB

  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. ------------------------------------------------------------------------------------------
  26. procedure terminal (colour : in terminal_colour := white;
  27. effect : in terminal_effect := normal) is
  28. format : string := character'val (27) & "[" & character'val (terminal_effect'pos (effect) + 48) & ";3" & character'val (terminal_colour'pos (colour) + 48) & "m";
  29. begin
  30. put (format);
  31. end terminal;
  32. ------------------------------------------------------------------------------------------
  33. procedure echo (status : in echo_status;
  34. text : in string) is
  35. begin
  36. if not echo_mark (status) then
  37. return;
  38. end if;
  39. --
  40. put ("[");
  41. case status is
  42. when failure => terminal (red, bold); put ("Failure"); terminal;
  43. when warning => terminal (yellow, bold); put ("Warning"); terminal;
  44. when success => terminal (green, bold); put ("Success"); terminal;
  45. when comment => terminal (grey, bold); put ("Comment"); terminal;
  46. when import => terminal (cyan, bold); put (" <-- "); terminal;
  47. when export => terminal (blue, bold); put (" --> "); terminal;
  48. end case;
  49. put ("] ");
  50. --
  51. put_line (text);
  52. end echo;
  53. ------------------------------------------------------------------------------------------
  54. procedure dash is
  55. begin
  56. terminal (grey, bold);
  57. put ("------------------------------------------------------------------------------------------");
  58. put ("------------------------------------------------------------------------------------------");
  59. terminal;
  60. new_line;
  61. end dash;
  62. ------------------------------------------------------------------------------------------
  63. procedure semi_dash is
  64. begin
  65. terminal (grey, bold);
  66. put (" ");
  67. put ("------------------------------------------------------------------------------------------");
  68. terminal;
  69. new_line;
  70. end semi_dash;
  71. ------------------------------------------------------------------------------------------
  72. function c_string (ada_string : string) return string is
  73. begin
  74. return (ada_string & character'val (0));
  75. end c_string;
  76. ------------------------------------------------------------------------------------------
  77. function random (minimum, maximum : in integer) return integer is
  78. begin
  79. return ray.get_random (minimum, maximum);
  80. end random;
  81. ------------------------------------------------------------------------------------------
  82. function clip (value, minimum, maximum : in integer) return integer is
  83. begin
  84. if value < minimum then return minimum; end if;
  85. if value > maximum then return maximum; end if;
  86. --
  87. return value;
  88. end clip;
  89. ------------------------------------------------------------------------------------------
  90. function lowercase (text : in string) return string is
  91. result : string (1 .. text'length);
  92. begin
  93. for index in text'range loop
  94. if text (index) in 'A' .. 'Z' then
  95. result (index) := character'val (character'pos (text (index)) + 32);
  96. else
  97. result (index) := text (index);
  98. end if;
  99. end loop;
  100. --
  101. return result;
  102. end lowercase;
  103. ------------------------------------------------------------------------------------------
  104. function window_width return integer is begin return ray.get_screen_width; end window_width;
  105. function window_height return integer is begin return ray.get_screen_height; end window_height;
  106. ------------------------------------------------------------------------------------------
  107. function import_sprite (file_path : in string; frames, states : in integer) return sprite is
  108. this : sprite;
  109. begin
  110. texture_array (texture_count) := ray.load_texture (c_string (file_path));
  111. --
  112. texture_count := texture_count + 1;
  113. this.index := texture_count - 1;
  114. this.width := texture_array (this.index).width / frames;
  115. this.height := texture_array (this.index).height / states;
  116. this.frames := frames;
  117. this.states := states;
  118. --
  119. if this.width = 0 or this.height = 0 then
  120. echo (failure, "Sprite not imported: " & file_path);
  121. end if;
  122. --
  123. return this;
  124. end import_sprite;
  125. ------------------------------------------------------------------------------------------
  126. function import_font (file_path : in string; scale, space : in integer) return font is
  127. this : font;
  128. begin
  129. font_array (font_count) := ray.load_font (c_string (file_path));
  130. --
  131. font_count := font_count + 1;
  132. this.index := font_count - 1;
  133. this.scale := scale;
  134. this.space := space;
  135. --
  136. return this;
  137. end import_font;
  138. ------------------------------------------------------------------------------------------
  139. function import_song (file_path : in string) return song is
  140. this : song;
  141. begin
  142. sound_array (sound_count) := ray.load_sound (c_string (file_path));
  143. --
  144. sound_count := sound_count + 1;
  145. this.index := sound_count - 1;
  146. --
  147. return this;
  148. end import_song;
  149. ------------------------------------------------------------------------------------------
  150. procedure draw (data : in sprite;
  151. x : in integer := 0;
  152. y : in integer := 0;
  153. u : in integer := 0;
  154. v : in integer := 0;
  155. width : in integer := 0;
  156. height : in integer := 0;
  157. state : in integer := 0;
  158. factor : in integer := zoom;
  159. tint : in ray.colour := (others => 255)) is
  160. new_width : constant float := float ((if width = 0 then data.width else width));
  161. new_height : constant float := float ((if height = 0 then data.height else height));
  162. begin
  163. ray.draw_texture (data => texture_array (data.index),
  164. uv => (float (if u = 0 then (animation_time mod data.frames) * data.width else u), float (v), new_width, new_height),
  165. view => (float (x), float (y), new_width * float (factor), new_height * float (factor)),
  166. tint => tint);
  167. end draw;
  168. ------------------------------------------------------------------------------------------
  169. procedure write (text : in string := "";
  170. x : in integer := 0;
  171. y : in integer := 0;
  172. data : in font) is
  173. begin
  174. ray.draw_text (data => font_array (data.index),
  175. text => c_string (text),
  176. view => (float ((icon - data.scale) / 2 + x), float ((icon - data.scale) / 2 + y)),
  177. scale => float (data.scale),
  178. space => float (data.space));
  179. end write;
  180. ------------------------------------------------------------------------------------------
  181. procedure play (index : in integer) is begin ray.play_sound (sound_array (index)); end play;
  182. procedure stop (index : in integer) is begin ray.stop_sound (sound_array (index)); end stop;
  183. ------------------------------------------------------------------------------------------
  184. procedure overlay is
  185. begin
  186. ray.draw_rectangle (0, 0, window_width, window_height, (0, 0, 0, 127));
  187. end overlay;
  188. ------------------------------------------------------------------------------------------
  189. procedure block_queue (data : in block) is
  190. begin
  191. if block_count = block_limit - 1 then
  192. return;
  193. end if;
  194. --
  195. block_array (block_count) := data;
  196. --
  197. increment (block_count);
  198. end block_queue;
  199. ------------------------------------------------------------------------------------------
  200. function read_text_box return string is
  201. begin
  202. return to_string (text_box.data);
  203. end read_text_box;
  204. ------------------------------------------------------------------------------------------
  205. procedure write_text_box (text : in string) is
  206. begin
  207. text_box.data := to_unbounded_string (text);
  208. end write_text_box;
  209. ------------------------------------------------------------------------------------------
  210. procedure increment (value : in out integer) is begin value := value + 1; end increment;
  211. procedure decrement (value : in out integer) is begin value := value - 1; end decrement;
  212. ------------------------------------------------------------------------------------------
  213. procedure idle is begin null; end idle;
  214. procedure move_camera_up is begin core.camera.y := core.camera.y - 1; end move_camera_up;
  215. procedure move_camera_down is begin core.camera.y := core.camera.y + 1; end move_camera_down;
  216. procedure move_camera_left is begin core.camera.x := core.camera.x - 1; end move_camera_left;
  217. procedure move_camera_right is begin core.camera.x := core.camera.x + 1; end move_camera_right;
  218. ------------------------------------------------------------------------------------------
  219. procedure initialize is
  220. begin
  221. echo (comment, "Initializing core components...");
  222. --
  223. engine_active := true;
  224. texture_array := new texture_data_array (0 .. 1600);
  225. sound_array := new sound_data_array (0 .. 4);
  226. font_array := new font_data_array (0 .. 8);
  227. --
  228. echo (comment, "-- Setting trace log level to none (ignoring all default Raylib logs).");
  229. ray.set_trace_log_level (ray.log_none);
  230. --
  231. ray.set_window_flags (ray.flag_window_resizable);
  232. --
  233. echo (comment, "-- Initializing Raylib window data...");
  234. echo (comment, "-- -- Window title : Chads of Might & Magic");
  235. echo (comment, "-- -- Window width : 1800");
  236. echo (comment, "-- -- Window height : 900");
  237. ray.open_window (1800, 900, "Chads of Might & Magic");
  238. --
  239. echo (comment, "-- Initializing Raylib audio device data...");
  240. ray.open_audio_device;
  241. --
  242. ray.randomization (19970725);
  243. ray.set_target_fps (60);
  244. --
  245. echo (success, "Initialized core components.");
  246. end initialize;
  247. ------------------------------------------------------------------------------------------
  248. procedure deinitialize is
  249. begin
  250. echo (comment, "Deinitializing core components...");
  251. --
  252. engine_active := false;
  253. --
  254. echo (comment, "-- -- Unloading Raylib" & texture_count'image & " textures.");
  255. echo (comment, "-- -- Unloading Raylib" & sound_count'image & " sounds.");
  256. echo (comment, "-- -- Unloading Raylib" & font_count'image & " fonts.");
  257. --
  258. for index in 0 .. texture_count - 1 loop ray.unload_texture (texture_array (index)); end loop;
  259. for index in 0 .. sound_count - 1 loop ray.unload_sound (sound_array (index)); end loop;
  260. for index in 0 .. font_count - 1 loop ray.unload_font (font_array (index)); end loop;
  261. --
  262. echo (comment, "-- Deinitializing Raylib audio device data...");
  263. ray.close_audio_device;
  264. --
  265. echo (comment, "-- Deinitializing Raylib window data...");
  266. ray.close_window;
  267. --
  268. echo (success, "Deinitialized core components.");
  269. end deinitialize;
  270. ------------------------------------------------------------------------------------------
  271. procedure synchronize is
  272. signal : integer := signal_code'pos (signal_none);
  273. begin
  274. global_time := global_time + 1;
  275. global_time := global_time mod (gameplay_framerate * animation_framerate);
  276. gameplay_time := global_time mod (gameplay_framerate);
  277. animation_time := global_time / (gameplay_framerate / animation_framerate);
  278. framerate := integer (ray.get_fps);
  279. signal := ray.get_key_pressed;
  280. cursor.x := ray.get_mouse_x;
  281. cursor.y := ray.get_mouse_y;
  282. --
  283. ray.end_drawing;
  284. --
  285. if ray.exit_key_is_pressed then
  286. engine_active := false;
  287. end if;
  288. --
  289. if ray.mouse_button_is_pressed (ray.mouse_button_left) then cursor_mode := 1; end if;
  290. if ray.mouse_button_is_pressed (ray.mouse_button_right) then cursor_mode := 2; end if;
  291. if ray.mouse_button_is_pressed (ray.mouse_button_middle) then cursor_mode := 3; end if;
  292. if ray.mouse_button_is_released (ray.mouse_button_left) then cursor_mode := 0; end if;
  293. if ray.mouse_button_is_released (ray.mouse_button_right) then cursor_mode := 0; end if;
  294. if ray.mouse_button_is_released (ray.mouse_button_middle) then cursor_mode := 0; end if;
  295. --
  296. case signal is
  297. when 48 .. 57 => signal_mode := signal_code'val (signal - 48 + signal_code'pos (signal_0));
  298. when 65 .. 90 => signal_mode := signal_code'val (signal - 65 + signal_code'pos (signal_a));
  299. when 320 .. 329 => signal_mode := signal_code'val (signal - 320 + signal_code'pos (signal_kp_0));
  300. --
  301. when 0 => signal_mode := signal_none;
  302. when 32 => signal_mode := signal_space;
  303. when 96 => signal_mode := signal_grave;
  304. when 340 => signal_mode := signal_left_shift;
  305. when 341 => signal_mode := signal_left_control;
  306. when 333 => signal_mode := signal_kp_subtract;
  307. when 334 => signal_mode := signal_kp_add;
  308. when 256 => signal_mode := signal_escape;
  309. when 257 => signal_mode := signal_enter;
  310. when 258 => signal_mode := signal_tab;
  311. when 259 => signal_mode := signal_backspace;
  312. when 262 => signal_mode := signal_right;
  313. when 263 => signal_mode := signal_left;
  314. when 264 => signal_mode := signal_down;
  315. when 265 => signal_mode := signal_up;
  316. when others => signal_mode := signal_none;
  317. end case;
  318. --
  319. --~for index in reverse 0 .. block_count - 1 loop
  320. --~if core.cursor.x > block_array (index).x and core.cursor.x < block_array (index).width
  321. --~and core.cursor.y > block_array (index).y and core.cursor.y < block_array (index).height
  322. --~and core.cursor_mode = block_array (index).mode then
  323. --~block_array (index).action.all;
  324. --~core.cursor_mode := 0;
  325. --~exit;
  326. --~end if;
  327. --~end loop;
  328. --
  329. block_count := 0;
  330. --
  331. ray.begin_drawing;
  332. --
  333. ray.clear_background ((0, 0, 0, 255));
  334. end synchronize;
  335. ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
  336. end core;