# Part 5 - Placing Enemies and kicking them (harmlessly)

What good is a dungeon with no monsters to bash? This chapter will focus on placing the enemies throughout the dungeon, and setting them up to be attacked (the actual attacking part we’ll save for next time). To start, we’ll need a function to place the enemies in the dungeon; let’s call it `place_entities` and put it in the `GameMap` class.

``````   def create_v_tunnel(self, y1, y2, x):
...

+   def place_entities(self, room, entities, max_monsters_per_room):
+       # Get a random number of monsters
+       number_of_monsters = randint(0, max_monsters_per_room)
+
+       for i in range(number_of_monsters):
+           # Choose a random location in the room
+           x = randint(room.x1 + 1, room.x2 - 1)
+           y = randint(room.y1 + 1, room.y2 - 1)
+
+           if not any([entity for entity in entities if entity.x == x and entity.y == y]):
+               if randint(0, 100) < 80:
+                   monster = Entity(x, y, 'o', libtcod.desaturated_green)
+               else:
+                   monster = Entity(x, y, 'T', libtcod.darker_green)
+
+               entities.append(monster)

def is_blocked(self, x, y):
...
``````
```    def create_v_tunnel(self, y1, y2, x):
...

def place_entities(self, room, entities, max_monsters_per_room):
# Get a random number of monsters
number_of_monsters = randint(0, max_monsters_per_room)

for i in range(number_of_monsters):
# Choose a random location in the room
x = randint(room.x1 + 1, room.x2 - 1)
y = randint(room.y1 + 1, room.y2 - 1)

if not any([entity for entity in entities if entity.x == x and entity.y == y]):
if randint(0, 100) < 80:
monster = Entity(x, y, 'o', libtcod.desaturated_green)
else:
monster = Entity(x, y, 'T', libtcod.darker_green)

entities.append(monster)

def is_blocked(self, x, y):
...```

In this function, we’re choosing a random amount of enemies to place, between 0 and the maximum we specify. Then, we take a random x and y, and, if no other monster is currently at that location, we place a monster there. There’s an 80% chance of it being an Orc, and a 20% chance of it being a Troll.

We’ll need to import both `libtcod` and the `Entity` class.

``````+import tcod as libtcod
from random import randint

+from entity import Entity
from map_objects.rectangle import Rect
from map_objects.tile import Tile
``````
```import tcod as libtcod
from random import randint

from entity import Entity
from map_objects.rectangle import Rect
from map_objects.tile import Tile```

Now let’s modify our `make_map` function to include the `place_entities` function.

``````                       ...
self.create_h_tunnel(prev_x, new_x, new_y)

+               self.place_entities(new_room, entities, max_monsters_per_room)

rooms.append(new_room)
...
``````
```                        ...
self.create_h_tunnel(prev_x, new_x, new_y)

self.place_entities(new_room, entities, max_monsters_per_room)

rooms.append(new_room)
...```

Because we now need the `entities` and `max_monsters_per_room` variables, we should modify our `make_map` function definition to include them.

``````-   def make_map(self, max_rooms, room_min_size, room_max_size, map_width, map_height, player):
+   def make_map(self, max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities,
+                max_monsters_per_room):
``````
```    def make_map(self, max_rooms, room_min_size, room_max_size, map_width, map_height, player):
def make_map(self, max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities,
max_monsters_per_room):```

We’re all set up here; now we have to modify `engine.py` to match this new `make_map` function. Also, we’ll need to create the `max_room_per_monsters` variable before calling the function. Finally, we’ll change our `entities` list to include only the player at first, and we’ll completely remove our dummy NPC from before.

``````   ...

+   max_monsters_per_room = 3

colors = {
'dark_wall': libtcod.Color(0, 0, 100),
'dark_ground': libtcod.Color(50, 50, 150),
'light_wall': libtcod.Color(130, 110, 50),
'light_ground': libtcod.Color(200, 180, 50)
}

-   player = Entity(int(screen_width / 2), int(screen_height / 2), '@', libtcod.white)
-   npc = Entity(int(screen_width / 2 - 5), int(screen_height / 2), '@', libtcod.yellow)
-   entities = [npc, player]
+   player = Entity(0, 0, '@', libtcod.white)
+   entities = [player]

libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD)

libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial revised', False)

con = libtcod.console_new(screen_width, screen_height)

game_map = GameMap(map_width, map_height)
-   game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player)
+   game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room)

