xhads/source/core.adb

575 lines
27 KiB
Ada

with core;
use core;
package body core is
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
type colour is range 0 .. 2 ** 32 - 1;
-- Quick fix...
type rectangle is record x, y, width, height : integer; end record;
-- Fucking abomination...
type texture_data is record id : natural; width, height, mipmaps, format : integer; end record;
type sound_data is record buffer, processor : integer; sampleRate, sampleSize, channels, frameCount : natural; end record;
type font_data is record baseSize, glyphCount, glyphPadding : integer; id : texture_data; recs, glyphs : integer; end record;
--
procedure initialize_video (width, height : in integer; title : in string) with import => true, convention => c, external_name => "InitWindow";
procedure initialize_audio with import => true, convention => c, external_name => "InitAudioDevice";
procedure deinitialize_video with import => true, convention => c, external_name => "CloseWindow";
procedure deinitialize_audio with import => true, convention => c, external_name => "CloseAudioDevice";
procedure initialize_frame with import => true, convention => c, external_name => "BeginDrawing";
procedure deinitialize_frame with import => true, convention => c, external_name => "EndDrawing";
--
procedure error_callback (callback : in integer) with import => true, convention => c, external_name => "SetTraceLogCallback";
procedure clear_frame (colour : in integer) with import => true, convention => c, external_name => "ClearBackground";
procedure limit_framerate (framerate : in integer) with import => true, convention => c, external_name => "SetTargetFPS";
function queue_framerate return float with import => true, convention => c, external_name => "GetFPS";
function close_callback return integer with import => true, convention => c, external_name => "WindowShouldClose";
--
function queue_event return integer with import => true, convention => c, external_name => "GetKeyPressed";
function mouse_pressed (button : in integer) return integer with import => true, convention => c, external_name => "IsMouseButtonPressed";
function mouse_released (button : in integer) return integer with import => true, convention => c, external_name => "IsMouseButtonReleased";
function mouse_x return integer with import => true, convention => c, external_name => "GetMouseX";
function mouse_y return integer with import => true, convention => c, external_name => "GetMouseY";
function screen_width return integer with import => true, convention => c, external_name => "GetScreenWidth";
function screen_height return integer with import => true, convention => c, external_name => "GetScreenHeight";
--
function load_texture (file_path : in string) return texture_data with import => true, convention => c, external_name => "LoadTexture";
function load_sound (file_path : in string) return sound_data with import => true, convention => c, external_name => "LoadSound";
function load_font (file_path : in string) return font_data with import => true, convention => c, external_name => "LoadFont";
--
procedure unload_texture (data : in texture_data) with import => true, convention => c, external_name => "UnloadTexture";
procedure unload_sound (data : in sound_data) with import => true, convention => c, external_name => "UnloadSound";
procedure unload_font (data : in font_data) with import => true, convention => c, external_name => "UnloadFont";
--
procedure play_sound (data : in sound_data) with import => true, convention => c, external_name => "PlaySound";
procedure stop_sound (data : in sound_data) with import => true, convention => c, external_name => "StopSound";
-- What the fuck...
procedure draw_texture (data : in texture_data; s, d : in rectangle; o : in vector; rotation : in float; tint : in colour) with import => true, convention => c, external_name => "DrawTexturePro";
procedure draw_string (data : in font_data; text : in string; p, o : in vector; r, t, s : in float; tint : in colour) with import => true, convention => c, external_name => "DrawTextPro";
procedure draw_vector (x1, y1, x2, y2 : in integer; tint : in colour) with import => true, convention => c, external_name => "DrawLine";
-- Please...
function get_random_value (minimum, maximum : in integer) return integer with import => true, convention => c, external_name => "GetRandomValue";
texture_count : integer := 0;
sound_count : integer := 0;
font_count : integer := 1;
type texture_data_array is array (natural range <>) of texture_data;
type sound_data_array is array (natural range <>) of sound_data;
type font_data_array is array (natural range <>) of font_data;
texture_array : access texture_data_array;
sound_array : access sound_data_array;
font_array : access font_data_array;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
procedure terminal (colour : in terminal_colour := white; effect : in terminal_effect := normal) is
format : string := character'val (27) & "[" & character'val (terminal_effect'pos (effect) + 48) & ";3" & character'val (terminal_colour'pos (colour) + 48) & "m";
begin
put (format);
end terminal;
------------------------------------------------------------------------------------------
procedure echo (status : in echo_status; message : in string) is
begin
put ("[");
--
case status is
when failure => terminal (red, bold); put ("Failure"); terminal;
when warning => terminal (yellow, bold); put ("Warning"); terminal;
when success => terminal (green, bold); put ("Success"); terminal;
when comment => terminal (grey, bold); put ("Comment"); terminal;
end case;
--
put_line ("] " & message);
--
if status = failure then
dash;
echo (comment, "Immediately terminating the program, no memory management clean-up.");
dash;
end if;
end echo;
------------------------------------------------------------------------------------------
procedure dash is
begin
terminal (grey, bold);
put ("------------------------------------------------------------------------------------------");
put ("------------------------------------------------------------------------------------------");
terminal;
new_line;
end dash;
------------------------------------------------------------------------------------------
procedure semi_dash is
begin
terminal (grey, bold);
put (" ");
put ("------------------------------------------------------------------------------------------");
terminal;
new_line;
end semi_dash;
------------------------------------------------------------------------------------------
function flip_coin return integer is
begin
return (random_integer (0, 1));
end flip_coin;
------------------------------------------------------------------------------------------
function roll_dice return integer is
begin
return (random_integer (1, 6));
end roll_dice;
------------------------------------------------------------------------------------------
function by_chance (chance : in integer) return integer is
begin
return (random_integer (0, 100) mod chance);
end by_chance;
------------------------------------------------------------------------------------------
function c_string (ada_string : string) return string is
begin
return (ada_string & character'val (0));
end c_string;
------------------------------------------------------------------------------------------
function random_integer (minimum, maximum : in integer) return integer is
begin
return get_random_value (minimum, maximum);
end random_integer;
------------------------------------------------------------------------------------------
function clip (value, minimum, maximum : in integer) return integer is
begin
if value < minimum then return minimum; end if;
if value > maximum then return maximum; end if;
return value;
end clip;
------------------------------------------------------------------------------------------
function load_sprite (file_path : in string; frames, states : in integer) return sprite is
this : sprite;
begin
this.index := import_texture (c_string (file_path));
this.width := texture_array (this.index).width / states;
this.height := texture_array (this.index).height / frames;
this.frames := frames;
this.states := states;
--
return this;
end load_sprite;
------------------------------------------------------------------------------------------
function load_font (file_path : in string; size, pad : in integer) return font is
this : font;
begin
this.index := import_font (c_string (file_path));
this.size := size;
this.pad := pad;
--
return this;
end load_font;
------------------------------------------------------------------------------------------
procedure crop (data : in sprite; x, y, u, v, width, height : in integer) is
begin
render_sprite (data.index, x, y, u, v, width, height);
end crop;
------------------------------------------------------------------------------------------
procedure view (data : in sprite; x, y, u, v, width, height : in integer) is
--~crop_u, crop_v, crop_width, crop_height : integer;
begin
if x > u + width
or y > v + height
or x < u - data.width
or y < v - data.height then
return;
end if;
--
--~crop_width := data.width - (if x + data.width > u + width then (x + data.width) mod (u + width) else 0);
--~crop_height := data.height - (if y + data.height > v + height then (y + data.height) mod (v + height) else 0);
--
--~crop_u := (if x < u then data.width - u mod (x + data.width) else 0);
--~crop_v := (if y < v then data.height - v mod (y + data.height) else 0);
--~crop_u := (if x < u and x < u - data.width then data.width - (x + data.width) mod u else 0);
--~crop_v := (if y < v and y < v - data.height then data.height - (y + data.height) mod v else 0);
--~crop_u := data.width - (if x < u then (x + data.width) mod u else 0);
--~crop_v := data.height - (if y < v then (y + data.height) mod v else 0);
--~crop_u := data.width - (if x < u then u mod x else 0);
--~crop_v := data.height - (if y < v then v mod y else 0);
--
--~render_sprite (data.index, x, y, crop_u, crop_v, crop_width, crop_height);
render_sprite (data.index, x, y, 0, 0, data.width, data.height);
end view;
------------------------------------------------------------------------------------------
procedure draw (data : in sprite; x, y : in integer) is
begin
render_sprite (data.index, x, y, 0, 0, data.width, data.height);
end draw;
------------------------------------------------------------------------------------------
procedure move (data : in sprite; x, y, frame, state : in integer) is
begin
render_sprite (data.index, x, y, state * data.width, (animation_time mod frame) * data.height, data.width, data.height);
end move;
------------------------------------------------------------------------------------------
procedure line (origin, offset : in vector) is
begin
render_vector (origin.x, origin.y, origin.x + offset.x, origin.y + offset.y);
end line;
------------------------------------------------------------------------------------------
procedure write (text : in string; x, y : in integer; data : in font; colour : in integer := 16#FFFFFF#) is
begin
render_string (c_string (text), x, y, colour, data.index, data.size, data.pad);
end write;
------------------------------------------------------------------------------------------
procedure debug (text : in string) is
begin
put_line ("> " & text);
end debug;
------------------------------------------------------------------------------------------
procedure hexagonal_grid (x, y, width, height : in integer; fill : in boolean) is
crop_width : constant integer := width mod hexagon_grid_sprite.width;
crop_height : constant integer := height mod hexagon_grid_sprite.height;
use_sprite : constant sprite := (if fill then hexagon_fill_sprite else hexagon_grid_sprite);
begin
for move_y in 0 .. height / hexagon_grid_sprite.height - 1
loop
for move_x in 0 .. width / hexagon_grid_sprite.width - 1
loop
draw (use_sprite, x + move_x * hexagon_grid_sprite.width, y + move_y * hexagon_grid_sprite.height);
end loop;
--
crop (use_sprite, x + width - crop_width, y + move_y * hexagon_grid_sprite.height, 0, 0, crop_width, hexagon_grid_sprite.height);
end loop;
--
for move_x in 0 .. width / hexagon_grid_sprite.width - 1
loop
crop (use_sprite, x + move_x * hexagon_grid_sprite.width, y + height - crop_height, 0, 0, hexagon_grid_sprite.width, crop_height);
end loop;
--
crop (use_sprite, x + width - crop_width, y + height - crop_height, 0, 0, crop_width, crop_height);
end hexagonal_grid;
------------------------------------------------------------------------------------------
function lowercase (text : in string) return string is
result : string (1 .. text'length);
begin
for index in text'range
loop
if text (index) in 'A' .. 'Z' then
result (index) := character'val (character'pos (text (index)) + 32);
else
result (index) := text (index);
end if;
end loop;
--
return result;
end lowercase;
------------------------------------------------------------------------------------------
function uppercase (text : in string) return string is
result : string (1 .. text'length);
begin
for index in text'range
loop
if text (index) in 'a' .. 'z' then
result (index) := character'val (character'pos (text (index)) - 32);
else
result (index) := text (index);
end if;
end loop;
--
return result;
end uppercase;
------------------------------------------------------------------------------------------
procedure draw_central_grid (x, y, width, height : in integer) is
begin
render_vector (width / 2 + x, y, width / 2 + x, height + y);
render_vector ( x, height / 2 + y, width + x, height / 2 + y);
end draw_central_grid;
------------------------------------------------------------------------------------------
procedure draw_squared_grid (x, y, width, height : in integer) is
offset : constant vector := (((width - base) / 2) mod base, ((height - base) / 2) mod base);
repeat : constant vector := (2 * (((width - base) / 2) / base) + 1, 2 * (((height - base) / 2) / base) + 1);
begin
for next in 0 .. repeat.y
loop
line ((x, y + offset.y + next * base), (width, 0));
end loop;
--
if repeat.y mod 4 = 1 then
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + base / 2 + next * base, y ), (0, offset.y)); end loop;
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + base / 2 + next * base, y + height - offset.y), (0, offset.y)); end loop;
--
for step in 0 .. repeat.y / 2 - 1 loop
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + base / 2 + next * base, y + base + offset.y + 2 * step * base), (0, base)); end loop;
end loop;
for step in 0 .. repeat.y / 2 loop
for next in 0 .. repeat.x loop line ((x + offset.x + next * base, y + offset.y + 2 * step * base), (0, base)); end loop;
end loop;
else
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + next * base, y ), (0, offset.y)); end loop;
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + next * base, y + height - offset.y), (0, offset.y)); end loop;
--
for step in 0 .. repeat.y / 2 - 1 loop
for next in 0 .. repeat.x loop line ((x + offset.x + next * base, y + base + offset.y + 2 * step * base), (0, base)); end loop;
end loop;
for step in 0 .. repeat.y / 2 loop
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + base / 2 + next * base, y + offset.y + 2 * step * base), (0, base)); end loop;
end loop;
end if;
end draw_squared_grid;
------------------------------------------------------------------------------------------
procedure draw_hexagon_grid (x, y, width, height : in integer) is
offset : constant vector := (((width - base) / 2) mod base, ((height - base) / 2) mod base);
repeat : constant vector := (2 * (((width - base) / 2) / base) + 1, 2 * (((height - base) / 2) / base) + 1);
begin
for step in 0 .. repeat.y
loop
if step mod 2 = 1 then
for next in 0 .. repeat.x - 1
loop
line ((x + offset.x + base / 2 + next * base, y + offset.y + step * base + base / 4), (-base / 2, -base / 2));
line ((x + offset.x + base / 2 + next * base, y + offset.y + step * base + base / 4), ( base / 2, -base / 2));
end loop;
else
for next in 0 .. repeat.x - 1
loop
line ((x + offset.x + base / 2 + next * base, y + offset.y + step * base - base / 4), (-base / 2, base / 2));
line ((x + offset.x + base / 2 + next * base, y + offset.y + step * base - base / 4), ( base / 2, base / 2));
end loop;
end if;
end loop;
--
if repeat.y mod 4 = 1 then
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + base / 2 + next * base, y ), (0, offset.y - base / 4)); end loop;
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + base / 2 + next * base, y + base / 4 + height - offset.y), (0, offset.y - base / 4)); end loop;
--
for step in 0 .. repeat.y / 2 - 1 loop
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + base / 2 + next * base, y + 5 * base / 4 + offset.y + 2 * step * base), (0, base / 2)); end loop;
end loop;
for step in 0 .. repeat.y / 2 loop
for next in 0 .. repeat.x loop line ((x + offset.x + next * base, y + base / 4 + offset.y + 2 * step * base), (0, base / 2)); end loop;
end loop;
else
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + next * base, y ), (0, offset.y)); end loop;
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + next * base, y + height - offset.y), (0, offset.y)); end loop;
--
for step in 0 .. repeat.y / 2 - 1 loop
for next in 0 .. repeat.x loop line ((x + offset.x + next * base, y + 5 * base / 4 + offset.y + 2 * step * base), (0, base / 2)); end loop;
end loop;
for step in 0 .. repeat.y / 2 loop
for next in 0 .. repeat.x - 1 loop line ((x + offset.x + base / 2 + next * base, y + base / 4 + offset.y + 2 * step * base), (0, base / 2)); end loop;
end loop;
end if;
end draw_hexagon_grid;
------------------------------------------------------------------------------------------
function read_text_box return string is
begin
return to_string (text_box.data);
end read_text_box;
------------------------------------------------------------------------------------------
procedure write_text_box (text : in string) is
begin
text_box.data := to_unbounded_string (text);
end write_text_box;
------------------------------------------------------------------------------------------
procedure render_sprite (sprite, x, y, u, v, width, height : in integer) is
begin
draw_texture (texture_array (sprite), (u, v, width, height), (x, y, abs width, abs height), (0, 0), 0.0, 16#FFFFFFFF#);
end render_sprite;
------------------------------------------------------------------------------------------
procedure render_string (text : in string; x, y, colour, index, size, pad : in integer) is
begin
draw_string (font_array (index), text, ((32 - size) / 2 + x, (32 - size) / 2 + y), (0, 0), 0.0, float (size), float (pad), 16#FFFFFFFF#);
end render_string;
------------------------------------------------------------------------------------------
procedure render_vector (x1, y1, x2, y2 : in integer) is
begin
draw_vector (x1, y1, x2, y2, 16#FF#);
end render_vector;
function window_width return integer is begin return screen_width; end window_width;
function window_height return integer is begin return screen_height; end window_height;
------------------------------------------------------------------------------------------
procedure initialize is
begin
engine_active := true;
texture_array := new texture_data_array (0 .. 1600);
sound_array := new sound_data_array (0 .. 2);
font_array := new font_data_array (1 .. 4);
--
error_callback (0);
initialize_video (1800, 900, "Chads of Might & Magic");
initialize_audio;
--
limit_framerate (60);
--
hexagon_grid_sprite := load_sprite ("./sprite/ui/hexagon_grid_tile.png", 1, 1);
hexagon_fill_sprite := load_sprite ("./sprite/ui/hexagon_fill_tile.png", 1, 1);
end initialize;
------------------------------------------------------------------------------------------
procedure deinitialize is
begin
engine_active := false;
--
for index in 0 .. texture_count - 1 loop unload_texture (texture_array (index)); end loop;
for index in 0 .. sound_count - 1 loop unload_sound (sound_array (index)); end loop;
for index in 1 .. font_count - 1 loop unload_font (font_array (index)); end loop;
--
deinitialize_video;
deinitialize_audio;
end deinitialize;
------------------------------------------------------------------------------------------
procedure synchronize is
signal : integer := signal_code'pos (signal_none);
begin
global_time := global_time + 1;
global_time := global_time mod (gameplay_framerate * animation_framerate);
gameplay_time := global_time mod (gameplay_framerate);
animation_time := global_time / (gameplay_framerate / animation_framerate);
framerate := integer (queue_framerate);
signal := queue_event;
cursor.x := mouse_x;
cursor.y := mouse_y;
--
deinitialize_frame;
--
if close_callback = 1 then
engine_active := false;
end if;
--
if mouse_pressed (0) = 1 then cursor_mode := 1; end if;
if mouse_pressed (1) = 1 then cursor_mode := 2; end if;
if mouse_pressed (2) = 1 then cursor_mode := 3; end if;
if mouse_released (0) = 1 then cursor_mode := 0; end if;
if mouse_released (1) = 1 then cursor_mode := 0; end if;
if mouse_released (2) = 1 then cursor_mode := 0; end if;
--
case signal is
when 48 .. 57 => signal_mode := signal - 48 + signal_code'pos (signal_0);
when 65 .. 90 => signal_mode := signal - 65 + signal_code'pos (signal_a);
when 320 .. 329 => signal_mode := signal - 320 + signal_code'pos (signal_kp_0);
--
when 0 => signal_mode := signal_code'pos (signal_none);
when 32 => signal_mode := signal_code'pos (signal_space);
when 96 => signal_mode := signal_code'pos (signal_grave);
when 340 => signal_mode := signal_code'pos (signal_left_shift);
when 341 => signal_mode := signal_code'pos (signal_left_control);
when 333 => signal_mode := signal_code'pos (signal_kp_subtract);
when 334 => signal_mode := signal_code'pos (signal_kp_add);
when 256 => signal_mode := signal_code'pos (signal_escape);
when 257 => signal_mode := signal_code'pos (signal_enter);
when 258 => signal_mode := signal_code'pos (signal_tab);
when 259 => signal_mode := signal_code'pos (signal_backspace);
when 262 => signal_mode := signal_code'pos (signal_right);
when 263 => signal_mode := signal_code'pos (signal_left);
when 264 => signal_mode := signal_code'pos (signal_down);
when 265 => signal_mode := signal_code'pos (signal_up);
when others => signal_mode := signal_code'pos (signal_none);
end case;
--
initialize_frame;
--
clear_frame (16#506070FF#);
end synchronize;
------------------------------------------------------------------------------------------
function import_texture (file_path : in string) return integer is
begin
echo (comment, "[" & integer'image (texture_count) & " ] Importing texture: " & file_path);
--
texture_count := texture_count + 1;
--~texture_array := realloc (texture_array, (unsigned long int) texture_count * sizeof (* texture_array));
texture_array (texture_count - 1) := load_texture (file_path);
--
return texture_count - 1;
end import_texture;
------------------------------------------------------------------------------------------
function import_sound (file_path : in string) return integer is
begin
sound_count := sound_count + 1;
--~sound_array := realloc (sound_array, (unsigned long int) sound_count * sizeof (* sound_array));
sound_array (sound_count - 1) := load_sound (file_path);
--
return sound_count - 1;
end import_sound;
------------------------------------------------------------------------------------------
function import_font (file_path : in string) return integer is
begin
font_count := font_count + 1;
--~font_array := realloc (font_array, (unsigned long int) font_count * sizeof (* font_array));
font_array (font_count - 1) := load_font (file_path);
--
return font_count - 1;
end import_font;
------------------------------------------------------------------------------------------
procedure play_song (index : in integer) is begin play_sound (sound_array (index)); end play_song;
procedure stop_song (index : in integer) is begin stop_sound (sound_array (index)); end stop_song;
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
end core;