Feb-11-2021, 02:51 AM
This is a project I have been working on for a couple of months. The project has drastically improved my understanding of Python3 and I have been pretty good about attacking most if not all of the problems so far by myself. However, once the project files start to get a little bigger (this being my largest project thus far) it gets much easier to miss simple mistakes. I think this needs a fresh pair of eyes. Don't worry too much about tweaking it into a more efficient version, I'll get there. I don't mind any critiques picking out obvious no-no's or offering any advice or suggestions unrelated to the main error issue..
With that out of the way, here is the problem I am experiencing that I need looked over. I will post the 2 main files first and then the rest of the project for others to observe and learn from as well. I noticed there aren't as many advanced RPG code examples provided online so I want to put together this project as a open-source text-based PyMUD. One obvious mistake is unnecessary imports but maybe I did right.
With that out of the way, here is the problem I am experiencing that I need looked over. I will post the 2 main files first and then the rest of the project for others to observe and learn from as well. I noticed there aren't as many advanced RPG code examples provided online so I want to put together this project as a open-source text-based PyMUD. One obvious mistake is unnecessary imports but maybe I did right.
Error:Traceback (most recent call last):
File "D:\Documents\Game Programming\Python Project Files\Self-Py Projects\SmallGame\play.py", line 8, in <module>
Interface.main_menu()
File "D:\Documents\Game Programming\Python Project Files\Self-Py Projects\SmallGame\uimenu.py", line 26, in main_menu
player.location['Name'],
AttributeError: 'NoneType' object has no attribute 'location'play.pyfrom uimenu import *
from account import *
import output
if __name__ == '__main__':
Account.create(Account)
Player.create()
Interface.main_menu()uimenu.pyfrom output import *
from player import *
import maps
class Interface:
def main_menu():
actions = ['gm', 'revive']
alphas = False
asci = False
commands = ['target', 'heal', 'n', 'north', 's', 'south', 'e', 'east', 'w', 'west']
esc = ['quit',
'exit',
'q',
'esc']
numeric = False
reset = ['cls',
'main',
'menu',
'reset',
'restart']
run = [True, False]
spaces = False
Output.iFrame(Output,
'#',
player.location['Name'],
'_',
player.location['Description'],
player.location['Content'])
print('\nActions:',actions,'\nCommands:',commands,'\nMenu:',reset,'\nQuit:',esc)
while run[0] is True:
uin = input(f'\n{player.tag}{player.name}[{player.level}] | Health: {player.health}/{player.mhp} | Experience: {player.exp}/{player.exp2lvl}\n\n>>> ').lower()
try:
if '.' in uin[:1]:
if uin[1:] not in actions:
for char in uin[1:]:
if char.isspace():
spaces = True
elif char.isalpha():
alphas = True
elif char.isdigit():
numeric = True
elif char.isascii():
asci = True
if spaces is True:
print('\n|Notice|- The (.)command must not contain any spaces! Please try again.')
spaces = False
continue
elif alphas is True and spaces is False and numeric is False and asci is False:
print('\n|Notice|- The (.)command was entered incorrectly or does not exist! Please try again.')
alphas = False
continue
elif asci is True and len(uin) > 1:
print('\n|Notice|- Except for (.) Special characters are not valid or accepted in (.)commands! Please try again.')
asci = False
spaces = False
alphas = False
numeric = False
continue
elif numeric is True:
print('\n|Notice|- The (.)command must not contain any numerical digits! Please try again.')
numeric = False
continue
elif uin[1:] == '' or alphas is False and numeric is False and asci is False and spaces is False:
print('\n|Notice|- No command was entered after the (.)! Please try again.')
continue
else:
try:
#Handles all (.)Actions
if uin[1:] == actions[0]:
#GM-ON
if player.tag == '':
player.tag = '[GM]-'
print('\n|Notice|- You have upgraded your rank to Game Master.')
else:
if player.tag == '[GM]-':
player.tag = ''
print('\n|Notice|- You have disabled your rank of Game Master.')
elif uin[1:] == actions[1]:
if player.tag == '':
print('\n|Notice|- You must be a Game Master in order to use the revive command!')
if player.health - 100 >= 1:
player.health -= 100
else:
player.health -= player.health
player.death()
elif player.tag == '[GM]-':
if player.health < 1:
print(f'\n|Notice|- You have been revived by Game Master {player.name}!')
player.health = 0
player.health += player.mhp
else:
print('\n|Notice|- You can not be revived if you are alive!')
finally:
#print('\n|Notice|- You have successfully executed a .command!\n')
pass
elif uin == '':
print('\n|Notice|- There was no command entered! Please try again.')
continue
elif ' ' in uin:
print('\n|Notice|- The command must not contain any spaces! Please try again.')
continue
elif uin not in esc and uin not in reset:
if uin not in commands:
for char in uin:
if char.isspace():
spaces = True
elif char.isalpha():
alphas = True
elif char.isdigit():
numeric = True
elif char.isascii():
asci = True
if alphas is True and spaces is False and numeric is False and asci is False:
print('\n|Notice|- The command was entered incorrectly or does not exist! Please try again.')
alphas = False
continue
elif numeric is True:
print('\n|Notice|- The command must not contain any numerical digits! Please try again.')
numeric = False
continue
elif asci is True:
print('\n|Notice|- The command contains special characters that are not valid or accepted! Please try again.')
asci = False
numeric = False
alphas = False
spaces = False
continue
else:
if player.health == 0:
print('\n|Notice|- You must first revive before you can enter a command! Only Action Commands work right now.')
else:
try:
#Handles all Commands
if uin == commands[0]:
player.get_target()
elif uin == commands[1]:
player.heal()
elif uin == commands[2] or uin == commands[3]:
if player.location['North'] == '':
print('\n|Notice|- You can no longer travel further North. Please pick one of the paths described in your current map\'s description.')
else:
print(f'\n{player.name} travels North!')
player.location = maps.Map.zonemap[player.location['North']]
elif uin == commands[4] or uin == commands[5]:
if player.location['South'] == '':
print('\n|Notice|- You can no longer travel further South. Please pick one of the paths described in your current map\'s description.')
else:
print(f'\n{player.name} travels South!')
player.location = maps.Map.zonemap[player.location['South']]
elif uin == commands[6] or uin == commands[7]:
if player.location['East'] == '':
print('\n|Notice|- You can no longer travel further East. Please pick one of the paths described in your current map\'s description.')
else:
print(f'\n{player.name} travels East!')
player.location = maps.Map.zonemap[player.location['East']]
elif uin == commands[8] or uin == commands[9]:
if player.location['West'] == '':
print('\n|Notice|- You can no longer travel further West. Please pick one of the paths described in your current map\'s description.')
else:
print(f'\n{player.name} travels West!')
player.location = maps.Map.zonemap[player.location['West']]
finally:
Interface.main_menu()
break
else:
if uin in esc:
print('\n|Notice|- Terminating Program Sequence. Good-bye!')
run.reverse()
Interface.UI_quit()
break
elif uin in reset:
print('\n|Notice|- Restarting Program Sequence. See you soon!')
run.reverse()
Interface.main_menu()
break
#except:
#print('|Notice|- An error has prevented a section of this code from being executed.\n')
finally:
pass
def UI_quit():
gap = ' '*20
print(' _____ _ _\n'+
'|_ _|| | | |\n'+
' | | | |__ __ _ _ __ | | __ ___\n'+
' | | | \'_ \ / _` || \'_ \ | |/ // __|\n'+
' | | | | | || (_| || | | || < \__ \\\n'+
' \_/ |_| |_| \__,_||_| |_||_|\_\|___/\n'+gap+
' _____\n'+gap+
'| ___|\n'+gap+
'| |_ ___ _ __\n'+gap+
'| _|/ _ \ | \'__|\n'+gap+
'| | | (_) || |\n'+gap+
'\_| \___/ |_|\n'+
' _____ _ _\n'+
'| ___ \| | (_)\n'+
'| |_/ /| | __ _ _ _ _ _ __ __ _\n'+
'| __/ | | / _` || | | || || \'_ \ / _` |\n'+
'| | | || (_| || |_| || || | | || (_| |\n'+
'\_| |_| \__,_| \__, ||_||_| |_| \__, |\n'+
' __/ | __/ |\n'+
' |___/ |___/\n')player.pyimport random, time, os, maps, uimenu
from enemy import *
from output import *
player = None
class Player:
max_level = 20
exp_mod = 1
def __init__(self,
name,
mhp,
health,
level,
exp,
exp2lvl,
target,
tag,
location):
self.name = name
self.health = health
self.mhp = health
self.level = level
self.exp = exp
self.exp2lvl = exp2lvl
self.target = target
self.tag = tag
self.location = location
def __str__(self):
if self.health < 0:
self.health = 0
return(f'\n[Player Details]\nCharacter: {self.tag}{self.name}\nLevel: {self.level}\nHealth: {self.health}/{self.mhp}\nExperience: {self.exp}/{self.exp2lvl}')
def create():
Output.iFrame(Output, '#', 'PyRona RPG v1.10', '_', 'Character Creation Menu', 'We will now create your in-game PyRona RPG character.', 50)
name = input('\nCreate Character: ')
health = random.randrange(500, 1500, 5)
mhp = health
level = 1
exp = 0
exp2lvl = 500 * level * (1+level)
target = [None]
tag = ''
location = maps.Map.zonemap['a1']
player = Player(name, mhp, health, level, exp, exp2lvl, target, tag, location)
print('\n[Character Details]')
time.sleep(random.uniform(0.25, 0.75))
print(f'Name: {player.name}')
time.sleep(random.uniform(0.25, 0.75))
print('Location:',player.location['Name'])
time.sleep(random.uniform(0.25, 0.75))
print(f'Level: {player.level}')
time.sleep(random.uniform(0.25, 0.75))
print(f'Health: {player.health}/{player.mhp}')
time.sleep(random.uniform(0.25, 0.75))
print(f'Experience: {player.exp}/{player.exp2lvl}')
time.sleep(random.uniform(0.25, 0.75))
while True:
input('\n|Notice|- Press the enter key to continue.')
break
def levelup(self):
self.target = [None]
if self.exp >= self.exp2lvl:
self.health = self.mhp
self.level += 1
self.exp2lvl = 500 * self.level * (1+self.level)
self.health += (random.randrange(25, 125, 25)) * self.level
self.mhp = self.health
print(f'Congratulations {self.name}! You have just advanced to level {self.level}!')
if self.level < Player.max_level:
if self.exp >= self.exp2lvl:
self.levelup()
else:
print(self)
else:
print('|Notice|- You may no longer gain experience from battles. You have reached the maximum level!')
self.exp = self.exp2lvl
def get_target(self):
try:
if self.health == 0:
print('\n|Notice|- You are dead and may not obtain a target!')
self.death()
else:
if None in self.target:
self.target.clear()
#Continue building map spawns by checking if index [0]-[3] in list A, B, C, or D are equal by comparison to the players self.location['Name']
vmaps = ['A1', 'A2', 'A3', 'A4', 'B1', 'B2', 'B3', 'B4', 'C1', 'C2', 'C3', 'C4', 'D1', 'D2', 'D3', 'D4']
if 'A' in self.location['Name']:
#65, 30, 5, 0
map_spawn = random.choices(creatures, [65, 30, 5, 0])
enemy = random.choice(map_spawn)
self.target = enemy()
elif 'B' in self.location['Name']:
#25, 42, 32, 1
map_spawn = random.choices(creatures, [25, 42, 32, 1])
enemy = random.choice(map_spawn)
self.target = enemy()
elif 'C' in self.location['Name']:
#5, 60, 30, 5
map_spawn = random.choices(creatures, [5, 60, 30, 5])
enemy = random.choice(map_spawn)
self.target = enemy()
elif 'D' in self.location['Name']:
#0, 25, 45, 30
map_spawn = random.choices(creatures, [0, 25, 45, 30])
enemy = random.choice(map_spawn)
self.target = enemy()
print(self.target)
self.attack()
except:
print(f'\n|Notice|- You are already attacking a {self.target.name}\n')
def attack(self):
attacker = ['Enemy', 'Player']
while self.health > 0 and self.target.health > 0:
if attacker[0] == 'Player':
if self.tag == '[GM]-':
self.dmg = round(random.randrange(50, 150, 1)*self.target.level/20*self.level)
else:
self.dmg = round(random.randrange(1, 5, 1)*self.target.level/2)
print(f'\nPlayer attacks target for {self.dmg} points of damage!')
self.target.health -= self.dmg
attacker.reverse()
print(self.target)
time.sleep(1)
elif attacker[0] == 'Enemy':
a = int(self.target.dmg[:2])
b = int(self.target.dmg[5:7])
self.target.damage = random.randrange(a, b, 1)
print(f'{self.target.name} attacks player for {self.target.damage} points of damage!')
self.health -= self.target.damage
attacker.reverse()
print(self)
time.sleep(1)
else:
if self.health <= 0:
print(f'{self.name} was just slain by a {self.target.name}... Better luck next time!')
self.death()
elif self.target.health <= 0:
if self.tag == '[GM]-':
Player.exp_mod = random.randrange(5, 20, 1)
exp_gain = (random.randrange(10, 35, 1) * self.target.level)*Player.exp_mod/2
else:
Player.exp_mod = 1
exp_gain = (random.randrange(10, 35, 1) * self.target.level)/2+50
if self.level < Player.max_level:
print(f'You have just slain a level {self.target.level} \'{self.target.name}\'.\nThis creature\'s type was: {self.target.ctype}\nYou have gained {exp_gain} experience!\nXP Modifier: {Player.exp_mod}')
self.exp += exp_gain
if self.exp >= self.exp2lvl:
self.levelup()
self.target = [None]
def print_inventory(self):
pass
def heal(self):
if self.health < 1:
print('\n|Notice|- You must first be revived by a Game Master before you can heal!')
else:
if self.health >= self.mhp:
self.health = self.mhp
print('\n|Notice|- You are already at max health and can no longer receive heals!')
else:
heals = random.randrange(75, 250, 1)
if self.health + heals <= self.mhp:
if heals > 175:
print(f'\nYou have been healed with a major healing touch for {heals} health points!')
else:
print(f'\nYou have been healed with a healing touch for {heals} health points!')
self.health += heals
else:
print(f'\nYou have been healed to max health from a healing touch spell.')
self.health = self.mhp
def death(self):
self.target = [None]
if self.health < 1:
#self.health = 0
print('You are dead... Now you must figure out a way to revive!')
else:
return('\n[Death]: You are not dead. Who do you think you are? Get outta here!')enemy.pyimport random, time
class Enemy:
def __init__(self, name, ctype, level, health, dmg):
self.name = name
self.ctype = ctype
self.level = level
self.health = health
self.max_health = health
self.dmg = dmg
def __str__(self):
if self.health < 0:
self.health = 0
return(f'\n[Enemy Details]\nName: {self.name}\nType: {self.ctype}\nLevel: {self.level}\nHealth: {self.health}/{self.max_health}\nDamage: {self.dmg}\n')
def display(self):
print(self.__str__())
class Zombie(Enemy):
def __init__(self):
super().__init__(name='Zombie', ctype='Undead', level=5, health=75, dmg = '05 - 15')
class Ghost(Enemy):
def __init__(self):
super().__init__(name='Ghost', ctype='Apparition', level=10, health=150, dmg = '15 - 30')
class Wolf(Enemy):
def __init__(self):
super().__init__(name='Wolf', ctype='Creature', level=15, health=300, dmg = '30 - 60')
class Troll(Enemy):
def __init__(self):
super().__init__(name='Troll', ctype='Humanoid', level=20, health=500, dmg = '60 - 99')
creatures = [Zombie, Ghost, Wolf, Troll]items.pyfrom output import *
class Item():
'The base class for all items'
def __init__(self, name, description, value):
self.name = name
self.description = description
self.value = value
def __str__(self):
return ('Name: {}\nDescription: {}\nValue: {}\n'.format(self.name, self.description, self.value))
class Weapon(Item):
'This is a subclass of Item: A class for all Weapons'
def __init__(self, name, description, value, damage):
self.damage = damage
super().__init__(name, description, value)
def __str__(self):
return("Name: {}\nDescription: {}\nValue: {}\nDamage: {}\n".format(self.name, self.description, self.value, self.damage))
class Rock(Weapon):
'class for Weapon: Rock'
def __init__(self):
super().__init__(name = 'Rock',
description = 'A fist-sized rock, suitable for bludgeoning.',
value = 0,
damage = 2.5)
class Dagger(Weapon):
def __init__(self):
super().__init__(name = "Dagger",
description = "A dull dagger with some rust. It's better than nothing..",
value = 20,
damage = 4.0)
class Gold(Item):
'This is the \'GoldCoin\' class'
def __init__(self, amt):
self.amt = amt
super().__init__(name = 'Gold',
description = 'A loot of \'Gold Coins\'. This is certainly a valuable stash.',
value = amt)output.pyimport random, sys, textwrap, time
class Output:
def iFrame(self,
border='#',
header='',
lbreak='_',
desc='',
content=(''),
width=50):
iFrame = {
'Border': f'{border}'*50,
'Header': f'{border}'+header.center(48)+f'{border}',
'Content': content.center(50),
'Desc': f'{border}'+desc.center(48)+f'{border}',
'Break': f'{border}'+lbreak*48+f'{border}'
}
print('\r')
print(iFrame['Border']),
print(iFrame['Header']),
print(iFrame['Break']),
print(iFrame['Desc']),
print(iFrame['Border']+'\n'),
Output.content(Output, content, width)
def content(self, content, width):
'''Formatting content with textwrap.'''
wrapper = textwrap.TextWrapper(width)
default_content = wrapper.wrap(text = content)
for element in default_content:
print(element)
def text_delay(text, delay):
for characters in text:
sys.stdout.write(characters)
sys.stdout.flush()
time.sleep(delay)account.pyfrom output import *
import errno, json, os, random, time
cache = None
account = None
class Account:
i = 0
data = {'ID': None,
'Username': None,
'Password': None,
'Date': None}
def __init__(self,
uid,
username,
password,
date):
self.uid = uid
self.username = username
self.password = password
self.date = date
def __str__(self):
return('\n##################################################\n# PyRona RPG v1.10 #\n#________________________________________________#\n# Account Login Menu #\n##################################################')
def create(self):
global cache
global account
Output.iFrame(Output, '#', 'PyRona RPG v1.10', '_', 'Account Creation Menu', 'Creating a new account is easy. Enter the following information into the prompt to register your account.')
account = Account(Account.i+1, input('\nCreate Username: '), input('Create Password: '), time.ctime()[11:24])
cache = [account.uid,
account.username,
account.password]
print('\nImporting Account {} to Databse @ {}'.format(account.username, time.ctime()[11:24]))
Account.data.update({'ID': account.uid,
'Username': account.username,
'Password': '*'*len(account.password),
'Date': time.ctime()[11:24]})
self.write_file()
print('Table Updated Successfully @ {}'.format(time.ctime()[11:24]))
print(account)
account.login(input('\nUsername: '),
input('Password: '))
def login(self, username, password):
global cache
print('\n--[Logging Into Account: {}'.format(self.username))
time.sleep(2)
if username == cache[1] and password == cache[2]:
print(f'Welcome, {self.username}. You have successfully logged in!')
else:
print('\nInvalid Login, please try again!\n')
self.login(input('Username: '),
input('Password: '))
def write_file():
filename = f'\Documents\Game Programming\Python Project Files\Self-Py Projects\SmallGame\Data\{account.username}.txt'
if not os.path.exists(os.path.dirname(filename)):
try:
os.makedirs(os.path.dirname(filename))
except OSError as exc:
raise
with open(filename, 'w') as file:
file.write('\r'+json.dumps(Account.data))maps.py#MAP REFERENCE
'''
*Starting on B2
____________
|A1|A2|A3|A4|
|B1|B2|B3|B4|
|C1|C2|C3|C4|
|D1|D2|D3|D4|
-------------
'''
class Map:
zonename = 'Name'
description = 'Description'
content = 'Content'
solved = False
north = 'North'
south = 'South'
west = 'West'
east = 'East'
solved_places = {'a1': False, 'a2': False, 'a3': False, 'a4': False,
'b1': False, 'b2': False, 'b3': False, 'b4': False,
'c1': False, 'c2': False, 'c3': False, 'c4': False,
'd1': False, 'd2': False, 'd3': False, 'd4': False
}
zonemap = {
'a1': {
zonename: 'A1',
description: 'Here is the description of A1',
content: 'MAP A1: You can travel in the directions South or East!',
solved: False,
north: '',
south: 'b1',
west: '',
east: 'a2'
},
'a2': {
zonename: 'A2',
description:'Here is the description of A2',
content: 'MAP A2: You can travel in the directions South, East, or West!',
solved: False,
north: '',
south: 'b2',
west: 'a1',
east: 'a3'
},
'a3': {
zonename: 'A3',
description: 'Here is the description of A3',
content: 'MAP A3: You can travel in the directions South, East, or West!',
solved: False,
north: '',
south: 'b3',
west: 'a2',
east: 'a4'
},
'a4': {
zonename: 'A4',
description: 'Here is the description of A4',
content: 'Map A4: You can travel in the directions South or West!',
solved: False,
north: '',
south: 'b4',
west: 'a3',
east: ''
},
'b1': {
zonename: 'B1',
description: 'Here is the description of B1',
content: 'Map B1: You can travel in the directions North, South, or East!',
solved: False,
north: 'a1',
south: 'c1',
west: '',
east: 'b2'
},
'b2': {
zonename: 'B2',
description: 'Here is the description of B2',
content: 'Map B2: You can travel in the directions North, South, East, and West!',
solved: False,
north: 'a2',
south: 'c2',
west: 'b1',
east: 'b3'
},
'b3': {
zonename: 'B3',
description: 'Here is the description of B3',
content: 'Map B3: You can travel in the directions North, South, East, and West!',
solved: False,
north: 'a3',
south: 'c3',
west: 'b2',
east: 'b4'
},
'b4': {
zonename: 'B4',
description: 'Here is the description of B4',
content: 'Map B4: You can travel in the directions North, South, or West!',
solved: False,
north: 'a4',
south: 'c4',
west: 'b3',
east: ''
},
'c1': {
zonename: 'C1',
description: 'Here is the description of C1',
content: 'Map C1: You can travel in the directions North, South, or East!',
solved: False,
north: 'b1',
south: 'd1',
west: '',
east: 'c2'
},
'c2': {
zonename: 'C2',
description: 'Here is the description of C2',
content: 'Map C2: You can travel in the directions North, South, East, or West!',
solved: False,
north: 'b2',
south: 'd2',
west: 'c1',
east: 'c3'
},
'c3': {
zonename: 'C3',
description: 'Here is the description of C3',
content: 'Map C3: You can travel in the directions North, South, East, and West!',
solved: False,
north: 'b3',
south: 'd3',
west: 'c2',
east: 'c4'
},
'c4': {
zonename: 'C4',
description: 'Here is the description of C4',
content: 'Map C4: You can travel in the directions North, South, or West!',
solved: False,
north: 'b4',
south: 'd4',
west: 'c3',
east: ''
},
'd1': {
zonename: 'D1',
description: 'Here is the description of D1',
content: 'Map D1: You can travel in the directions North or East!',
solved: False,
north: 'c1',
south: '',
west: '',
east: 'd2'
},
'd2': {
zonename: 'D2',
description: 'Here is the description of D2',
content: 'Map D2: You can travel in the directions North, East, or West!',
solved: False,
north: 'c2',
south: '',
west: 'd1',
east: 'd3'
},
'd3': {
zonename: 'D3',
description: 'Here is the description of D3',
content: 'Map D3: You can travel in the directions North, East, or West!',
solved: False,
north: 'c3',
south: '',
west: 'd2',
east: 'd4'
},
'd4': {
zonename: 'D4',
description: 'Here is the description of D4',
content: 'Map D4: You can travel in the directions North, East, or West!',
solved: False,
north: 'c4',
south: '',
west: 'c3',
east: ''
}
}
