Pythong text based game - Looking to close out a loop - python

New to Python and coding. This is my first project and I'm having trouble closing a loop once one of my classes reaches zero. Any help would be appreciated. Thank you.
# Space Warriors Game
import random
import time
class Spacecraft:
def __init__(self, type, health):
self.type = type
self.health = health
self.ship_destroyed = False
def __repr__(self):
return "This {type} spacecraft has {health} starting hit points ".format(type=self.type, health=self.health)
def ship_gone(self):
self.ship_destroyed = True
if self.health != 0:
self.health = 0
print("Your spacecraft has been destroyed!")
def ship_gone_def(self):
self.ship_destroyed = True
if self.health != 0:
self.health = 0
print("Your enemy spacecraft has been destroyed! YOU WON!!")
def lose_health(self, amount):
self.health -= amount
if self.health <= 0:
self.ship_gone()
else:
print("Your spacecraft now has {health} hit points remaining.".format(health=self.health))
def lose_health_def(self, amount):
self.health -= amount
if self.health <= 0:
self.health = 0
self.ship_gone_def()
else:
print("The enemy spacecraft now has {health} hit points remaining.".format(health=self.health))
def attack(self, enemy_ship):
while True:
damage_fighter = random.randrange(6, 14)
damage_defender = random.randrange(4, 10)
if self.type == "fighter":
#time.sleep(2)
print('Your {type} spacecraft attacked the enemy ship for {damage} damage!'.format(type=self.type, damage=damage_fighter))
#time.sleep(2)
enemy_ship.lose_health_def(damage_fighter)
#time.sleep(2)
print()
print('The enemy {enemy_ship} spacecraft attacked your ship for {damage2} damage!'.format(enemy_ship=enemy_ship.type, damage2=damage_defender))
#time.sleep(2)
self.lose_health(damage_defender)
print()
elif self.type == "defender":
#time.sleep(2)
print('Your {type} spacecraft attacked the enemy ship for {damage} damage!'.format(type=self.type, damage=damage_defender))
#time.sleep(2)
enemy_ship.lose_health_def(damage_defender)
#time.sleep(2)
print()
print('The enemy {enemy_ship} spacecraft attacked your ship for {damage2} damage!'.format(enemy_ship=enemy_ship.type, damage2=damage_fighter))
#time.sleep(2)
self.lose_health(damage_fighter)
print()
class Player:
def __init__(self, type):
self.type = type
self.current_type = 0
def attack_enemy_ship(self, enemy_ship):
my_ship = self.type[self.current_type]
their_ship = enemy_ship.type[enemy_ship.current_type]
my_ship.attack(their_ship)
a = Spacecraft("fighter", 40)
b = Spacecraft("defender", 50)
print()
player_name = input('''Welcome to SPACE WARRIORS! Please enter your name and hit enter. ''')
print('''
Welcome ''' + player_name + '''! Space Warriors is a game that allows you to chose one of two spacecrafts and battle it out with
the CPU! There are two classes: Fighter Class and a Defender Class. Each class is unique in it's own way.''')
print()
player_style = input('Please type in "Fighter" or "Defender" and press enter. ''').lower()
print()
if player_style == 'fighter':
print('You have selected the fighter class which has 40 life and does 6 - 12 damage. Goodluck!')
time.sleep(2)
elif player_style == 'defender':
print('You have selected the defender class which has 50 life and does 4 - 10 damage. Goodluck!')
time.sleep(2)
else:
print('Wrong selection. Restart the game')
raise SystemExit
player_selected = []
computer_selected = []
player_selected.append(a)
computer_selected.append(b)
player_selected.append(b)
computer_selected.append(a)
live_player = Player(player_selected)
computer_player = Player(computer_selected)
print()
print("Let's get ready to fight! Both ships are launched!")
print()
live_player.attack_enemy_ship(computer_player)
In the attack function each player does damage back and forth until one reaches 0. At that point it prints the enemy won or the player won. However, once the hit points reach 0 it continues to print the loser is defeated and the winner's damage. Any help on closing this loop would be great! Thank you.

Related

Who can I select the same index but from 2 different arrays witch change from the user input?

