Member Avatar for Mouche

Zonr and I have been working on a fun text game containing different rooms, monsters (with a D&D-esque battle system), and save/load functions.

Here are the files. You need to have all of them for it to work correctly:

www.glenwinters.com/RPG/RPG_jan20.py
www.glenwinters.com/RPG/data.txt
www.glenwinters.com/RPG/Glen.txt
www.glenwinters.com/RPG/George.txt

Here's the main code:

import random
import cPickle
# Load file_list
try:    
    f = open("data.txt","r")
    file_list = cPickle.load(f)
    f.close()
except EOFError: # If data.txt is empty and cannot load
    file_list = []
 
# Room class
class Room(object):
    def __init__(self,name,description):
        self.name = name
        self.description = description
        self.north = 0
        self.east  = 0
        self.south = 0
        self.west  = 0
        # possible list of monsters in room,monster in room
        self.current_monster = None
        self.monster_probability = 0
        self.possible_monsters_names = []
# Create rooms
bedroom = Room("bedroom","You are in a bedroom. You can go NORTH, EAST, or SOUTH.")
garden = Room("garden","You are in a garden. You can go NORTH or EAST.")
pathway = Room("pathway","You are on a pathway. You can go WEST or EAST.")
open_area = Room("open area","You are in an open area. You can go WEST or NORTH. The open area expands to the SOUTH.")
study = Room("study","You are in your private study. You can go WEST.")
cliff = Room("cliff", "You are in an open area that ends in a steep cliff on the south side. There seems to be a small rocky path to the WEST.")
rocky_path = Room("rocky path","You are on a narrow cliff winding down the side of the cliff to the south. Be careful not to fall! The top of the cliff is to the EAST. There is a small cave to the WEST.")
hallway = Room("hallway","You are in a long fancy hallway outside your bedroom. There are doors to the west, north, and east (but they're locked). Your room is to the SOUTH.")
cave = Room("cave","You are in a dark cave. You can go EAST back to the rocky path.")
# These room variables point to the same instance!
# After a room changes, these don't have to be updatesd.
bedroom.north = hallway
bedroom.east = study
bedroom.south = garden
bedroom.west = 0
garden.north = bedroom
garden.east = pathway
garden.south = 0
garden.west = 0
pathway.north = 0
pathway.east = open_area
pathway.south = 0
pathway.west = garden
open_area.north = 0
open_area.east = 0
open_area.south = cliff
open_area.west = pathway
study.north = 0
study.east = 0
study.south = 0
study.west = bedroom
hallway.north = 0
hallway.east = 0
hallway.south = bedroom
hallway.west = 0
cliff.north = open_area
cliff.east = 0
cliff.south = 0
cliff.west = rocky_path
rocky_path.north = 0
rocky_path.east = cliff
rocky_path.south = 0
rocky_path.west = cave
cave.north = 0
cave.east = rocky_path
cave.south = 0
cave.west = 0
# Room monster control
# bedroom
bedroom.possible_monsters_names = None
bedroom.current_monster = None
bedroom.monster_probability = 0
garden.possible_monsters_names = ["rat"]
garden.current_monster = None
garden.monster_probability = 10
pathway.possible_monsters_names = ["rat"]
pathway.current_monster = None
pathway.monster_probability = 10
open_area.possible_monsters_names = ["rat"]
open_area.current_monster = None
open_area.monster_probability = 10
study.possible_monsters_names = None
study.current_monster = None
study.monster_probability = 0
hallway.possible_monsters_names = None
hallway.current_monster = None
hallway.monster_probability = 0
cliff.possible_monsters_names = ["rat","goblin"]
cliff.current_monster = None
cliff.monster_probability = 10
rocky_path.possible_monsters_names = ["goblin"]
rocky_path.current_monster = None
rocky_path.monster_probability = 20
cave.possible_monsters_names = ["troll"]
cave.current_monster = None
cave.monster_probability = 1
# Monster class
class Monster(object):
    def __init__(self,name,level,strength,ac,hp,dex,give_exp,run_probability):
        self.name = name
        self.level = level
        self.str = strength
        self.ac = ac
        self.hp = hp
        self.dex = dex
        self.give_exp = give_exp
        self.run_probability = 10 # 90% of running is default
