MI Python Text Adventure RPG Tutorial 3 |Battle System and Inventory Management

REPL HERE:

https://repl.it/@MANDREWS85/pythontextadventuretutorial3#main.py

PLAY IT:

https://pythontextadventuretutorial3.mandrews85.repl.run

Lets start writing out our battle method in our Game class today. We are passing in an attacker and a defender as arguments for our text adventure RPG battle method in Python. Lets explore nested functions while we are at it as well. I wanted to have nested functions in my battle method to better organize. There is an initiative function, and a to_hit function. The initiative function determines who attacks first. Then the to hit function resolves the to hit phase and damage. These are nested functions local to our Game.battle() method so have no scope outside of this method.


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def battle(self,attacker,defender):

    def initative(attacker,defender):
      ###   INITIATIVE PHASE
      if attacker.roll_die(100) + (attacker.dex/5) >= defender.roll_die(100) + (defender.dex/5):
        print(attacker.name + " HAS INITIATIVE")
        ###  ATTACKER ATTACK PHASE
        to_hit(attacker,defender)
      else:
        print( defender.name + " HAS INITATIVE ")
        ###   DEFENDER ATTACK PHASE
        to_hit(defender,attacker)
     

    def to_hit(attacker,defender):
      print(attacker.name + " IS ATTACKING " + defender.name)

      if attacker.roll_die(100) >= defender.roll_die(100):
        print(attacker.name + " HITS " + defender.name )
        defender.hp -= attacker.dmg
        print(attacker.name + " DOES " + str(attacker.dmg) + " DAMAGE")
        print(defender.name + " NOW HAS " + str(defender.hp) + " HP")
      else:
        print(attacker.name + " MISSES " + defender.name)

    ###    RUN BATTLE
    initative(attacker,defender)

Update our battle method with the above code and we should be able to move N one space and fight the orc peons in the peon room. When we do eventually kill the peons they don’t drop there loot and are still in the room enemies list. Lets fix that.

We will remove the enemy’s from the Room’s enemies list. then we will append the enemy’s items, weapons and armor into the Room’s corresponding lists. Lets make a queue free method for out Character class. This will be called when the characters hp are less then 0. The Character will then remove it’s self from the Room’s list and append it’s items,weapons and armor to the Room’s list’s.

Then lets add a queue_free method to our Character class. This will be called when hp’s reach 0 in the Game battle method.

CHARACTER MODULE:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
    ###   QUE CHARACTERS FREE
  def queue_free(self,enemy,room):
    print(self.name + " IS DEAD ")

    for item in enemy.items:
      enemy.items.remove(item)
      room.items.append(item)

    for weapon in enemy.weapons:
      enemy.weapons.remove(weapon)
      room.weapons.append(weapon)
     
    for armor in enemy.armors:
      enemy.armors.remove(armor)
      room.armors.append(armor)
   
    room.enemies.remove(enemy)

Now lets add a pick up and drop function to our Player class. I think this is a good use case for nested functions. Lets create an inventory method for our player and nest a pick_up and drop function. The inventory method will encapsulate the nested functions within to better organize the structure.

In the below code we initialize our inventory method with self and the current room passed in from the Game grid method as arguments. Then we instantiate the inventory method in the main.py file within the Game grid method. The Game grid method passes in the room as the argument for the Player inventory method.

We define our first nested function, pick_up. For our pick_up function, we pass in a room object list and a player object list. These are simply the Room and Player: items, weapons and armors lists. When we instantiate the pick_up function within the inventory method. Later we pass in which Room list and which Player list to pick_up from. The pick up method loops through the room object list passed in (items,weapons or armors). If there is an object in the object list and the length of the enemies list is 0 (no enemies in the room). The Player is given the option to pick_up. If the user imputes “P” the Player picks up the object at index 0 of the passed in list. Other wise we pass.

The second nested function within our inventory method is the drop function. Here we give the user some options. Drop an item, weapon or armor. “I”, “W”,”A” respectively. If user input is “I”,”W”, or “A” the Player corresponding list is looped through and the object is removed. The object is then appended to the current Room list. If the user imputes something other then the above strings. The statement passes.

Finally we have our inventory options printed. If the user input is a “P” or a “D”. The corresponding nested function is called, pick_up or drop. For the pick_up function we pass in the room from the parent inventory method. We also pass in the room object list type (items ,weapons or armors) along with the Players corresponding list type. For the drop function we are just passing in the room from the parent method.

PLAYER MODULE:


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
def inventory(self,room):
   
    def pick_up(room_obj_list,player_obj_list):
      for obj in room_obj_list:  
        if obj in room_obj_list and len(room.enemies) == 0:
          print("(P)ICK UP?")
          user_input = self.user_input()
          if user_input == "P":
           
              print(self.name + " PICKS UP " + obj.name )
              room_obj_list.remove(obj)
              player_obj_list.append(obj)
           
        else:
          pass
         

    def drop(room):
      print("DROP (I)TEM | (W)EAPON | (A)RMOR ")
      user_input = self.user_input()
      if user_input == "I":
        print("DROPPING ITEM")
        for item in self.items:
          print("DROPPING " + item.name)
          self.items.remove(item)
          room.items.append(item)

       
      elif user_input == "W":
        print("DROPPING WEAPON")
       
      elif user_input == "A":
        print("DROPPING ARMOR")
       
      else:
        pass


     
    print("INVENTORY OPTIONS (P)ICK UP | (D)ROP | (ENTER) TO RETURN")
    user_input = self.user_input()

    if user_input == "P":
      pick_up(room.items,self.items)
      pick_up(room.weapons,self.weapons)
      pick_up(room.armors,self.armors)
    elif user_input == "D":
      drop(room)
    else:
      print("GOING BACK TO MOVEMENT MENU")

Lets run our Python txt adventure / RPG. Create the Player. Then try (“L”)ooking. You should see the friendly wizard in the 0,0 position of the grid. Try moving South. The gem room is at grid position 0,-1. Try looking here. The pick up and drop functions should be printed out. Pick up some gems. Move North, look and try dropping some gems. You should see the rooms status being updated with the new items upon terminal refresh. Move North once more to grid position 0,1. Fight the orc peons and try to steal their gems…

What did we learn so far?

We have basic player generation with our Player create method. We have 2d grid based movement. We did this with a 1 dimensional list that contains objects with properties in our Game grid method. Room’s have an x and y property for placement on the “grid”. Each of these Room objects has other objects: items, weapons, armors in list attributes. Our battle method within our Game class handles combat. When Player and enemy Character positional arguments are equal. A Battle ensues. Our user can pick up and drop game objects in each rooms object lists.

Next time lets clean up our user interface and add some ascii graphics to our Python RPG text adventure. Lets also implement our experience and gold system. Then a random function for the game grid when the player is not on a specific room. Maybe we should add a quest system along with a store to sell our items aswell?

FILES ARE HERE:

https://repl.it/@MANDREWS85/pythontextadventuretutorial3#main.py

Related posts