This is very similar in spirit to other text adventure questions on the site, notably Better way to code this game? Better way to code this game?
This is very similar in spirit to other text adventure questions on the site, notably Better way to code this game?
This is very similar in spirit to other text adventure questions on the site, notably Better way to code this game?
# instead of using an if/then tree, first we store the damage range
# of all the weapons in the game
WEAPONS = {'stick': (3, 10)), None:(1,8), 'knife':(4,16)}
#and instead of tracking inventory with one variable, have a 'player' who
# has stuff in a dictionary:
player = {'weapon':None, 'health': None}
#to give the player stuff, you add it to his dictionary:
player['weapon'] = 'stick'
# while we're at it, we can treat the monsters the same way:
SPIDER = {name:'spider', 'health':5, 'attack':(1, 5) }
# so for any given fight there's a player and an enemy:
# and two possible outcomes for each combatant. You'll want to report
# the damage (which varies) and the result:
def combat (player, enemy):
player_damage = random.range(*WEAPONS[player['weapon'])
enemy_damage = random.range(*enemy['attack'])
player_win = player_damage > enemy['health']
enemy_win= enemy_damage > player['health']
return player_damage, player_win , enemy_damage, enemy_win
# of course, you also want flavor text. So you can set that up as another dictionary.
# you might want to make different dictionaries for different parts of the game
# to give a different flavor to the fights as you did above:
SIMPLE_FIGHT += {
player_damage: 'You hit the %s for %i damage',
enemy_damage: '%s hits you for %i damage',
player_win: 'The %s dies!',
enemy_win: 'You die!'
}
def describe_combat(player, enemy, fight_description):
player_damage, player_win , enemy_damage, enemy_win = combat(player, enemy)
print fight_description['player_damage'] % (enemy['name'], player_damage)
print fight_description['enemy_damage'] % (enemy['name'], enemy_damage)
if player_win:
print fight_description['player_win'] % (enemy['name'], player_damage)
return True
if enemy_win:
print fight_description['enemy_win']fight_description['player_win'] % (enemy['name'])
return False
return None # this means a draw :)
# with that in place, player_damageyou can play out a fight like so:
fight_result = describe_combat(player, SPIDER, SIMPLE_FIGHT)
if fight_result is None:
# what do you do for draws?
elif fight_result:
# you've won.
else:
# game over
This may seem like a lot of indirection at first, but you can create a whole different fight with just two new bits of data:
ELEPHANT = {'name':'Huge bull elephant', 'attack': (10,30)}
ELEPHANT_FIGHT = {
player_damage: 'You desperately try to stop the %s for %i damage',
enemy_damage: '%s gores you for %i damage',
player_win: 'The %s collapses with a thunderous boom',
enemy_win: 'You are squished'
}
and so on. I'm sure you can see how the same strategy will help with things like different weapons and armor, different rooms and so on. The key principle is to keep the LOGIC as simple and streamlined as possible and make the DATA do the descriptive work.
# instead of using an if/then tree, first we store the damage range
# of all the weapons in the game
WEAPONS = {'stick': (3, 10)), None:(1,8), 'knife':(4,16)}
#and instead of tracking inventory with one variable, have a 'player' who
# has stuff in a dictionary:
player = {'weapon':None, 'health': None}
#to give the player stuff, you add it to his dictionary:
player['weapon'] = 'stick'
# while we're at it, we can treat the monsters the same way:
SPIDER = {name:'spider', 'health':5, 'attack':(1, 5) }
# so for any given fight there's a player and an enemy:
# and two possible outcomes for each combatant. You'll want to report
# the damage (which varies) and the result:
def combat (player, enemy):
player_damage = random.range(*WEAPONS[player['weapon'])
enemy_damage = random.range(*enemy['attack'])
player_win = player_damage > enemy['health']
enemy_win= enemy_damage > player['health']
return player_damage, player_win , enemy_damage, enemy_win
# of course, you also want flavor text. So you can set that up as another dictionary.
# you might want to make different dictionaries for different parts of the game
# to give a different flavor to the fights as you did above:
SIMPLE_FIGHT + {
player_damage: 'You hit the %s for %i damage',
enemy_damage: '%s hits you for %i damage',
player_win: 'The %s dies!',
enemy_win: 'You die!'
}
def describe_combat(player, enemy, fight_description):
player_damage, player_win , enemy_damage, enemy_win = combat(player, enemy)
print fight_description['player_damage'] % (enemy['name'], player_damage)
print fight_description['enemy_damage'] % (enemy['name'], enemy_damage)
print fight_description['player_win'] % (enemy['name'], player_damage)
print fight_description['enemy_win'] % (enemy['name'], player_damage)
# instead of using an if/then tree, first we store the damage range
# of all the weapons in the game
WEAPONS = {'stick': (3, 10)), None:(1,8), 'knife':(4,16)}
#and instead of tracking inventory with one variable, have a 'player' who
# has stuff in a dictionary:
player = {'weapon':None, 'health': None}
#to give the player stuff, you add it to his dictionary:
player['weapon'] = 'stick'
# while we're at it, we can treat the monsters the same way:
SPIDER = {name:'spider', 'health':5, 'attack':(1, 5) }
# so for any given fight there's a player and an enemy:
# and two possible outcomes for each combatant. You'll want to report
# the damage (which varies) and the result:
def combat (player, enemy):
player_damage = random.range(*WEAPONS[player['weapon'])
enemy_damage = random.range(*enemy['attack'])
player_win = player_damage > enemy['health']
enemy_win= enemy_damage > player['health']
return player_damage, player_win , enemy_damage, enemy_win
# of course, you also want flavor text. So you can set that up as another dictionary.
# you might want to make different dictionaries for different parts of the game
# to give a different flavor to the fights as you did above:
SIMPLE_FIGHT = {
player_damage: 'You hit the %s for %i damage',
enemy_damage: '%s hits you for %i damage',
player_win: 'The %s dies!',
enemy_win: 'You die!'
}
def describe_combat(player, enemy, fight_description):
player_damage, player_win , enemy_damage, enemy_win = combat(player, enemy)
print fight_description['player_damage'] % (enemy['name'], player_damage)
print fight_description['enemy_damage'] % (enemy['name'], enemy_damage)
if player_win:
print fight_description['player_win'] % enemy['name'])
return True
if enemy_win:
print fight_description['player_win'] % enemy['name'])
return False
return None # this means a draw :)
# with that in place, you can play out a fight like so:
fight_result = describe_combat(player, SPIDER, SIMPLE_FIGHT)
if fight_result is None:
# what do you do for draws?
elif fight_result:
# you've won.
else:
# game over
This may seem like a lot of indirection at first, but you can create a whole different fight with just two new bits of data:
ELEPHANT = {'name':'Huge bull elephant', 'attack': (10,30)}
ELEPHANT_FIGHT = {
player_damage: 'You desperately try to stop the %s for %i damage',
enemy_damage: '%s gores you for %i damage',
player_win: 'The %s collapses with a thunderous boom',
enemy_win: 'You are squished'
}
and so on. I'm sure you can see how the same strategy will help with things like different weapons and armor, different rooms and so on. The key principle is to keep the LOGIC as simple and streamlined as possible and make the DATA do the descriptive work.
This is very similar in spirit to other text adventure questions on the site, notably Better way to code this game?
The basic goal you should pursue here is to reduce the amount of completely repetitive code: Since the basic game loop is so simple, the 'code' part should be equally simple. In a game like this that's actually very easy: almost everything breaks down to presenting the user with a list of choices, getting their input, and using it to move to a new list of choices.
The 'right' way to do it, long term, is to follow @mrMishhall's advice and learn object-oriented techniques. However if you're still new to Ptthon and terms like OOP are intimidating, you can also do it using basic python data types - particularly dictionaries. That's what the example linked above does: every node in the game is a dictionary containing a description, a list of options, and a link to the nodes -- that is, other dictionaries -- you reach by folllowing a given option.
Rather than duplicate the example in the link above, i'll give you an example of how the same idea can simplify the combat portion. Here's an attempt to do the same kind of combat system with less reliance on if/then.
# instead of using an if/then tree, first we store the damage range
# of all the weapons in the game
WEAPONS = {'stick': (3, 10)), None:(1,8), 'knife':(4,16)}
#and instead of tracking inventory with one variable, have a 'player' who
# has stuff in a dictionary:
player = {'weapon':None, 'health': None}
#to give the player stuff, you add it to his dictionary:
player['weapon'] = 'stick'
# while we're at it, we can treat the monsters the same way:
SPIDER = {name:'spider', 'health':5, 'attack':(1, 5) }
# so for any given fight there's a player and an enemy:
# and two possible outcomes for each combatant. You'll want to report
# the damage (which varies) and the result:
def combat (player, enemy):
player_damage = random.range(*WEAPONS[player['weapon'])
enemy_damage = random.range(*enemy['attack'])
player_win = player_damage > enemy['health']
enemy_win= enemy_damage > player['health']
return player_damage, player_win , enemy_damage, enemy_win
# of course, you also want flavor text. So you can set that up as another dictionary.
# you might want to make different dictionaries for different parts of the game
# to give a different flavor to the fights as you did above:
SIMPLE_FIGHT + {
player_damage: 'You hit the %s for %i damage',
enemy_damage: '%s hits you for %i damage',
player_win: 'The %s dies!',
enemy_win: 'You die!'
}
def describe_combat(player, enemy, fight_description):
player_damage, player_win , enemy_damage, enemy_win = combat(player, enemy)
print fight_description['player_damage'] % (enemy['name'], player_damage)
print fight_description['enemy_damage'] % (enemy['name'], enemy_damage)
print fight_description['player_win'] % (enemy['name'], player_damage)
print fight_description['enemy_win'] % (enemy['name'], player_damage)