Skip to main content

Item() rundown

 The item() class holds the information of the item and also runs the item effect when it gets used. Constructor def __init__ ( self , command , name , cost , usage): self .effect = command self .name = name self .cost = cost self .usage = usage The effect holds the string name of the effect for the item,  usage holds the value of the Effect . The rest are self-explanatory. EffectHandler() def effectHandler ( self , user: PlayableCharacter , equip= True ): #learned how to specify type of parameter. if equip: if self .effect == "Def" : user.defense = user.defense + self .usage elif self .effect == "AtkPhy" or self .effect == "AtkMag" : user.attack = user.attack + self .usage else : if self .effect == "hp" : user = self .healing(user) return user This handles the effects of the item when it is used. If equip is true then it will check for the equip...

Combat() completion! Fights exist now!

Combat() has been completed and the game now is starting to feel like a game. It was a lot of work, but I will be honest I was distracted by holiday events and starting University and that's why it took so long to complete. There is so much to go over with Combat() that I'll be making separate posts for each piece of the Combat class with breakdowns on what they do and how. Here I'll post the results and an implementation overview.

Comba() as of now:

class Combat(object):

def __init__(self, continueStatus = True):
self.order = []
self.listing = {}
self.continueStatus = continueStatus
self.taunt = []
self.defRaise = []
self.atkRaise = []
self.protected = []
self.exp = 0

def combatantOrganizer(self):
organizedOrder = []
theStringOrder = []
NumOrder = []
for listing in self.order:
NumOrder.append(listing[1])
NumOrder.sort()
for Num in NumOrder:
for item in self.order:
if Num == item[1]:
theStringOrder.append(item[0])
counter = 0
while counter < len(NumOrder):
organizedOrder.append([theStringOrder[counter], NumOrder[counter]])
counter += 1
self.order = organizedOrder

def skillHandler(self, ally :PlayableCharacter, skill):
if skill == "Axe" or skill == "Smiting Arrow" or skill == "Dagger Poke" or skill == "Slash":
target = self.targetChooser()
if ally.attack - self.listing[target].defense > 0:
self.listing[target].currentHealth = self.listing[target].currentHealth - (ally.attack - self.listing[target].defense)
else:
self.listing[target].currentHealth = self.listing[target].currentHealth - 1
elif skill == "Sweeping Slash":
for figther in self.listing:
if isinstance(self.listing[figther], Monster):
if ally.attack - self.listing[figther].defense > 0:
self.listing[figther].currentHealth = self.listing[figther].currentHealth - (
ally.attack - self.listing[figther].defense)
else:
self.listing[figther].currentHealth = self.listing[figther].currentHealth - 1
elif skill == "Second Wind":
luck = int(random.random() * 10)
ally.currentHealth = ally.currentHealth + luck
if ally.currentHealth > ally.health:
ally.currentHealth = ally.health
elif skill == "Guard up":
luck = int(random.random() * 10) + 1
change = ally.defense/2
self.defRaise.append([ally.displayName, luck, change])
ally.defense = ally.defense + change
elif skill == "Restoring Arrow":
target = self.targetChooser(Ally=True, User=ally.displayName)
self.listing[target].currentHealth = self.listing[target].currentHealth + ally.attack
if self.listing[target].currentHealth > self.listing[target].health:
self.listing[target].currentHealth = self.listing[target].health
elif skill == "Focus Light" or skill == "Focus Light0":
luck = int(random.random()*10) + 1
change = ally.attack
self.atkRaise.append([ally.displayName, luck, change])
ally.attack = ally.attack + change
elif skill == "Lightning Bolt":
target = self.targetChooser()
potential = ally.attack + ally.currentEnergy
if potential - self.listing[target].defense > 0:
self.listing[target].currentHealth = self.listing[target].currentHealth - (potential - self.listing[target].defense)
else:
self.listing[target].currentHealth = self.listing[target].currentHealth - 1
elif skill == "Close Wound":
target = self.targetChooser(Ally=True , User= ally.displayName)
self.listing[target].currentHealth = self.listing[target].currentHealth + ally.currentEnergy
if self.listing[target].currentHealth > self.listing[target].health:
self.listing[target].currentHealth = self.listing[target].health
elif skill == "Fire Ball":
potential = ally.attack + ally.currentEnergy
for figther in self.listing:
if isinstance(self.listing[figther], Monster):
if potential - self.listing[figther].defense > 0:
self.listing[figther].currentHealth = self.listing[figther].currentHealth - (
potential - self.listing[figther].defense)
else:
self.listing[figther].currentHealth = self.listing[figther].currentHealth - 1
elif skill == "Full Guard":
luck = int(random.random() * 10) + 2
change = ally.defense
self.defRaise.append([ally.displayName, luck, change])
ally.defense = ally.defense + change
elif skill == "Taunting Cry":
luck = int(random.random() * 10) + 1
self.taunt.append([ally.displayName, luck])
elif skill == "Rally":
for fighter in self.listing:
if isinstance(self.listing[fighter], PlayableCharacter):
self.skillHandler(self.listing[fighter], "Focus Light0")
elif skill == "Quick Hands":
menuMoment = GameMenu()
menuMoment.update([ally])
itemChoices = menuMoment.displayPC(ally, pcSkip= True)
itemSlected = inputAndCheck("Lauren's call: ", itemChoices)
target = self.targetChooser(Ally= True, User= PlayableCharacter("No One"))
item = ally.inventory[itemSlected]
updatedTarget = item.effectHandler(self.listing[target], equip= False)
self.listing[target] = updatedTarget
ally.inventory.remove(item)
self.listing[ally.displayName] = ally



