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.pyclass 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.pyimport 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.pyclass 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.pyimport 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.pyimport 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))
