Hello everyone, I am following a guide that is for an RPG Game. It's titled, 'How to Write a Text Adventure in Python'
I have finished the tutorial and have fixed most of the errors I was receiving, now I am stuck on this one. Any help is appreciated, thank you!
Directory Hierarchy
You play the game by running the game.py file. That is the module that contains the overall game-loopu!. I hope that this tutorial is teaching me a good practice in OOP programming with Python 3. I could really use advice on anything I may have done wrong or could do better with a link or reference to the material / documentation so I can start learning. I have no problem studying! I appreciate any feedback from anyone willing to take the time, I know these things are free contribution. I will provide reputation to the person who helps me out!
Here is the python code to all the files.
actions.py
I have finished the tutorial and have fixed most of the errors I was receiving, now I am stuck on this one. Any help is appreciated, thank you!
Traceback (most recent call last): File "C:\*\rpggame\game.py", line 26, in <module> play() File "C:\*\rpggame\game.py", line 5, in play world.load_tiles() File "C:\*\rpggame\world.py", line 13, in load_tiles tile_name = cols[x].replace('\n', '') # Windows users may need to replace '\r\n' IndexError: list index out of rangeI shortened the file path so that it's easier to read. This is the structure of the file system.
Directory Hierarchy
Quote:|->Learning-Py Projects
--|->rpggame
----|->__pycache__
----|->resources
----|__init__.py
----|actions.py
----|enemies.py
----|game.py
----|items.py
----|player.py
----|tiles.py
----|world.py
You play the game by running the game.py file. That is the module that contains the overall game-loopu!. I hope that this tutorial is teaching me a good practice in OOP programming with Python 3. I could really use advice on anything I may have done wrong or could do better with a link or reference to the material / documentation so I can start learning. I have no problem studying! I appreciate any feedback from anyone willing to take the time, I know these things are free contribution. I will provide reputation to the person who helps me out!
Here is the python code to all the files.
actions.py
from player import Player class Action(): def __init__(self, method, name, hotkey, **kwargs): self.method = method self.hotkey = hotkey self.name = name self.kwargs = kwargs def __str__(self): return "{}: {}".format(self.hotkey, self.name) class MoveNorth(Action): def __init__(self): super().__init__(method=Player.move_north, name='Move North', hotkey='n') class MoveSouth(Action): def __init__(self): super().__init__(method=Player.move_north, name='Move South', hotkey='s') class MoveEast(Action): def __init__(self): super().__init__(method=Player.move_north, name='Move East', hotkey='e') class MoveWest(Action): def __init__(self): super().__init__(method=Player.move_north, name='Move West', hotkey='w') class ViewInventory(Action): """Prints the player's inventory""" def __init__(self): super().__init__(method=Player.print_inventory, name='View Inventory', hotkey='i') class Attack(Action): def __init__(self, enemy): super().__init__(method=Player.attack, name="Attack", hotkey="a", enemy=enemy) class Flee(Action): def __init__(self, tile): super().__init__(method=Player.flee, name="Flee", hotkey="f", tile=tile)enemies.py
class Enemy: 'Base class for all mobs: \'Enemy\' class' def __init__(self, name, hp, damage): self.name = name self.hp = hp self.damage = damage def is_alive(self): return self.hp > 0 class GiantSpider(Enemy): def __init__(self): super().__init__(name="Giant Spider", hp=10, damage=2) class Ogre(Enemy): def __init__(self): super().__init__(name="Ogre", hp=30, damage=15)game.py
import world import player def play(): world.load_tiles() player = Player() #These lines load the starting room and display the text. room = world.tile_exists(player.location_x, player.location_y) print(room.intro_text()) while player.is_alive() and not player.victory: room = world.tile_exists(player.location_x, player.location_y) room.modify_player(player) #Check again since the room could have changed the player's state if player.is_alive() and not player.victory: print("Choose an action:\n") available_actions = room.available_actions() for action in available_actions: print(action) action_input = input('[CommandLine] >>> ') for action in available_actions: if action_input == action.hotkey: player.do_action(action, **action.kwargs) break if __name__ == "__main__": play()items.py
class Item(): 'The base class for all items' def __init__(self, name, description, value): self.name = name self.description = description self.value = value def __str__(self): return ('Name: {}\nDescription: {}\nValue: {}\n'.format(self.name, self.description, self.value)) class Weapon(Item): 'This is a subclass of Item: A class for all Weapons' def __init__(self, name, description, value, damage): self.damage = damage super().__init__(name, description, value) def __str__(self): return("Name: {}\nDescription: {}\nValue: {}\nDamage: {}\n".format(self.name, self.description, self.value, self.damage)) class Rock(Weapon): 'class for Weapon: Rock' def __init__(self): super().__init__(name = 'Rock', description = 'A fist-sized rock, suitable for bludgeoning.', value = 0, damage = 2.5) class Dagger(Weapon): def __init__(self): super().__init__(name = "Dagger", description = "A dull dagger with some rust. It's better than nothing..", value = 20, damage = 4.0) class Gold(Item): 'This is the \'GoldCoin\' class' def __init__(self, amt): self.amt = amt super().__init__(name = 'Gold', description = 'A loot of \'Gold Coins\'. This is certainly a valuable stash.', value = self.amt)player.py
import random import items, world class Player(): def __init__(self): self.inventory = [items.Gold(random.randrange(0, 100)), items.Rock()] self.hp = random.randrange(100, 300) self.location_x, self.location_y = world.starting_position self.victory = False def flee(self, tile): """Moves the player randomly to an adjacent tile""" available_moves = tile.adjacent_moves() r = random.randint(0, len(available_moves) - 1) self.do_action(available_moves[r]) def is_alive(self): return self.hp > 0 def print_inventory(self): for item in self.inventory: print(item, '\n') def move(self, dx, dy): self.location_x += dx self.location_y += dy print(world.tile_exists(self.location_x, self.location_y).intro_text()) def move_north(self): self.move(dx=0, dy=-1) def move_south(self): self.move(dx=0, dy=1) def move_east(self): self.move(dx=1, dy=0) def move_west(self): self.move(dx=-1, dy=0) def attack(self, enemy): best_weapon = None max_dmg = 0 for i in self.inventory: if isinstance(i, items.Weapon): if i.damage > max_dmg: max_dmg = i.damage best_weapon = i def do_action(self, action, **kwargs): action_method = getattr(self, action.method.__name__) if action_method: action_method(**kwargs) print("You use {} against {}!".format(best_weapon.name, enemy.name)) enemy.hp -= best_weapon.damage if not enemy.is_alive(): print("You killed {}!".format(enemy.name)) else: print("Opponent: {}\nHit Point's Left: {}.".format(enemy.name, enemy.hp))tiles.py
import items, enemies, actions, world class MapTile: def __init__(self, x, y): self.x = x self.y = y def intro_text(self): raise NotImplementedError() def modify_player(self, player): raise NotImplementedError() def adjacent_moves(self): """ Returns all move actions for adjacent tiles.""" moves = [] if world.tile_exists(self.x + 1, self.y): moves.append(actions.MoveEast()) if world.tile_exists(self.x - 1, self.y): moves.append(actions.MoveWest()) if world.tile_exists(self.x, self.y - 1): moves.append(actions.MoveNorth()) if world.tile_exists(self.x, self.y + 1): moves.append(actions.MoveSouth()) return moves def available_actions(self): """Returns alll of the available actions in this room.""" moves = self.adjacent_moves() moves.append(actions.ViewInventory()) return moves class LeaveCaveRoom(MapTile): def intro_text(self): return """ You see a bright light in the distance... ... it grows as you get closer! It's sunlight! Victory is yours! """ def modify_player(self, player): player.victory = True class StartingRoom(MapTile): def intro_text(self): return """ You come into conciousness.. Awakened by the sudden drops of rain falling from the midnight sky. You check the time.. The time is: 3:12 A.M What happened? Your character is confused and still soaked of ale from the previous evening. Note: It seems you were knocked unconcious. While you were out all your possesions were stolen. You are left with nothing but the clothes on your back. """ def modify_player(self, player): #Room has no action on player pass class LootRoom(MapTile): def __init__(self, x, y, item): self.item = item super().__init__(x, y) def add_loot(self, player): player.inventory.append(self.item) def modify_player(self, player): self.add_loot(player) class EnemyRoom(MapTile): def __init__(self, x, y, enemy): self.enemy = enemy super().__init__(x, y) def modify_player(self, the_player): if self.enemy.is_alive(): the_player.hp = the_player.hp - self.enemy.damage print("Enemy does {} damage. You have {} HP remaining.".format(self.enemy.damage, the_player.hp)) def available_actions(self): if self.enemy.is_alive(): return [actions.Flee(tile=self), actions.Attack(enemy=self.enemy)] else: return self.adjacent_moves() class EmptyCavePath(MapTile): def intro_text(self): return """ Another unremarkable part of the cave. You must forge onwards. """ def modify_player(self, player): #Room has no action on player pass class GiantSpiderRoom(EnemyRoom): def __init__(self, x, y): super().__init__(x, y, enemies.GiantSpider()) def intro_text(self): if self.enemy.is_alive(): return """ A giant spider jumps down from its web in front of you! """ else: return """ The corpse of a dead spider rots on the ground. """ class FindDaggerRoom(LootRoom): def __init__(self, x, y): super().__init__(x, y, items.Dagger()) def intro_text(self): return """ Your notice something shiny in the corner. It's a dagger! You pick it up. """world.py
_world = {} starting_position = (0, 0) def load_tiles(): """Parses a file that describes the world space into the _world object""" with open('resources/map.txt', 'r') as f: rows = f.readlines() x_max = len(rows[0].split('\t')) # Assumes all rows contain the same number of tabs. for y in range(len(rows)): cols = rows[y].split('\t') for x in range(x_max): tile_name = cols[x].replace('\n', '') # Windows users may need to replace '\r\n' if tile_name == 'StartingRoom': global starting_position starting_position = (x, y) _world[(x, y)] = None if tile_name == '' else getattr(__import__('tiles'), tile_name)(x, y) def tile_exists(x, y): return _world.get((x, y))