nickgermaine / python_text_battle

Simple rpg type text-based python battle script
103 stars 48 forks source link

Check for Winner #5

Open mechengmaster opened 7 years ago

mechengmaster commented 7 years ago

Hi Nick,

Great tutorial! I noticed something in the code which meant that it doesn't realise when all enemies or players have been killed. Hopefully below provides a solution for others (unless it is not the issue I thought it was, in which case, the below is an alternative way to do things)

We have hard coded:

       # Check if battle is over
    defeated_enemies = 0
    defeated_players = 0

    for enemy in enemies:
        if enemy.get_hp() == 0:
            defeated_enemies += 1

    for player in players:
        if player.get_hp() == 0:
            defeated_players += 1

     # Check if Player won
    if defeated_enemies == 2:
        print(bcolors.OKGREEN + "You win!" + bcolors.ENDC)
        running = False

    # Check if Enemy won
    elif defeated_players == 2:
        print(bcolors.FAIL + "Your enemies have defeated you!" + bcolors.ENDC)
        running = False

which means that we need to kill 2 players or enemies (a small note is that we actually have 3 on each team) for the other team to win.

After each Person dies we've used the del enemies[enemy] or del players[player] (another small note: I think the second one should actually be del players[target]). This means the code above is never able to reach our hard coded limit as the number of "enemy in enemies" and "player in players" also reduces each time we use the del function. We also reset defeated_enemies = 0 defeated_players = 0 each time too.

I have made the following edits: First declare:

defeated_enemies = 0
defeated_players = 0

directly after instantiating People at the top of main.py

instead of

    del enemies[enemies]

use

    del enemies[enemies]
    defeated_enemies += 1

and vice-versa for del players[player]

I have deleted:

       # Check if battle is over
    defeated_enemies = 0
    defeated_players = 0

    for enemy in enemies:
        if enemy.get_hp() == 0:
            defeated_enemies += 1

    for player in players:
        if player.get_hp() == 0:
            defeated_players += 1

and moved:

    # Check if Enemy won
    elif defeated_players == 2:
        print(bcolors.FAIL + "Your enemies have defeated you!" + bcolors.ENDC)
        running = False

to after the bottom of main.py after the enemy attack phase (but not included in the enemy attack phase)

The above seems to have fixed the issue but let me know if you think I've gone wrong anywhere.

CodyVollrath commented 7 years ago

Could you show me exactly what the code looks like after the edit is finished, I am having trouble applying the fix. Thank you in advanced

mechengmaster commented 7 years ago

Hi, I have just pasted in my entire main.py file for you to look at. Apologies if there are a few other changes from Nick's original tutorial. I may have tweaked a few things and forgotten what I did.

from classes.game import Person, bcolours
from classes.magic import Spell
from classes.inventory import Item
import random

# Create Black Magic
fire = Spell("Fire", 25, 600, "black")
thunder = Spell("Thunder", 25, 600, "black")
blizzard = Spell("Blizzard", 25, 600, "black")
meteor = Spell("Meteor", 40, 1200, "black")
quake = Spell("Quake", 14, 140, "black")

# Create white magic
cure = Spell("Cure", 25, 620, "white")
cura = Spell("Cura", 32, 1500, "white")
curaga = Spell("Curaga", 50, 6000, "white")

#Creat some items
potion = Item("Potion", "potion", "Heals 50HP", 50)
hipotion = Item("Hi-Potion", "potion", "Heals 100HP", 100)
superpotion = Item("Super Potion", "potion", "Heals 500 HP", 500)
elixer = Item("Elixer", "elixer", "Fully restores HP/MP of one party member", 9999)
hielixer = Item("MegaElixer", "elixer", "Fully restores party's HP/MP", 9999)

grenade = Item("Grenade", "attack", "Deals 500 damage", 500)

