Skip to content

Commit

Permalink
simple mob ai and ui base
Browse files Browse the repository at this point in the history
  • Loading branch information
jossse69 committed Sep 23, 2023
1 parent 409debb commit 8326e1f
Show file tree
Hide file tree
Showing 4 changed files with 100 additions and 87 deletions.
110 changes: 29 additions & 81 deletions src/AI/BaseAI.cs
Original file line number Diff line number Diff line change
@@ -1,112 +1,60 @@
using GoRogue;
using GoRogue.Pathing;
using SadConsole;
using SadRogue.Primitives;
using SadRogue.Primitives.GridViews;

namespace MIST.AI
{
internal class MonsterAI
{
public AStar Pathfinder { get; private set; }
public Action? OnAITurn { get; set; }
public GoRogue.Pathing.Path? CurrentPath { get; private set; }
public Point Target { get; private set; } = new Point(-1, -1);

private int _currentPathIndex = 0;

public MonsterAI(Map map)
{
Pathfinder = new AStar(map.GetFOV().TransparencyView, Distance.Chebyshev);


}

public void AITurn(GameObject go, Map map, List<GameObject> objects)
public void AITurn(GameObject go, Map map, List<GameObject> objects, GameObject player)
{
// if tis dead, do nothing
if (go == null || go.Fighter == null || go.Fighter.IsDead)
{
return;
}

if (CurrentPath == null)
// player alive, and monster is in fov
if (!player.Fighter.IsDead && map.IsInFov(go.Position.X, go.Position.Y))
{
// if the target is (-1, -1), find a new one
if (Target.X == -1 && Target.Y == -1)
{
int maxAttempts = 100; // You can adjust the number of attempts as needed
Point newTarget;

var rng = ScreenContainer.Instance.Random;
do
{
int xOffset = rng.Next(-7, 7);
int yOffset = rng.Next(-7, 7);

int newX = Math.Clamp(go.Position.X + xOffset, 0, map.Width - 1);
int newY = Math.Clamp(go.Position.Y + yOffset, 0, map.Height - 1);

newTarget = new Point(newX, newY);
maxAttempts--;

} while (maxAttempts > 0 && go.IsBlocked(newTarget.X, newTarget.Y, map, objects));

if (maxAttempts <= 0)
{
// Handle the case where a valid target couldn't be found after several attempts
Console.WriteLine("Could not find a valid path.");
return;
}
else
{
Target = newTarget;
}
}
CurrentPath = FindPath(go.Position, Target);
}

// step the path
if (CurrentPath == null)
{
Console.WriteLine("Could not find a valid path for target " + Target + " | Resetting path!");
Target = (-1, -1);
return;
Target = player.Position;
}

var step = StepPath(CurrentPath, _currentPathIndex, out bool finished);

// TODO: Verify if we can actually walk to this step, if not we should finish this path

go.MoveAndAttack(step.X, step.Y, map, objects);

if (finished)
// move to target if its set
if (Target != new Point(-1, -1))
{
CurrentPath = null;
Target = (-1, -1);
_currentPathIndex = 0;
Console.WriteLine("Finished ai turn!");
}
else
{
_currentPathIndex++;
Console.WriteLine("Increased path index, Target: " + Target);
if (Target.X > go.Position.X)
{
go.MoveAndAttack(1, 0, map, objects);
} else if (Target.X < go.Position.X)
{
go.MoveAndAttack(-1, 0, map, objects);
}

if (Target.Y > go.Position.Y)
{
go.MoveAndAttack(0, 1, map, objects);
}
else if (Target.Y < go.Position.Y)
{
go.MoveAndAttack(0, -1, map, objects);
}
}
}

public GoRogue.Pathing.Path? FindPath(Point start, Point end)
{
var path = Pathfinder.ShortestPath(start, end);
return path;

}

public Point StepPath(GoRogue.Pathing.Path path, int idx, out bool finished) {

// if its the last step, return the target
finished = false;
if (idx == path.Steps.Count() - 1)
{
finished = true;
return Target;
}

var movement = path.Steps.ElementAt(idx);
return new Point(movement.Y, movement.Y);
}
}
}
44 changes: 39 additions & 5 deletions src/Map.cs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ public IFOV GetFOV()
return _fov;
}

public ArrayView<Tile> GetTiles()
{
return _tiles;
}

/// <summary>
/// generates a map with a border and random tiles
/// <param name="width">the width of the map</param>
Expand All @@ -59,7 +64,7 @@ public static Map GenerateMap(int width, int height, List<GameObject> objects)
{
for (int y = 0; y < height; y++)
{
map[x, y] = new Tile(TileType.Wall);
map[x, y] = new Tile(TileType.Wall); // floor for debuging
}
}