I want to turn two enemies into just one enemy by changing the array depending on the user input.
I've created two different enemies and two different functions for the attack, but I wanted to just create one attack to give to the diferent enemies.
#Warrior
warrior = [32,5,2,5,2] #HP, MP , AP, WP, Init
#vampire 1
vampire1 = [15,0,2,2,2] #HP, MP, AP, WP, Init
#vampire 2
vampire2 = [15,0,2,2,2] #HP, MP, AP, WP, Init
#Attack from the warrior on the enemy 1
def warrior_attack1(): #If the vampire1 got the armor up
if vampire1[2] > 0: #If the vampire1 got the armor up, then attack the armor
vampire1[2] = vampire1[2] - random.randrange(1,warrior[3]) #Enemy's AP less the random number inside WP from the warrior
if vampire1[2] > 0:
print("You damaged the enemy armor! Enemy's current armor :" + str(vampire1[2]))
elif vampire1[2] <= 0:
print("You have destroyed the enemy armor!")
elif vampire1[2] <= 0: #If the vampire1 got no armor, then attack life
vampire1[0] = vampire1[0] - random.randrange(1,warrior[3]) #Enemy's HP less the random number inside WP from the warrior
if vampire1[0] > 0:
print("You hit the enemy, enemy current life: " + str(vampire1[0]))
#Attack from the warrior on the enemy 2
def warrior_attack2(): #If the vampire2 got the armor up
if vampire2[2] > 0: #If the vampire2 got the armor up, then attack the armor
vampire2[2] = vampire2[2] - random.randrange(1,warrior[3]) #Enemy's AP less the random number inside WP from the warrior
if vampire2[2] > 0:
print("You damaged the enemy armor! Enemy's current armor :" + str(vampire2[2]))
elif vampire2[2] <= 0:
print("You have destroyed the enemy armor!")
elif vampire2[2] <= 0: #If the vampire2 got no armor, then attack life
vampire2[0] = vampire2[0] - random.randrange(1,warrior[3]) #Enemy's HP less the random number inside WP from the warrior
if vampire2[0] > 0:
print("You hit the enemy, enemy current life: " + str(vampire2[0]))
def warrior_turn():
command = input("\nWarrior is playing: " +
"\nChoose your action" +
"\n1. Attack." +
"\n2. Magic.\n")
if command == "1": #Execute the warrior attack
command = input("\nEach enemy do you want to attack?: " +
"\n1. Vampire 1" +
"\n2. Vampire 2" +
"\n3. Vampire 3" +
"\n4. Vampire 4\n") #Let the player select what enemy he want's to attack
if command == "1":
if vampire1[0] > 0: #If the vampire 1 is alive
warrior_attack1() #Attack enemy 1
else: #If the vampire 1 is dead
print("The vampire 1 is dead, choose another target!")
warrior_turn()
warrior_turn()
You can use a list of enemy:
vampires = [[15,0,2,2,2], [15,0,2,2,2]]
I've modified a bit the attack function
(vampire := vampire - damage for assignment within condition check)
(no need to check twice in elif, a simple else does the trick)
(don't put comments within code, ahead the function it's clearer)
def warrior_attack(index):
damage = random.randrange(1, warrior[3])
if vampires[index][2] > 0:
if (vampires[index][2]:= vampires[index][2] - damage) > 0:
print("You damaged the enemy armor! Enemy's current armor :" + str(vampires[index][2]))
else:
print("You have destroyed the enemy armor!")
else:
if (vampires[index][0] := vampires[index][0] - damage) > 0:
print("You hit the enemy, enemy current life: " + str(vampires[index][0]))
else:
print("You killed the enemy !")
And in warrior_turn function, in enemy selection part:
if command.isdigit():
index = int(command)
if index >= len(vampires):
print("The vampire {} doesn't exist, there is only {] enemies".format(index, len(vampires)))
warrior_turn()
if vampires[index][0] > 0:
warrior_attack(index)
else:
print("The vampire {} is dead, choose another target!".format(index))
warrior_turn()
else:
print("Bad entry, please write down a number")
Keep in mind that you call the function warrior_turn within warrior_turn, better to do a loop than resistivity (might crash the game with stack error).

creating a monster battle with a multisided dice class