# Monster models (name,level strength, ac, hitpoints in form (mix,max), dex, give_exp,run_probability)
rat =    (   "rat", 1, 1, 7 ,(5 ,10), 0, 5 , 10)
goblin = ("goblin", 2, 2, 12,(16,16), 0, 10, 5 )
troll =  ( "troll", 5, 4, 16,(60,60),-1, 30, 2 )
# Character class
class Character(object):
    def __init__(self,name):
        self.name = name
        self.level = 1
        self.exp = 0
        self.location = bedroom
        self.str = 0
        self.ac = 0
        self.max_hp = 0
        self.hp = 0
        self.dex = 0
        self.update_stats()
        self.current_weapon = fists
    def update_stats(self):
        self.str = eval("level" + str(self.level))[0]
        self.ac = eval("level" + str(self.level))[1]
        self.hp = eval("level" + str(self.level))[2]
        self.max_hp = eval("level" + str(self.level))[2]
        self.dex = eval("level" + str(self.level))[3]
 
    def level_up(self):
        if self.level < 10:
            while self.exp >= 25:
                self.level += 1
                self.exp -= 25
                self.update_stats()
                print "LEVEL UP!"
                print \
'''
NEW STATS
Level:       %s
Strength:    %s
Armor Class: %s
Hit Points:  %s
Dexterity:    %s 
''' % (self.level,self.str,self.ac,self.hp,self.dex)
        else:
            print "You can't level any higher. 10 is the max."
 
# Char level models [str,ac,hp,dex]
level1  =  [1,10,12,0]
level2  =  [1,10,19,0]
level3  =  [2,11,26,0]
level4  =  [2,11,33,0]
level5  =  [3,12,40,0]
level6  =  [3,12,47,0]
level7  =  [4,13,54,0]
level8  =  [4,13,61,0]
level9  =  [5,14,68,0]
level10 =  [6,15,75,0]
#level11 =  [500,20,2000,0] for fun... *shifty eyes*
class Weapon(object):
    def __init__(self,name,roll):
        self.name = name
        self.roll = roll
    def attack(self):
        dice_numbers = self.roll.split("d")
        dice_count = int(dice_numbers[0])
        dice_sides = int(dice_numbers[1])
        total_damage = 0
        for i in range(dice_count):
            total_damage += random.randrange(1,dice_sides+1)
        return total_damage + currentchar.str
# Default weapon
fists = Weapon("Fists","1d6")
# Prototypes
dagger = ("Dagger","1d6")
def create_monster():
    #print "CHECK: ", currentchar.location.current_monster
    if not currentchar.location.current_monster and currentchar.location.possible_monsters_names and currentchar.location.monster_probability != 0:
        ifmonster = random.randrange(1,currentchar.location.monster_probability+1) # Pick a number between 1 and 10
        #print "CHECK: ", ifmonster
        if ifmonster == 1:
            new_monster_name = random.choice(currentchar.location.possible_monsters_names)
            # evalutes new_monster_name (string) to the variable that contains the monster's attributes
            new_monster = Monster(eval(new_monster_name)[0],eval(new_monster_name)[1],eval(new_monster_name)[2],eval(new_monster_name)[3],random.randrange(eval(new_monster_name)[4][0],eval(new_monster_name)[4][1]+1),eval(new_monster_name)[5],eval(new_monster_name)[6],eval(new_monster_name)[7])
            currentchar.location.current_monster = new_monster
            print "There is a %s in the room." % (new_monster.name)
            #print "CHECK: It has %d strength, %d AC, %d hitpoints." % (new_monster.str,new_monster.ac,new_monster.hp)
def see_if_fight():
    fight_yn = "none"
    while fight_yn not in ("y","n"):
        fight_yn = raw_input("Do you want to fight it? (y/n) ").lower()
    if fight_yn == "y":
        return battle()