def foePrep(self, autoSlected= ""):
luck = int(random.random() * 100)
while luck < 1:
luck = int(random.random() * 100)
if autoSlected == "":
for figther in self.listing:
if isinstance(self.listing[figther], Monster):
starter = self.listing[figther]
else:
enemyCatalog = []
f = open("monsterStats.csv")
fReader = csv.reader(f)
for line in fReader:
if line == []:
continue
enemyCatalog.append(line)
for enemy in enemyCatalog:
if autoSlected == enemy[0]:
starter = Monster(attack=int(enemy[2]), health=int(enemy[1]), defense=int(enemy[3]), displayName=autoSlected, experince=int(enemy[7]), petRate=int(enemy[4]), buddyRate=int(enemy[5]), weapon=enemy[6])
self.intiativeRoll(starter)
break
f.close()
dividers = []
if starter.buddyRate > 0:
dividers.append(starter.buddyRate)
dividers.append(starter.buddyRate + starter.petRate)
else:
dividers.append(0)
dividers.append(starter.petRate)
if luck < dividers[0]:
buddy = Monster(attack= starter.attack, health= starter.health, defense= starter.defense, displayName= starter.displayName + "(0)", experince= starter.experience, petRate=starter.petRate, buddyRate= starter.buddyRate, weapon=starter.weapon )
self.intiativeRoll(buddy)
flag = True
counter = 1
while flag:
luck = int(random.random() * 100)
if luck < dividers[0]:
buddy = Monster(attack=starter.attack, health=starter.health, defense=starter.defense,
displayName=starter.displayName + "(" + str(counter) + ")", experince=starter.experience,
petRate=starter.petRate, buddyRate=starter.buddyRate, weapon=starter.weapon)
self.intiativeRoll(buddy)
else:
flag = False
counter += 1
if counter == 6:
flag = False
if luck < dividers[1]:
f = open("encounters.csv")
reader = csv.reader(f)
regionCounter = 0
endFlag = False
for line in reader:
if line == []:
continue
for item in line:
if starter.displayName == item:
endFlag = True
break
if endFlag:
break
regionCounter += 1
f.close()
f = open("pets.csv")
reader = csv.reader(f)
pets = []
for line in reader:
if line == []:
continue
if int(line[0]) == regionCounter:
for pet in line:
try:
int(pet)
continue
except ValueError:
pets.append(pet)
division = int(100/len(pets))
dividers = []
while division < 100:
dividers.append(division)
division += division
dividers.append(100)
luck = int(random.random() * 100)
while luck < 1:
luck = int(random.random() * 100)
counter = 0
for divider in dividers:
if luck < divider:
break
counter += 1
self.foePrep(autoSlected= pets[counter])
else:
pass