player_spells = [fire, thunder, blizzard, meteor, cure, cura]
enemy_spells = [fire, meteor, curaga]
player_items = [{"item": potion, "quantity": 15},{"item": hipotion, "quantity": 5},
                {"item": superpotion, "quantity": 5}, {"item": elixer, "quantity": 5},
                {"item": hielixer, "quantity": 2}, {"item": grenade, "quantity": 5}]

#Instantiate People
player1 = Person("Valos:",3260, 132, 300, 34, player_spells, player_items)
player2 = Person("Nick :",4160, 188, 311, 34, player_spells, player_items)
player3 = Person("Robot:",3089, 174, 288, 34, player_spells, player_items)

enemy1 = Person("Imp1 :", 1250, 130, 560, 325, enemy_spells, [])
enemy2 = Person("Magus:",11200, 701, 525, 25, enemy_spells,[])
enemy3 = Person("Imp2 :", 1250, 130, 560, 325, enemy_spells, [])

players = [player1, player2, player3]
enemies = [enemy1, enemy2, enemy3]

defeated_enemies = 0
defeated_players = 0

running = True
i = 0

print (bcolours.HEADER + bcolours.BOLD + "AN ENEMY ATTACKS!" + bcolours.ENDC)

while running:
    print("============================")

    print("NAME               HP                                  MP")
    for player in players:
        player.get_stats()

    print("\n")
    for enemy in enemies:
        enemy.get_enemy_stats()

    for player in players:

        player.choose_action()
        choice = input("    Choose action:")
        index = int(choice) - 1

        if index == 0:
            dmg = player.generate_damge()
            enemy = player.choose_target(enemies)
            enemies[enemy].take_damage(dmg)
            print(bcolours.BOLD + player.name.replace(" ", "").replace(":", "") + " attacked " + enemies[enemy].name.replace(" ", "").replace(":", "") +
                  " for", dmg, "points of damage." + bcolours.ENDC)

            if enemies[enemy].get_hp() == 0:
                print(bcolours.OKGREEN + bcolours.BOLD + enemies[enemy].name.replace(" ", "").replace(":", "") + " has died!" + bcolours.ENDC)
                del enemies[enemy]
                defeated_enemies += 1

        elif index == 1:
            player.choose_magic()
            magic_choice = int(input("    Choose magic:")) - 1

            if magic_choice == -1:
                continue

            spell = player.magic[magic_choice]
            magic_dmg = spell.generate_damage()

            current_mp = player.get_mp()
            if spell.cost > current_mp:
                print(bcolours.FAIL + "\nNot enough MP\n" + bcolours.ENDC)
                continue

            player.reduce_mp(spell.cost)

            if spell.type == "white":
                player.heal(magic_dmg)
                print(bcolours.OKBLUE + "\n" + spell.name + " heals for", str(magic_dmg), "HP." + bcolours.ENDC)
            elif spell.type == "black":
                enemy = player.choose_target(enemies)
                enemies[enemy].take_damage(magic_dmg)
                print(bcolours.OKBLUE + "\n" + spell.name + " deals", str(magic_dmg), "points of damage to " +
                      enemies[enemy].name.replace(" ", "").replace(":", "") + bcolours.ENDC)

                if enemies[enemy].get_hp() == 0:
                    print(bcolours.OKGREEN + bcolours.BOLD + enemies[enemy].name.replace(" ", "").replace(":", "") +
                          " has died!" + bcolours.ENDC)
                    del enemies[enemy]
                    defeated_enemies += 1

        elif index == 2:
            player.choose_item()
            item_choice = int(input("    Choose item:")) - 1

            if item_choice == -1:
                continue

            item = player.items[item_choice]["item"]

            if player.items[item_choice]["quantity"] == 0:
                print(bcolours.FAIL + "\n" + "None left..." + bcolours.ENDC)
                continue

            player.items[item_choice]["quantity"] -= 1

            if item.type == "potion":
                player.heal(item.prop)
                print(bcolours.OKGREEN + "\n" + item.name + " heals for", str(item.prop), " HP" + bcolours.ENDC)
            elif item.type == "elixer":
                if item.name == "MegaElixer":
                    for i in players:
                        i.hp = i.maxhp
                        i.mp = i.maxmp
                else:
                    player.hp = player.maxhp
                    player.mp = player.maxmp
                print(bcolours.OKGREEN + "\n" + item.name + " fully restores HP/MP" + bcolours.ENDC)
            elif item.type == "attack":
                enemy = player.choose_target(enemies)
                enemies[enemy].take_damage(item.prop)
                print(bcolours.FAIL + "\n" + item.name + " deals", str(item.prop), " points of damage to " +
                      enemies[enemy].name + bcolours.ENDC)

                if enemies[enemy].get_hp() == 0:
                    print(bcolours.OKGREEN + bcolours.BOLD + enemies[enemy].name.replace(" ", "").replace(":", "") +
                          " has died!" + bcolours.ENDC)
                    del enemies[enemy]
                    defeated_enemies += 1

    #Check is player has won
    if defeated_enemies == 3:
        print(bcolours.OKGREEN + "You win!" + bcolours.ENDC)
        running = False

    print("\n")
    # Enemy attack phase
    for enemy in enemies:
        enemy_choice = random.randrange(0,2)

        if enemy_choice == 0:
            # Choose attack
            target = random.randrange(0, len(players))
            enemy_dmg = enemy.generate_damge()

            players[target].take_damage(enemy_dmg)
            print(bcolours.FAIL + bcolours.BOLD + enemy.name.replace(" ", "").replace(":", "") + " attacks " +
                  players[target].name.replace(" ", "").replace(":", "") + " for", enemy_dmg, bcolours.ENDC)

            if players[target].get_hp() == 0:
                print(bcolours.FAIL + bcolours.BOLD + players[target].name.replace(" ", "").replace(":", "") +
                      " has died!" + bcolours.ENDC)
                del players[target]
                defeated_players += 1

        elif enemy_choice == 1:
            spell, magic_dmg = enemy.choose_enemy_spell()
            # magic_dmg = spell.generate_damage()
            enemy.reduce_mp(spell.cost)

            if spell.type == "white":
                enemy.heal(magic_dmg)
                print(bcolours.FAIL + spell.name + " heals " + enemy.name.replace(" ", "").replace(":", "") +
                      " for", str(magic_dmg), "HP." + bcolours.ENDC)
            elif spell.type == "black":
                target = random.randrange(0, len(players))
                players[target].take_damage(magic_dmg)
                print(bcolours.FAIL + bcolours.BOLD + enemy.name.replace(" ", "").replace(":","") + "'s " + spell.name +
                      " deals", str(magic_dmg), "points of damage to " +
                      players[target].name.replace(" ", "").replace(":","") + bcolours.ENDC)

                if players[target].get_hp() == 0:
                    print(bcolours.FAIL + bcolours.BOLD + players[target].name.replace(" ", "").replace(":", "") +
                          " has died!" + bcolours.ENDC)
                    del players[target]
                    defeated_players += 1

    #Check if Enemy won
    if defeated_players == 3:
        print(bcolours.FAIL + "Your enemies have defeated you!" + bcolours.ENDC)
        running = False