def enter_room(direction):
    results = "none"
    if direction == "n":
        if currentchar.location.north:
            currentchar.location = currentchar.location.north
            print currentchar.location.description
            if currentchar.location.current_monster:
                print "There is a %s in the room." % (currentchar.location.current_monster.name)
                results = see_if_fight()
                if results == "won": # If just battled, print description of room
                    print currentchar.location.description
            else:
                create_monster()
            if currentchar.location.current_monster:
                results = see_if_fight()
                if results == "won":
                    print currentchar.location.description
        else:
            print "You cannot move north."
            print currentchar.location.description
    elif direction == "e":
        if currentchar.location.east:
            currentchar.location = currentchar.location.east
            print currentchar.location.description
            if currentchar.location.current_monster:
                print "There is a %s in the room." % (currentchar.location.current_monster.name)
                results = see_if_fight()
                if results == "won":
                    print currentchar.location.description
            else:
                create_monster()
            if currentchar.location.current_monster:
                results = see_if_fight()
                if results == "won":
                    print currentchar.location.description
        else:
            print "You cannot move east."
            print currentchar.location.description
    elif direction == "s":
        if currentchar.location.south:
            currentchar.location = currentchar.location.south
            print currentchar.location.description
            if currentchar.location.current_monster:
                print "There is a %s in the room." % (currentchar.location.current_monster.name)
                results = see_if_fight()
                if results == "won":
                    print currentchar.location.description
            else:
                create_monster()
            if currentchar.location.current_monster:
                results = see_if_fight()
                if results == "won":
                    print currentchar.location.description
        else:
            print "You cannot move south."
            print currentchar.location.description
    elif direction == "w":
        if currentchar.location.west:
            currentchar.location = currentchar.location.west
            print currentchar.location.description
            if currentchar.location.current_monster:
                print "There is a %s in the room." % (currentchar.location.current_monster.name)
                results = see_if_fight()
                if results == "won":
                    print currentchar.location.description
            else:
                create_monster()
            if currentchar.location.current_monster:
                results = see_if_fight()
                if results == "won":
                    print currentchar.location.description
        else:
            print "You cannot move west."
            print currentchar.location.description
        if currentchar.location == bedroom:
            print "There is a bed in the corner of the room."
            heal = "none"
            while heal not in ("y","n"):
                heal = raw_input("Would you like to rest and heal? (y/n) ").lower()
            if heal == "y":
                print "You take a nap.\nYour health is replenished!"
                currentchar.hp = currentchar.max_hp
    if results == "none":
        heal_monsters()
    return results
def roll_1d20():
    return random.randrange(1,20+1)
def roll_1d6():
    return random.randrange(1,6+1)
def who_first():
    monster_roll = roll_1d20() + currentchar.location.current_monster.dex
    char_roll = roll_1d20() + currentchar.dex
    if char_roll >= monster_roll:
        return "char","monster"  # (who goes first, who goes second)
    else:
        return "monster","char"  # (Who goes first, who goes second)
def swap_turn(attacker,defender):
    if attacker == "char":
        new_attacker = "monster"
        new_defender = "char"
    else:
        new_attacker = "char"
        new_defender = "monster"
    return new_attacker,new_defender
# You can fight once; never replenishes health
def battle():
    the_monster = currentchar.location.current_monster
    attacker,defender = who_first()
    if attacker != "char":
        print "The %s attacks you!" % (the_monster.name)
    menu = \