Expand Down Expand Up @@ -176,11 +181,11 @@ private void CreateMonster(Map map, Rectangle room)
// 20% to be an smile, alse its a spider
if (random.Next(20) == 0)
{
monster = new GameObject(new ColoredGlyph(Color.LimeGreen, Color.Black, 'S'), new Point(monsterX, monsterY), map, new Fighter(15, 15, 2, 1), new Info("Smile", "a mass of gelatic green goo... that is alive, it digest any food it comes across.", monsterType.smlie), new AI.MonsterAI(map));
monster = new GameObject(new ColoredGlyph(Color.LimeGreen, Color.Black, 'S'), new Point(monsterX, monsterY), map, new Fighter(15, 15, 3, 1), new Info("Smile", "a mass of gelatic green goo... that is alive, it digest any food it comes across.", monsterType.smlie), new AI.MonsterAI(map));
}
else
{
monster = new GameObject(new ColoredGlyph(Color.Red, Color.Black, 's'), new Point(monsterX, monsterY), map, new Fighter(5, 5, 1, 1), new Info("Spider", "a oddly big arachnid. its black and has a big skull-shaped symbol on it's abdomen, that probably means something.", monsterType.insect), new AI.MonsterAI(map));
monster = new GameObject(new ColoredGlyph(Color.Red, Color.Black, 's'), new Point(monsterX, monsterY), map, new Fighter(5, 5, 2, 1), new Info("Spider", "a oddly big arachnid. its black and has a big skull-shaped symbol on it's abdomen, that probably means something.", monsterType.insect), new AI.MonsterAI(map));
}
success = true;
// add it to the list
Expand Down Expand Up @@ -338,11 +343,28 @@ public override bool ProcessKeyboard(Keyboard keyboard)
if (_moveTimer <= 0)
{
var player = ScreenContainer.Instance.Player;
var UI = ScreenContainer.Instance.UI;
if (!player.Fighter.IsDead)
{
player.MoveAndAttack(dx, dy, this, _objects);
}

UpdateFOV(player.Position.X, player.Position.Y, radius: 5);

Draw();

// set visble of map true (debuging purposes)

for (var x = 0; x < _tiles.Width; x++)
{
for (var y = 0; y < _tiles.Height; y++)
{
//_tiles[x, y].Visible = true;
//_tiles[x, y].Explored = true;
}
}


// make list of objects to draw
var drawList = _objects.ToList();

Expand All @@ -352,6 +374,8 @@ public override bool ProcessKeyboard(Keyboard keyboard)
.OrderBy(obj => obj.Fighter?.IsDead)
.ToList();



// draw the list
for (var index = 0; index < drawList.Count; index++)
{
Expand All @@ -360,14 +384,20 @@ public override bool ProcessKeyboard(Keyboard keyboard)
if (obj == null || obj.AI == null) continue;

// Do AI turn
obj.AI.AITurn(drawList[index], this, _objects);
obj.AI.AITurn(drawList[index], this, _objects, player);



// if not in FOV, don't draw
if (_fov.BooleanResultView[drawList[index].Position.X, drawList[index].Position.Y] == false) continue;
if (_tiles[obj.Position.X, obj.Position.Y].Visible == false) continue;

drawList[index].Draw();
}
// draw player
player.Draw();

// draw UI
UI.Draw(player);
_moveTimer = 5;
}
}
Expand All @@ -385,5 +415,9 @@ public override void Update(TimeSpan delta)
}
}

public bool IsInFov(int x, int y)
{
return _fov.BooleanResultView[x, y];
}
}
}
5 changes: 4 additions & 1 deletion src/ScreenContainer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,24 @@ internal class ScreenContainer : ScreenObject
public List<GameObject> Objects;
public readonly Random Random;

public UI UI { get; set; }

public ScreenContainer()
{
Instance = this;
Width = Constants.ScreenWidth;
Height = Constants.ScreenHeight;
Objects = new List<GameObject>();
Random = new Random();
UI = new UI(this);

// generate the map
Map = Map.GenerateMap(Width, Height, Objects);
Map.Draw();
Map.IsFocused = true;

// add the player
Player = new GameObject(new ColoredGlyph(Color.White, Color.Black, '@'), Map.start, Map, new Fighter(10, 10, 3, 3), new Info("Player", "It's you!", monsterType.player), null);
Objects.Add(Player);
Player.Draw();


Expand Down
28 changes: 28 additions & 0 deletions src/UI.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
using SadRogue.Primitives;
using SadConsole;
using SadRogue.Primitives.GridViews;
using SadConsole.Input;
using GoRogue.Messaging;
namespace MIST
{
internal class UI
{
public ScreenContainer display { get; set; }

public MessageBus Messages { get; set; }


public UI(ScreenContainer Display)
{
display = Display;
Messages = new MessageBus();
}

public void Draw(GameObject player)
{

display.Map.Print(0,0, "HP: " + player.Fighter.HP + " / " + player.Fighter.maxHP);

}
}
}

0 comments on commit 8326e1f

Please sign in to comment.