4
\$\begingroup\$

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 *
init()
'''
import pygame, sys
from pygame.locals import *
# set up pygame
pygame.init()
# 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
windowSurface.fill(WHITE)
# 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
 ########
 @staticmethod
 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
 else:
 print "You missed!"
 break
 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
 else:
 print "You missed!"
 break
 else:
 error("typo")
 continue
 if is_hit == True:
 break
 return damage
def accuracy_calc (accuracy):
 rand = random.randint(0,100)
 if rand <= accuracy:
 #It DID hit
 is_hit = True
 else:
 #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.
#REDO THIS FOR MAGICAL ABILITIES, not added yet
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":
 help()
 continue
 elif input == "attack":
 player_damage = Ability.attack("normal")
 enemy.health -= player_damage
 #Add in accuracy
 elif input == "defend":
 player_defend = True
 #CHANGE THIS TO A MAGIC SYSTEM. RENAME EVERYTHING AND REDO.
 #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":
 help()
 continue
 elif input in ability_list:
 break
 elif input == "back":
 went_back = True
 break
 # player_damage = Ability.attack(input)
 # enemy.health -= player_damage
 # print enemy.health, "enemy hp"
 # break
 else:
 error("typo")
 continue
 else:
 error("typo")
 continue
 if went_back == True:
 went_back = False
 continue
 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!"
 break
 #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
 else:
 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)
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Apr 3, 2017 at 6:00
\$\endgroup\$
2
  • 1
    \$\begingroup\$ What's up with the two elif attack_type == "blahblah"? \$\endgroup\$ Commented 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\$ Commented Apr 3, 2017 at 20:03

1 Answer 1

3
\$\begingroup\$

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:

ABILITY_DESCRIPTIONS = {
 "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
answered Apr 3, 2017 at 12:49
\$\endgroup\$
1
  • \$\begingroup\$ I really appreciate the addition of styling with this bit of help, all of this was very useful. Thank you ! \$\endgroup\$ Commented Apr 4, 2017 at 1:47

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.