'''
What do you want to do?
(1) Attack
(2) Run'''
    print "-" * 12
    print " You: %s hp" % (currentchar.hp)
    print " %s: %s hp" % (the_monster.name.title(),the_monster.hp)
    print "-" * 12
    battle = "going"
    while currentchar.hp > 0 and the_monster.hp > 0:
        if attacker == "char":
            print menu
            choice = "none"
            while choice not in ("1","2"):
                choice = raw_input("Enter choice: ")
            # ATTACK
            if choice == "1":
                ac_roll = roll_1d20() + currentchar.str
                if ac_roll >= the_monster.ac:
                    damage = currentchar.current_weapon.attack()
                    the_monster.hp = the_monster.hp - damage
                    if the_monster.hp < 0:
                        the_monster.hp = 0
                    print "You hit for %d damage.\n" % (damage)
                    print "-" * 12
                    print " %s: %s hp" % (currentchar.name,currentchar.hp)
                    print " %s: %s hp" % (the_monster.name.title(),the_monster.hp)
                    print "-" * 12
                    raw_input("Enter to continue...")
                else:
                    print "You didn't hit him.\n"
                    raw_input("Enter to continue...")
            # RUN
            elif choice == "2":
                # Can't run if you get a 1
                ifrun = random.randrange(1,the_monster.run_probability+1)
                if ifrun != 1:
                    battle = "character ran"
                    break
 
        else:
            ac_roll = roll_1d20() + the_monster.str
            if ac_roll >= currentchar.ac:
                damage = roll_1d6()
                currentchar.hp = currentchar.hp - damage
                if currentchar.hp < 0:
                    currentchar.hp = 0
                print "The %s hit for %d damage.\n" % (the_monster.name,damage)
                print "-" * 12
                print " You: %s hp" % (currentchar.hp)
                print " %s: %s hp" % (the_monster.name.title(),the_monster.hp)
                print "-" * 12
                raw_input("Enter to continue...")
            else:
                print "The %s missed.\n" % (the_monster.name)
                raw_input("Enter to continue...")
        # Switch who is attacker and defender
        attacker,defender = swap_turn(attacker,defender)
    if currentchar.hp <= 0:
        print "You died."
        return "dead"
    elif the_monster.hp <= 0:
        print "You killed the %s." % (the_monster.name)
        currentchar.exp += the_monster.give_exp
        print "You gained %d experience points.\nYou have %d experience points.\n" % (the_monster.give_exp,currentchar.exp)
        currentchar.location.current_monster = None
        currentchar.level_up()
        return "won"
    elif battle == "character ran":
        print "You successfully ran from the battle."
 
def stats():
    print \
'''
Name: %s
Level: %d
Experience points: %d
Strength: %d
Armor Class: %d
Hit Points: %d
Dexterity: %d
Current Weapon: %s
''' % (currentchar.name,currentchar.level,currentchar.exp,currentchar.str,currentchar.ac,currentchar.hp,currentchar.dex,currentchar.current_weapon.name)
def heal_monsters():
    rooms = ["bedroom","garden","pathway","open_area","study","cliff","rocky_path","hallway","cave"]
    for room_str in rooms:
        room = eval(room_str)
        if room != currentchar.location and room.current_monster:
            room.current_monster.hp += 2
def commands():
    print "The commands are: 'n','e','s','w' for moving; 'exit' to exit; 'stats' to see your stats; 'help' to see these commands again."
def save():
    print "Saving..."
    save_file = str(currentchar.name) + ".txt"
    game_d = {}
    # Save the rooms' monsters
    rooms = ["bedroom","garden","pathway","open_area","study","cliff","rocky_path","hallway","cave"]
    info_names = ["currentchar"]
    info_values = [currentchar]
    for room in rooms:
        info_names.append(room+"_monster")
        info_values.append(eval(room+".current_monster"))
    info_names.append("files")
    info_values.append(file_list)
    for index in range(len(info_names)):
         game_d[info_names[index]] = info_values[index]
    f = open(save_file,"w")
    cPickle.dump(game_d,f)
    f.close()
    if save_file not in file_list:
        file_list.append(save_file)
    f = open("data.txt","w")
    cPickle.dump(file_list,f)
    f.close()
    print "Game Saved."
def delete_file():
    print "Files:"
    for f in file_list:
        print f,
    print
    f_del = raw_input("What file would you like to delete? ")
    if f_del in file_list:
        print "%s has been deleted from the game." % (f_del)
        print "Don't forget to remove the actual file."
        file_list.remove(f_del)
        f = open("data.txt","w")
        cPickle.dump(file_list,f)
        f.close()
    else:
        print "There is no such file."
 
 
def load(data_file="not given"):
    if data_file == "not given" and file_list:
        for num,f in enumerate(file_list):
            print "%s %s" % ("(" + str(num+1) + ")",f)
        choose_file = "none"
        while choose_file not in range(len(file_list)+1):
            choose_file = raw_input("Choose a file number: ")
            choose_file = int(choose_file)
        data_d = cPickle.load(file_list[choose_file-1])
    else:            
        f = open(data_file,"r")
        data_d = cPickle.load(f)
    new_char = data_d["currentchar"]
    bedroom.current_monster = data_d["bedroom_monster"]
    garden.current_monster = data_d["garden_monster"]
    pathway.current_monster = data_d["pathway_monster"]
    open_area.current_monster = data_d["open_area_monster"]
    study.current_monster = data_d["study_monster"]
    cliff.current_monster = data_d["cliff_monster"]
    rocky_path.current_monster = data_d["rocky_path_monster"]
    hallway.current_monster = data_d["hallway_monster"]
    cave.current_monster = data_d["cave_monster"]
    f.close()
    return new_char