Hopefully the above helps.

Dasrite commented 7 years ago

Hi mechengmaster,

I just wanted to add that I used a lot of your code to help me out on my code. I do have to add though that without the break statement after each check to see who won, the players would continue to do an action. For the enemy, there would be an error since they have no players to attack.


#Check if Enemy won
if defeated_players == 3:
    print(bcolours.FAIL + "Your enemies have defeated you!" + bcolours.ENDC)
    running = False
    break
PramodJana commented 6 years ago

from classes.game import Person, bcolours from classes.magic import Spell from classes.inventory import Item import random

Create Black Magic

fire = Spell("Fire", 25, 600, "black") thunder = Spell("Thunder", 25, 600, "black") blizzard = Spell("Blizzard", 25, 600, "black") meteor = Spell("Meteor", 40, 1200, "black") quake = Spell("Quake", 14, 140, "black")

Create white magic

cure = Spell("Cure", 25, 620, "white") cura = Spell("Cura", 32, 1500, "white") curaga = Spell("Curaga", 50, 6000, "white")

Creat some items

potion = Item("Potion", "potion", "Heals 50HP", 50) hipotion = Item("Hi-Potion", "potion", "Heals 100HP", 100) superpotion = Item("Super Potion", "potion", "Heals 500 HP", 500) elixer = Item("Elixer", "elixer", "Fully restores HP/MP of one party member", 9999) hielixer = Item("MegaElixer", "elixer", "Fully restores party's HP/MP", 9999)