def targetChooser(self, Ally= False, User= None):
choices = []
i = 0
forum = []
if Ally:
for target in self.listing:
if isinstance(self.listing[target], PlayableCharacter):
if not self.listing[target].displayName == User:
if self.listing[target].level > 0:
choices.append(i)
print(str(i) + ": " + self.quickdisplay(self.listing[target], newLineOverride= True))
forum.append(target)
i += 1
i = inputAndCheck("Target: ", choices)
return forum[i]
else:
for target in self.listing:
if isinstance(self.listing[target], Monster):
choices.append(i)
print(str(i) + ": " + target)
forum.append(target)
i += 1
i = inputAndCheck("Target: ", choices)
return forum[i]

def intiativeRoll(self, Combatant):
# defualt for now
self.listing.update({Combatant.displayName : Combatant})
self.order.append([Combatant.displayName, random.random()])

def combatEndCheck(self):
removalList = []
follow = False
playerCounter = 0
for figther in self.listing:
removeFlag = self.listing[figther].deathCheck()
if removeFlag == True:
removalList.append(figther)
i = 0
for thing in self.order:
if thing[0] == figther:
self.order.pop(i)
break
i += 1
continue
if isinstance(self.listing[figther], Monster):
follow = True
if isinstance(self.listing[figther], PlayableCharacter) and self.listing[figther].currentHealth > 0:
playerCounter += 1
for body in removalList:
self.exp = self.exp + self.listing[body].experience
self.listing.pop(body)
if playerCounter <= 0:
follow = False
return follow

def baseAttack(self, attacker):
targetingNum = int(random.random() * 100)
while targetingNum < 1:
targetingNum = int(random.random() * 100)
targets = []
for fighter in self.listing:
if isinstance(self.listing[fighter], PlayableCharacter):
targets.append(fighter)
if self.taunt == []:
dividers = [81, 61, 41, 21]
else:
dividers = []
counter = 100
for peep in targets:
if peep == self.taunt[0][0]:
counter -= 34
dividers.append(counter)
else:
counter -= 14
dividers.append(counter)
flag = False
for divider in dividers:
if flag:
break
if targetingNum > divider:
target = targets[dividers.index(divider)]
flag = True
try:
if target not in self.protected:
if self.listing[target].level > 0 and self.listing[target].currentHealth > 0:
self.attackDispaly(attacker, target)
if (attacker.attack - self.listing[target].defense >= 0):
self.listing[target].currentHealth = self.listing[target].currentHealth - attacker.attack + self.listing[target].defense
else:
self.listing[target].currentHealth = self.listing[target].currentHealth - 1
except UnboundLocalError:
pass

# defualt for now

def turn(self, ally):
choices = []
chosen = 0
i = 0
if isinstance(ally, Monster):
print("Turn: " + ally.displayName)
self.baseAttack(ally)
else:
if ally.currentHealth > 0:
try:
print("up next:" + self.intiativeDisplay(ally.displayName))
print("Current turn: " + self.quickdisplay(ally))
if ally.displayName not in self.protected:
for skill in ally.skills:
if ally.skillCosts[i] <= ally.currentEnergy:
print(str(i) + ": " + skill)
choices.append(i)
i += 1
protect = i
if self.saftey():
print(str(protect)+ ": Fall back")
choices.append(i)
chosen = inputAndCheck("What will " + ally.displayName + " do? ", choices)
if chosen == protect:
self.saftey(availability= False, Ally= ally.displayName)
else:
ally.currentEnergy = ally.currentEnergy - ally.skillCosts[chosen]
self.skillHandler(ally, ally.skills[chosen])
else:
choices = [0,1]
print("0: Stay back")
print("1: go back to front")
chosen = inputAndCheck("What will " + ally.displayName + " do? ", choices)
if chosen == 0:
self.safteyRecovery(ally.displayName)
else:
self.saftey(Ally= ally.displayName, Removal= True)
except TypeError:
pass
counter = 0
for defender in self.defRaise:
if defender[0] == ally.displayName:
defender[1] = defender[1] - 1
if defender[1] <= 0:
ally.defense = ally.defense - defender[2]
self.defRaise.pop(counter)
counter += 1
counter = 0
for attacker in self.atkRaise:
if attacker[0] == ally.displayName:
attacker[1] = attacker[1] - 1
if attacker[1] <= 0:
ally.attack = ally.attack - attacker[2]
self.defRaise.pop(counter)
counter += 1
counter = 0
for annoyance in self.taunt:
if annoyance[0] == ally.displayName:
annoyance[1] = annoyance[1] - 1
if annoyance[1] <= 0:
self.defRaise.pop(counter)
counter += 1