fov_recompute = True
...
``````
```    ...

max_monsters_per_room = 3

colors = {
'dark_wall': libtcod.Color(0, 0, 100),
'dark_ground': libtcod.Color(50, 50, 150),
'light_wall': libtcod.Color(130, 110, 50),
'light_ground': libtcod.Color(200, 180, 50)
}

player = Entity(int(screen_width / 2), int(screen_height / 2), '@', libtcod.white)
npc = Entity(int(screen_width / 2 - 5), int(screen_height / 2), '@', libtcod.yellow)
entities = [npc, player]
player = Entity(0, 0, '@', libtcod.white)
entities = [player]

libtcod.console_set_custom_font('arial10x10.png', libtcod.FONT_TYPE_GREYSCALE | libtcod.FONT_LAYOUT_TCOD)

libtcod.console_init_root(screen_width, screen_height, 'libtcod tutorial revised', False)

con = libtcod.console_new(screen_width, screen_height)

game_map = GameMap(map_width, map_height)
game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player)
game_map.make_map(max_rooms, room_min_size, room_max_size, map_width, map_height, player, entities, max_monsters_per_room)

fov_recompute = True
...```

Run the project now, and you should see some orcs and trolls beginning to populate our dungeon!

One obvious issue with our newly created monsters (you know, besides the fact that they just sit there lifelessly) is that the player can just walk right through them. Unless you’re planning on making a game about a ghost walking through monsters and possessing them (doesn’t sound like a bad idea actually!), this isn’t what we want; if the player “moves into” an enemy, we should attack!

One might think that we can just check if we’re moving into an Entity, and attack it if we are, but we actually do want some Entities to not block movement. Why? Because we’ll be using that same Entity class to represent items, and we’ll want to be able to move over those and pick them up. So it seems we need a class attribute that tells us if the Entity “blocks” our movement or not.

Let’s modify the `Entity` class to include the “blocks” variable. While we’re modifying this class, we should also pass in a “name” for the Entity, which will be useful a little later.

``````class Entity:
-   def __init__(self, x, y, char, color):
+   def __init__(self, x, y, char, color, name, blocks=False):
self.x = x
self.y = y
self.char = char
self.color = color
+       self.name = name
+       self.blocks = blocks

def move(self, dx, dy):
...
``````
```class Entity:
def __init__(self, x, y, char, color):
def __init__(self, x, y, char, color, name, blocks=False):
self.x = x
self.y = y
self.char = char
self.color = color
self.name = name
self.blocks = blocks

def move(self, dx, dy):
...```

Notice that “blocks” is optional; if we don’t pass it on initialization, it will be False by default.

Go back to `game_map.py` and modify the `place_entities` method, where we declare our monsters.

``````           if randint(0, 100) < 80:
-               monster = Entity(x, y, 'o', libtcod.desaturated_green)
+               monster = Entity(x, y, 'o', libtcod.desaturated_green, 'Orc', blocks=True)
else:
-               monster = Entity(x, y, 'T', libtcod.darker_green)
+               monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True)
``````
```            if randint(0, 100) < 80:
monster = Entity(x, y, 'o', libtcod.desaturated_green)
monster = Entity(x, y, 'o', libtcod.desaturated_green, 'Orc', blocks=True)
else:
monster = Entity(x, y, 'T', libtcod.darker_green)
monster = Entity(x, y, 'T', libtcod.darker_green, 'Troll', blocks=True)```

We also need to update the initialization of the player in `engine.py`:

``````-   player = Entity(0, 0, '@', libtcod.white)
+   player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True)
``````
```    player = Entity(0, 0, '@', libtcod.white)
player = Entity(0, 0, '@', libtcod.white, 'Player', blocks=True)```

With our new attribute in place, we need to make a check if a blocking entity is in the way when we try to move into a tile. One thing that will definitely help is a function to get a “blocking” entity in a tile, given the list of entities and the x and y coordinates. We’ll put this function in `entity.py`, but not in the `Entity` class itself. The reasoning is that it’s a function that relates to the entities, but it doesn’t relate to a specific Entity, so it doesn’t need to belong to the class.

Add the function to `entity.py` like this:

``````class Entity:
...

+def get_blocking_entities_at_location(entities, destination_x, destination_y):
+   for entity in entities:
+       if entity.blocks and entity.x == destination_x and entity.y == destination_y:
+           return entity
+
+   return None
``````
```class Entity:
...

def get_blocking_entities_at_location(entities, destination_x, destination_y):
for entity in entities:
if entity.blocks and entity.x == destination_x and entity.y == destination_y:
return entity

return None```

The function loops through the entities, and if one of them is “blocking” and is at the x and y location we specified, we return it. If none of them match, then we return “None” instead. Note that the function is assuming that only one “blocking” entity will be at each location; this should be fine, as we’ll make sure two entities can’t move into the same tile.

With that in place, let’s return to our movement function. Modify the code that moves the player in `engine.py` like this:

``````       if move:
dx, dy = move

-           player.move(dx, dy)
-
-           fov_recompute = True

+           destination_x = player.x + dx
+           destination_y = player.y + dy

-           if not game_map.is_blocked(player.x + dx, player.y + dy):
+           if not game_map.is_blocked(destination_x, destination_y):
+               target = get_blocking_entities_at_location(entities, destination_x, destination_y)
+
+               if target:
+                   print('You kick the ' + target.name + ' in the shins, much to its annoyance!')
+               else:
+                   player.move(dx, dy)
+
+                   fov_recompute = True
``````
```        if move:
dx, dy = move
destination_x = player.x + dx
destination_y = player.y + dy

if not game_map.is_blocked(player.x + dx, player.y + dy):
if not game_map.is_blocked(destination_x, destination_y):
target = get_blocking_entities_at_location(entities, destination_x, destination_y)

if target:
print('You kick the ' + target.name + ' in the shins, much to its annoyance!')
else:
player.move(dx, dy)

fov_recompute = True
```