grenade = Item("Grenade", "attack", "Deals 500 damage", 500)

player_spells = [fire, thunder, blizzard, meteor, cure, cura] enemy_spells = [fire, meteor, curaga] player_items = [{"item": potion, "quantity": 15},{"item": hipotion, "quantity": 5}, {"item": superpotion, "quantity": 5}, {"item": elixer, "quantity": 5}, {"item": hielixer, "quantity": 2}, {"item": grenade, "quantity": 5}]

Instantiate People

player1 = Person("Valos:",3260, 132, 300, 34, player_spells, player_items) player2 = Person("Nick :",4160, 188, 311, 34, player_spells, player_items) player3 = Person("Robot:",3089, 174, 288, 34, player_spells, player_items)

enemy1 = Person("Imp1 :", 1250, 130, 560, 325, enemy_spells, []) enemy2 = Person("Magus:",11200, 701, 525, 25, enemy_spells,[]) enemy3 = Person("Imp2 :", 1250, 130, 560, 325, enemy_spells, [])

players = [player1, player2, player3] enemies = [enemy1, enemy2, enemy3]

defeated_enemies = 0 defeated_players = 0

running = True i = 0

print (bcolours.HEADER + bcolours.BOLD + "AN ENEMY ATTACKS!" + bcolours.ENDC)

while running: print("============================")

print("NAME               HP                                  MP")
for player in players:
    player.get_stats()

print("\n")
for enemy in enemies:
    enemy.get_enemy_stats()

for player in players:

    player.choose_action()
    choice = input("    Choose action:")
    index = int(choice) - 1

    if index == 0:
        dmg = player.generate_damge()
        enemy = player.choose_target(enemies)
        enemies[enemy].take_damage(dmg)
        print(bcolours.BOLD + player.name.replace(" ", "").replace(":", "") + " attacked " + enemies[enemy].name.replace(" ", "").replace(":", "") +
              " for", dmg, "points of damage." + bcolours.ENDC)

        if enemies[enemy].get_hp() == 0:
            print(bcolours.OKGREEN + bcolours.BOLD + enemies[enemy].name.replace(" ", "").replace(":", "") + " has died!" + bcolours.ENDC)
            del enemies[enemy]
            defeated_enemies += 1

    elif index == 1:
        player.choose_magic()
        magic_choice = int(input("    Choose magic:")) - 1

        if magic_choice == -1:
            continue

        spell = player.magic[magic_choice]
        magic_dmg = spell.generate_damage()

        current_mp = player.get_mp()
        if spell.cost > current_mp:
            print(bcolours.FAIL + "\nNot enough MP\n" + bcolours.ENDC)
            continue

        player.reduce_mp(spell.cost)

        if spell.type == "white":
            player.heal(magic_dmg)
            print(bcolours.OKBLUE + "\n" + spell.name + " heals for", str(magic_dmg), "HP." + bcolours.ENDC)
        elif spell.type == "black":
            enemy = player.choose_target(enemies)
            enemies[enemy].take_damage(magic_dmg)
            print(bcolours.OKBLUE + "\n" + spell.name + " deals", str(magic_dmg), "points of damage to " +
                  enemies[enemy].name.replace(" ", "").replace(":", "") + bcolours.ENDC)

            if enemies[enemy].get_hp() == 0:
                print(bcolours.OKGREEN + bcolours.BOLD + enemies[enemy].name.replace(" ", "").replace(":", "") +
                      " has died!" + bcolours.ENDC)
                del enemies[enemy]
                defeated_enemies += 1

    elif index == 2:
        player.choose_item()
        item_choice = int(input("    Choose item:")) - 1

        if item_choice == -1:
            continue

        item = player.items[item_choice]["item"]

        if player.items[item_choice]["quantity"] == 0:
            print(bcolours.FAIL + "\n" + "None left..." + bcolours.ENDC)
            continue

        player.items[item_choice]["quantity"] -= 1

        if item.type == "potion":
            player.heal(item.prop)
            print(bcolours.OKGREEN + "\n" + item.name + " heals for", str(item.prop), " HP" + bcolours.ENDC)
        elif item.type == "elixer":
            if item.name == "MegaElixer":
                for i in players:
                    i.hp = i.maxhp
                    i.mp = i.maxmp
            else:
                player.hp = player.maxhp
                player.mp = player.maxmp
            print(bcolours.OKGREEN + "\n" + item.name + " fully restores HP/MP" + bcolours.ENDC)
        elif item.type == "attack":
            enemy = player.choose_target(enemies)
            enemies[enemy].take_damage(item.prop)
            print(bcolours.FAIL + "\n" + item.name + " deals", str(item.prop), " points of damage to " +
                  enemies[enemy].name + bcolours.ENDC)

            if enemies[enemy].get_hp() == 0:
                print(bcolours.OKGREEN + bcolours.BOLD + enemies[enemy].name.replace(" ", "").replace(":", "") +
                      " has died!" + bcolours.ENDC)
                del enemies[enemy]
                defeated_enemies += 1

