summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore2
-rw-r--r--CHANGELOG.md19
-rw-r--r--CHANGELOG.txt34
-rw-r--r--LICENSE.txt (renamed from LICENSE)40
-rw-r--r--assets/fonts/Vollkorn/OFL.txt93
-rw-r--r--assets/fonts/Vollkorn/static/Vollkorn-Regular.ttfbin0 -> 345232 bytes
-rw-r--r--assets/map-new.pngbin0 -> 1467 bytes
-rw-r--r--assets/sounds/CREDITS.txt9
-rw-r--r--assets/sounds/popup-show.wavbin0 -> 33122 bytes
-rwxr-xr-xbuild-linux.sh4
-rw-r--r--eepers.adb391
-rw-r--r--raylib.ads43
12 files changed, 492 insertions, 143 deletions
diff --git a/.gitignore b/.gitignore
index a21feec..be5a6ae 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,6 +1,6 @@
*.ali
*.o
-eepers
+eepers-linux
eepers.exe
test
test.exe
diff --git a/CHANGELOG.md b/CHANGELOG.md
deleted file mode 100644
index d5cff39..0000000
--- a/CHANGELOG.md
+++ /dev/null
@@ -1,19 +0,0 @@
-# Eepers v1.3
-
-- @Eropi4 - MacOS build - https://github.com/tsoding/eepers/pull/13
-- @cornishon - Sprint with Right Shift - https://github.com/tsoding/eepers/pull/18
-- Port the Source Code to Ada 2012 making it accessible to more setups. We were not using anything important from Ada 2022 anyway.
-- ...
-
-# Eepers v1.2
-
-- @LainLayer - Vary the turn duration based on how rapidly the player presses the keys - https://github.com/tsoding/eepers/pull/15
-
-# Eepers v1.1
-
-- @rexim - Fixed skipping keys when they are pressed in a rapid succession - https://github.com/tsoding/eepers/issues/4
-- @rexim - Fixed crash if you accidentally place several items into a single cell - https://github.com/tsoding/eepers/issues/8
-
-# First Release of Eepers v1.0
-
-This is a result of 20 days of Game Programming in Ada "Challenge". I don't know Ada, I'm not a Game Developer. So lower your expectations. But I hope this game will still provide some fun for you. Because it did for me. :)
diff --git a/CHANGELOG.txt b/CHANGELOG.txt
new file mode 100644
index 0000000..39acd8c
--- /dev/null
+++ b/CHANGELOG.txt
@@ -0,0 +1,34 @@
+# Eepers v1.4
+
+- @rexim - Added items that extend the amount of bombs you can carry
+- @rexim - Do not restart on Any Key Press. Restart automatically after 2 seconds.
+- @ProgKea - Fix the Boss killing the Player on the same turn as it dies - https://github.com/tsoding/eepers/pull/24
+- @slukovic - Camera adjusts its zoom on bigger screen - https://github.com/tsoding/eepers/pull/27
+- ...
+
+# Eepers v1.3
+
+- @rexim - Implemented a Basic Tutorial that explains how to play the Game.
+- @cornishon - Sprint with Right Shift - https://github.com/tsoding/eepers/pull/18
+- @Eropi4 - MacOS build - https://github.com/tsoding/eepers/pull/13
+
+> Since I don't have a MacOS setup I'm not able to provide the MacOS binaries.
+> So if you want to play on MacOS you have to build the Game from the Source Code
+> yourself, sorry.
+> - @rexim
+
+- @rexim - Increased Path Finding Limit. Now Bosses give up on chasing the Player if the distance is over 10 turns instead of just 4. - https://github.com/tsoding/eepers/issues/16
+- @rexim - Custom font for "You Died!" sign (Vollkorn)
+
+# Eepers v1.2
+
+- @LainLayer - Vary the turn duration based on how rapidly the player presses the keys - https://github.com/tsoding/eepers/pull/15
+
+# Eepers v1.1
+
+- @rexim - Fixed skipping keys when they are pressed in a rapid succession - https://github.com/tsoding/eepers/issues/4
+- @rexim - Fixed crash if you accidentally place several items into a single cell - https://github.com/tsoding/eepers/issues/8
+
+# First Release of Eepers v1.0
+
+This is a result of 20 days of Game Programming in Ada "Challenge". I don't know Ada, I'm not a Game Developer. So lower your expectations. But I hope this game will still provide some fun for you. Because it did for me. :)
diff --git a/LICENSE b/LICENSE.txt
index 40b7de3..e329270 100644
--- a/LICENSE
+++ b/LICENSE.txt
@@ -1,20 +1,20 @@
-Copyright 2024 Alexey Kutepov <reximkut@gmail.com>
-
-Permission is hereby granted, free of charge, to any person obtaining
-a copy of this software and associated documentation files (the
-"Software"), to deal in the Software without restriction, including
-without limitation the rights to use, copy, modify, merge, publish,
-distribute, sublicense, and/or sell copies of the Software, and to
-permit persons to whom the Software is furnished to do so, subject to
-the following conditions:
-
-The above copyright notice and this permission notice shall be
-included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+Copyright 2024 Alexey Kutepov <reximkut@gmail.com> and Eeper Contributors
+
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of this software and associated documentation files (the
+"Software"), to deal in the Software without restriction, including
+without limitation the rights to use, copy, modify, merge, publish,
+distribute, sublicense, and/or sell copies of the Software, and to
+permit persons to whom the Software is furnished to do so, subject to
+the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
+LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
+OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
+WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
diff --git a/assets/fonts/Vollkorn/OFL.txt b/assets/fonts/Vollkorn/OFL.txt
new file mode 100644
index 0000000..f72bad1
--- /dev/null
+++ b/assets/fonts/Vollkorn/OFL.txt
@@ -0,0 +1,93 @@
+Copyright 2017 The Vollkorn Project Authors (https://github.com/FAlthausen/Vollkorn-Typeface)
+
+This Font Software is licensed under the SIL Open Font License, Version 1.1.
+This license is copied below, and is also available with a FAQ at:
+https://openfontlicense.org
+
+
+-----------------------------------------------------------
+SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
+-----------------------------------------------------------
+
+PREAMBLE
+The goals of the Open Font License (OFL) are to stimulate worldwide
+development of collaborative font projects, to support the font creation
+efforts of academic and linguistic communities, and to provide a free and
+open framework in which fonts may be shared and improved in partnership
+with others.
+
+The OFL allows the licensed fonts to be used, studied, modified and
+redistributed freely as long as they are not sold by themselves. The
+fonts, including any derivative works, can be bundled, embedded,
+redistributed and/or sold with any software provided that any reserved
+names are not used by derivative works. The fonts and derivatives,
+however, cannot be released under any other type of license. The
+requirement for fonts to remain under this license does not apply
+to any document created using the fonts or their derivatives.
+
+DEFINITIONS
+"Font Software" refers to the set of files released by the Copyright
+Holder(s) under this license and clearly marked as such. This may
+include source files, build scripts and documentation.
+
+"Reserved Font Name" refers to any names specified as such after the
+copyright statement(s).
+
+"Original Version" refers to the collection of Font Software components as
+distributed by the Copyright Holder(s).
+
+"Modified Version" refers to any derivative made by adding to, deleting,
+or substituting -- in part or in whole -- any of the components of the
+Original Version, by changing formats or by porting the Font Software to a
+new environment.
+
+"Author" refers to any designer, engineer, programmer, technical
+writer or other person who contributed to the Font Software.
+
+PERMISSION & CONDITIONS
+Permission is hereby granted, free of charge, to any person obtaining
+a copy of the Font Software, to use, study, copy, merge, embed, modify,
+redistribute, and sell modified and unmodified copies of the Font
+Software, subject to the following conditions:
+
+1) Neither the Font Software nor any of its individual components,
+in Original or Modified Versions, may be sold by itself.
+
+2) Original or Modified Versions of the Font Software may be bundled,
+redistributed and/or sold with any software, provided that each copy
+contains the above copyright notice and this license. These can be
+included either as stand-alone text files, human-readable headers or
+in the appropriate machine-readable metadata fields within text or
+binary files as long as those fields can be easily viewed by the user.
+
+3) No Modified Version of the Font Software may use the Reserved Font
+Name(s) unless explicit written permission is granted by the corresponding
+Copyright Holder. This restriction only applies to the primary font name as
+presented to the users.
+
+4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
+Software shall not be used to promote, endorse or advertise any
+Modified Version, except to acknowledge the contribution(s) of the
+Copyright Holder(s) and the Author(s) or with their explicit written
+permission.
+
+5) The Font Software, modified or unmodified, in part or in whole,
+must be distributed entirely under this license, and must not be
+distributed under any other license. The requirement for fonts to
+remain under this license does not apply to any document created
+using the Font Software.
+
+TERMINATION
+This license becomes null and void if any of the above conditions are
+not met.
+
+DISCLAIMER
+THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
+OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
+INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
+DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
+FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
+OTHER DEALINGS IN THE FONT SOFTWARE.
diff --git a/assets/fonts/Vollkorn/static/Vollkorn-Regular.ttf b/assets/fonts/Vollkorn/static/Vollkorn-Regular.ttf
new file mode 100644
index 0000000..88b0657
--- /dev/null
+++ b/assets/fonts/Vollkorn/static/Vollkorn-Regular.ttf
Binary files differ
diff --git a/assets/map-new.png b/assets/map-new.png
new file mode 100644
index 0000000..3d01c7c
--- /dev/null
+++ b/assets/map-new.png
Binary files differ
diff --git a/assets/sounds/CREDITS.txt b/assets/sounds/CREDITS.txt
new file mode 100644
index 0000000..527030c
--- /dev/null
+++ b/assets/sounds/CREDITS.txt
@@ -0,0 +1,9 @@
+Used Sounds:
+ https://opengameart.org/content/magic-sfx-sample
+ https://opengameart.org/content/beep-tone-sound-sfx
+ https://opengameart.org/content/ambient-soundtrack
+ https://opengameart.org/content/pickupplastic-sound
+ https://opengameart.org/content/picked-coin-echo
+ https://opengameart.org/content/level-up-power-up-coin-get-13-sounds
+ https://opengameart.org/content/fire-whip-hit-yo-frankie
+ https://opengameart.org/content/ui-soundpack-by-m1chiboi-bleeps-and-clicks
diff --git a/assets/sounds/popup-show.wav b/assets/sounds/popup-show.wav
new file mode 100644
index 0000000..22564e5
--- /dev/null
+++ b/assets/sounds/popup-show.wav
Binary files differ
diff --git a/build-linux.sh b/build-linux.sh
index 8d17811..12f57f5 100755
--- a/build-linux.sh
+++ b/build-linux.sh
@@ -2,8 +2,8 @@
set -xe
-gnatmake -f -O3 -Wall -Wextra -gnat2012 eepers.adb -bargs -static -largs -L./raylib/raylib-5.0_linux_amd64/lib/ -l:libraylib.a -lm -pthread
-./eepers
+gnatmake -f -O3 -Wall -Wextra -gnat2012 -o eepers-linux eepers.adb -bargs -static -largs -L./raylib/raylib-5.0_linux_amd64/lib/ -l:libraylib.a -lm -pthread
+./eepers-linux
# gnatmake -f -Wall -Wextra -gnat2022 test.adb -largs -L./raylib/raylib-5.0_linux_amd64/lib/ -l:libraylib.a -lm
# ./test
diff --git a/eepers.adb b/eepers.adb
index 3dcee82..991150f 100644
--- a/eepers.adb
+++ b/eepers.adb
@@ -33,7 +33,13 @@ procedure Eepers is
Checkpoint_Sound: Sound;
Plant_Bomb_Sound: Sound;
Guard_Step_Sound: Sound;
+ Popup_Show_Sound: Sound;
Ambient_Music: Music;
+ Tutorial_Font: Font;
+ Death_Font: Font;
+
+ Tutorial_Font_Size: constant Int := 42;
+ Death_Font_Size: constant Int := 68;
DEVELOPMENT : constant Boolean := False;
@@ -66,6 +72,26 @@ procedure Eepers is
return Color_From_HSV(H, S, V);
end;
+ procedure Inc(X: in out Integer; Offset: Integer := 1) is
+ begin
+ X := X + Offset;
+ end;
+
+ procedure Dec(X: in out Integer; Offset: Integer := 1) is
+ begin
+ X := X - Offset;
+ end;
+
+ procedure Inc(X: in out Byte; Offset: Byte := 1) is
+ begin
+ X := X + Offset;
+ end;
+
+ procedure Dec(X: in out Byte; Offset: Byte := 1) is
+ begin
+ X := X - Offset;
+ end;
+
Palette_RGB: array (Palette) of Color := (others => (A => 255, others => 0));
Palette_HSV: array (Palette) of HSV := (others => (others => 0));
@@ -91,7 +117,7 @@ procedure Eepers is
begin
Open(F, In_File, File_Name);
while not End_Of_File(F) loop
- Line_Number := Line_Number + 1;
+ Inc(Line_Number);
declare
Line: Unbounded_String := To_Unbounded_String(Get_Line(F));
@@ -142,16 +168,21 @@ procedure Eepers is
Put_Line("WARNING: could not load colors from file " & File_Name & ": " & Exception_Message(E));
end;
- BASE_TURN_DURATION_SECS : constant Float := 0.125;
- TURN_DURATION_SECS : Float := BASE_TURN_DURATION_SECS;
- GUARD_ATTACK_COOLDOWN : constant Integer := 10;
- EEPER_EXPLOSION_DAMAGE : constant Float := 0.45;
- GUARD_TURN_REGENERATION : constant Float := 0.01;
- BOMB_GENERATOR_COOLDOWN : constant Integer := 10;
- GUARD_STEPS_LIMIT : constant Integer := 4;
- GUARD_STEP_LENGTH_LIMIT : constant Integer := 100;
- EXPLOSION_LENGTH : constant Integer := 10;
- EYES_ANGULAR_VELOCITY : constant Float := 10.0;
+ BASE_TURN_DURATION_SECS : constant Float := 0.125;
+ TURN_DURATION_SECS : Float := BASE_TURN_DURATION_SECS;
+ GUARD_ATTACK_COOLDOWN : constant Integer := 10;
+ EEPER_EXPLOSION_DAMAGE : constant Float := 0.45;
+ GUARD_TURN_REGENERATION : constant Float := 0.01;
+ BOMB_GENERATOR_COOLDOWN : constant Integer := 10;
+ GUARD_STEPS_LIMIT : constant Integer := 10;
+ GUARD_STEP_LENGTH_LIMIT : constant Integer := 100;
+ EXPLOSION_LENGTH : constant Integer := 10;
+ EYES_ANGULAR_VELOCITY : constant Float := 10.0;
+ TUTORIAL_MOVE_WAIT_TIME_SECS : constant C_Float := 5.0;
+ TUTORIAL_BOMB_WAIT_TIME_SECS : constant C_Float := 4.0;
+ TUTORIAL_SPRINT_WAIT_TIME_SECS : constant C_Float := 15.0;
+ POPUP_ANIMATION_DURATION : constant C_Float := 0.1;
+ RESTART_TIMEOUT_SECS : constant Double := 2.0;
type IVector2 is record
X, Y: Integer;
@@ -209,7 +240,12 @@ procedure Eepers is
return (A.X*S, A.Y*S);
end;
- type Item_Kind is (Item_None, Item_Key, Item_Bomb_Gen, Item_Checkpoint);
+ type Item_Kind is (
+ Item_None,
+ Item_Key,
+ Item_Bomb_Refill,
+ Item_Checkpoint,
+ Item_Bomb_Slot);
type Item is record
Kind: Item_Kind := Item_None;
Position: IVector2;
@@ -267,6 +303,7 @@ procedure Eepers is
Bombs: Integer := 0;
Bomb_Slots: Integer := 1;
Dead: Boolean := False;
+ Death_Time: Double;
end record;
type Eeper_Kind is (Eeper_Guard, Eeper_Mother, Eeper_Gnome, Eeper_Father);
@@ -295,7 +332,7 @@ procedure Eepers is
type Bomb_State_Array is array (1..10) of Bomb_State;
- type Eeper_Index is range 1..15;
+ type Eeper_Index is range 1..30;
type Eeper_Array is array (Eeper_Index) of Eeper_State;
type Checkpoint_State is record
@@ -309,6 +346,75 @@ procedure Eepers is
Bombs: Bomb_State_Array;
end record;
+ type Direction is (Left, Right, Up, Down);
+
+ Direction_Vector: constant array (Direction) of IVector2 := (
+ Left => (X => -1, Y => 0),
+ Right => (X => 1, Y => 0),
+ Up => (X => 0, Y => -1),
+ Down => (X => 0, Y => 1));
+
+ type Popup_State is record
+ Label: Char_Array(1..50);
+ Visible: Boolean := False;
+ Animation: C_Float := 0.0;
+ end record;
+
+ procedure Show_Popup(Popup: in out Popup_State; Text: String) is
+ Ignore: Size_t;
+ begin
+ if not Popup.Visible then
+ Play_Sound(Popup_Show_Sound);
+ end if;
+ Popup.Visible := True;
+ To_C(Text, Popup.Label, Ignore);
+ end;
+
+ procedure Hide_Popup(Popup: in out Popup_State) is
+ begin
+ Popup.Visible := False;
+ end;
+
+ procedure Draw_Popup(Popup: in out Popup_State; Start, Size: Vector2) is
+ begin
+ if Popup.Visible then
+ if Popup.Animation < 1.0 then
+ Popup.Animation := (Popup.Animation*POPUP_ANIMATION_DURATION + Get_Frame_Time)/POPUP_ANIMATION_DURATION;
+ end if;
+ else
+ if Popup.Animation > 0.0 then
+ Popup.Animation := (Popup.Animation*POPUP_ANIMATION_DURATION - Get_Frame_Time)/POPUP_ANIMATION_DURATION;
+ end if;
+ end if;
+
+ if Popup.Animation > 0.0 then
+ declare
+ Font_Size: constant C_Float := C_Float(Tutorial_Font_Size)*Popup.Animation;
+ Popup_Bottom_Margin: constant C_Float := Font_Size*0.05;
+ Label_Size: constant Vector2 := Measure_Text_Ex(Tutorial_Font, Popup.Label, Font_Size, 0.0);
+ Label_Position: constant Vector2 := Start + Size*(0.5, 0.0) - Label_Size*(0.5, 1.0) - (0.0, Popup_Bottom_Margin);
+ begin
+ Draw_Text_Ex(Tutorial_Font, Popup.Label, Label_Position + (-2.0, 2.0), Font_Size, 0.0, Palette_RGB(COLOR_WALL));
+ Draw_Text_Ex(Tutorial_Font, Popup.Label, Label_Position, Font_Size, 0.0, Palette_RGB(COLOR_PLAYER));
+ end;
+ end if;
+ end;
+
+ type Tutorial_Phase is (Tutorial_Move, Tutorial_Place_Bombs, Tutorial_Waiting_For_Sprint, Tutorial_Sprint, Tutorial_Done);
+ type Tutorial_State is record
+ Phase: Tutorial_Phase := Tutorial_Move;
+ Waiting: C_Float := 0.0;
+
+ Prev_Step_Timestamp: Double := 0.0;
+ Hurry_Count: Integer := 0;
+
+ Popup: Popup_State;
+
+ Knows_How_To_Move: Boolean := False;
+ Knows_How_To_Place_Bombs: Boolean := False;
+ Knows_How_To_Sprint: Boolean := False;
+ end record;
+
type Game_State is record
Map: Map_Access := Null;
Player: Player_State;
@@ -318,8 +424,13 @@ procedure Eepers is
Items: Item_Array;
Bombs: Bomb_State_Array;
- Camera_Position: Vector2 := (x => 0.0, y => 0.0);
+ Camera: Camera2D := (
+ offset => (x => 0.0, y => 0.0),
+ target => (x => 0.0, y => 0.0),
+ rotation => 0.0,
+ zoom => 1.0);
+ Tutorial: Tutorial_State;
Checkpoint: Checkpoint_State;
Duration_Of_Last_Turn: Double;
@@ -338,14 +449,6 @@ procedure Eepers is
return M1;
end;
- type Direction is (Left, Right, Up, Down);
-
- Direction_Vector: constant array (Direction) of IVector2 := (
- Left => (X => -1, Y => 0),
- Right => (X => 1, Y => 0),
- Up => (X => 0, Y => -1),
- Down => (X => 0, Y => 1));
-
function Inside_Of_Rect(Start, Size, Point: in IVector2) return Boolean is
begin
return Start <= Point and then Point < Start + Size;
@@ -572,25 +675,27 @@ procedure Eepers is
Level_Wall,
Level_Door,
Level_Checkpoint,
- Level_Bomb_Gen,
+ Level_Bomb_Refill,
Level_Barricade,
Level_Key,
Level_Player,
- Level_Father);
+ Level_Father,
+ Level_Bomb_Slot);
Level_Cell_Color: constant array (Level_Cell) of Color := (
- Level_None => Get_Color(16#00000000#),
- Level_Gnome => Get_Color(16#FF9600FF#),
- Level_Mother => Get_Color(16#96FF00FF#),
- Level_Guard => Get_Color(16#00FF00FF#),
- Level_Floor => Get_Color(16#FFFFFFFF#),
- Level_Wall => Get_Color(16#000000FF#),
- Level_Door => Get_Color(16#00FFFFFF#),
- Level_Checkpoint => Get_Color(16#FF00FFFF#),
- Level_Bomb_Gen => Get_Color(16#FF0000FF#),
- Level_Barricade => Get_Color(16#FF0096FF#),
- Level_Key => Get_Color(16#FFFF00FF#),
- Level_Player => Get_Color(16#0000FFFF#),
- Level_Father => Get_Color(16#265FDAFF#));
+ Level_None => Get_Color(16#00000000#),
+ Level_Gnome => Get_Color(16#FF9600FF#),
+ Level_Mother => Get_Color(16#96FF00FF#),
+ Level_Guard => Get_Color(16#00FF00FF#),
+ Level_Floor => Get_Color(16#FFFFFFFF#),
+ Level_Wall => Get_Color(16#000000FF#),
+ Level_Door => Get_Color(16#00FFFFFF#),
+ Level_Checkpoint => Get_Color(16#FF00FFFF#),
+ Level_Bomb_Refill => Get_Color(16#FF0000FF#),
+ Level_Barricade => Get_Color(16#FF0096FF#),
+ Level_Key => Get_Color(16#FFFF00FF#),
+ Level_Player => Get_Color(16#0000FFFF#),
+ Level_Father => Get_Color(16#265FDAFF#),
+ Level_Bomb_Slot => Get_Color(16#BC5353FF#));
function Cell_By_Color(Col: Color; Out_Cel: out Level_Cell) return Boolean is
begin
@@ -668,7 +773,8 @@ procedure Eepers is
Game.Map(Row, Column) := Cell_Floor;
when Level_Father =>
if Update_Camera then
- Game.Camera_Position := Screen_Size*0.5 - (To_Vector2((Column, Row))*Cell_Size + To_Vector2((7, 7))*Cell_Size*0.5);
+ Game.Camera.target := (To_Vector2((Column, Row)) + To_Vector2((7, 7))*0.5) * Cell_Size;
+ Game.Camera.offset := Screen_Size*0.5 - Cell_Size*0.5;
end if;
Spawn_Father(Game, (Column, Row));
Game.Map(Row, Column) := Cell_Floor;
@@ -678,9 +784,12 @@ procedure Eepers is
when Level_Checkpoint =>
Game.Map(Row, Column) := Cell_Floor;
Allocate_Item(Game, (Column, Row), Item_Checkpoint);
- when Level_Bomb_Gen =>
+ when Level_Bomb_Refill =>
Game.Map(Row, Column) := Cell_Floor;
- Allocate_Item(Game, (Column, Row), Item_Bomb_Gen);
+ Allocate_Item(Game, (Column, Row), Item_Bomb_Refill);
+ when Level_Bomb_Slot =>
+ Game.Map(Row, Column) := Cell_Floor;
+ Allocate_Item(Game, (Column, Row), Item_Bomb_Slot);
when Level_Barricade =>
Game.Map(Row, Column) := Cell_Barricade;
when Level_Key =>
@@ -760,13 +869,15 @@ procedure Eepers is
begin
Draw_Rectangle_V(To_Vector2(Item.Position)*Cell_Size + Cell_Size*0.5 - Checkpoint_Item_Size*0.5, Checkpoint_Item_Size, Palette_RGB(COLOR_CHECKPOINT));
end;
- when Item_Bomb_Gen =>
+ when Item_Bomb_Refill =>
if Item.Cooldown > 0 then
Draw_Bomb(Item.Position, Color_Brightness(Palette_RGB(COLOR_BOMB), -0.5));
Draw_Number(Item.Position, Item.Cooldown, Palette_RGB(COLOR_LABEL));
else
Draw_Bomb(Item.Position, Palette_RGB(COLOR_BOMB));
end if;
+ when Item_Bomb_Slot =>
+ Draw_Bomb(Item.Position, Palette_RGB(COLOR_DOORKEY));
end case;
end loop;
end;
@@ -825,17 +936,21 @@ procedure Eepers is
case Item.Kind is
when Item_None => null;
when Item_Key =>
- Game.Player.Keys := Game.Player.Keys + 1;
+ Inc(Game.Player.Keys);
Item.Kind := Item_None;
Play_Sound(Key_Pickup_Sound);
- when Item_Bomb_Gen => if
+ when Item_Bomb_Refill => if
Game.Player.Bombs < Game.Player.Bomb_Slots
and then Item.Cooldown <= 0
then
- Game.Player.Bombs := Game.Player.Bombs + 1;
+ Inc(Game.Player.Bombs);
Item.Cooldown := BOMB_GENERATOR_COOLDOWN;
Play_Sound(Bomb_Pickup_Sound);
end if;
+ when Item_Bomb_Slot =>
+ Item.Kind := Item_None;
+ Inc(Game.Player.Bomb_Slots);
+ Game.Player.Bombs := Game.Player.Bomb_Slots;
when Item_Checkpoint =>
Item.Kind := Item_None;
Game.Player.Bombs := Game.Player.Bomb_Slots;
@@ -846,7 +961,7 @@ procedure Eepers is
end loop;
when Cell_Door =>
if Game.Player.Keys > 0 then
- Game.Player.Keys := Game.Player.Keys - 1;
+ Dec(Game.Player.Keys);
Flood_Fill(Game, New_Position, Cell_Floor);
Game.Player.Position := New_Position;
Play_Sound(Open_Door_Sound);
@@ -857,6 +972,12 @@ procedure Eepers is
end;
end;
+ procedure Kill_Player(Game: in out Game_State) is
+ begin
+ Game.Player.Dead := True;
+ Game.Player.Death_Time := Get_Time;
+ end;
+
procedure Explode(Game: in out Game_State; Position: in IVector2) is
procedure Explode_Line(Dir: Direction) is
New_Position: IVector2 := Position;
@@ -871,7 +992,7 @@ procedure Eepers is
Game.Map(New_Position.Y, New_Position.X) := Cell_Explosion;
if New_Position = Game.Player.Position then
- Game.Player.Dead := True;
+ Kill_Player(Game);
end if;
for Eeper of Game.Eepers loop
@@ -904,20 +1025,17 @@ procedure Eepers is
);
procedure Game_Update_Camera(Game: in out Game_State) is
- Camera_Target: constant Vector2 :=
- Screen_Size*0.5 - To_Vector2(Game.Player.Position)*Cell_Size - Cell_Size*0.5;
- Camera_Velocity: constant Vector2 := (Camera_Target - Game.Camera_Position)*2.0;
- begin
- Game.Camera_Position := Game.Camera_Position + Camera_Velocity*Get_Frame_Time;
- end;
-
- function Game_Camera(Game: in Game_State) return Camera2D is
+ Camera_Target: constant Vector2 := To_Vector2(Game.Player.Position)*Cell_Size;
+ Camera_Offset: constant Vector2 := Screen_Size*0.5 - Cell_Size*0.5;
+ Camera_Velocity: constant Vector2 := (Camera_Target - Game.Camera.target)*2.0;
begin
- return (
- offset => Game.Camera_Position,
- target => (x => 0.0, y => 0.0),
- rotation => 0.0,
- zoom => 1.0);
+ Game.Camera.offset := Camera_Offset;
+ Game.Camera.target := Game.Camera.target + Camera_Velocity*Get_Frame_Time;
+ -- TODO: animate zoom similarly to Game.Camera.target
+ -- So it looks cool when you resize the game in the window mode.
+ -- TODO: The tutorial signs look gross on bigger screens.
+ -- We need to do something with the fonts
+ Game.Camera.zoom := C_Float'Max(Screen_Size.x/1920.0, Screen_Size.y/1080.0);
end;
function Interpolate_Positions(IPrev_Position, IPosition: IVector2; T: Float) return Vector2 is
@@ -946,7 +1064,7 @@ procedure Eepers is
begin
Q.Items((Q.Start + Q.Size) mod Command_Capacity) := C;
if Q.Size < Command_Capacity then
- Q.Size := Q.Size + 1;
+ Inc(Q.Size);
else
Q.Start := (Q.Start + 1) mod Command_Capacity;
end if;
@@ -958,18 +1076,18 @@ procedure Eepers is
return False;
end if;
C := Q.Items(Q.Start);
- Q.Size := Q.Size - 1;
+ Dec(Q.Size);
Q.Start := (Q.Start + 1) mod Command_Capacity;
return True;
end;
Command_Queue: Command_Queue_Record;
- Any_Key_Pressed: Boolean := False;
+ Holding_Shift: Boolean := False;
procedure Swallow_Player_Input is
begin
Command_Queue.Size := 0;
- Any_Key_Pressed := False;
+ Holding_Shift := False;
end;
procedure Game_Bombs_Turn(Game: in out Game_State) is
@@ -979,7 +1097,7 @@ procedure Eepers is
end loop;
for Bomb of Game.Bombs loop
if Bomb.Countdown > 0 then
- Bomb.Countdown := Bomb.Countdown - 1;
+ Dec(Bomb.Countdown);
if Bomb.Countdown <= 0 then
Play_Sound(Blast_Sound);
Explode(Game, Bomb.Position);
@@ -1059,7 +1177,7 @@ procedure Eepers is
when Eeper_Guard | Eeper_Mother =>
Recompute_Path_For_Eeper(Game, Me, GUARD_STEPS_LIMIT, GUARD_STEP_LENGTH_LIMIT);
if Eeper.Path(Eeper.Position.Y, Eeper.Position.X) = 0 then
- Game.Player.Dead := True;
+ Kill_Player(Game);
Eeper.Eyes := Eyes_Surprised;
elsif Eeper.Path(Eeper.Position.Y, Eeper.Position.X) > 0 then
if Eeper.Attack_Cooldown <= 0 then
@@ -1076,7 +1194,7 @@ procedure Eepers is
Position := Position + Direction_Vector(Dir);
if Within_Map(Game, Position) and then Eeper.Path(Position.Y, Position.X) = Current - 1 then
Available_Positions(Count) := Position;
- Count := Count + 1;
+ Inc(Count);
exit;
end if;
end loop;
@@ -1089,7 +1207,7 @@ procedure Eepers is
end;
Eeper.Attack_Cooldown := GUARD_ATTACK_COOLDOWN;
else
- Eeper.Attack_Cooldown := Eeper.Attack_Cooldown - 1;
+ Dec(Eeper.Attack_Cooldown);
end if;
if Eeper.Path(Eeper.Position.Y, Eeper.Position.X) = 1 then
@@ -1100,7 +1218,7 @@ procedure Eepers is
Eeper.Eyes_Target := Game.Player.Position;
if Inside_Of_Rect(Eeper.Position, Eeper.Size, Game.Player.Position) then
- Game.Player.Dead := True;
+ Kill_Player(Game);
end if;
else
Eeper.Eyes := Eyes_Closed;
@@ -1130,7 +1248,7 @@ procedure Eepers is
and then Eeper.Path(New_Position.Y, New_Position.X) > Eeper.Path(Position.Y, Position.X)
then
Available_Positions(Count) := New_Position;
- Count := Count + 1;
+ Inc(Count);
end if;
end;
end loop;
@@ -1155,9 +1273,9 @@ procedure Eepers is
procedure Game_Items_Turn(Game: in out Game_State) is
begin
for Item of Game.Items loop
- if Item.Kind = Item_Bomb_Gen then
+ if Item.Kind = Item_Bomb_Refill then
if Item.Cooldown > 0 then
- Item.Cooldown := Item.Cooldown - 1;
+ Dec(Item.Cooldown);
end if;
end if;
end loop;
@@ -1222,6 +1340,53 @@ procedure Eepers is
end loop;
end;
+ procedure Game_Tutorial(Game: in out Game_State) is
+ begin
+ case Game.Tutorial.Phase is
+ when Tutorial_Move =>
+ if Game.Tutorial.Knows_How_To_Move then
+ Game.Tutorial.Phase := Tutorial_Place_Bombs;
+ Game.Tutorial.Waiting := 0.0;
+ Hide_Popup(Game.Tutorial.Popup);
+ elsif Game.Tutorial.Waiting < TUTORIAL_MOVE_WAIT_TIME_SECS then
+ Game.Tutorial.Waiting := Game.Tutorial.Waiting + Get_Frame_Time;
+ else
+ Show_Popup(Game.Tutorial.Popup, "WASD to Move");
+ end if;
+ when Tutorial_Place_Bombs =>
+ if Game.Tutorial.Knows_How_To_Place_Bombs then
+ Game.Tutorial.Phase := Tutorial_Waiting_For_Sprint;
+ Hide_Popup(Game.Tutorial.Popup);
+ elsif Game.Player.Bombs > 0 then
+ if Game.Tutorial.Waiting < TUTORIAL_BOMB_WAIT_TIME_SECS then
+ Game.Tutorial.Waiting := Game.Tutorial.Waiting + Get_Frame_Time;
+ else
+ Show_Popup(Game.Tutorial.Popup, "SPACE to Place Bombs");
+ end if;
+ end if;
+ when Tutorial_Waiting_For_Sprint =>
+ if Game.Tutorial.Hurry_Count >= 10 then
+ Game.Tutorial.Phase := Tutorial_Sprint;
+ Game.Tutorial.Waiting := 0.0;
+ end if;
+ when Tutorial_Sprint =>
+ if Game.Tutorial.Knows_How_To_Sprint then
+ Game.Tutorial.Phase := Tutorial_Done;
+ Hide_Popup(Game.Tutorial.Popup);
+ else
+ if Game.Tutorial.Waiting < TUTORIAL_SPRINT_WAIT_TIME_SECS then
+ Show_Popup(Game.Tutorial.Popup, "Hold SHIFT to Sprint");
+ Game.Tutorial.Waiting := Game.Tutorial.Waiting + Get_Frame_Time;
+ else
+ Game.Tutorial.Phase := Tutorial_Done;
+ Hide_Popup(Game.Tutorial.Popup);
+ end if;
+ end if;
+ when Tutorial_Done => null;
+ end case;
+ Draw_Popup(Game.Tutorial.Popup, Screen_Player_Position(Game), Cell_Size);
+ end;
+
procedure Game_Player(Game: in out Game_State) is
Eyes_Angular_Direction: constant Float := Delta_Angle(Game.Player.Eyes_Angle, Look_At(To_Vector2(Game.Player.Position)*Cell_Size + Cell_Size*0.5, To_Vector2(Game.Player.Eyes_Target)*Cell_Size + Cell_Size*0.5));
begin
@@ -1232,7 +1397,7 @@ procedure Eepers is
Draw_Eyes(Screen_Player_Position(Game), Cell_Size, Game.Player.Eyes_Angle, Game.Player.Prev_Eyes, Game.Player.Eyes, Game.Turn_Animation);
end if;
- if Any_Key_Pressed then
+ if (Get_Time - Game.Player.Death_Time) > RESTART_TIMEOUT_SECS then
Game_Restore_Checkpoint(Game);
Game.Player.Dead := False;
end if;
@@ -1256,12 +1421,31 @@ procedure Eepers is
declare
Start_Of_Turn: constant Double := Get_Time;
begin
+ Game.Tutorial.Knows_How_To_Move := True;
+ if Holding_Shift then
+ Game.Tutorial.Knows_How_To_Sprint := True;
+ end if;
+
+ if Game.Tutorial.Phase = Tutorial_Waiting_For_Sprint then
+ declare
+ Step_Timestamp: constant Double := Get_Time;
+ Delta_Timestamp: constant Double := Step_Timestamp - Game.Tutorial.Prev_Step_Timestamp;
+ begin
+ if Delta_Timestamp < 0.2 Then
+ Inc(Game.Tutorial.Hurry_Count);
+ elsif Game.Tutorial.Hurry_Count > 0 then
+ Dec(Game.Tutorial.Hurry_Count);
+ end if;
+ Game.Tutorial.Prev_Step_Timestamp := Step_Timestamp;
+ end;
+ end if;
+
Game.Turn_Animation := 1.0;
Game_Explosions_Turn(Game);
Game_Items_Turn(Game);
Game_Player_Turn(Game, C.Dir);
- Game_Eepers_Turn(Game);
Game_Bombs_Turn(Game);
+ Game_Eepers_Turn(Game);
Game.Duration_Of_Last_Turn := Get_Time - Start_Of_Turn;
end;
when Command_Plant =>
@@ -1269,6 +1453,8 @@ procedure Eepers is
declare
Start_Of_Turn: constant Double := Get_Time;
begin
+ Game.Tutorial.Knows_How_To_Place_Bombs := True;
+
Game.Turn_Animation := 1.0;
Game_Explosions_Turn(Game);
Game_Items_Turn(Game);
@@ -1277,8 +1463,8 @@ procedure Eepers is
Game.Player.Prev_Eyes := Game.Player.Eyes;
Game.Player.Prev_Position := Game.Player.Position;
- Game_Eepers_Turn(Game);
Game_Bombs_Turn(Game);
+ Game_Eepers_Turn(Game);
if Game.Player.Bombs > 0 then
for Bomb of Game.Bombs loop
@@ -1288,7 +1474,7 @@ procedure Eepers is
exit;
end if;
end loop;
- Game.Player.Bombs := Game.Player.Bombs - 1;
+ Dec(Game.Player.Bombs);
Play_Sound(Plant_Bomb_Sound);
end if;
@@ -1320,23 +1506,27 @@ procedure Eepers is
end;
end loop;
- for Index in 1..Game.Player.Bombs loop
+ for Index in 1..Game.Player.Bomb_Slots loop
declare
- Position: constant Vector2 := (100.0 + C_float(Index - 1)*Cell_Size.X, 200.0);
+ Padding: constant C_Float := Cell_Size.X*0.5;
+ Position: constant Vector2 := (100.0 + C_float(Index - 1)*(Cell_Size.X + Padding), 200.0);
begin
- Draw_Circle_V(Position, Cell_Size.X*0.5, Palette_RGB(COLOR_BOMB));
+ if Index <= Game.Player.Bombs then
+ Draw_Circle_V(Position, Cell_Size.X*0.5, Palette_RGB(COLOR_BOMB));
+ else
+ Draw_Circle_V(Position, Cell_Size.X*0.5, Color_Brightness(Palette_RGB(COLOR_BOMB), -0.5));
+ end if;
end;
end loop;
if Game.Player.Dead then
declare
Label: constant Char_Array := To_C("You Died!");
- Label_Height: constant Integer := 48;
- Label_Width: constant Integer := Integer(Measure_Text(Label, Int(Label_Height)));
- Text_Size: constant Vector2 := To_Vector2((Label_Width, Label_Height));
+ Text_Size: constant Vector2 := Measure_Text_Ex(Death_Font, Label, C_Float(Death_Font_Size), 0.0);
Position: constant Vector2 := Screen_Size*0.5 - Text_Size*0.5;
begin
- Draw_Text(Label, Int(Position.X), Int(Position.Y), Int(Label_Height), Palette_RGB(COLOR_LABEL));
+ Draw_Text_Ex(Death_Font, Label, Position + (-2.0, 2.0), C_Float(Death_Font_Size), 0.0, Palette_RGB(COLOR_WALL));
+ Draw_Text_Ex(Death_Font, Label, Position, C_Float(Death_Font_Size), 0.0, Palette_RGB(COLOR_PLAYER));
end;
end if;
end;
@@ -1404,7 +1594,7 @@ procedure Eepers is
end;
Game: Game_State;
- Title: constant Char_Array := To_C("Eepers (v1.2)");
+ Title: constant Char_Array := To_C("Eepers (v1.4)");
Palette_Editor: Boolean := False;
Palette_Editor_Choice: Palette := Palette'First;
@@ -1440,6 +1630,11 @@ begin
Set_Sound_Pitch(Checkpoint_Sound, 0.8);
Guard_Step_Sound := Load_Sound(To_C("assets/sounds/guard-step.ogg")); -- https://opengameart.org/content/fire-whip-hit-yo-frankie
Plant_Bomb_Sound := Load_Sound(To_C("assets/sounds/plant-bomb.wav")); -- https://opengameart.org/content/ui-soundpack-by-m1chiboi-bleeps-and-clicks
+ Popup_Show_Sound := Load_Sound(To_C("assets/sounds/popup-show.wav")); -- https://opengameart.org/content/ui-soundpack-by-m1chiboi-bleeps-and-clicks
+ Tutorial_Font := Load_Font_Ex(To_C("assets/fonts/Vollkorn/static/Vollkorn-Regular.ttf"), Tutorial_Font_Size, 0, 0);
+ Gen_Texture_Mipmaps(Tutorial_Font.Texture'Access);
+ Death_Font := Load_Font_Ex(To_C("assets/fonts/Vollkorn/static/Vollkorn-Regular.ttf"), Death_Font_Size, 0, 0);
+ Gen_Texture_Mipmaps(Death_Font.Texture'Access);
Random_Integer.Reset(Gen);
Load_Colors("assets/colors.txt");
@@ -1454,10 +1649,11 @@ begin
Begin_Drawing;
Clear_Background(Palette_RGB(COLOR_BACKGROUND));
+ Holding_Shift := Boolean(Is_Key_Down(KEY_LEFT_SHIFT)) or else Boolean(Is_Key_Down(KEY_RIGHT_SHIFT));
if Game.Player.Dead then
Command_Queue.Size := 0;
else
- if (Boolean(Is_Key_Down(KEY_LEFT_SHIFT)) or else Boolean(Is_Key_Down(KEY_RIGHT_SHIFT))) and then Game.Turn_Animation <= 0.0 then
+ if Holding_Shift and then Game.Turn_Animation <= 0.0 then
if Is_Key_Down(KEY_A) or else Is_Key_Down(KEY_LEFT) then
Command_Queue.Size := 0;
Command_Enqueue(Command_Queue, (Kind => Command_Step, Dir => Left));
@@ -1492,7 +1688,7 @@ begin
Command_Enqueue(Command_Queue, (Kind => Command_Plant));
end if;
end if;
- if Boolean(Is_Key_Down(KEY_LEFT_SHIFT)) or else Boolean(Is_Key_Down(KEY_RIGHT_SHIFT)) then
+ if Holding_Shift then
TURN_DURATION_SECS := BASE_TURN_DURATION_SECS * 0.8;
else
if Command_Queue.Size /= 0 then
@@ -1502,11 +1698,6 @@ begin
end if;
end if;
- Any_Key_Pressed := False;
- while not Any_Key_Pressed and then Get_Key_Pressed /= KEY_NULL loop
- Any_Key_Pressed := True;
- end loop;
-
if DEVELOPMENT then
if Is_Key_Pressed(KEY_R) then
Load_Game_From_Image("assets/map.png", Game, Update_Player => False, Update_Camera => False);
@@ -1538,12 +1729,12 @@ begin
end if;
if Is_Key_Down(Keys(Up)) then
- Palette_HSV(Palette_Editor_Choice)(Palette_Editor_Component) := Palette_HSV(Palette_Editor_Choice)(Palette_Editor_Component) + 1;
+ Inc(Palette_HSV(Palette_Editor_Choice)(Palette_Editor_Component));
Palette_RGB(Palette_Editor_Choice) := HSV_To_RGB(Palette_HSV(Palette_Editor_Choice));
end if;
if Is_Key_Down(Keys(Down)) then
- Palette_HSV(Palette_Editor_Choice)(Palette_Editor_Component) := Palette_HSV(Palette_Editor_Choice)(Palette_Editor_Component) - 1;
+ Dec(Palette_HSV(Palette_Editor_Choice)(Palette_Editor_Component));
Palette_RGB(Palette_Editor_Choice) := HSV_To_RGB(Palette_HSV(Palette_Editor_Choice));
end if;
else
@@ -1577,12 +1768,13 @@ begin
end if;
Game_Update_Camera(Game);
- Begin_Mode2D(Game_Camera(Game));
+ Begin_Mode2D(Game.Camera);
Game_Cells(Game);
Game_Items(Game);
Game_Player(Game);
Game_Eepers(Game);
Game_Bombs(Game);
+ Game_Tutorial(Game);
if DEVELOPMENT then
if Is_Key_Down(KEY_P) then
for Row in Game.Map'Range(1) loop
@@ -1641,6 +1833,12 @@ begin
end;
-- TODO: Items in HUD may sometimes blend with the background
+-- TODO: Different palettes on each NG+
+-- TODO: NG+ must make the Game harder while retaining the collected bomb slots
+-- TODO: The gnome blocking trick was never properly explained.
+-- We should introduce an extra room that entirely relies on that mechanic,
+-- so it does not feel out of place, when you discover it on Mother.
+-- TODO: The puzzle with Gnome blocking Guard repeated twice (which sucks)
-- TODO: Footstep variation for Mother/Guard bosses (depending on the distance traveled?)
-- TODO: Footsteps for mother should be lower
-- TODO: Restarting should be considered a turn
@@ -1648,7 +1846,6 @@ end;
-- Or maybe we should just save Path Maps too?
-- TODO: If you are standing on the refilled bomb gen and place a bomb you should refill your bomb in that turn.
-- TODO: Checkpoints should be circles (like all the items)
--- TODO: Custom font
-- TODO: Mother should require several attacks before being "split"
-- TODO: Enemies should attack on zero just like a bomb.
-- TODO: Properly disablable DEV features
@@ -1658,17 +1855,11 @@ end;
-- TODO: Visual Clue that the Eeper is about to kill the Player when Completely outside of the Screen
-- - Cooldown ball is shaking
-- TODO: Cool animation for New Game
--- TODO: Tutorial
--- - Sign that says "WASD" to move when you start the game for the first time.
--- - And how to place the bomb on picking it up.
--- - How to sprint after you blow up firt Barricade.
-- TODO: Count the player's turns towards the final score of the game
-- We can even collect different stats, like bombs collected, bombs used,
-- times died etc.
-- TODO: Animate key when you pick it up
-- Smoothly move it into the HUD.
--- TODO: Different palettes depending on the area
--- Or maybe different palette for each NG+
-- TODO: Particles
-- - Player Death animation
-- - Eeper Death animation
diff --git a/raylib.ads b/raylib.ads
index 74e6eac..295108c 100644
--- a/raylib.ads
+++ b/raylib.ads
@@ -7,6 +7,8 @@ package Raylib is
type Bool is new Boolean;
pragma Convention (C, Bool);
+ type Addr is mod 2 ** Standard'Address_Size;
+
procedure Init_Window(Width, Height: int; Title: in char_array)
with
Import => True,
@@ -164,6 +166,30 @@ package Raylib is
Import => True,
Convention => C,
External_Name => "DrawText";
+ type Texture2D is record
+ Id: unsigned;
+ Width: int;
+ Height: int;
+ Mipmaps: int;
+ Format: int;
+ end record
+ with Convention => C_Pass_By_Copy;
+
+ type Font is record
+ Base_Size: int;
+ Glyph_Count: int;
+ Glyph_Padding: int;
+ Texture: aliased Texture2D;
+ Rects: Addr;
+ Glyph_Info: Addr;
+ end record
+ with Convention => C_Pass_By_Copy;
+
+ procedure Draw_Text_Ex(F: Font; Text: Char_Array; Position: Vector2; Font_Size: C_Float; Spacing: C_Float; Tint: Color)
+ with
+ Import => True,
+ Convention => C,
+ External_Name => "DrawTextEx";
procedure Set_Target_FPS(Fps: int)
with
Import => True,
@@ -199,7 +225,6 @@ package Raylib is
Import => True,
Convention => C,
External_Name => "GetTime";
- type Addr is mod 2 ** Standard'Address_Size;
type Image is record
Data: Addr;
Width: int;
@@ -333,4 +358,20 @@ package Raylib is
Import => True,
Convention => C,
External_Name => "SetWindowIcon";
+
+ function Load_Font_Ex(File_Name: char_array; Font_Size: int; Codepoints: Addr; Codepoint_Count: Integer) return Font
+ with
+ Import => True,
+ Convention => C,
+ External_Name => "LoadFontEx";
+ function Measure_Text_Ex(F: Font; Text: Char_Array; Font_Size: C_Float; Spacing: C_Float) return Vector2
+ with
+ Import => True,
+ Convention => C,
+ External_Name => "MeasureTextEx";
+ procedure Gen_Texture_Mipmaps(T: access Texture2D)
+ with
+ Import => True,
+ Convention => C,
+ External_Name => "GenTextureMipmaps";
end Raylib;