I plan to flesh this out into a hopefully full 2-3 minute text adventure game, and the most fun part to start with is the combat.

The fight function down at the bottom repeats itself quite a bit, the help() function call is in multiple places and I was wondering if there's any way to reduce that? Also general tips on how I can improve would be appreciated.

# -*- coding: utf-8 -*-

import random
from colorama import Fore, Back, Style
from colorama import init
from Tkinter import *


import pygame, sys
from pygame.locals import *

# set up pygame

# set up the window
windowSurface = pygame.display.set_mode((500, 400), 0, 32)
pygame.display.set_caption('Hello world!')

# set up the colors
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
RED = (255, 0, 0)
GREEN = (0, 255, 0)
BLUE = (0, 0, 255)

# set up fonts
basicFont = pygame.font.SysFont(None, 48)

# set up the text
text = basicFont.render('Hello world!', True, WHITE, BLUE)
textRect = text.get_rect()
textRect.centerx = windowSurface.get_rect().centerx
textRect.centery = windowSurface.get_rect().centery

# draw the white background onto the surface

# draw a green polygon onto the surface
pygame.draw.polygon(windowSurface, GREEN, ((146, 0), (291, 106), (236, 277), (56, 277), (0, 106)))

Attack: The amount of damage you do.
Health: Amount of damage you can take.
Armor: (not in yet)
Accuracy: The percentage something will hit.


class Player(object):
    def __init__(self, name):
        self.name = name
        self.attack = 3
        self.health = 10
        #not used
        self.magic_attack = 2
        self.armor = 1

    def description(self):
        print "%s the mighty hero!" % (self.name)

#A class full of the character's fighting abilities
class Ability(object):
    def __init__(self, damage, accuracy):
        self.damage = damage
        self.accuracy = accuracy

    def description(self, name):
        #None of this is used yet, either
        if name == "slash":
            print "A very accurate attack with low damage."

        elif name == "stab":
            print "A high damaging attack with low accuracy."

        elif name == "normal":
            print "A normal attack."

    #def defend

    def attack(attack_type):
        while True:
            damage = 0
            is_hit = False

            if attack_type == "normal":
                if accuracy_calc (normal_attack.accuracy) == True:
                    damage = player.attack
                    is_hit = True
                    print "You missed!"

            elif attack_type == "blahblah":
                damage = player.attack
                is_hit = True

            elif attack_type == "blahblah":
                if accuracy_calc(stab_attack.accuracy) == True:
                    damage = player.attack * 2
                    is_hit = True
                    print "You missed!"


            if is_hit == True:

        return damage

def accuracy_calc (accuracy):
    rand = random.randint(0,100)
    if rand <= accuracy:
        #It DID hit
        is_hit = True
        #It didn't hit
        is_hit = False

    return is_hit

class Enemy(object):
    def __init__(self, name, attack, health, armor):
        self.name = name
        self. attack = attack
        self.health = health
        self.armor = armor

    def description(self):
        print "A %s." % (self.name)

def help():
    print "Combat commands:"
    print "Attack: Attacks the enemy."
    print "Defend: Defends an attack."
    print "Magic: Some advanced stuff you don't know yet"

#Defining a goblin. (att, def, ar)
goblin = Enemy("small goblin", 2, 8, 0)

#Prints a blank line, making things more readable.
print "\n"

#Defining the player. (name)
player = Player("Adam")

#Maybe make multiple characters?

#Not actually used, switch all this shiznit to magic.
normal_attack = Ability(1, 90)

#Defining abilities. It takes the percentage of an objects stat
#(dmg, acc)
slash_attack = Ability(1, 100)

#(dmg, acc)
stab_attack = Ability(2, 50)

#A list of abilities the player has. Abilities can't be used if they're set
#above in the class, but they can be if they're set up there AND put here.
ability_list = ["normal"]

#A random sentence every time someone makes a mistake. Type = "typo", "path", something else
def error (type):

    #The list of errors that come up when someone typoes
    typo_error = ["That's not a command!", "Could you say that again?",\
    "Stop speaking gibberish!"]

    if type == "typo":
        error = random.choice(typo_error)

    print error