#Check is player has won
if defeated_enemies == 3:
    print(bcolours.OKGREEN + "You win!" + bcolours.ENDC)
    running = False
break

print("\n")
# Enemy attack phase
for enemy in enemies:
    enemy_choice = random.randrange(0,2)

    if enemy_choice == 0:
        # Choose attack
        target = random.randrange(0, len(players))
        enemy_dmg = enemy.generate_damge()

        players[target].take_damage(enemy_dmg)
        print(bcolours.FAIL + bcolours.BOLD + enemy.name.replace(" ", "").replace(":", "") + " attacks " +
              players[target].name.replace(" ", "").replace(":", "") + " for", enemy_dmg, bcolours.ENDC)

        if players[target].get_hp() == 0:
            print(bcolours.FAIL + bcolours.BOLD + players[target].name.replace(" ", "").replace(":", "") +
                  " has died!" + bcolours.ENDC)
            del players[target]
            defeated_players += 1

    elif enemy_choice == 1:
        spell, magic_dmg = enemy.choose_enemy_spell()
        # magic_dmg = spell.generate_damage()
        enemy.reduce_mp(spell.cost)

        if spell.type == "white":
            enemy.heal(magic_dmg)
            print(bcolours.FAIL + spell.name + " heals " + enemy.name.replace(" ", "").replace(":", "") +
                  " for", str(magic_dmg), "HP." + bcolours.ENDC)
        elif spell.type == "black":
            target = random.randrange(0, len(players))
            players[target].take_damage(magic_dmg)
            print(bcolours.FAIL + bcolours.BOLD + enemy.name.replace(" ", "").replace(":","") + "'s " + spell.name +
                  " deals", str(magic_dmg), "points of damage to " +
                  players[target].name.replace(" ", "").replace(":","") + bcolours.ENDC)

            if players[target].get_hp() == 0:
                print(bcolours.FAIL + bcolours.BOLD + players[target].name.replace(" ", "").replace(":", "") +
                      " has died!" + bcolours.ENDC)
                del players[target]
                defeated_players += 1

#Check if Enemy won
if defeated_players == 3:
    print(bcolours.FAIL + "Your enemies have defeated you!" + bcolours.ENDC)
    running = False
break

i had modified my codes as you have suggested but still its not working properly.... it is showing the following error

Traceback (most recent call last): File "main.py", line 254, in players[target].take_damage(magic_dmg) IndexError: list index out of range