Also be sure to import the function `get_blocking_entities_at_location` at the top of `engine.py`.

``````-   from entity import Entity
+   from entity import Entity, get_blocking_entities_at_location
``````
`from entity import Entity, get_blocking_entities_at_location`

Now the player gets blocked when trying to move through another entity. We’re putting that humorous (hey, I think it’s funny!) print statement as a placeholder, for the moment. We’ll implement real combat in the next chapter.

Our player should only be able to move during their turn, and the same applies for the monsters. We’ll need a variable to keep track of whose turn it actually is. We could store a string in this variable, say, ‘players_turn’ and ’enemy_turn’, but that seems error prone. If you happen to mistype one of those strings, you’ll end up with some bugs. Not to mention our number of game states will inevitably grow, and we’ll need a better way to keep track of them all.

Let’s keep the game states in an Enum. An “Enum” is a set of named values that won’t change, so it’s perfect for things like game states. Create a new file called `game_states.py` and put the following class in it:

``````from enum import Enum

class GameStates(Enum):
PLAYERS_TURN = 1
ENEMY_TURN = 2``````

This will make our game state switching much easier to manage, especially in the future when we have more than two.

* Note: The numbers for the states don’t necessarily mean anything. In fact, if you’re using Python 3.6 or higher, you can use the ‘auto’ feature to just increment the number for you. Check it out if you’re able to.

Let’s put this new `GameStates` enum into action. Start by importing it at the top.

``````...
from fov_functions import initialize_fov, recompute_fov
+from game_states import GameStates
from input_handlers import handle_keys
...
``````
```...
from fov_functions import initialize_fov, recompute_fov
from game_states import GameStates
from input_handlers import handle_keys
...```

Then, create a variable called `game_state`, which we’ll set initially to the player’s turn.

``````   ...
mouse = libtcod.Mouse()

+   game_state = GameStates.PLAYERS_TURN

while not libtcod.console_is_window_closed():
...
``````
```    ...
mouse = libtcod.Mouse()

game_state = GameStates.PLAYERS_TURN

while not libtcod.console_is_window_closed():
...```

Depending on whether or not its the players turn, we want to control the player’s movement. The player can only move on the players turn, so let’s modify our `if move:` section to handle this. After the player successfully moves, we’ll set the state to `ENEMY_TURN`.

``````-       if move:
+       if move and game_state == GameStates.PLAYERS_TURN:
dx, dy = move
destination_x = player.x + dx
destination_y = player.y + dy

if not game_map.is_blocked(destination_x, destination_y):
target = get_blocking_entities_at_location(entities, destination_x, destination_y)

if target:
print('You kick the ' + target.name + ' in the shins, much to its annoyance!')
else:
player.move(dx, dy)

fov_recompute = True

+               game_state = GameStates.ENEMY_TURN
``````
```        if move:
if move and game_state == GameStates.PLAYERS_TURN:
dx, dy = move
destination_x = player.x + dx
destination_y = player.y + dy

if not game_map.is_blocked(destination_x, destination_y):
target = get_blocking_entities_at_location(entities, destination_x, destination_y)

if target:
print('You kick the ' + target.name + ' in the shins, much to its annoyance!')
else:
player.move(dx, dy)

fov_recompute = True

game_state = GameStates.ENEMY_TURN```

If you run the project now, the player will be able to move once… and then get stuck forever. That’s because we need to implement the enemy’s moves, and set the `game_state` back to the player’s turn afterwards. Note that you can exit the game and make it full screen, because we’re not stopping the player from doing those things when it isn’t the player’s turn.

``````       ...
if fullscreen:
libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen())

+       if game_state == GameStates.ENEMY_TURN:
+           for entity in entities:
+               if entity != player:
+                   print('The ' + entity.name + ' ponders the meaning of its existence.')
+
+           game_state = GameStates.PLAYERS_TURN
``````
```        ...
if fullscreen:
libtcod.console_set_fullscreen(not libtcod.console_is_fullscreen())

if game_state == GameStates.ENEMY_TURN:
for entity in entities:
if entity != player:
print('The ' + entity.name + ' ponders the meaning of its existence.')

game_state = GameStates.PLAYERS_TURN```

This is simple enough. Assuming it’s the enemy turn, we’re looping through each of the entities (excluding the player) and allowing them to take a turn. Right now, we don’t have any AI in place for our enemies, so they’ll just sit there contemplating their lives for now. In the next chapter, we’ll give them some more interesting behavior, but for now, this works as a placeholder.

If you want to see the code so far in its entirety, click here.

Click here to move on to the next part of this tutorial.