I'm making a basic battle program with a multi-sided dice class and a while loop. Basically, you and a dragon start with 100 health, and a 20 sided dice is randomly thrown to determine how much damage you each do. For example, if I rolled a six, and the dragon rolled an 8, then I would have 92 health left, and the dragon would have 94 health left. And this would continue until one health value reaches 0. Here's an example of my code below:
import random
class MSDie:
def __init__(self, num_sides):
self.num_sides = num_sides
self.current_value = self.roll()
def roll(self):
self.current_value = random.randrange(1,self.num_sides+1)
return self.current_value
def __int__(self):
return int(self.current_value)
def getValue(self):
return self.value
def setValue(self, value):
self.value = value
print("you are a legendary hero on a quest to save the kingdom from an evil dragon.")
print("You find him outside his lair and the two of you begin to battle.")
print("Both you and the dragon start with 100 health.")
print("You each will both randomly deal between 1-20 damage.")
print("The first whose health drops to 0 loses.")
playerHealth = 100
DragonHealth = 100
while(playerHealth > 0 or DragonHealth > 0):
print("You have ", playerHealth, "Health.")
print("The dragon has ", DragonHealth, "Health.")
myDamage = MSDie(20)
DragonDamage = MSDie(20)
playerHealth = playerHealth - DragonDamage
DragonHealth = DragonHealth - myDamage
print("")
print("You dealt ", myDamage, "to the dragon.")
print("The dragon dealth ", DragonDamage, "to you.")
print("")
However, each time I try to subtract the damage roll from the health, I keep getting this error:
File "C:\Users\Jacks\OneDrive\Documents\Python files\Ds files\monsterbattle.py", line 52, in <module>
playerHealth = playerHealth - DragonDamage
TypeError: unsupported operand type(s) for -: 'int' and 'MSDie'
DragonDamage is an instance of the MSDie class. Python won't convert it to an integer automatically, even though you implemented the __int__ method. You need to do this explicitly. Try playerHealth - int(DragonDamage).
import random
class MSDie:
def __init__(self, num_sides):
self.num_sides = num_sides
self.current_value = self.roll()
def roll(self):
self.current_value = random.randrange(1,self.num_sides+1)
return self.current_value
def __int__(self):
return int(self.current_value)
def getValue(self):
return self.value
def setValue(self, value):
self.value = value
print("you are a legendary hero on a quest to save the kingdom from an evil dragon.")
print("You find him outside his lair and the two of you begin to battle.")
print("Both you and the dragon start with 100 health.")
print("You each will both randomly deal between 1-20 damage.")
print("The first whose health drops to 0 loses.")
playerHealth = 100
DragonHealth = 100
while(playerHealth > 0 or DragonHealth > 0):
print("You have ", playerHealth, "Health.")
print("The dragon has ", DragonHealth, "Health.")
myDamage = MSDie(20)
DragonDamage = MSDie(20)
playerHealth = playerHealth - int(DragonDamage)
As #mcsoini suggested above, you need to explicitly convert to int.
I'd suggest you smiplify a lot your code. You need only one MSDie instance, not 2 at each loop iteration, and the dice may just provide values, it doesn't need an internal value . Also you may use and in your condition, to stop when one reach 0
class MSDie:
def __init__(self, num_sides):
self.num_sides = num_sides
def roll(self):
return random.randrange(1, self.num_sides + 1)
Using
player_health = 100
dragon_health = 100
multi_dice = MSDie(20)
while player_health > 0 and dragon_health > 0:
player_damage = multi_dice.roll()
dragon_damage = multi_dice.roll()
player_health -= dragon_damage
dragon_health -= player_damage
print("You dealt ", player_damage, "to the dragon, it now have", dragon_health)
print("The dragon dealth ", dragon_damage, "to you, you now have", player_health)
print("")
if player_health > dragon_health:
print(f"You won with {player_health}PV, dragon is dead")
else:
print(f"You loose, you're dead, dragon has {dragon_health}PV")

How do I properly loop through a portion of code using methods in a class?