# Load new character
if file_list:
    for num,f in enumerate(file_list):
        print "%-4s %s" % ("(" + str(num+1) + ")",f)
    choose_file = "none"
    print
    while choose_file != "new" and choose_file not in range(len(file_list)+1):
        try:
            choose_file = raw_input("Choose a file number, or 'new' for new character:\n")
            if choose_file != "new":
                choose_file = int(choose_file)
        except:
            pass
    if choose_file == "new":
        print "New character!"
        name = raw_input("Name: ")
        currentchar = Character(name)
    else:
        currentchar = load(file_list[int(choose_file)-1])
 
else:
    print "New character!"
    name = raw_input("Name: ")
    currentchar = Character(name)
battle_results = "alive"
print "\nWelcome to Glen's RPG. Enjoy..."
commands()
print currentchar.location.description
while battle_results != "dead":
    command = raw_input("Enter a Command: ").lower()
    if command == "n":
        battle_results = enter_room("n")
    elif command == "e":
        battle_results = enter_room("e")
    elif command == "s":
        battle_results = enter_room("s")
    elif command == "w":
        battle_results = enter_room("w")
    elif command == "stats":
        stats()
    elif command == "save":
        save()
    elif command == "load":
        currentchar = load()
    elif command == "delete":
        delete_file()
    elif command == "help":
        commands()
    # Levels up the current character
    elif command == "xp":
        currentchar.exp += 25
        currentchar.level_up()
        print currentchar.exp
    elif command == "exit":
        break
    else:
        print "That's not a command."
print "Thanks for playing."

So, you can walk around nine rooms and there is a probability of encountering monsters as you walk along in certain rooms. The cave always contains a troll, but it's too tough for the beginner. As the user fights rats along the path of the garden, pathway, and open area for awhile, he/she will level up every 25 exp points (rats give 5). As the user gains levels, he/she will get better stats.

I understand that it's not so interesting at this point since we haven't implemented keys to open doors, weapons/items dropped by monsters, and a more complex fighting system (something other than attack and run). This is just a fun project we're doing independently, so it's not destined to be some huge project, just something to do to better our python skills.

Feedback would be great, both code-wise and conceptually.

Thanks.

note: the save/load functions are currently being debugged, so please just test the game once you load a file.

Recommended Answers

All 12 Replies

I finally got them all to work. Kinda neat! Can hardly wait until you get some good sound with it!

What does Rpg mean? Reverse Polish Game?

Member Avatar for Mouche

RPG = Role Playing Game... right now I'm implementing locked doors to open and a "look" command to look at things.

Theb link to dowenloads is broken? please help

Member Avatar for Mouche

I believe this will work if you just copy the code into a file, save it as game.py and then run it.

Thanks LaMouche for your reply. But this code does not run when copied into python because the first few line of the code is looking for a list which you are to get from the links above the coding, But they are not working, so justing wondering how the program will work without them.

Also the list is look for within the coding !

Thanks again for time

Member Avatar for Mouche

Ah, ok. My error catching wasn't too good.

Change that first block of code to this:

# Load file_list
try:    
    f = open("data.txt","r")
    file_list = cPickle.load(f)
    f.close()
except: # If data.txt is empty and cannot load
    file_list = []

Thanks LeMouche now working fine....Many thanks

Member Avatar for Mouche

You're welcome. Send me a PM if you want some more help with this. This is a pretty old thread.

Hi, I was just wondering how to get the game to work, I'm new to Python and I'm probably doing something wrong. I copy and pasted the code into a new file, with the first block of code replaced with the newer one, but when I run it doesn't seem to work. What am I doing wrong?

Member Avatar for Mouche

Are you running Python 2.6? This wasn't written for Python 3.0, so if you're using that, you may have a problem. Otherwise, what is your error?

Hi The_Castle scroll up page and find some code to help you run program posted 5 days ago by LaMouche, it made the program work for me..

Not bad...

Nice stuff ;)

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.