summaryrefslogtreecommitdiff
path: root/game.adb
diff options
context:
space:
mode:
authorrexim <reximkut@gmail.com>2024-03-16 03:35:08 +0700
committerrexim <reximkut@gmail.com>2024-03-16 03:35:08 +0700
commit6658d0649e83f3dd4ec863abadc7c187a4f66276 (patch)
tree900c7b66e9ab0867ecadb9112de97f565016e243 /game.adb
parent3cf4da268e63689f4e40a7ea7d5cebc0c44f8251 (diff)
Make bosses not bump into each other during path finding
Diffstat (limited to 'game.adb')
-rw-r--r--game.adb149
1 files changed, 94 insertions, 55 deletions
diff --git a/game.adb b/game.adb
index f190eea..c11ca31 100644
--- a/game.adb
+++ b/game.adb
@@ -250,7 +250,8 @@ procedure Game is
type Bomb_State_Array is array (1..10) of Bomb_State;
- type Boss_Array is array (1..10) of Boss_State;
+ type Boss_Index is range 1..10;
+ type Boss_Array is array (Boss_Index) of Boss_State;
type Checkpoint_State is record
Map: Map_Access := Null;
@@ -293,11 +294,6 @@ procedure Game is
return M1;
end;
- function Inside_Of_Rect(Start, Size, Point: in IVector2) return Boolean is
- begin
- return Start <= Point and then Point < Start + Size;
- end;
-
type Direction is (Left, Right, Up, Down);
procedure Step(D: in Direction; Position: in out IVector2) is
@@ -320,7 +316,13 @@ procedure Game is
end case;
end;
- function Body_Can_Stand_Here(Game: Game_State; Start, Size: IVector2) return Boolean is
+ function Inside_Of_Rect(Start, Size, Point: in IVector2) return Boolean is
+ begin
+ return Start <= Point and then Point < Start + Size;
+ end;
+
+ function Boss_Can_Stand_Here(Game: Game_State; Start: IVector2; Me: Boss_Index) return Boolean is
+ Size: constant IVector2 := Game.Bosses(Me).Size;
begin
for X in Start.X..Start.X+Size.X-1 loop
for Y in Start.Y..Start.Y+Size.Y-1 loop
@@ -330,15 +332,25 @@ procedure Game is
if Game.Map(Y, X) /= Floor then
return False;
end if;
+ for Index in Boss_Index loop
+ if not Game.Bosses(Index).Dead and then Index /= Me then
+ declare
+ Boss : constant Boss_State := Game.Bosses(Index);
+ begin
+ if Inside_Of_Rect(Boss.Position, Boss.Size, (X, Y)) then
+ return False;
+ end if;
+ end;
+ end if;
+ end loop;
end loop;
end loop;
return True;
end;
- procedure Recompute_Path_For_Body
- (Game: in Game_State;
- Path: out Path_Map;
- Start, Size: IVector2;
+ procedure Recompute_Path_For_Boss
+ (Game: in out Game_State;
+ Me: Boss_Index;
Steps_Limit: Integer;
Step_Length_Limit: Integer)
is
@@ -347,19 +359,19 @@ procedure Game is
Q: Queue.Vector;
begin
- for Y in Path'Range(1) loop
- for X in Path'Range(2) loop
- Path(Y, X) := -1;
+ for Y in Game.Bosses(Me).Path'Range(1) loop
+ for X in Game.Bosses(Me).Path'Range(2) loop
+ Game.Bosses(Me).Path(Y, X) := -1;
end loop;
end loop;
- for Dy in 0..Size.Y-1 loop
- for Dx in 0..Size.X-1 loop
+ for Dy in 0..Game.Bosses(Me).Size.Y-1 loop
+ for Dx in 0..Game.Bosses(Me).Size.X-1 loop
declare
Position: constant IVector2 := Game.Player.Position - (Dx, Dy);
begin
- if Body_Can_Stand_Here(Game, Position, Size) then
- Path(Position.Y, Position.X) := 0;
+ if Boss_Can_Stand_Here(Game, Position, Me) then
+ Game.Bosses(Me).Path(Position.Y, Position.X) := 0;
Q.Append(Position);
end if;
end;
@@ -372,11 +384,11 @@ procedure Game is
begin
Q.Delete_First;
- if Position = Start then
+ if Position = Game.Bosses(Me).Position then
exit;
end if;
- if Path(Position.Y, Position.X) >= Steps_Limit then
+ if Game.Bosses(Me).Path(Position.Y, Position.X) >= Steps_Limit then
exit;
end if;
@@ -386,11 +398,11 @@ procedure Game is
begin
Step(Dir, New_Position);
for Limit in 1..Step_Length_Limit loop
- if not Body_Can_Stand_Here(Game, New_Position, Size) then
+ if not Boss_Can_Stand_Here(Game, New_Position, Me) then
exit;
end if;
- if Path(New_Position.Y, New_Position.X) < 0 then
- Path(New_Position.Y, New_Position.X) := Path(Position.Y, Position.X) + 1;
+ if Game.Bosses(Me).Path(New_Position.Y, New_Position.X) < 0 then
+ Game.Bosses(Me).Path(New_Position.Y, New_Position.X) := Game.Bosses(Me).Path(Position.Y, Position.X) + 1;
Q.Append(New_Position);
end if;
Step(Dir, New_Position);
@@ -429,6 +441,23 @@ procedure Game is
Game.Items := Game.Checkpoint.Items;
end;
+ procedure Spawn_Shrek(Game: in out Game_State; Position: IVector2) is
+ begin
+ for Boss of Game.Bosses loop
+ if Boss.Dead then
+ Boss.Behavior := Shrek;
+ Boss.Background := COLOR_SHREK;
+ Boss.Dead := False;
+ Boss.Position := Position;
+ Boss.Prev_Position := Position;
+ Boss.Health := 1.0;
+ Boss.Size := (3, 3);
+ Boss.Attack_Cooldown := SHREK_ATTACK_COOLDOWN;
+ exit;
+ end if;
+ end loop;
+ end;
+
procedure Load_Game_From_File(File_Name: in String; Game: in out Game_State; Update_Player: Boolean) is
package Rows is new
Ada.Containers.Vectors(
@@ -493,18 +522,7 @@ procedure Game is
end loop;
Game.Map(Row, Column) := Floor;
when 'B' =>
- for Boss of Game.Bosses loop
- if Boss.Dead then
- Boss.Behavior := Shrek;
- Boss.Background := COLOR_SHREK;
- Boss.Dead := False;
- Boss.Position := (Column, Row);
- Boss.Prev_Position := (Column, Row);
- Boss.Health := 1.0;
- Boss.Size := (3, 3);
- exit;
- end if;
- end loop;
+ Spawn_Shrek(Game, (Column, Row));
Game.Map(Row, Column) := Floor;
when '.' => Game.Map(Row, Column) := Floor;
when '#' => Game.Map(Row, Column) := Wall;
@@ -569,6 +587,9 @@ procedure Game is
Position: constant Vector2 := To_Vector2((Column, Row))*Cell_Size;
begin
Draw_Rectangle_V(position, cell_size, Cell_Colors(Game.Map(Row, Column)));
+ if Is_Key_Down(KEY_P) then
+ Draw_Number((Column, Row), Game.Bosses(1).Path(Row, Column), (A => 255, others => 0));
+ end if;
end;
end loop;
end loop;
@@ -661,10 +682,23 @@ procedure Game is
for Boss of Game.Bosses loop
if not Boss.Dead and then Inside_Of_Rect(Boss.Position, Boss.Size, New_Position) then
- Boss.Health := Boss.Health - BOSS_EXPLOSION_DAMAGE;
- if Boss.Health <= 0.0 then
- Boss.Dead := True;
- end if;
+ case Boss.Behavior is
+ when Shrek =>
+ Boss.Health := Boss.Health - BOSS_EXPLOSION_DAMAGE;
+ if Boss.Health <= 0.0 then
+ Boss.Dead := True;
+ end if;
+ when Urmom =>
+ declare
+ Position: constant IVector2 := Boss.Position;
+ begin
+ Boss.Dead := True;
+ Spawn_Shrek(Game, Position + (0, 0));
+ Spawn_Shrek(Game, Position + (3, 0));
+ Spawn_Shrek(Game, Position + (0, 3));
+ Spawn_Shrek(Game, Position + (3, 3));
+ end;
+ end case;
return;
end if;
end loop;
@@ -803,14 +837,14 @@ procedure Game is
end loop;
end;
- for Boss of Game.Bosses loop
- if not Boss.Dead then
- Recompute_Path_For_Body(Game, Boss.Path.all, Boss.Position, Boss.Size, SHREK_STEPS_LIMIT, SHREK_STEP_LENGTH_LIMIT);
- Boss.Prev_Position := Boss.Position;
+ for Me in Boss_Index loop
+ if not Game.Bosses(Me).Dead then
+ Recompute_Path_For_Boss(Game, Me, SHREK_STEPS_LIMIT, SHREK_STEP_LENGTH_LIMIT);
+ Game.Bosses(Me).Prev_Position := Game.Bosses(Me).Position;
-- TODO: Shrek should attack on zero just like a bomb.
- if Boss.Attack_Cooldown <= 0 then
+ if Game.Bosses(Me).Attack_Cooldown <= 0 then
declare
- Current : constant Integer := Boss.Path(Boss.Position.Y, Boss.Position.X);
+ Current : constant Integer := Game.Bosses(Me).Path(Game.Bosses(Me).Position.Y, Game.Bosses(Me).Position.X);
begin
-- TODO: maybe pick the paths
-- randomly to introduce a bit of
@@ -818,27 +852,27 @@ procedure Game is
-- deterministic game
Search: for Dir in Direction loop
declare
- Position: IVector2 := Boss.Position;
+ Position: IVector2 := Game.Bosses(Me).Position;
begin
- while Body_Can_Stand_Here(Game, Position, Boss.Size) loop
+ while Boss_Can_Stand_Here(Game, Position, Me) loop
Step(Dir, Position);
- if Boss.Path(Position.Y, Position.X) = Current - 1 then
- Boss.Position := Position;
+ if Game.Bosses(Me).Path(Position.Y, Position.X) = Current - 1 then
+ Game.Bosses(Me).Position := Position;
exit Search;
end if;
end loop;
end;
end loop Search;
end;
- Boss.Attack_Cooldown := SHREK_ATTACK_COOLDOWN;
+ Game.Bosses(Me).Attack_Cooldown := SHREK_ATTACK_COOLDOWN;
else
- Boss.Attack_Cooldown := Boss.Attack_Cooldown - 1;
+ Game.Bosses(Me).Attack_Cooldown := Game.Bosses(Me).Attack_Cooldown - 1;
end if;
- if Inside_Of_Rect(Boss.Position, Boss.Size, Game.Player.Position) then
+ if Inside_Of_Rect(Game.Bosses(Me).Position, Game.Bosses(Me).Size, Game.Player.Position) then
Game.Player.Dead := True;
end if;
- if Boss.Health < 1.0 then
- Boss.Health := Boss.Health + SHREK_TURN_REGENERATION;
+ if Game.Bosses(Me).Health < 1.0 then
+ Game.Bosses(Me).Health := Game.Bosses(Me).Health + SHREK_TURN_REGENERATION;
end if;
end if;
end loop;
@@ -911,7 +945,12 @@ procedure Game is
begin
if not Boss.Dead then
Draw_Rectangle_V(Position, Cell_Size*To_Vector2(Boss.Size), Palette_RGB(Boss.Background));
- Health_Bar(Position, Size, C_Float(Boss.Health));
+ case Boss.Behavior is
+ when Shrek =>
+ Health_Bar(Position, Size, C_Float(Boss.Health));
+ when Urmom =>
+ null;
+ end case;
Draw_Number(Position, Size, Boss.Attack_Cooldown, (A => 255, others => 0));
end if;
end;