5
\$\begingroup\$

Short (Non-Explanatory) Summary of Code

I just started learning Python a month or 2 ago, and this (small) 955 line mess is what I've worked on since summer started in June. I am basing it on Dungeons and Dragons, and so far, the coding has gone relatively smooth. I used Enthought Canopy to code this, as it allows me to call anything in the code using the input/output box.

So far, I have:

  • A class for NPCs/enemies with methods covering most of the basics.
  • An item class with its own child classes for weapons, armour, and bags.
  • A skill class for attack moves and such.
  • An effect class, which is just for dealing damage and healing so far.
  • An effect-over-time class, which handles the basic damage/heal each turn.
  • A (currently) empty treasure generator, which I'm planning to link to a .txt file.

Explanation of Code

  • An underscore (_) before a variable/method name signifies that it is 'raw'. It's not meant to be accessed by itself or is the backbone of a similarly named method. eg: _inven and inven(), _drop() and drop(). Note that some 'raw' variables and methods do not yet have a non-underscored method.
  • Similar brackets, eg: ((, )), [[, {{, etc. have a space between them to make it easier (for me) to read.
  • Empty lines are added at the ends of if, elif, and else statements. ie:

    if statement:
     #do something
    elif otherStatement:
     if moreStatment:
     #do moreSomething
     else:
     #do somethingElse
    else:
     #do otherSomething
    
  • I also randomly add an empty line whenever it makes it easier (for me) to read.

What to Do

I will accept any and all criticism given to me provided it isn't a blatant stab at my lack of skill. Please include at least 1 Must Change and/or Recommended Change. These can be structure formatting, renaming variables, confused queries of what a method does, etc. I will only accept praise if you hide it within a criticism.

The Code

'''
To Do List:
 * Add _drop() and drop() methods to NPC (in-progress on doc)
 - Convert to suitable format for Bag
 * Create file for treasure
 - Adapt getTreasure() to access file (in-progress)
 * Add Trap
 * Add talk() method to NPC
 * Create GUI (Later)
'''
import math
import random
#import tkinter
class NPC:
 def __init__(self, name='Shrouded Figure', agil=0.0, char=0.0, endur=0.0, stren=0.0, tough=0.0, will=0.0, wis=0.0, luck=0.0, focus=0.0, magpot=0.0, level=None, gold=0, skills={}, inven={}, equipment={}):
 #Name
 self.name = name
 #Attributes
 self._attributes = {
 'agility' : agil, 
 'charisma' : char, 
 'endurance' : endur, 
 'strength' : stren, 
 'toughness' : tough, 
 'willpower' : will, 
 'wisdom' : wis, 
 'luck' : luck, 
 'focus' : focus, 
 'magic potential' : magpot
 }
 #Random attribute generator
 for attrib in self._attributes: 
 if type(self._attributes[attrib]) == list:
 self._attributes[attrib] = float(random.randint(self._attributes[attrib][0], self._attributes[attrib][1]) )
 if type(level) == int:
 for n in range(level):
 self._attributes[random.choice(list(self._attributes) )] += 1.0
 #Stats
 self._stats = {
 'speed' : math.ceil( ( ( (self._attributes['agility'] + ( (self._attributes['agility'] * self._attributes['endurance']) ** 0.5)/3 + self._attributes['endurance']/2) + 1) * (self._attributes['willpower'] + 1) ) ** 0.5), 
 'health' : math.ceil( ( ( self._attributes['toughness']**2 - self._attributes['toughness'])/2 + self._attributes['endurance']/5 + 1) * (self._attributes['willpower']/10 + 1) + 24), 
 'accuracy' : math.ceil( (40*(1 - 0.9**self._attributes['focus']) + 30*(1 - 0.9**self._attributes['luck']) + 20*(1 - 0.9**self._attributes['willpower']) + 10) * 10) / 10, 
 'stamina' : math.ceil( (self._attributes['endurance'] - 1/(self._attributes['willpower'] + 1) + 1) + (self._attributes['willpower'] - 1/(self._attributes['endurance'] + 1) + 1)/2 + 5), 
 'power' : math.ceil( (self._attributes['strength'] + self._attributes['willpower']/2 + (self._attributes['strength']*self._attributes['willpower'] + self._attributes['endurance']/3)/(self._attributes['strength'] + self._attributes['willpower'] + 1) + 1 + self._attributes['endurance']/5) * 10) / 10, 
 'recovery' : math.ceil( (self._attributes['magic potential']/5 + self._attributes['endurance'] + self._attributes['toughness']/3 + 1 + ( (self._attributes['magic potential'] * self._attributes['endurance'] * self._attributes['toughness']) ** 0.5) / 4) / 1.5), 
 'awareness' : math.ceil( ( ( ( (self._attributes['luck']/5 + self._attributes['focus'] + self._attributes['willpower']/3) ** 1.5) + 1.25) / 5) * 10) / 10, 
 'sneaking' : math.ceil( ( ( (self._attributes['luck'] + self._attributes['focus']/2 + self._attributes['agility']/3 + 1) ** 0.75) * (self._attributes['focus']/2 + 1) / 4) * 10) / 10, 
 'dodging' : math.ceil( (50*(1 - 0.9**self._attributes['agility']) + 30*(1 - 0.9**self._attributes['willpower']) + 20*(1 - 0.9**self._attributes['luck']) ) * 10) / 10, 
 'shielding' : math.ceil( (self._attributes['toughness']/2 + self._attributes['willpower']/3 + self._attributes['strength']) * self._attributes['strength']/4), 
 'mPower' : math.ceil( ( ( (self._attributes['magic potential'] + self._attributes['strength']/2 + self._attributes['willpower']/5) * self._attributes['magic potential']/4) ** (1/3) ) * 10) / 10, 
 'mReserves' : math.ceil(self._attributes['magic potential'] + (self._attributes['magic potential'] * self._attributes['endurance'])**0.5 + (self._attributes['endurance']/2)**1.25), 
 'mSkill' : math.ceil( (self._attributes['magic potential'] + self._attributes['wisdom']/2 + (self._attributes['magic potential']*(self._attributes['wisdom'] + 1) ) ) ** 0.5), 
 'mConcentration' : math.ceil( (50*(1 - 0.9**self._attributes['magic potential']) + 30*(1 - 0.9**self._attributes['focus']) + 10*(1 - 0.9**self._attributes['willpower']) + 10*(1 - 0.9**self._attributes['luck']) ) * 10) / 10, 
 'looting' : math.ceil(0.9 * (1 - 0.8**self._attributes['luck'])/0.2 * 20) + 10,
 'capacity' : math.ceil( ( (self._attributes['endurance']/3 + self._attributes['strength'] + 1) * (self._attributes['willpower']/4 + 1) ) + 9)
 }
 '''Unused stats'''
 #'knowledge' : math.ceil( ( ( (self._attributes['charisma']/7 + self._attributes['wisdom'] + self._attributes['magic potential']/11) * (self._attributes['charisma']/5 + self._attributes['wisdom'] + 1) + 1) ** 0.75) * 10) / 10
 #'trading' : math.ceil( (self._attributes['charisma']**2 + self._attributes['wisdom'] + self._attributes['luck']*(self._attributes['luck'] - 1) + 1) ** 0.25)
 #Starting stats
 self.hp = self._stats['health']
 self.sp = self._stats['stamina']
 self.mp = self._stats['mReserves']
 #Skillset
 self._skills = skills
 #Gold
 self.gold = gold
 #Inventory
 self._inven = inven
 #Equipment
 self._equipment = equipment
 #Adjust equality factor
 def __eq__(self, other):
 return self.__dict__ == other.__dict__
 #Adjust string value
 def __str__(self):
 returnStr = 'NPC(name=\'' + self.name + '\''
 if self._attributes['agility'] != 0.0:
 returnStr += ', agil=' + str(self._attributes['agility'])
 if self._attributes['endurance'] != 0.0:
 returnStr += ', endur=' + str(self._attributes['endurance'])
 if self._attributes['charisma'] != 0.0:
 returnStr += ', char=' + str(self._attributes['charisma'])
 if self._attributes['toughness'] != 0.0:
 returnStr += ', tough=' + str(self._attributes['toughness'])
 if self._attributes['strength'] != 0.0:
 returnStr += ', stren=' + str(self._attributes['strength'])
 if self._attributes['wisdom'] != 0.0:
 returnStr += ', wis=' + str(self._attributes['wisdom'])
 if self._attributes['willpower'] != 0.0:
 returnStr += ', will=' + str(self._attributes['willpower'])
 if self._attributes['luck'] != 0.0:
 returnStr += ', luck=' + str(self._attributes['luck'])
 if self._attributes['focus'] != 0.0:
 returnStr += ', focus=' + str(self._attributes['focus'])
 if self._attributes['magic potential'] != 0.0:
 returnStr += ', magpot=' + str(self._attributes['magic potential'])
 if self.gold > 0:
 returnStr += ', gold=' + str(self.gold)
 if len(self._skills) > 0:
 returnStr += ', skills={' + str(self._skills)
 #Used for multiple items
 m = 0
 for skill in self._skills:
 if m > 0:
 returnStr += ', '
 returnStr += '\'' + skill + '\':' + str(self._skills[skill])
 m += 1
 returnStr += '}'
 if len(self._inven) > 0:
 returnStr += ', inven={' + str(self._inven)
 #Used for multiple items
 m = 0
 for item in self._inven:
 if m > 0:
 returnStr += ', '
 returnStr += '\'' + item + '\':' + str(self._inven[item])
 m += 1
 returnStr += '}'
 if len(self._equipment) > 0:
 returnStr += ', equipment={'
 #Used for multiple items
 m = 0
 for item in self._equipment:
 if m > 0:
 returnStr += ', '
 returnStr += '\'' + item + '\':' + str(self._equipment[item])
 m += 1
 returnStr += '}'
 returnStr += ')'
 return returnStr
 #Display info
 def show(self):
 print(self.name)
 print('HP: ' + str(self.hp) + '/' + str(self._stats['health']) )
 print('SP: ' + str(self.sp) + '/' + str(self._stats['stamina']) )
 print('MP: ' + str(self.mp) + '/' + str(self._stats['mReserves']) )
 print('')
 #Activate end-of-turn effects
 def endTurn(self):
 DOT.cycleDOT(target=self)
 self.hp = min(self.hp + self._stats['recovery'], self._stats['health'])
 self.sp = min(self.hp + self._stats['recovery'], self._stats['stamina'])
 self.mp = min(self.hp + self._stats['recovery'], self._stats['mReserves'])
 self.display()
 #Get loot from NPC
 def getLoot(self, user):
 loot = {}
 #Generate loot from inventory
 for item in self._inven:
 #Check for stackable item
 if type(self._inven[item]) == int:
 #Apply looting chances to individual items in stack
 for n in range(self._inven[item]):
 rand = random.randint(1, 100)
 if rand <= user._stats['looting']:
 #Check for/add missing item
 if item not in loot:
 loot[item] = 0
 loot[item] += 1
 else:
 rand = random.randint(1, 100)
 if rand <= user._stats['looting']:
 loot[item] = self._inven[item]
 #Generate loot from equipment
 for item in self._equipment:
 rand = random.randint(1, 100)
 if rand <= user._stats['looting']:
 loot[self._equipment[item].name] = self._equipment[item]
 #Generate loot from gold
 randG = random.randint(0, self.gold**2)
 randG = randG * (user._stats['looting']/100)
 randG = math.ceil(math.sqrt(randG) )
 loot['Gold'] = randG
 #Generate loot from levels (not affected by looting)
 randXp = 0
 for attrib in self._attributes:
 randXp += math.ceil(self._attributes[attrib] ** 1.5)
 loot['XP'] = randXp
 return loot
 #Get dmg of NPC
 def getDmg(self, mult=1, mod=0):
 #Check for weapon
 if 'weapon' in self._equipment:
 #Differentiate between int and list dmg ranges
 if type(self._equipment['weapon'].dmgRange) == int:
 dmg = math.ceil(mult * self._equipment['weapon'].dmgRange) + mod
 elif type(self._equipment['weapon'].dmgRange) == list:
 dmg = math.ceil(mult * random.randint(self._equipment['weapon'].dmgRange[0], self._equipment['weapon'].dmgRange[1]) ) + mod
 else:
 dmg = math.ceil(mod + mult)
 #Keep dmg above or equal to 0
 dmg = max(0, dmg)
 return dmg
 #Get defence of NPC
 def getDef(self):
 defence = 0
 if 'head' in self._equipment:
 defence += self._equipment['head'].defence
 if 'body' in self._equipment:
 defence += self._equipment['body'].defence
 if 'hands' in self._equipment:
 defence += self._equipment['hands'].defence
 if 'legs' in self._equipment:
 defence += self._equipment['legs'].defence
 if 'feet' in self._equipment:
 defence += self._equipment['feet'].defence
 return defence
 #Add item(s) to inventory
 def give(self, items):
 #Check if items is a dict
 if type(items) == dict:
 for item in items:
 #Item variable
 _item = items[item]
 #Name editor
 nameEdit = ''
 #Re-iterate search algorithm until resolved
 while True:
 #Check if item is a list w/ an Item instance
 if type(_item) == list and isinstance(_item[1], Item):
 #Check if item w/ same name is in inven
 if (item + nameEdit) in self._inven:
 #Check if inven item is a list w/ in Item instance
 if type(self._inven[item + nameEdit]) == list and isinstance(self._inven[item + nameEdit][1], Item):
 #Check if item and inven item are the same
 if _item[1] == self._inven[item + nameEdit][1]:
 self._inven[item + nameEdit][0] += _item[0]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 #Check if inven item is an int
 elif type(self._inven[_item[1].name + nameEdit]) == int:
 #Misfire, add *
 nameEdit += '*'
 #Check if item and inven item are the same
 elif item[1] == self._inven[item[1].name + nameEdit]:
 self._inven[item + nameEdit] = [_item[0] + 1, _item[1] ]
 break
 else:
 #Add new item
 self._inven[item + nameEdit] = _item
 break
 #Check if item in an int
 elif type(_item) == int:
 #Check if item is in inven
 if (item + nameEdit) in self._inven:
 #Check if inven item is int
 if type(self._inven[item + nameEdit]) == int:
 self._inven[item + nameEdit] += _item
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 else:
 #Add new item
 self._inven[item + nameEdit] = _item
 break
 #Check if item is an Item instance
 elif isinstance(_item, Item):
 #Check if item w/ same name is in inven
 if (item + nameEdit) in self._inven:
 #Check if inven item is a list w/ in Item instance
 if type(self._inven[item + nameEdit]) == list and isinstance(self._inven[item + nameEdit][1], Item):
 #Check if item and inven item are the same
 if _item == self._inven[item + nameEdit][1]:
 self._inven[item + nameEdit][0] += 1
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 #Check if inven item is Item instance and the same as item
 elif isinstance(self._inven[item + nameEdit], Item) and self._inven[item + nameEdit] == _item:
 self._inven[item + nameEdit] = [2, _item]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 else:
 #Add new item
 self._inven[item + nameEdit] = _item
 break
 else:
 print('Item type(?) not available: ' + str(type(_item) ) )
 break
 #Check if items is a list w/ Item instance
 elif type(items) == list and isinstance(items[1], Item):
 #Name editor
 nameEdit =''
 #Item variable
 _item = items[1]
 while True:
 #Check if item w/ same name is in inven
 if (_item.name + nameEdit) in self._inven:
 #Check if inven item is a list w/ in Item instance
 if type(self._inven[_item.name + nameEdit]) == list and isinstance(self._inven[_item.name + nameEdit][1], Item):
 #Check if item and inven item are the same
 if _item[1] == self._inven[_item.name + nameEdit][1]:
 self._inven[_item.name + nameEdit][0] += items[0]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 #Check if item and inven item are the same
 elif _item == self._inven[_item.name + nameEdit]:
 self._inven[_item.name + nameEdit] = [items[0] + 1, _item]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 else:
 #Add new item
 self._inven[_item.name + nameEdit] = items
 break
 #Check if items is an Item instance
 elif isinstance(items, Item):
 #Name editor
 nameEdit = ''
 #Re-iterate search algorithm until resolved
 while True:
 #Check if item w/ same name is in inven
 if (items.name + nameEdit) in self._inven:
 #Check if inven item is a list w/ in Item instance
 if type(self._inven[items.name + nameEdit]) == list and isinstance(self._inven[items.name + nameEdit][1], Item):
 #Check if item and inven item are the same
 if items == self._inven[items.name + nameEdit][1]:
 self._inven[items.name + nameEdit][0] += 1
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 #Check if inven item is Item instance and the same as item
 elif isinstance(self._inven[items.name + nameEdit], Item) and self._inven[items.name + nameEdit] == items:
 self._inven[items.name + nameEdit] = [2, items]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 else:
 #Add new item
 self._inven[items.name + nameEdit] = items
 break
 else:
 print('Items type(?) not available: ' + str(type(items) ) )
 if len(self._inven) > self._stats['capacity']:
 print(self.name + '\'s inventory is overflowing: ' + str(len(self._inven) ) + '/' + str(self._stats['capacity']) )
 #Change stats of NPC
 def editStat(self, stat, newAmount):
 self._stats[stat] = newAmount
 if stat == 'health':
 self.hp = newAmount
 elif stat == 'stamina':
 self.sp = newAmount
 elif stat == 'mReserves':
 self.mp = newAmount
 print(self.name + '\'s ' + stat + " is now " + str(newAmount) )
 print('')
 def recalc(self, reset=False):
 self._stats = {
 'speed' : math.ceil( ( ( (self._attributes['agility'] + ( (self._attributes['agility'] * self._attributes['endurance']) ** 0.5)/3 + self._attributes['endurance']/2) + 1) * (self._attributes['willpower'] + 1) ) ** 0.5), 
 'health' : math.ceil( ( ( self._attributes['toughness']**2 - self._attributes['toughness'])/2 + self._attributes['endurance']/5 + 1) * (self._attributes['willpower']/10 + 1) + 24), 
 'accuracy' : math.ceil( (40*(1 - 0.9**self._attributes['focus']) + 30*(1 - 0.9**self._attributes['luck']) + 20*(1 - 0.9**self._attributes['willpower']) + 10) * 10) / 10, 
 'stamina' : math.ceil( (self._attributes['endurance'] - 1/(self._attributes['willpower'] + 1) + 1) + (self._attributes['willpower'] - 1/(self._attributes['endurance'] + 1) + 1)/2 + 5), 
 'power' : math.ceil( (self._attributes['strength'] + self._attributes['willpower']/2 + (self._attributes['strength']*self._attributes['willpower'] + self._attributes['endurance']/3)/(self._attributes['strength'] + self._attributes['willpower'] + 1) + 1 + self._attributes['endurance']/5) * 10) / 10, 
 'recovery' : math.ceil( (self._attributes['magic potential']/5 + self._attributes['endurance'] + self._attributes['toughness']/3 + 1 + ( (self._attributes['magic potential'] * self._attributes['endurance'] * self._attributes['toughness']) ** 0.5) / 4) / 1.5), 
 'awareness' : math.ceil( ( ( ( (self._attributes['luck']/5 + self._attributes['focus'] + self._attributes['willpower']/3) ** 1.5) + 1.25) / 5) * 10) / 10, 
 'sneaking' : math.ceil( ( ( (self._attributes['luck'] + self._attributes['focus']/2 + self._attributes['agility']/3 + 1) ** 0.75) * (self._attributes['focus']/2 + 1) / 4) * 10) / 10, 
 'dodging' : math.ceil( (50*(1 - 0.9**self._attributes['agility']) + 30*(1 - 0.9**self._attributes['willpower']) + 20*(1 - 0.9**self._attributes['luck']) ) * 10) / 10, 
 'shielding' : math.ceil( (self._attributes['toughness']/2 + self._attributes['willpower']/3 + self._attributes['strength']) * self._attributes['strength']/4), 
 'mPower' : math.ceil( ( ( (self._attributes['magic potential'] + self._attributes['strength']/2 + self._attributes['willpower']/5) * self._attributes['magic potential']/4) ** (1/3) ) * 10) / 10, 
 'mReserves' : math.ceil(self._attributes['magic potential'] + (self._attributes['magic potential'] * self._attributes['endurance'])**0.5 + (self._attributes['endurance']/2)**1.25), 
 'mSkill' : math.ceil( (self._attributes['magic potential'] + self._attributes['wisdom']/2 + (self._attributes['magic potential']*(self._attributes['wisdom'] + 1) ) ) ** 0.5), 
 'mConcentration' : math.ceil( (50*(1 - 0.9**self._attributes['magic potential']) + 30*(1 - 0.9**self._attributes['focus']) + 10*(1 - 0.9**self._attributes['willpower']) + 10*(1 - 0.9**self._attributes['luck']) ) * 10) / 10, 
 'looting' : math.ceil(0.9 * (1 - 0.8**self._attributes['luck'])/0.2 * 20) + 10,
 'capacity' : math.ceil( ( (self._attributes['endurance']/3 + self._attributes['strength'] + 1) * (self._attributes['willpower']/4 + 1) ) + 9)
 }
 if reset:
 #Starting stats
 self.hp = self._stats['health']
 self.sp = self._stats['stamina']
 self.mp = self._stats['mReserves']
 else:
 self.hp = min(self.hp, self._stats['health'])
 self.sp = min(self.sp, self._stats['stamina'])
 self.mp = min(self.mp, self._stats['mReserves'])
 def _levelUp(self,attrib,value=1):
 self._attributes[attrib] +=value
 self.recalc()
 def inven(self):
 if len(self._inven) > 0:
 print(self.name + '\'s inventory:')
 m = 0
 for item in self._inven:
 m += 1
 if isinstance(self._inven[item], Bag):
 print(str(m) + '/' + str(self._stats['capacity']) + '\t' + item + ':')
 n = 0
 for _item in self._inven[item]._inven:
 n += 1
 if type(self._inven[item]._inven[_item]) == list:
 print('\t' + str(n) + '/' + str(self._inven[item].capacity) + '\t' + _item + ': ' + str(self._inven[item]._inven[_item][0]) + ' x ' + str(self._inven[item]._inven[_item][1]) )
 else:
 print('\t' + str(n) + '/' + str(self._inven[item].capacity) + '\t' + _item + ': ' + str(self._inven[item]._inven[_item]) )
 elif type(self._inven[item]) == list:
 print(str(m) + '/' + str(self._stats['capacity']) + '\t' + item + ': ' + str(self._inven[item][0]) + ' x ' + str(self._inven[item][1]) )
 else:
 print(str(m) + '/' + str(self._stats['capacity']) + '\t' + item + ': ' + str(self._inven[item]) )
 else:
 print(self.name + '\'s inventory is empty.')
#Items
class Item:
 def __init__(self, name, desc=''):
 self.name = name
 self.desc = desc
 def __str__(self):
 returnStr = 'Item(\'' + self.name + '\''
 if len(self.desc) > 0:
 returnStr += ', desc=\'' + self.desc + '\''
 returnStr += ')'
 return returnStr
 def __eq__(self, other):
 return self.__dict__ == other.__dict__
#Weapons
class Weapon(Item):
 def __init__(self, name, kind, dmgRange, minPower=0, mods={}):
 self.name = name
 self.kind = kind
 self.dmgRange = dmgRange
 self.minPower = minPower
 #Currently unused
 self.mods = mods
 #Show weapon info
 def show(self):
 print(self.name)
 print(self.kind)
 #Differentiate between int/list
 if type(self.dmgRange) == list:
 print('Dmg: ' + str(self.dmgRange[0]) + '-' + str(self.dmgRange[1]) )
 else:
 print('Dmg: ' + str(self.dmgRange) )
 if self.minPower > 0:
 print('Minimum Power: ' + str(self.minPower) )
 def __str__(self):
 returnStr = 'Weapon(\'' + self.name + '\', \'' + self.kind + '\', ' + str(self.dmgRange)
 if self.minPower > 0:
 returnStr += ', minPower=' + str(self.minPower)
 if len(self.mods) > 0:
 returnStr += ', mods=' + str(self.mods)
 returnStr += ')'
 return returnStr
#Armour
class Armour(Item):
 def __init__(self, name, place, defence=0, minPower=0, mods={}):
 self.name = name
 self.place = place
 self.defence = defence
 self.minPower = minPower
 #Currently unused
 self.mods = mods
 #Show armour info
 def show(self):
 print(self.name)
 print(self.place)
 print('Defence: ' + str(self.defence) )
 print('Minimum Power: ' + str(self.minPower) )
 def __str__(self):
 returnStr = 'Armour(\'' + self.name + '\', \'' + self.place + '\''
 if self.defence > 0:
 returnStr += ', defence=' + str(self.defence)
 if self.minPower > 0:
 returnStr += ', minPower=' + str(self.minPower)
 if len(self.mods) > 0:
 returnStr += ', mods=' + str(self.mods)
 returnStr += ')'
 return returnStr
class Bag(Item):
 def __init__(self, name, capacity, inven={}):
 self.name = name
 self.capacity = capacity
 self._inven = inven
 def __str__(self):
 returnStr = 'Bag(\'' + self.name + '\', ' + str(self.capacity)
 if len(self._inven) > 0:
 returnStr += ', inven={' + str(self._inven)
 #Used for multiple items
 m = 0
 for item in self._inven:
 if m > 0:
 returnStr += ', '
 returnStr += '\'' + item + '\':' + str(self._inven[item])
 m += 1
 returnStr += '}'
 returnStr += ')'
 return returnStr
 def inven(self):
 if len(self._inven) > 0:
 print(self.name + ':')
 m = 0
 for item in self._inven:
 m += 1
 if type(self._inven[item]) == list:
 print(str(m) + '/' + str(self.capacity) + '\t' + item + ': ' + str(self._inven[item][0]) + ' x ' + str(self._inven[item][1]) )
 else:
 print(str(m) + '/' + str(self.capacity) + '\t' + item + ': ' + str(self._inven[item]) )
 else:
 print(self.name + ' is empty.')
 def add(self,items):
 #Rejected items
 rejects = {}
 #Check if items is a dict
 if type(items) == dict:
 for item in items:
 if len(self._inven) < self.capacity:
 #Item variable
 _item = items[item]
 #Name editor
 nameEdit = ''
 #Re-iterate search algorithm until resolved
 while True:
 #Check if item is a list w/ an Item instance that is not a Bag
 if type(_item) == list and isinstance(_item[1], Item) and not isinstance(_item[1],Bag):
 #Check if item w/ same name is in inven
 if (item + nameEdit) in self._inven:
 #Check if inven item is a list w/ in Item instance
 if type(self._inven[item + nameEdit]) == list and isinstance(self._inven[item + nameEdit][1], Item):
 #Check if item and inven item are the same
 if _item[1] == self._inven[item + nameEdit][1]:
 self._inven[item + nameEdit][0] += _item[0]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 #Check if inven item is an int
 elif type(self._inven[_item[1].name + nameEdit]) == int:
 #Misfire, add *
 nameEdit += '*'
 #Check if item and inven item are the same
 elif item[1] == self._inven[item[1].name + nameEdit]:
 self._inven[item + nameEdit] = [_item[0] + 1, _item[1] ]
 break
 else:
 #Add new item
 self._inven[item + nameEdit] = _item
 break
 #Check if item in an int
 elif type(_item) == int:
 #Check if item is in inven
 if (item + nameEdit) in self._inven:
 #Check if inven item is int
 if type(self._inven[item + nameEdit]) == int:
 self._inven[item + nameEdit] += _item
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 else:
 #Add new item
 self._inven[item + nameEdit] = _item
 break
 #Check if item is an Item instance that is not a Bag
 elif isinstance(_item, Item) and not isinstance(_item,Bag):
 #Check if item w/ same name is in inven
 if (item + nameEdit) in self._inven:
 #Check if inven item is a list w/ in Item instance
 if type(self._inven[item + nameEdit]) == list and isinstance(self._inven[item + nameEdit][1], Item):
 #Check if item and inven item are the same
 if _item == self._inven[item + nameEdit][1]:
 self._inven[item + nameEdit][0] += 1
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 #Check if inven item is Item instance and the same as item
 elif isinstance(self._inven[item + nameEdit], Item) and self._inven[item + nameEdit] == _item:
 self._inven[item + nameEdit] = [2, _item]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 else:
 #Add new item
 self._inven[item + nameEdit] = _item
 break
 else:
 print('Item type(?) not available: ' + str(type(_item) ) )
 rejects[str(items)] = items
 break
 else:
 rejects[item] = items[item]
 #Check if items is a list w/ Item instance that is not a Bag
 elif type(items) == list and isinstance(items[1], Item) and not isinstance(items[1],Bag):
 #Name editor
 nameEdit =''
 #Item variable
 _item = items[1]
 while True:
 #Check if item w/ same name is in inven
 if (_item.name + nameEdit) in self._inven:
 #Check if inven item is a list w/ in Item instance
 if type(self._inven[_item.name + nameEdit]) == list and isinstance(self._inven[_item.name + nameEdit][1], Item):
 #Check if item and inven item are the same
 if _item[1] == self._inven[_item.name + nameEdit][1]:
 self._inven[_item.name + nameEdit][0] += items[0]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 #Check if item and inven item are the same
 elif _item == self._inven[_item.name + nameEdit]:
 self._inven[_item.name + nameEdit] = [items[0] + 1, _item]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 elif len(self._inven) < self.capacity:
 #Add new item
 self._inven[_item.name + nameEdit] = items
 break
 else:
 rejects[items[1].name] = items
 break
 #Check if items is an Item instance that is not a Bag
 elif isinstance(items, Item) and not isinstance(items,Bag):
 #Name editor
 nameEdit = ''
 #Re-iterate search algorithm until resolved
 while True:
 #Check if item w/ same name is in inven
 if (items.name + nameEdit) in self._inven:
 #Check if inven item is a list w/ in Item instance
 if type(self._inven[items.name + nameEdit]) == list and isinstance(self._inven[items.name + nameEdit][1], Item):
 #Check if item and inven item are the same
 if items == self._inven[items.name + nameEdit][1]:
 self._inven[items.name + nameEdit][0] += 1
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 #Check if inven item is Item instance and the same as item
 elif isinstance(self._inven[items.name + nameEdit], Item) and self._inven[items.name + nameEdit] == items:
 self._inven[items.name + nameEdit] = [2, items]
 break
 else:
 #Misfire, add *
 nameEdit += '*'
 elif len(self._inven) < self.capacity:
 #Add new item
 self._inven[items.name + nameEdit] = items
 break
 else:
 rejects[items.name] = items
 break
 else:
 print('Items type(?) not available: ' + str(type(items) ) )
 rejects[str(items)] = items
 if len(rejects) > 0:
 print(self.name + ' is too full, or cannot accept certain items. ' + str(len(rejects) ) + ' items were rejected.')
 return rejects
#Skills
class Skill:
 def __init__(self, name, effects, desc=''):
 self.name = name
 self.effects = effects
 self.desc = desc
 def useSkill(self, user, Target):
 print(user.name + ' used ' + self.name + ' on ' + Target.name)
 if type(self.effects) == list:
 for effect in self.effects:
 eval(effect)
 else:
 eval(self.effects)
 def __str__(self):
 returnStr = 'Skill(\'' + self.name + '\', '
 if type(self.effects) == list:
 returnStr = returnStr + '['
 m = 0
 for effect in self.effects:
 if m > 0:
 returnStr += ','
 returnStr += '\'' + effect + '\''
 m += 1
 returnStr += ']'
 return returnStr
#Effects
class Effects:
 #Dmg target
 def dealDmg(target, dmg):
 print(target.name + ' received ' + str(dmg) + ' damage')
 target.hp -= dmg
 print(target.name + " " + str(target.hp) + "/" + str(target._stats['health']) )
 print('')
 #Heal target
 def heal(target, health):
 print(target.name + ' received ' + str(health) + ' health')
 target.hp = min(target.hp + health, target._stats['health'])
 print(target.name + " " + str(target.hp) + "/" + str(target._stats['health']) )
 print('')
#Deal dmg/heal over x turns
class DealOverTime:
 def __init__(self):
 self.DOTeffects = []
 #add DOT
 def addDOT(self, target, dmg, turns):
 self.DOTeffects.append([target, dmg, turns])
 #Activate any/all stored DOTs
 def cycleDOT(self, target=None):
 for dot in self.DOTeffects:
 #Check if target is in stored DOTs
 if target == None or dot[0] == target:
 #Check if turns remain
 if dot[2] > 0:
 #Differentiate between dmg/heal
 if dot[1] > 0:
 Effects.dealDmg(dot[0], dot[1])
 elif dot[1] < 0:
 Effects.heal(dot[0], -dot[1])
 #Reduce turn counter
 dot[2] -= 1
 #Remove DOT w/ 0 remaining turns
 if dot[2] == 0:
 self.DOTeffects.remove(dot)
#Generate treasure
def getTreasure(size):
 pass
#Initialize new DOT storage
DOT = DealOverTime()
#Test stuff
dummy = NPC("Training Dummy", tough=100)
dummy.show()
200_success
146k22 gold badges190 silver badges479 bronze badges
asked Jul 25, 2017 at 23:02
\$\endgroup\$
5
  • 3
    \$\begingroup\$ maybe write a library for this program, and break this program into multiple modules... I have never realized 955 lines can be so hard to read for another person. \$\endgroup\$ Commented Jul 26, 2017 at 3:52
  • \$\begingroup\$ Those nested ifs with gazillion levels is a horror for readers. Break that into multiple functions please ... my head was spinning when I saw that. \$\endgroup\$ Commented Jul 26, 2017 at 3:54
  • 1
    \$\begingroup\$ Separate calculation (math) and the interface (printing) might be a good idea. When the proof reader/translator tries to work on the text messages, it is not fun if they are all scattered over everywhere in the code. \$\endgroup\$ Commented Jul 26, 2017 at 3:58
  • \$\begingroup\$ @rxu Thanks for all these tips. Please compile them into a review, with some basic solutions, and I'll get right on them. \$\endgroup\$ Commented Jul 27, 2017 at 0:30
  • 1
    \$\begingroup\$ With @hamsteronwheels point about a library I would probably put NPC in a file on its own to be imported and then leave the rest there \$\endgroup\$ Commented Dec 16, 2017 at 17:24

1 Answer 1

2
\$\begingroup\$

Sorry to be the person who does this (I always have this happen when someone reviews my code) but PEP8. The lines between the statements are good but please try and keep your line length under 80 characters. For instance, your init line of NPC is at least three times the recommended line length in PEP8 and later on in init the sums reach even longer. I am not sure what to do for the initialisation apart from maybe have the values set in a few functions you call one after the other (although this seems unnecessary) however the sums should either be separated so that you do some sums on the variable then some more on the next line or just have some line breaks because it helps with readability no end.

Another thing to do with PEP8 is that it may help to add docstrings to the start of your classes and possibly functions as well just explaining briefly what it does (trust me, if you have nothing like that then you will come back to your code a year later and have no idea what the different bits do). It also makes later development a lot easier. Also, with most of your classes you have a comment just before them detailing what they do and it is more pythonesque to put them as the first thing in the class and it also means you can poll the class for it.

I can kind of understand why you have a commented out import tkinter because you plan to add a GUI later but it just seems unnecessary at this stage.

answered Dec 16, 2017 at 17:16
\$\endgroup\$

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.