def fight (player, enemy):
    while player.health >= 0 and enemy.health >= 0:
        #Splits combat into player and enemy turn
        turn = "player"
        #Repeats the last loop if a mistake is made
        went_back = False
        #Tracks if the players defends on his turn.
        player_defend = False

        while turn == "player":
            input = raw_input("What would you like to do? (Use 'help' for commands.)")
            if input == "help":

            elif input == "attack":
                player_damage = Ability.attack("normal")
                enemy.health -= player_damage
                #Add in accuracy

            elif input == "defend":
                player_defend = True

                #remember to put in resistances, mayve a flat subtration or 
                #a percentage

                #Add a running mechanic
            elif input == "magic":
                while True:
                    input = raw_input("Which ability would you like to use? (type 'back' there's nothing here yet")
                    if input == "help":

                    elif input in ability_list:

                    elif input == "back":
                        went_back = True

                    # player_damage = Ability.attack(input)
                    # enemy.health -= player_damage
                    # print enemy.health, "enemy hp"
                    # break


            if went_back == True:
                went_back = False

            print "You strike the enemy for ", (Fore.GREEN + str(player_damage) + Style.RESET_ALL), " damage!"
            turn = "enemy"

            #Prints if the player dies
        if player.health <= 0:
            print "You have been slain!"

        #Checks if the enemy is dead, if it is then ends the fight
        enemy_is_dead = False

        if enemy.health <= 0:
            print "You've defeated %s!" % (goblin.name)
            enemy_is_dead = True

        #Enemy's turn to attack.
        if enemy_is_dead == False:  
            while turn == "enemy":
                #If the play defends, do half damage
                if player_defend == False:
                    enemy_damage = enemy.attack
                    enemy_damage = enemy.attack / 2
                player.health -= enemy_damage
                text1 = str(enemy_damage)
                text2 = str(player.health)
                print "The monster did ", (Fore.RED + text1 + Style.RESET_ALL), "damage!"\
                , "You have ", (Fore.RED + text2 + Style.RESET_ALL), "health left."
                turn = "player"

# print(Style.RESET_ALL)
# print(Fore.RED + 'some red text')

fight (player, goblin)
  • 1
    \$\begingroup\$ What's up with the two elif attack_type == "blahblah"? \$\endgroup\$ Apr 3, 2017 at 14:07
  • \$\begingroup\$ I was going to add different types of attacks that do more damage but less accuracy, more accuracy but less damage etc. Decided not to do that and instead add some magic! Just placeholders, really. \$\endgroup\$ Apr 3, 2017 at 20:03

1 Answer 1


There are multiple things you can improve/simplify.

Code Style

  • remove the extra newlines between the parts of the code, keeping 2 blank lines between the top-level class and function definitions, 1 blank line between the class methods (PEP8 reference)
  • the docstrings should be put into triple double-quotes. The module level docstring should be on top, before the import statements.
  • put the main execution code block into the if __name__ == '__main__':
  • use print() as a function instead of a statement for Python-3.x compatibility
  • when you put an inline comment, start with a space (PEP8 reference)

Code Simplifications

You can replace these multiple if/elif/elses:

def description(self, name):
    #None of this is used yet, either
    if name == "slash":
        print "A very accurate attack with low damage."

    elif name == "stab":
        print "A high damaging attack with low accuracy."

    elif name == "normal":
        print "A normal attack."

with a dictionary lookup:

    "slash": "A very accurate attack with low damage.",
    "stab": "A high damaging attack with low accuracy.",
    "normal": "A normal attack."

def description(self, name):
    print(ABILITY_DESCRIPTIONS.get(name, "Ability description not found"))

You can replace expressions like if is_hit == True: with if is_hit: - there is no need to explicitly check for equality with True. Same applies for other places when you compare with True or False.

accuracy_calc() function can be rewritten as:

def accuracy_calc(accuracy):
    return random.randint(0, 100) <= accuracy
  • \$\begingroup\$ I really appreciate the addition of styling with this bit of help, all of this was very useful. Thank you ! \$\endgroup\$ Apr 4, 2017 at 1:47

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.