7
\$\begingroup\$

This is my first text-based game I made. It's very small because I just learned Python and wanted to start small, and then code bigger programs. I added some stuff since the last time. Please give your honest opinion.

Here is my original question about this game.

import random
import time
import sys

def fight_enemy_3(enemy_name, min_enemy_damage, max_enemy_damage, min_player_damage, max_player_damage):
    enemy_damage_dealt = random.randint(min_enemy_damage, max_enemy_damage)
    player_damage_dealt = random.randint(min_player_damage, max_player_damage)

    if enemy_damage_dealt > player_damage_dealt:
        print("Uh-oh! You died!")
        game_over()
    elif enemy_damage_dealt < player_damage_dealt:
        print("You killed the {enemy_name}".format(enemy_name=enemy_name))
        cold()
    else:
        print("You walk away unscathed, but the {enemy_name} still lives.".format(enemy_name=enemy_name))
        cold()


def fight_enemy(enemy_name, min_enemy_damage, max_enemy_damage, min_player_damage, max_player_damage):
    enemy_damage_dealt = random.randint(min_enemy_damage, max_enemy_damage)
    player_damage_dealt = random.randint(min_player_damage, max_player_damage)

    if enemy_damage_dealt > player_damage_dealt:
        print("Uh-oh! You died!")
        game_over()
    elif enemy_damage_dealt < player_damage_dealt:
        print("You killed the {enemy_name}".format(enemy_name=enemy_name))
        its_getting_late()
    else:
        print("You walk away unscathed, but the {enemy_name} still lives.".format(enemy_name=enemy_name))
        its_getting_late()

def fight_enemy_2(enemy_name, min_enemy_damage, max_enemy_damage, min_player_damage, max_player_damage):
    enemy_damage_dealt = random.randint(min_enemy_damage, max_enemy_damage)
    player_damage_dealt = random.randint(min_player_damage, max_player_damage)

    if enemy_damage_dealt > player_damage_dealt:
        print("Uh-oh! You died!")
        game_over()
    elif enemy_damage_dealt < player_damage_dealt:
        print("You killed the {enemy_name}".format(enemy_name=enemy_name))
        game_end()
    else:
        print("You walk away unscathed, but the {enemy_name} still lives.".format(enemy_name=enemy_name))
        game_end()


def intro():
    name = input("Enter you name: ")
    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    print("Welcome to the Wildlife %s" %(name))
    print("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~")
    time.sleep(1)
    desert()

def desert():
    print("You are in the middle of a Desert in Africa")
    time.sleep(2)
    print("All you see is Sand. EVERYWHERE!!!")
    time.sleep(2)
    print("You start walking")
    time.sleep(2)
    print("You see a Snake")
    ch1 = str(input("Do you wanna attck the Snake? [y/n]: "))

    if ch1 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        time.sleep(2)
        fight_enemy('Snake', 1, 7, 1, 7)
    elif ch1 in ['n', 'N', 'No', 'NO', 'no']:
        print("You slowly back away")
        time.sleep(1)
        print("You managed to get away from the Snake")
        mountain_2()

def game_end():
    print("Congratulations you finished lvl 1!!!")
    ch4 = str(input("Do you wanna play lvl 2? [y/n] "))

    if ch4 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
        level_2_intro()
    elif ch4 in ['n', 'N', 'No', 'NO', 'no']:
        print("Thank you for playing")

def its_getting_late():
    time.sleep(1)
    print("Its starting to get late")
    ch2 = str(input("Do you wanna go to sleep? [y/n]: "))

    if ch2 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        print("You were stabbed dead last Night")
    elif ch2 in ['n', 'N', 'No', 'NO', 'no']:
        print("You stay up")
        time.sleep(1)
        print("You see a person")
        ch3 = str(input("Do you wanna attack the person? [y/n]: "))

        if ch3 in ['y', 'Y', 'YES', 'Yes', 'yes']:
            time.sleep(1)
            fight_enemy_2('Enemy', 4, 8, 1, 7)
        elif ch3 in ['n', 'N', 'No', 'NO', 'no']:
            print("You try to run away")
            print("But the Enemy is faster then you")
            fight_enemy_2('Enemy', 4, 8, 1, 6)