def saftey(self, availability= True, Ally= None, Removal= False):
counter = 0
if Removal:
self.protected.remove(Ally)
return 0
if availability:
if len(self.protected) > 0:
return False
for figther in self.listing:
if self.listing[figther].currentHealth > 0:
if isinstance(self.listing[figther], PlayableCharacter):
counter += 1
if counter > 1:
return True
else:
return False
else:
self.protected.append(Ally)

def safteyRecovery(self, ally):
luck = int(random.random() * 20)
friend = self.listing[ally]
if isinstance(friend, PlayableCharacter):
friend.currentHealth = friend.currentHealth + luck
friend.currentEnergy = friend.currentEnergy + luck
if friend.currentEnergy > friend.energyValue:
friend.currentEnergy = friend.energyValue
if friend.currentHealth > friend.health:
friend.currentHealth = friend.health
self.listing[ally] = friend

def quickdisplay(self, ally, newLineOverride= False):
if newLineOverride:
return ally.displayName + "(hp: " + str(ally.currentHealth) + "/" + str(
ally.health) + " " + ally.energyName + ": " + str(ally.currentEnergy) + "/" + str(ally.energyValue) + ")"
return ally.displayName + "\nhp: " + str(ally.currentHealth) + "/" + str(ally.health) + " " + ally.energyName + ": " + str(ally.currentEnergy) + "/" + str(ally.energyValue)

def intiativeDisplay(self, allyName):
string = ""
setup = []
flag = False
counter = 0
for fighter in self.order:
if fighter[0] == allyName:
flag = True
continue
if isinstance(self.listing[fighter[0]], PlayableCharacter):
if self.listing[fighter[0]].level <= 0:
continue
playableDisplay = self.quickdisplay(self.listing[fighter[0]],newLineOverride= True)
if flag:
setup.insert(counter, playableDisplay)
else:
setup.append(playableDisplay)
continue

if flag:
setup.insert(counter, fighter[0])
counter += 1
else:
setup.append(fighter[0])
flag = False
for peep in setup:
if flag:
string = string + ", " + peep
else:
string = string + " " + peep
flag = True
return string

def attackDispaly(self, attacker, target, attackName= None):
#might remove if it slows down game to much. Might rewrite for more flavor.
if isinstance(attacker, Monster):
input(attacker.displayName + " used their " + attacker.weapon + " on " + target + "(Enter to continue)")

As you see a lot of new functions and variables hadn’t been planned from the get-go. This stems from my wanting to organize this very complex class better so that it’s easier to explain and debug. I’ll be doing breakdowns of all the functions in separate posts so that it’s easier to digest and so I can go more in-depth in the explanation of the process. Here will give a brief overview of how these functions are implemented into the runComabt() function, as well as the class variables and their purpose.

Class Variables:

def __init__(self, continueStatus = True):
self.order = []
self.listing = {}
self.continueStatus = continueStatus
self.taunt = []
self.defRaise = []
self.atkRaise = []
self.protected = []
self.exp = 0

The first 3 class variables you see are the most important ones: the dictionary called listing, the list called order, and the Boolean called continueStatus. Listing is a dictionary that has the character names as keys and the objects as the value. Order is a 2d list where each column is a character in the fight, and the first row is the name while the second row is the initiative number that was rolled in rollInitiative(). The others hold characters with those said effects on them. Protected is the combat gimmick for my game which I'll talk about in its own post. Exp adds up the exp from each monster slain to award to the characters at the end of the fight.

Class Implementation:

def runCombat(intialBadie, wifus, location):
global gold
input("fight!")
#temporary^^
theBattle = Combat()
enemyCatalog = []
postBattleWifus = []
for ally in wifus:
theBattle.intiativeRoll(ally)
f = open("monsterStats.csv")
fReader = csv.reader(f)
for line in fReader:
if line == []:
continue
enemyCatalog.append(line)
for badie in intialBadie:
for enemy in enemyCatalog:
if badie == enemy[0]:
theBattle.intiativeRoll(Monster(attack= int(enemy[2]), health= int(enemy[1]), defense= int(enemy[3]), displayName=badie, experince= int(enemy[7]),petRate= int(enemy[4]), buddyRate= int(enemy[5]), weapon= enemy[6]))
theBattle.foePrep()
theBattle.combatantOrganizer()
while theBattle.continueStatus:
for fighter in theBattle.order:
theBattle.turn(theBattle.listing[fighter[0]])
theBattle.listing[fighter[0]].deathCheck()
theBattle.continueStatus = theBattle.combatEndCheck()
if not theBattle.continueStatus:
break
os.system("cls")
checker = 0
for fighter in theBattle.listing:
if isinstance(theBattle.listing[fighter], PlayableCharacter):
theBattle.listing[fighter].experience = theBattle.listing[fighter].experience + theBattle.exp
gold = gold + theBattle.exp
if theBattle.listing[fighter].currentHealth > 0:
checker += 1
postBattleWifus.append(theBattle.listing[fighter])
if checker == 0:
input("GAME OVER")
exit()
del theBattle
return postBattleWifus