I am learning about classes in Python and tried to make a simple battle game. This code runs fine and as long as I print devin.battle() multiple times, but I want a while loop so that it will revert back to asking if the user would like to start a battle while also deducting the attack from the hit points.
start_battle = input("Would you like to start a battle? Y/N ===> ")
class People:
max_hit_points = 150
current_hit_points = 150
current_strength = 5
defence = 0
def __init__(self, name, current_hit_points):
self.name = name
self.current_hit_points
self.damage = 50
def battle(self):
if start_battle == "Y":
self.attacked()
elif start_battle == "N":
print("okay, nevermind then")
def attacked(self):
self.current_hit_points -= self.damage
print("You have been attacked")
if self.current_hit_points > 0:
print("Try again newb!")
else:
print("Your HP has reached 0, you are dead")
def __str__(self):
return f"{self. name} has {self.current_hit_points}HP remaining"
devin = People("Devin", 150)
devin.battle()
print(devin)
However, when I add one to the whole thing Python freezes up.
start_battle = input("Would you like to start a battle? Y/N ===> ")
class People:
max_hit_points = 150
current_hit_points = 150
current_strength = 5
defence = 0
def __init__(self, name, current_hit_points):
self.name = name
self.current_hit_points
self.damage = 50
while current_hit_points > 0:
def battle(self):
if start_battle == "Y":
self.attacked()
elif start_battle == "N":
print("okay, nevermind then")
def attacked(self):
self.current_hit_points -= self.damage
print("You have been attacked")
if self.current_hit_points > 0:
print("Try again newb!")
else:
print("Your HP has reached 0, you are dead")
def __str__(self):
return f"{self. name} has {self.current_hit_points}HP remaining"
continue
else:
print("You are dead")
devin = People("Devin", 150)
devin.battle()
print(devin)
If anyone can explain to me why its freezing up and how I can properly loop a battle, it would be greatly appreciated.
You have multiple issues here and its not super clear what you are trying to do but here is some direction according to your comment, make sure ot read the # code comments
class People:
max_hit_points = 150
current_hit_points = 150
current_strength = 5
defence = 0
def __init__(self, name, current_hit_points):
self.name = name
# you forgot to actually assign the hit points
self.current_hit_points = current_hit_points
self.damage = 50
def battle(self):
while self.current_hit_points > 0:
# you want to ask the user every round?
start_battle = input("Would you like to start a battle? Y/N ===> ")
if start_battle == "Y":
self.attacked()
# note that the user didnt get to attack back
# maybe print(self) here so the user can see his hp?
elif start_battle == "N":
print("okay, nevermind then")
break
else:
print("You are dead")
def attacked(self):
self.current_hit_points -= self.damage
print("You have been attacked")
if self.current_hit_points > 0:
print("Try again newb!")
else:
print("Your HP has reached 0, you are dead")
def __str__(self):
return f"{self. name} has {self.current_hit_points}HP remaining"
devin = People("Devin", 150)
devin.battle()
print(devin)

Getting a function call to wait until an input via ui is received

I'm a novice programmer and I'm using Pythonista to create a bad UI fighting game that utilizes buttons. My code references a ui script with buttons related to the attack or defend functions listed in the code below. My issue, is that I want the game to wait until a function in the ui is called to be able to move onto the enemy's turn which is labeled eturn. Currently it pulls up the ui takes the enemy turn instantly and then continues to layer the ui and take enemy turns in an indefinite loop. If someone knows how to make the script wait until a ui input completes the users turn while keeping it in novice knowledge level it would be greatly appreciated.
Code below:
import ui
import random
import time
hp = 100
pots = 3
atk = 7
guard = False
#enemy values
ehp = random.randint(50, 75)
eatk = random.randint(8, 11)
eguard = False
def menu():
global guard
v = ui.load_view('option menu')
v.present('sheet')
def attack(sender):
v.close()
if eguard == False:
ehp -= atk
print('You slash at the enemy and deal %r damage' % atk)
print('\nIt has %r hp left' % ehp)
return ehp
elif eguard == True:
dmg = (atk - 3)
ehp -= dmg
print('You slash at the enemy and deal %r damage' % dmg)
print('\nIt has %r hp left' % ehp)
return ehp
def defend(sender):
v.close()
print('You put up your guard')
guard = True
return guard
def heal(sender):
global hp, pots
v.close()
if pots > 0:
pots -= 1
hp += 25
if hp > 100:
hp = 100
print('You use a health potion and gain 25hp, you have %r potions and %r hp left' % (pots, hp))
elif pots == 0:
print('You are out of potions!')
def eturn():
global eguard, hp, ehp
choice = random.randint(1, 3)
eguard = False
if choice == 1:
if guard == True:
dmg = eatk - 3
hp -= dmg
print('The creature swipes at you and deals %r damage, you have %r hp left' % (dmg, hp))
elif guard == False:
hp -= eatk
print('The creature swipes at you and deals %r damage, you have %r hp left' % (eatk, hp))
elif choice == 2:
print('The creature defends itself')
eguard = True
elif choice == 3:
ehp += 10
if ehp > 75:
ehp = 75
print('The creature heals itself for 10 hp')
def turn():
menu()
def game():
print('instructions')
turn()
eturn()
game()
Try this.
def menu():
global guard
v = ui.load_view('option menu')
v.present('sheet')
v.wait_modal() # Waits until the dialog is off the screen
v.close() # Properly cleans up the dialog

