4
\$\begingroup\$

I'm new to coding and this is a text based adventure game with combat. Sleep and choice functions based on idea from https://codereview.stackexchange.com/a/52292/179642. Map idea from Codecademy battleship tutorial.

The actions in the fight function are not in a loop because attacks reduce the opponent's hp but healing affects your own hp.

Any comments on new ideas/features, better coding methods greatly appreciated.

import random, time, sys
#initial variables or settings, and map generation
hp = 100
rMap = [('G', 'G', 'G', 'C', 'W'), ('F', 'F', 'G', 'W', 'M'), ('B', 'W', 'W', 'G', 'M'), ('F', 'F', 'G', 'G', 'G'), ('F', 'F', 'F', 'G', 'V')]
pMap = []
for x in range(5):
 pMap.append(['?'] * 5)
legend = {'X': 'You', '?': 'Unexplored', 'G': 'Grassland', 'V': 'Village', 'F': 'Forest', 'M': 'Mountain', 'B': 'Bridge', 'W': 'Water', 'C': 'Castle'}
enemy = {'G': ('Wolf', 30, 0, 33, 33, 50), 'F': ('Bandit', 30, 1, 50, 33, 50), 'M': ('Troll', 80, 0, 33, 50, 50), 'C': ('Dragon', 170, 2, 0, 0, 100), 'B': ('Ogre', 100, 0.5, 100, 100, 100)}
posR = 4
posC = 4
inv = {'Bow' : 1, 'Arrow' : 0, 'Potion' : 0}
action = {'Punch': (8, 12, 'p'), 'Kick': (6, 20, 'k')}
def wait(value): #can be commented away for quicker testing
 #time.sleep(value)
 pass
def new_loc(): #whether there is an enemy when the player moves to a new location
 for i in enemy:
 if rMap[posR][posC] == i:
 if random.randint(1, 100) <= enemy[i][5]:
 fight(enemy[i][0], enemy[i][1], enemy[i][2])
 loot(enemy[i][3], enemy[i][4])
 if i == 'C':
 print ('You win! Congratulations!')
 sys.exit()
 updatepos()
 turn()
def turn(): #every turn or action by the player
 global hp
 print ('What do you want to do?')
 wait(0.5)
 print ('t to Travel, i to view Inventory, m to view Map')
 c = choice(['t', 'i', 'm'])
 if c == 't':
 print ('Which direction do you want to move?')
 d = []
 if posR != 0:
 if rMap[posR - 1][posC] != 'W':
 print ('f to move forward')
 d.append('f')
 if posR != 4:
 if rMap[posR + 1][posC] != 'W':
 print ('b to move backward')
 d.append('b')
 if posC != 0:
 if rMap[posR][posC - 1] != 'W':
 print ('l to move left')
 d.append('l')
 if posC != 4:
 if rMap[posR][posC + 1] != 'W':
 print ('r to move right')
 d.append('r')
 sel_dir = choice(d)
 if sel_dir == 'f':
 move(-1, 0)
 if sel_dir == 'b':
 move(1, 0)
 if sel_dir == 'l':
 move(0, -1)
 if sel_dir == 'r':
 move(0, 1)
 if c == 'i':
 showInv()
 turn()
 if c == 'm':
 updatepos()
 turn()
def start(): #introduction to the game
 print ('Your village has been burnt down by a dragon!')
 wait(0.5)
 print (' ')
 print ('You have to find it and take revenge!')
 print (' ')
 updatepos()
 turn()
def showAction(): #for debugging player actions in battle
 for i in action:
 print (i, action[i])
def updateAction(): #for updating actions linked to items
 if inv['Potion'] > 0:
 if 'Heal' not in action:
 action['Heal'] = (40, 50, 'h')
 if inv['Potion'] == 0:
 if 'Heal' in action:
 action.pop('Heal')
 if inv['Arrow'] > 0:
 if 'Shoot' not in action:
 action['Shoot'] = (30, 40, 's')
 if inv['Arrow'] == 0:
 if 'Shoot' in action:
 action.pop('Shoot')
def showInv(): #for viewing inventory
 global hp
 for i in inv:
 if inv[i] > 0:
 print (i + ':', inv[i])
 if inv['Potion'] > 0:
 updateAction()
 print('Do you want to drink a Potion? y/n')
 drink = choice(['y', 'n'])
 if drink == 'y':
 h = random.randint(action['Heal'][0], action['Heal'][1])
 hp += h
 print('You used a Potion')
 wait(0.5)
 print('You healed yourself for %d HP!' % h)
 wait(0.5)
 inv['Potion'] -= 1
 print('You have %d Potions left' % (inv['Potion']))
 turn()
def move(r, c): #when the player moves
 global posR
 global posC
 posR = posR + r
 posC = posC + c
 wait(0.5)
 if r == -1:
 print ('Moving Forward...')
 if r == 1:
 print ('Moving Backward...')
 if c == 1:
 print ('Moving Right...')
 if c == -1:
 print ('Moving Left...')
 new_loc()
def updatepos(): #updating the map position
 pMap[posR][posC] = 'X'
 if posR != 4:
 pMap[posR + 1][posC] = rMap[posR + 1][posC]
 if posR != 0:
 pMap[posR - 1][posC] = rMap[posR - 1][posC]
 if posC != 4:
 pMap[posR][posC + 1] = rMap[posR][posC + 1]
 if posC != 0:
 pMap[posR][posC - 1] = rMap[posR][posC - 1]
 showMap()
 wait(0.5)
 print ('You are now in %s' % legend[rMap[posR][posC]])