The combat() class is initiated as theBattle. Then it adds and rolls initiative for the heroes by iterating through the list of them. It opens the monsterStats.csv to find the stats for the monster that was declared by encounterCheck() beforehand.  Then it uses the data it found to create the initial monster() object. Then it runs foePrep() and combatOrganizer() to prepare the allies and pets for the monster and organize the initiative rolls from greatest to least. The while loop does all the turns of characters until combatEndCheck() returns false. CombatEndCheck() returns false when there are no monster or no players left. Then It counts all the allies who have hp greater than 0 to see if the player lost or not. At the same time, we add those playable characters to an updated list of our heroes called updatedPostBattleWifus. If we count zero heros with hp greater than 0, then we display the game over screen and exit the program. Otherwise, we return the updated list updatedPostBattleWifus.

Results:

With the combat setup, we actually have a game to play! I’ve started playing and have begun to have other people play it too. A few things I’ve noticed right off the bat:

1.       The game needs a manual to map out locations and describe character abilities.

2.       I need to add more comments to my code to make explaining and debugging easier.

3.       Map needs to be smaller for easier travel.





Comments

Popular posts from this blog

Shop() run down

 This class is responsible for running the shop and creating the Item() objects. Constructor: def __init__ ( self ): self .items = [] f = open ( "items.csv" ) fReader = csv.reader(f) for line in fReader: if line == []: continue self .items.append(Item(line[ 2 ] , line[ 0 ] , int (line[ 1 ]) , int (line[ 3 ]))) f.close() When the class is called the class list items are filled with Item() objects created by opening items.csv and taking the data in there to instantiate the items. Then we close the file. WhoIsShopping(): def whoIsShopping ( self , squad : list ): counter = 0 choices = [] print ( "Who is shopping?" ) for member in squad: if member.level > 0 : print ( str (counter) + ": " + member.displayName) choices.append(counter) counter += 1 selection = inputAndCheck( "Selection: " , choices) return squad[selection] T...

Explorer() progress

I decided to start with the explorer() method because of how central it is to the program. I quickly realized I'd need new functions for accessing specific pieces of data from the CVSs, so I made a few for detecting what region the part is in, another for fetching the region name and fetching the region z coordinate. Here is what explorer looks like now. def explorer (): global x global y global z global chapter global region global regionDisplay global Lori global Lauren global Julius global Marcus menu = GameMenu() characters = [Lori , Lauren , Julius , Marcus] menu.update(characters) selections = [ 4 , 5 ] #Code goes here print (regionDisplay + ":" ) print (regionDiscribe(region)) # need and area scanner for detecting nearby locations if regionCheck(x+ 1 , y , z) >= 0 and \ (fetchRegionZ(regionCheck(x+ 1 , y , z))-fetchRegionZ(region) <= 5 and fetchRegionZ(region)-fetchRegionZ(regionCheck...

Flow Charts are Born

Flow charts weren't that difficult to make. I honestly already had a decent idea of how my program would run, so this was really taking what was on my mind and putting it into a graphic. For those who don't know, I'm using a common key for software design for all of the flow charts: Source:  https://www.zenflowchart.com/flowchart-symbols First I have the simplest of my flow charts: theInstaller.py Flow chart. Then I made the Flow chart for theMain.py: Finally, I decided to include 2 flow charts for the important subprocess in the game: Explore() and runCombat(). For all of these, I used color codes to help subdivide the pieces of the code into their smaller loops or different paths. I'll be using these flow charts a lot to point out where exactly I'm at in the game as I go along with this blog.