def game_over():
    print("You lost")
    ch5 = str(input("Do you wanna play again? [y/n] "))

    if ch5 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        print('~~~~~~~~~~~~~~~~~~~~~~~~~~~~')
        intro()
    elif ch5 in ['n', 'N', 'No', 'NO', 'no']:
        print("Thank you for playing")

def level_2_intro():
    print("Welcome to level 2!!!")
    print("You got a spear!!!")
    mountain()

def mountain():
    print("You start walking up a mountain")
    time.sleep(2)
    print("Oh no you see a a Tiger!!!")
    ch6 = str(input("Do you wanna attack the Tiger with you spear? [y/n]: "))

    if ch6 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        time.sleep(1)
        fight_enemy_3('Tiger', 5, 10, 4, 8)
    elif ch6 in ['n', 'N', 'No', 'NO', 'no']:
        print("The Tiger killed you")
        game_over()

def mountain_2():
    print("And start walking up a mountain")
    time.sleep(2)
    print("Oh no you see a Tiger!!!")
    ch6 = str(input("Do you wanna attack the Tiger? [y/n]: "))

    if ch6 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        time.sleep(1)
        fight_enemy_3('Tiger', 5, 10, 1, 7)
    elif ch6 in ['n', 'N', 'No', 'NO', 'no']:
        print("The Tiger killed you")
        game_over()


def cold():
    print("You are getting cold")
    time.sleep(1)
    ch7 = str(input("Do you wanna make a fire? [y/n]: "))

    if ch7 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        print("You made a fire")
        time.sleep(1)
        sleep()
    elif ch7 in ['n', 'N', 'No', 'NO', 'no']:
        print("You died")
        game_over()


def sleep():
    ch8 = str(input("Do you wanna go to sleep? [y/n]: "))

    if ch8 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        print("You go to sleep")
        time.sleep(2)
        you_slept()
    elif ch8 in ['n', 'N', 'No', 'NO', 'no']:
        print("You stay up")

def you_slept():
    print("The next day you wake up")
    print("You keep on walking")
    print("You see a person")
    ch9 = str(input("Do you wanna attck the person? [y/n]: "))

    if ch9 in ['y', 'Y', 'YES', 'Yes', 'yes']:
        print("You attack the person")
        time.sleep(1)
        fight_enemy_4('Enemy', 1, 7, 1, 7)
    elif ch9 in ['n', 'N', 'No', 'NO', 'no']:
        print("It turns out the person is nice and want to be friends")
        time.sleep(1)
        print("You have a friend now")
        friends()


def fight_enemy_4(enemy_name, min_enemy_damage, max_enemy_damage, min_player_damage, max_player_damage):
    enemy_damage_dealt = random.randint(min_enemy_damage, max_enemy_damage)
    player_damage_dealt = random.randint(min_player_damage, max_player_damage)

    if enemy_damage_dealt > player_damage_dealt:
        print("Uh-oh! You died!")
        game_over()
    elif enemy_damage_dealt < player_damage_dealt:
        print("You killed the {enemy_name}".format(enemy_name=enemy_name))
        you_killed_him()
    else:
        print("You walk away unscathed, but the {enemy_name} still lives.".format(enemy_name=enemy_name))
        you_killed_him()


def you_killed_him():
    print("You keep walking")


def friends():
    print("You and your friend combined powers")




intro()
\$\endgroup\$
5
\$\begingroup\$

Design

As it stands, in order for you to create "stages" you create multiple functions, each containing many if statements, each determining which function or "stage" is going to be run next. This isn't a great way to do this, and it can make code very hard to read.

I've actually created a library, along with the help of a few other users, which makes creating adventure games like this much easier. It's called Cactus, and you can find the repository here, along with the download links. You can also visit the website.

From the official docs:

Imports

It’s super easy to import Cactus into your project. Once you’ve added Cactus/cactus to your PYTHONPATH, this is all you need to do:

import cactus

Creating a cactus.Position instance

A cactus.Position instance stores relevant data about a position on a cactus.Flowchart. For reference, here’s a list of the cactus.Position attributes.

  • "name" - The position’s name.
  • "desc_enter" - The description to display when the player “enters” the position.
  • "desc_exit" - The description to display when the player “exits” the position.
  • "choices" - A dictionary of choices representing other positions on the flowchart. The key is what the user enters, and the value is the reference key to the other position in the flowchart.

Here’s how a simple cactus.Position instance is structured:

cactus.Position({
    "name":       "start",
    "desc_enter": "Description on enter.",
    "desc_exit":  "Description on exit.",
    "choices": {
        "choice1": "1",
        "choice2": "2"
    }
})

Creating a cactus.Flowchart instance

Flowcharts are essential to Cactus. Flowcharts are how you stucture the "map" that the player of your game will traverse. For reference, here’s a list of the cactus.Flowchart attributes.

  • "data" - Stores the actual flowchart data as a dictionary.

Here’s how a simple Flowchart instance is structured.

FLOWCHART = cactus.Flowchart({
    "data": {
        "position_name": cactus.Position(
            ...
        )
    }
})

Creating a cactus.Game instance

The cactus.Game class stores general data about your game that isn’t relevant to flowcharts or positions. The cactus.Game class is also where event handlers and global commands are stored. For reference, here’s a list of the cactus.Game attributes.

  • "name" - The game’s name.
  • "desc" - The game’s description.
  • "prompt" - The prompt to be used for entering commands.
  • "invalid_input_msg" - The message to be displayed when the user enters invalid input.
  • "flowchart" - The flowchart instance that has been created.
  • "case_sensitive" - If this is False, then all user input, and certain attribute values a converted to lowercase. If it’s True, then none of that happens.
  • "allow_help" - If this is True, then the user can obtain help.
  • "about_text" - The game’s about text, including the reqiuired attribution text.
  • "event_handlers" - A dictionary of the event handlers and their corresponding functions.
  • "global_commands" - A dictionary of commands that can be executed anywhere, and their corresponding functions.

Here’s how a simple cactus.Game instance is structured.

GAME = cactus.Game({
    "name":              "Game Name",
    "desc":              "Game Description",
    "prompt":            "> ",
    "invalid_input_msg": "Invalid input",
    "flowchart":         FLOWCHART,
    "case_sensitive":    False,
    "allow_help":        True,
    "about_text":        "Write about your game here.",
    "event_handlers": {
        "position.Name Goes Here 1.enter.after": exit,
        "position.Name Goes Here 2.enter.after": exit
    },
    "global_commands": {
        "exit": exit
    }
})

Running your game

Once you’ve done all of the above, you’re ready to play your game. Assuming you’ve created an instance of cactus.Game, named it GAME, and everything checks out, all you need to do is the below:

GAME.play_game()

Removing duplication

Rather than (again) recreating the fight_enemy function to run a different function each time, you can add an additional argument to the end of the function signature, function_to_run. You fight_enemy function would then become this:

def fight_enemy(enemy_name, min_enemy_damage, max_enemy_damage, min_player_damage, max_player_damage, function_to_run):
    enemy_damage_dealt = random.randint(min_enemy_damage, max_enemy_damage)
    player_damage_dealt = random.randint(min_player_damage, max_player_damage)

    if enemy_damage_dealt > player_damage_dealt:
        print("Uh-oh! You died!")
        game_over()
    elif enemy_damage_dealt < player_damage_dealt:
        print("You killed the {enemy_name}".format(enemy_name=enemy_name))
        function_to_run()
    else:
        print("You walk away unscathed, but the {enemy_name} still lives.".format(enemy_name=enemy_name))
        function_to_run()

Nitpicks

You're also converting the result of an input call using the str function in many places. This is not needed. You can just call input like this:

... = input( ... )

I'd also remove the various time.sleeps, it's a little annoying to have to wait when playing the game, especially when it's more than 1-2 seconds.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.