Dice generator using class in Python

You loop over all the values of the dict:

part = hit_loc.values()
for w in part:
    # loop over each part, so print a damage message for all 12 bodyparts

Perhaps you meant to pick the one that is affected instead?

part = hit_loc[loc]  # assign *one* body part to `part`
if loc <= 9:
    print part, "has been severed!"
elif loc == 10:
    print "You sink your blade into his", part, "and pierce the heart!"
elif loc == 11:
    print "You slash him across the", part, "and eviscerate him!"
elif loc == 12:
    print "You shred the enemy's", part, "to ribbons!"

In other words, you do not need a loop here at all.

Note that, whenever you find yourself using a sequential series of numbers as keys to a dictionary, you may as well make it a list instead:

hit_loc = [
    'Head', 'Left Arm', 'Right Arm', 'Left Leg', 
    'Right Leg', 'Left Hand', 'Right Hand', 'Left Foot', 'Right Foot',
    'Chest', 'Stomach', 'Body'
]

except now the indexes run from 0 to 11, so use loc - 1 to find the right body part:

part = hit_loc[loc - 1]

Tangent...

A simpler version of your dice class might be something like:

class Die(object):
    def __init__(self, sides = 6):
        self.sides = sides

    def roll(self):
        return randint(1, self.sides)

You now have a general purpose dice object that doesn't require you to add a new method every time you come up with a new roll mode. E.g.

d = Die(10);
d.roll() # ---> some value between 1 and 10

Adding optional start and increment attributes so that you can have a D20 that produces 5, 10, ..., 95, 100 left as an exercise to the student.


This looks like a fun program for learning Python. The other answers have mostly covered what you need, but I just wanted to point out one thing:

If you are trying to choose something in real life using dice, the way to do it is to assign numbers to the things, then roll the dice, and use the number from the dice to figure out which thing was chosen. But, in Python, you can do things more simply than that: you can tell Python "here is a bunch of stuff, I want one item chosen at random." The function for this is: random.choice()

So for the critical hit stuff, you can replace this:

hit_loc = {1 : 'Head',
           2 : 'Left Arm',
           3 : 'Right Arm',
           4 : 'Left Leg',
           5 : 'Right Leg',
           6 : 'Left Hand',
           7 : 'Right Hand',
           8 : 'Left Foot',
           9 : 'Right Foot',
          10 : 'Chest',
          11 : 'Stomach',
          12 : 'Body'}

# two steps to randomly choose a hit location
loc = roll.d12()
part = hit_loc[loc]

with this:

locations = ('Head', 'Left Arm', 'Right Arm', 'Left Leg', 'Right Leg',
         'Left Hand', 'Right Hand', 'Left Foot', 'Right Foot',
         'Chest', 'Stomach', 'Body')

# one step to randomly choose a hit location
part = random.choice(locations)

In general, when you want to figure out how to use a module like random, it really pays to read the documentation. In Python, there is always some terse documentation provided with the code; from the Python prompt you can do this:

>> import random
>> help(random)

The help() command will print out terse documentation, and if you read through it you will find random.choice(), random.shuffle(), and other nifty stuff.

Have fun with Python!

P.S. This is a fun example program. It's not the best example of classes, though. You are using a class here just to get a namespace that groups related functions together, which isn't wrong, but a class is even more useful when it encapsulates some data and some functions that go together. Here is a suggestion: make a Person() class, which has a member variable called hit_points, and write a method function .attack() that attacks another Person instance. Then write a program that makes two Person() instances and has them fight each other!

I suggest it should work something like this:

black_knight = Person()
king_arthur = Person()

while True:
    king_arthur.attack(black_knight)
    if black_knight.hit_points <= 0:
        print "Victory is mine!"
        break
    black_knight.attack(king_arthur)
    if king_arthur.hit_points <= 0:
        print "None shall pass!"
        break

In this example, a Person instance bundles together the information about a person (hit points) and functions that work with a person (a person can attack another person).

You could extend the model to include critical hits; a Person instance could keep track of which critical hits it has received; a Person could have inventory, including weapons that always score a critical hit (such as "Vorpal Bunny Teeth", "Holy Hand Grenade of Antioch"), etc.

Indeed, you could keep adding more things for a Person to track, and more method functions, and if you kept at it you might turn the whole thing into a real game.