def showMap(): #prints the map and legend (for revealed areas)
 print ('Map:')
 for row in pMap:
 for i in row:
 print (i, end = ' ')
 print()
 print (' ')
 legList = []
 for row in pMap:
 for i in row:
 legList.append(i)
 for i in legend:
 if i in legList:
 print (i, legend[i])
 print (' ')
def choice(list): #get a valid choice from the user
 while True:
 userChoice = input('Choose an action:')
 userChoice = userChoice.lower()
 if userChoice in list:
 return userChoice
 else:
 print ('Invalid choice. Try again.')
def fight(enemy, eHP, level): #fighting an enemy
 print ('%s appeared!' % enemy)
 wait(0.5)
 global hp
 enemyHP = eHP
 while True:
 if hp <= 0:
 print ("You died :(. Game over")
 sys.exit()
 wait(1)
 print ('Your hp: %d, %s hp: %d' % (hp, enemy, enemyHP))
 wait(1)
 updateAction()
 act = []
 for i in action:
 print (i + ': ' + str(action[i][0]) + ' - ' + str(action[i][1]))
 act.append(action[i][2])
 act_str = ', '.join(str(x) for x in act)
 print ('Choices: ' + act_str)
 pmove = choice(act)
 wait(0.7)
 if pmove == 'p':
 d = random.randint(action['Punch'][0], action['Punch'][1])
 enemyHP -= d
 print ('You punch %s for %d damage!' % (enemy, d))
 elif pmove == 'k':
 d = random.randint(action['Kick'][0], action['Kick'][1])
 enemyHP -= d
 print ('You kick %s for %d damage!' % (enemy, d))
 elif pmove == 'h':
 h = random.randint(action['Heal'][0], action['Heal'][1])
 print ('You used a Potion')
 print ('You heal yourself for %d HP!' % h)
 inv['Potion'] -= 1
 print ('You have %d Potions left' % (inv['Potion']))
 updateAction()
 hp += h
 elif pmove == 's':
 d = random.randint(action['Shoot'][0], action['Shoot'][1])
 print ('You used an Arrow')
 print ('You shoot %s for %d damage!' % (enemy, d))
 inv['Arrow'] -= 1
 print('You have %d Arrows left' % (inv['Arrow']))
 updateAction()
 enemyHP -= d
 if enemyHP <= 0:
 print("You defeated %s!" % enemy)
 return
 wait(1)
 emove = random.randint (1, 3)
 if emove == 1:
 dam = random.randint(1, 5) + 10 * level
 print ('%s scratches you for %d damage!' % (enemy, dam))
 hp -= dam
 elif emove == 2:
 dam = random.randint(6, 10) + 0.5 * level
 print ('%s bites you for %d damage!' % (enemy, dam))
 hp -= dam
 else:
 heal = random.randint(9, 15) + 1 * level
 print ('%s healed for %d HP!' % (enemy, heal))
 enemyHP += heal
def loot(a, p): #probability of getting loot from enemy
 wait(1)
 pArrow = random.randint(1, 100)
 pPotion = random.randint(1, 100)
 if pArrow <= a:
 inv['Arrow'] += 1
 print ('You found an Arrow!')
 wait(0.5)
 print('You now have %d Arrows' % inv['Arrow'])
 wait(0.7)
 if pPotion <= p:
 inv['Potion'] += 1
 print ('You found a Potion!')
 wait(0.5)
 print('You now have %d Potions' % inv['Potion'])
 wait(0.7)
start()
200_success
145k22 gold badges190 silver badges478 bronze badges
asked Sep 14, 2018 at 22:16
\$\endgroup\$
3
  • 2
    \$\begingroup\$ I'm not very good at Python so I don't have any criticism other than to say, I've briefly played your game, got into a fight with a wolf, defeated the wolf and thoroughly enjoyed it. :) \$\endgroup\$ Commented Sep 14, 2018 at 22:58
  • \$\begingroup\$ One thing you might consider is putting another new line after Choose an action: to give a little separation between each turn. \$\endgroup\$ Commented Sep 15, 2018 at 4:33
  • \$\begingroup\$ @I0_ol Glad you enjoyed it! I'll implement a turn counter along with the other updates so the user knows which turn they are on. \$\endgroup\$ Commented Sep 15, 2018 at 5:54

1 Answer 1

1
\$\begingroup\$

Nice work!

Here are some things you can improve:

  • Style: PEP8 - you can check it with http://pep8online.com/ and there are many editors / editor-plugins that autocorrect or at least complain.
  • #can be commented away for quicker testing is useless
  • Variable names:
    • inv: inventory would be better
    • What is an rMap, what a pMap?
  • Documentation: Adding docstrings is usually a good idea.

Object Orientation

You could create a couple of objects and assign attributes / functions to them:

  • Game: Command line interactions, contains the other objects.
    • Has the map(s) as a property
  • Player: Has an intentory, a position, hp, ...
answered Sep 14, 2018 at 22:58
\$\endgroup\$
1
  • \$\begingroup\$ Thanks for the feedback!. Forgot to remove the # in wait. rMap is the real map, but is not shown to the player so there is some element of exploration. pMap is the map shown to the player, and is updated to reveal the adjacent areas whenever the player moves to a new location. I'll update their names to reflect that. Right, realised that I used an object oriented language but did not use any objects... Silly me! Creating a class would also be a better way to manage the enemies' stats instead of a list within a dictionary. \$\endgroup\$ Commented Sep 15, 2018 at 5:46

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.