How can I get new results from randint while in a loop?

My code thus far:
from random import randint
Dice1 = randint(1,6)
Dice2 = randint(1,6)
Dice3 = randint(1,6)
DiceRoll2 = Dice1 + Dice2
DiceRoll3 = Dice1 + Dice2 + Dice3
class Item(object):
def __init__(self, name, value, desc):
self.name = name
self.value = value
self.desc = desc
sword = Item("Sword", 2, "A regular sword.")
class Monster(object):
def __init__(self, name, health, attack):
self.name = name
self.health = health
self.attack = attack
monster = Monster("Monster", 50, DiceRoll2)
Damage = DiceRoll3 + sword.value
NewHealth = monster.health - Damage
print("You see a monster!")
while True:
action = input("? ").lower().split()
if action[0] == "attack":
print("You swing your", sword.name, "for", Damage, "damage!")
print("The", monster.name, "is now at", NewHealth, "HP!")
elif action[0] == "exit":
break
The intension is that with every time you enter "attack" you get a random result of DiceRoll3 (three random numbers from 1 to 6, that three times), add the value of the sword and substract that from the monster's starting health. This goes well until I enter "attack" a second time, which results in the same damage and the same reduced health being printed instead of using a new value. How can I properly do this?
You need to make the call to randint everytime. Below is one way to do it
def Dice1(): return randint(1,6)
def Dice2(): return randint(1,6)
def Dice3(): return randint(1,6)
This isn't great though because of all the repeated code. Here is a better way
class Dice(object):
def roll_dice(self):
return randint(1,6)
Dice1 = Dice()
Dice2 = Dice()
Dice3 = Dice()
Now in your code where ever you call Dice1, Dice2 or Dice3; instead call Dice1.roll_dice(), Dice2.roll_dice(), Dice3.roll_dice(). This abstract away the dice implementation and you are free to change it later without having to change your code.
If you need have dice with different number of faces, you only need to change your dice class
class Dice(object):
def __init__ (self, num_faces=6):
self.faces = num_faces
def roll_dice(self):
return randint(1,self.faces)
Dice1 = Dice() # 6 faced die
Dice2 = Dice(20) # 20 faced die
Put your dice-rolling into a separate function and calculate Damage and NewHealth inside your loop. (Also, update your Monster's health. :))
from random import randint
def dice_roll(times):
sum = 0
for i in range(times):
sum += randint(1, 6)
return sum
class Item(object):
def __init__(self, name, value, desc):
self.name = name
self.value = value
self.desc = desc
sword = Item("Sword", 2, "A regular sword.")
class Monster(object):
def __init__(self, name, health, attack):
self.name = name
self.health = health
self.attack = attack
monster = Monster("Monster", 50, dice_roll(2))
print("You see a monster!")
while True:
action = input("? ").lower().split()
if action[0] == "attack":
Damage = dice_roll(3) + sword.value
NewHealth = max(0, monster.health - Damage) #prevent a negative health value
monster.health = NewHealth #save the new health value
print("You swing your", sword.name, "for", Damage, "damage!")
print("The", monster.name, "is now at", NewHealth, "HP!")
elif action[0] == "exit":
break
if monster.health < 1:
print("You win!")
break

Categories

Resources