Skip to content

Instantly share code, notes, and snippets.

@hyperdriveguy
Last active March 5, 2021 20:54
Show Gist options
  • Save hyperdriveguy/142b5d2fa60a83c43c71d5289d04a039 to your computer and use it in GitHub Desktop.
Save hyperdriveguy/142b5d2fa60a83c43c71d5289d04a039 to your computer and use it in GitHub Desktop.
A text adventure with rpg elements I wrote for class in less than 2 weeks.
#!/usr/bin/env python
"""
Copyright (C) 2021 Hyperdriveguy
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>.
Full plain text license https://www.gnu.org/licenses/gpl-3.0.txt
"""
import random
import sys
# Raw ANSI codes for color coding
# Unsure about Windows support
class Color:
bold = '\033[01m'
yellow = '\033[93m'
green = '\033[32m'
red = '\033[31m'
# If no color outputs in the terminal, uncomment the code below
#red = '*'
end = '\033[0m'
#end = '*'
# Used with random.choice() in a few different functions
stat_list = ['Health', 'Strength', 'Skill', 'Stamina', 'Speed']
def clear(prompt=False):
if prompt == True:
input('Press Enter to continue...')
print('\033c')
def coinflip():
rand = random.randint(0, 1)
if rand == 0:
return True
else:
return False
def new_game():
# Name
name_confirm = ''
while name_confirm != 'y':
clear()
your_name = input('What is your name? ').title()
name_confirm = input(f'So, {your_name} is your name? (y/N) ').lower()
# Gender
gender = ''
while gender != 'boy' and gender != 'girl':
clear()
gender = input(f'Are you a {Color.bold}b{Color.end}oy or a {Color.bold}g{Color.end}irl? ').lower()
if 'b' in gender:
gender = 'boy'
elif 'g' in gender:
gender = 'girl'
else:
continue
gender_confirm = input(f'So, you\'re a {gender}? (y/N) ').lower()
if gender_confirm != 'y':
gender = ''
# Character point distribution
clear()
print('Now you need to distribute your Character Points.')
print('Character Points are associtated with different skills that will benefit you in a variety of ways.')
clear(True)
stat_confirm = ''
while stat_confirm != 'y':
stats = distribute_char_points()
clear()
print_char_point_table(stats)
stat_confirm = input('\nIs this okay? (y/N) ').lower()
# How to play
clear()
how_to_prompt = input('Would you like instructions on how to play? (y/N) ').lower()
if how_to_prompt == 'y':
print('This is a text based adventure game where you will need to type out certain actions.')
print(f'Actions will be formatted with {Color.red}Red text{Color.end}, like so.')
print(f'For example, if you\'re given an option to either {Color.red}Run{Color.end} away or {Color.red}Hide{Color.end} in the bushes...')
print(f'You would type {Color.red}"run"{Color.end} or {Color.red}"hide"{Color.end}, '
f'or just {Color.red}"r"{Color.end} or {Color.red}"h"{Color.end} for short, as that is what\'s capitalized.')
print(f'Unlisted actions that are always available are {Color.red}Quit{Color.end}, {Color.red}Stats{Color.end}, and {Color.red}Inventory.{Color.end}')
print(f'These options have the reserved shortcuts {Color.red}qt{Color.end}, {Color.red}ss{Color.end}, and {Color.red}in{Color.end}.')
clear(True)
return({'name': your_name, 'gender': gender, 'stats': stats})
def distribute_char_points():
avail_points = 25
char_points = {'Health': 1, 'Strength': 1, 'Skill': 1, 'Stamina': 1, 'Speed': 1}
while avail_points > 0:
clear()
print_char_point_table(char_points)
print(f'\nYou have {avail_points} points left to distribute.\n')
char_dist_target = input('What attribute will you add points to? ').title()
try:
char_points[char_dist_target]
except KeyError:
if char_dist_target == 'Auto':
char_points = {'Health': 10, 'Strength': 5, 'Skill': 5, 'Stamina': 5, 'Speed': 5}
return char_points
print('That attribute doesn\'t exist. Please try again.')
clear(True)
continue
try:
# Type changes from string to integer here
char_dist_amount = input(f'How many points would you like to add to {char_dist_target}? ').lower()
if char_dist_amount == 'all':
char_dist_amount = avail_points
elif char_dist_amount == 'max':
char_dist_amount = 10 - char_points[char_dist_target]
else:
char_dist_amount = int(char_dist_amount)
except ValueError:
print('Not a valid integer. No parital points may be allotted.')
clear(True)
continue
# Conditions for adding points
if char_dist_amount > avail_points:
print('Not enough Character Points.')
clear(True)
continue
elif char_dist_amount + char_points[char_dist_target] > 10:
char_point_overflow = char_dist_amount + char_points[char_dist_target] - 10
print(f'Max character points per attribute is 10. You attempted to allot {char_point_overflow} in excess.')
if char_points[char_dist_target] < 10:
max_out_attribute_points = 10 - char_points[char_dist_target]
change_allotment = input(f'Would you like to max {char_dist_target} by allotting {max_out_attribute_points} instead? (y/N) ').lower()
if change_allotment == 'y':
char_dist_amount = max_out_attribute_points
else:
continue
else:
continue
# Conditions for subtracting points
elif char_dist_amount + char_points[char_dist_target] < 0:
print('Minimum character points per attribute is 0 (minimum recommended is 1).')
change_allotment = input(f'Would you like to take back all points currently allotted to {char_dist_target}? (y/N)').lower()
if change_allotment == 'y':
char_dist_amount = char_points[char_dist_target] * -1
else:
continue
char_points[char_dist_target] = char_points[char_dist_target] + char_dist_amount
avail_points = avail_points - char_dist_amount
return(char_points)
def print_char_point_table(char_points):
# The funky tricks used for alignment and bold require double quotes
print(f"{Color.bold}{'Attribute' : <15}{'Description' : ^45}{'Level' : ^15}{Color.end}")
print('-' * (15 + 45 + 15))
print(f"{'Health' : <15}{'How much damage you can take before you die' : ^45}{round(char_points['Health'], 2) : ^15}")
print(f"{'Strength' : <15}{'Your brute power without weapons' : ^45}{round(char_points['Strength'], 2) : ^15}")
print(f"{'Skill' : <15}{'How practiced you are in your talents' : ^45}{round(char_points['Skill'], 2) : ^15}")
print(f"{'Stamina' : <15}{'How long it takes before you get exhausted' : ^45}{round(char_points['Stamina'], 2) : ^15}")
print(f"{'Speed' : <15}{'How fast your movement and reactions are' : ^45}{round(char_points['Speed'], 2) : ^15}")
def action_prompt(story, *actions):
valid_action = []
# Prompt specific actions
for action in actions:
# The only time there should be a list here is if this is called from the battle function
if type(action) is list:
for sub_action in action:
valid_action.append(sub_action.lower())
# generate action shortcuts
shortcut = ''
for letter in sub_action:
if letter.isupper():
shortcut = shortcut + letter
# In case no uppercase was found
if len(shortcut) > 0:
valid_action.append(shortcut.lower())
else:
valid_action.append(action.lower())
# generate action shortcuts
shortcut = ''
for letter in action:
if letter.isupper():
shortcut = shortcut + letter
# In case no uppercase was found
if len(shortcut) > 0:
valid_action.append(shortcut.lower())
statuses = apply_status()
# Decision loop
choice = ''
while choice not in valid_action:
if is_dead():
clear(True)
sys.exit(0)
clear()
print(story)
print()
for status in statuses:
print(status)
print()
choice = input(f'{Color.green}>>> {Color.end}').lower()
# Check for reserved commands
# Stats screen
if choice == 'stats' or choice == 'ss':
clear()
print(character['name'].title())
print(character['gender'].title())
print(f"\nAbility: {character['ability'].title()}")
print('\nStatus:')
if len(character['status']) == 0:
print('\tNone')
else:
for status in character['status']:
print(f'\t{Color.green}{status}{Color.end}')
print()
print_char_point_table(character['stats'])
clear(True)
# Inventory screen
elif choice == 'inventory' or choice == 'in':
clear()
for item, num_item in character['inventory'].items():
if type(num_item) is dict:
print(f'{Color.yellow}{item.title()}{Color.end} contains:')
for contained_item, num_contained_item in num_item.items():
print(f'\t{Color.yellow}{contained_item.title()}{Color.end}: {num_contained_item}')
else:
if num_item > 0:
print(f'{Color.yellow}{item.title()}{Color.end}: {num_item}')
if len(character['inventory']) == 0:
print('Nothing in inventory.')
clear(True)
elif choice == 'help' or choice == 'hl':
clear()
print('This is a text based adventure game where you will need to type out certain actions.')
print(f'Actions are formatted with {Color.red}Red text{Color.end}, like so.')
print(f'For example, if you\'re given an option to either {Color.red}Run{Color.end} away or {Color.red}Hide{Color.end} in the bushes...')
print(f'You would type {Color.red}"run"{Color.end} or {Color.red}"hide"{Color.end}, '
f'or just {Color.red}"r"{Color.end} or {Color.red}"h"{Color.end} for short, as that is what\'s capitalized.')
print(f'Unlisted actions that are always available are {Color.red}Help{Color.end}, {Color.red}Quit{Color.end}, {Color.red}Stats{Color.end}, and {Color.red}Inventory.{Color.end}')
print(f'These options have the reserved shortcuts {Color.red}hl{Color.end}, {Color.red}qt{Color.end}, {Color.red}ss{Color.end}, and {Color.red}in{Color.end}.')
clear(True)
elif choice == 'quit' or choice == 'qt':
clear()
ask_quit = input('Are you sure you want to quit? (y/N) ').lower()
if ask_quit == 'y':
sys.exit(0)
return choice
def is_dead():
if character['stats']['Health'] <= 0:
clear()
print(f'{Color.bold}{Color.red}You died unexpectedly. Try again next time.{Color.end}')
return True
else:
return False
def apply_status():
global character
global danger_health_flag
status_messages = []
# Specific case for exhaustion status
if character['stats']['Stamina'] < 0:
# Random stat debuff
debuff_stat = random.choice(stat_list)
character['stats'][debuff_stat] = character['stats'][debuff_stat] - character['stats']['Stamina'] / random.randint(2, 5)
character['stats']['Health'] = character['stats']['Health'] + character['stats']['Stamina'] / random.randint(1, 5)
character['stats']['Stamina'] = 0
status_messages.append(f'{Color.bold}{Color.red}Warning! You have started to take damage from exhaustion.{Color.end}')
elif character['stats']['Stamina'] > 10:
character['stats']['Health'] = character['stats']['Health'] + character['stats']['Stamina'] - 10
character['stats']['Stamina'] = 10
# This is just to make the exhaustion status show and hide in the menu
if character['stats']['Stamina'] < 1:
character['status'].append('Exhaustion')
else:
try:
character['status'].remove('Exhaustion')
except ValueError:
pass
if 'Poisoned' in character['status']:
character['stats']['Health'] = character['stats']['Health'] - 0.25
status_messages.append(f'{Color.bold}{Color.red}Warning! You have started to take damage from poison.{Color.end}')
# If HP is below a certain threshold, buff stats
if character['stats']['Health'] < 3 and not danger_health_flag:
danger_health_flag = True
character['stats']['Strength'] = character['stats']['Strength'] * 1.5
character['stats']['Skill'] = character['stats']['Skill'] * 1.5
character['stats']['Stamina'] = character['stats']['Stamina'] * 1.5
character['stats']['Speed'] = character['stats']['Speed'] * 1.5
character['status'].append('Adrenaline')
status_messages.append('You feel your adrenaline start pumping.')
elif character['stats']['Health'] >= 3 and danger_health_flag:
danger_health_flag = False
# Got stat increases while the buff applied? Sucks for you!
character['stats']['Strength'] = character['stats']['Strength'] / 1.5
character['stats']['Skill'] = character['stats']['Skill'] / 1.5
character['stats']['Stamina'] = character['stats']['Stamina'] / 1.5
character['stats']['Speed'] = character['stats']['Speed'] / 1.5
character['status'].remove('Adrenaline')
status_messages.append('Your adrenaline levels drop and you feel more calm.')
return status_messages
def give_damage(damage):
global character
if damage < 0:
damage = 0
character['stats']['Health'] = character['stats']['Health'] - damage
return damage
def shooting_plot():
global character
print('You arrive in the desert and find a nice hill to shoot against.\n'
f'You set up your {Color.yellow}target{Color.end} and reload your '
f'{Color.yellow}rifle{Color.end} using {Color.yellow}ammo{Color.end} from '
f'the {Color.yellow}ammo box{Color.end}.')
clear(True)
print('You hold your breath and take a shot.')
num_field_tannerite = 0
result = 'shoot'
rand_buff = [0.1, 0.1, 0.1, 0.1, 0.5, 1, -0.1, -0.5]
target_destroyed = False
# Target shooting
while not target_destroyed:
if result == 'shoot' or result == 's':
hit_or_miss = target_shot_calc(character['stats']['Skill'], character['stats']['Strength'], num_field_tannerite)
character['inventory']['rifle']['ammo'] = character['inventory']['rifle']['ammo'] - 1
if character['stats']['Skill'] >= 10:
character['stats']['Skill'] = character['stats']['Skill'] - random.choice(rand_buff)
elif character['stats']['Skill'] < 0:
character['stats']['Skill'] = 0
else:
character['stats']['Skill'] = character['stats']['Skill'] + random.choice(rand_buff)
if hit_or_miss < 20:
print(f'You missed the {Color.yellow}target{Color.end} by a mile. You may need more practice shots.')
character['stats']['Stamina'] = character['stats']['Stamina'] - 0.1
elif hit_or_miss >= 20 and hit_or_miss <= 80:
if num_field_tannerite <= 0:
print(f'You hit the {Color.yellow}target{Color.end}, but it wasn\'t a particularly impressive shot.')
else:
print(f'You hit the {Color.yellow}target{Color.end}, but you still managed to miss the {Color.yellow}tannerite{Color.end}.')
# > 80 percent
else:
if num_field_tannerite <= 0:
print(f'You hit the target dead center! You consider setting out your {Color.yellow}tannerite{Color.end}.')
elif num_field_tannerite == 1:
print(f'The {Color.yellow}tannerite{Color.end} made a satisfying explosion near the {Color.yellow}target{Color.end}. '
f'The {Color.yellow}target{Color.end} still stands.')
num_field_tannerite = 0
else:
target_destroyed = True
continue
clear(True)
total_ammo = character['inventory']['rifle']['ammo'] + character['inventory']['ammo box']['ammo']
if total_ammo == 0:
print(f'You ran out of {Color.yellow}ammo{Color.end} entirely. Disappointed, you returned home.')
print('Game over.')
clear(True)
sys.exit(0)
if character['inventory']['tannerite'] > 0:
if character['inventory']['rifle']['ammo'] < 15 and character['inventory']['rifle']['ammo'] > 0 and character['inventory']['ammo box']['ammo'] > 0:
action_text = (f'Will you continue to {Color.red}Shoot{Color.end} the {Color.yellow}target{Color.end}, '
f'{Color.red}Reload{Color.end} your {Color.yellow}rifle{Color.end}, '
f'or set out {Color.red}Tannerite{Color.end}?')
result = action_prompt(action_text, 'Shoot', 'Reload', 'Tannerite')
elif character['inventory']['rifle']['ammo'] > 0 or character['inventory']['ammo box']['ammo'] == 0:
action_text = (f'Will you continue to {Color.red}Shoot{Color.end} the {Color.yellow}target{Color.end}, '
f'or set out {Color.red}Tannerite{Color.end}?')
result = action_prompt(action_text, 'Shoot', 'Tannerite')
# No ammo in rifle, ammo in ammo box
else:
action_text = (f'You ran out of {Color.yellow}ammo{Color.end}. Will you {Color.red}Reload{Color.end} your {Color.yellow}rifle{Color.end} '
f'or set out {Color.red}Tannerite{Color.end}?')
result = action_prompt(action_text, 'Reload', 'Tannerite')
else:
if character['inventory']['rifle']['ammo'] < 15 and character['inventory']['rifle']['ammo'] > 0 and character['inventory']['ammo box']['ammo'] > 0:
action_text = (f'Will you continue to {Color.red}Shoot{Color.end} the {Color.yellow}target{Color.end} or '
f'{Color.red}Reload{Color.end} your {Color.yellow}rifle{Color.end}?')
result = action_prompt(action_text, 'Shoot', 'Reload')
elif character['inventory']['rifle']['ammo'] > 0 or character['inventory']['ammo box']['ammo'] == 0:
action_text = (f'Will you continue to {Color.red}Shoot{Color.end} the {Color.yellow}target{Color.end}?')
result = action_prompt(action_text, 'Shoot')
# No ammo in rifle, ammo in ammo box
else:
action_text = (f'You ran out of {Color.yellow}ammo{Color.end}. Will you {Color.red}Reload{Color.end} your {Color.yellow}rifle{Color.end}?')
result = action_prompt(action_text, 'Reload')
if result == 'reload' or result == 'r':
potential_reload = 15 - character['inventory']['rifle']['ammo']
if character['inventory']['ammo box']['ammo'] < potential_reload:
character['inventory']['rifle']['ammo'] = character['inventory']['rifle']['ammo'] + character['inventory']['ammo box']['ammo']
character['inventory']['ammo box']['ammo'] = 0
else:
character['inventory']['ammo box']['ammo'] = character['inventory']['ammo box']['ammo'] - potential_reload
character['inventory']['rifle']['ammo'] = 15
print(f'Your {Color.yellow}rifle{Color.end} was reloaded.')
elif result == 'tannerite' or result == 't':
print(f"You have {character['inventory']['tannerite']} {Color.yellow}tannerite{Color.end} in your inventory.")
queued_tannerite = input('How much will you set out? ')
try:
if queued_tannerite == 'all' or queued_tannerite == 'max':
queued_tannerite = character['inventory']['tannerite']
queued_tannerite = int(queued_tannerite)
except ValueError:
continue
if queued_tannerite > character['inventory']['tannerite']:
print('You do not have that much.')
clear(True)
continue
character['inventory']['tannerite'] = character['inventory']['tannerite'] - queued_tannerite
num_field_tannerite = queued_tannerite
print(f'The {Color.yellow}tannerite{Color.end} ignited and destroyed the {Color.yellow}target{Color.end}, '
'sending shrapnels of metal everywhere.')
# Metal flying back at you
if num_field_tannerite == 3:
num_field_tannerite = 0
print('...\nIncluding at you!')
clear(True)
avoid_metal = (f'Will you attempt to {Color.red}Brace{Color.end} for impact, {Color.red}Dodge{Color.end}, '
f'or {Color.red}Run{Color.end} away from the metal?')
result = action_prompt(avoid_metal, 'Brace', 'Dodge', 'Run')
clear()
if result == 'brace' or result == 'b':
damage_taken = character['stats']['Health'] - (7 - character['stats']['Stamina'])
give_damage(damage_taken)
print(f'You braced for the impact and took {Color.green}{damage_taken} damage{Color.end}.')
clear(True)
elif result == 'dodge' or result == 'd':
dodge_chance = (character['stats']['Speed'] + character['stats']['Skill']) * 0.05 * random.randint(0, 100)
if dodge_chance > 80:
print('You were able to evade the metal shards entirely!')
elif dodge_chance > 50 and dodge_chance <= 80:
damage_taken = 10 - round(dodge_chance / 10)
give_damage(damage_taken)
print(f'You evaded most of the metal shards, but still took {Color.green}{damage_taken} damage{Color.end}.')
else:
give_damage(7)
print(f'You failed to evade the shards and took {Color.green}7 damage{Color.end}.')
clear(True)
# Run
elif result == 'run' or choice == 'r':
run_chance = (character['stats']['Speed'] + character['stats']['Stamina']) * 0.03 * random.randint(0, 100) + random.randint(0, 40)
if run_chance > 80:
print('You were able to run from the metal shards!')
elif run_chance > 30 and run_chance <= 80:
damage_taken = 10 - round(run_chance / 10)
give_damage(damage_taken)
print(f'You ran from most of the metal shards, but still took {Color.green}{damage_taken} damage{Color.end}.')
else:
give_damage(9)
print(f'You tripped and took {Color.green}9 damage{Color.end} from the shards and your fall.')
clear(True)
else:
clear(True)
print('The flying metal agitated some agressive wildlife nearby. A hog-like creature is rapidly approaching!')
clear(True)
cur_kill_count = 0
while True:
if cur_kill_count > 0:
print(f'Your current kill streak is {cur_kill_count}.')
clear(True)
battle('Agressive Javelina', 15, 8, 3, 6, {'Ram': 4, 'Mega Ram': 7}, {'Bellow': 1})
cur_kill_count = cur_kill_count + 1
victory_scream_prompt = ('You\'re very satisfied with how fended off that animal.\nYou instinctively want to'
f' give a victory {Color.red}Yell{Color.end}, but something tells you it might be '
f'{Color.red}Quiet{Color.end} instead.')
victory_scream = action_prompt(victory_scream_prompt, 'Yell', 'Quiet')
if victory_scream == 'yell' or victory_scream == 'y':
print('You agitated another wild animal!')
clear(True)
elif victory_scream == 'quiet' or victory_scream == 'q':
if cur_kill_count > 1:
print(f'Your final kill streak was {cur_kill_count}.')
print('You quietly celebrated your victory. Feeling exhausted, you pack up and go home.')
print('The end.')
clear(True)
sys.exit(0)
def target_shot_calc(skill, strength, tannerite):
chance = skill * 0.1 + skill * strength * 0.02 * (tannerite + 1)
return chance * random.randint(0, 100)
def explore_plot():
global character
explore_prompt_1 = ('You arrive in the desert and stumble upon a small ruined building.\n'
'You see a small glimmer in the rubble as well as something in the distance.\n'
f'Do you want to use your {Color.red}Binoculars{Color.end} to investigate the '
f'object in the distance, {Color.red}Sift{Color.end} through the rubble, or '
f'or ignore these and {Color.red}Continue{Color.end} on the path?')
choice = action_prompt(explore_prompt_1, 'Binoculars', 'Sift', 'Continue')
if choice == 'sift' or choice == 's':
print(f'You sifted through the rubble and found an {Color.yellow}odd gem{Color.end}. You added it to your inventory.')
character['inventory']['odd gem'] = 1
clear(True)
post_sift_prompt = (f'Do you want to use your {Color.red}Binoculars{Color.end} to investigate the '
f'object in the distance or or ignore it and {Color.red}Continue{Color.end} on the path?')
choice = action_prompt(post_sift_prompt, 'Binoculars', 'Continue')
# Not elif due to the choice also being modified if the player chooses to take the odd gem
if choice == 'binoculars' or choice == 'b':
binocular_prompt = ('You see a larger building as you put on your binoculars. Maybe this is part of a larger ghost town?\n'
f'Will you go {Color.red}West{Color.end} towards the ruins, or {Color.red}Continue{Color.end} on the path?')
choice = action_prompt(binocular_prompt, 'West', 'Continue')
if choice == 'west' or choice == 'w':
if 'odd gem' in character['inventory']:
haunted_ruins_prompt = ('The sky turns an ominous red as you approach the large ruinous building.\n'
'The building\'s original use is not easily identified due to its decay.\n'
f'Nearby the building, you see what appears to be an old {Color.red}Mineshaft{Color.end}\n'
f'and a barely recognizable {Color.red}Cemetery{Color.end}, faded from its age.')
choice = action_prompt(haunted_ruins_prompt, 'Mineshaft', 'Cemetery')
if choice == 'mineshaft' or choice == 'm':
clear()
print('The mineshaft is deceptively short. You see what appears to be a miner blankly staring at the end of the mine.')
print('You try to greet him, but he doesn\'t respond for a moment. About to leave, you hear a gunshot and feel a bullet barely miss your cheek.')
print('You quickly turn back to inside the shaft and see the crazed face of the miner, revolver in hand.')
print('The miner picks up a pickaxe nearby and runs toward you. He isn\'t going to let you leave without a fight.')
clear(True)
battle('Crazed Miner', 12, 4, 3, 4, {'Pickaxe Swing': 7, 'Feeble Punch': 2}, {'Revolver Shot': 7, 'Pebble Throw': 1})
print('You exit the mine as fast as your legs will carry you and call for a helicopter to come pick you up.')
print('You\'re safe now, but wonder about the old town you stepped upon...')
print('The end.')
clear(True)
sys.exit(0)
elif choice == 'cemetery' or choice == 'c':
clear()
print('The cemetery is very obviously over a couple centuries old. You can\'t make out anything on the headstones.')
print('Suddenly, one of the graves breaks open with an undead being set on destroying you.')
clear(True)
battle('Zombie', 10, 4, 3, 20, {'Chomp': 4, 'Feeble Punch': 2}, {'Piercing Screech': 5, 'Pebble Throw': 1})
print('You run away from the cemetery as fast as your legs will carry you and call for a helicopter to come pick you up.')
print('You\'re safe now, but wonder about the old town you stepped upon...')
print('The end.')
clear(True)
sys.exit(0)
else:
abandoned_ruins_prompt = ('You approach the large ruinous building.\n'
'The building\'s original use is not easily identified due to its decay.\n'
f'Nearby the building, you see what appears to be an old {Color.red}Mineshaft{Color.end}\n'
f'and a barely recognizable {Color.red}Cemetery{Color.end}, faded from its age.')
choice = action_prompt(abandoned_ruins_prompt, 'Mineshaft', 'Cemetery')
if choice == 'mineshaft' or choice == 'm':
mineshaft_prompt = ('The mineshaft is deceptively short. You see a pickaxe and lamp lying around.\n'
f'Will you {Color.red}Examine{Color.end} the pickaxe and lamp or {Color.red}eXit{Color.end}'
f' the mine and call for a ride home?')
choice = action_prompt(mineshaft_prompt, 'Examine', 'eXit')
if choice == 'exit' or choice == 'x':
print('You exited the mine and called for a helicopter to give you a lift home.')
print('You can\'t help but wonder if there was more to the old town you stepped upon...')
print('The end.')
clear(True)
sys.exit(0)
elif choice == 'examine' or 'e':
print('You tried to touch the pickaxe and lamp to examine them, but they started moving on their own!')
print('You need to defend yourself from these inanimate fiends!')
clear(True)
battle('Pickaxe and Lamp', 10, 2, 7, 4, {'Pickaxe Swing': 5, 'Lamp Bash': 4}, {'Blinding Lights': 2, 'Pickaxe Rapid Spin': 4})
print('Relieved, scared and confused, you exit the mine and call for a ride home.')
print('You\'re safe now, but wonder about the old town you stepped upon...')
print('The end.')
clear(True)
sys.exit(0)
elif choice == 'cemetery' or choice == 'c':
clear()
print('The cemetery is very obviously over a couple centuries old. You can\'t make out anything on the headstones.')
print('There isn\'t much here, so you decide to make your way back to the path you were on.')
clear(True)
choice = 'continue'
# Fall through to continue
if choice == 'continue' or choice == 'c':
continue_path_prompt = ('A rattlesnake blocks the path at a very narrow point. You aren\'t likely to get by without provoking '
f'it. Will you try to {Color.red}sNeak{Color.end} around it or {Color.red}Shoot{Color.end} with '
f'your {Color.yellow}Pistol{Color.end}?')
choice = action_prompt(continue_path_prompt, 'sNeak', 'Shoot')
if choice == 'sneak' or choice == 'n':
print('You attempted to sneak around the snake.')
sneak_chance = (character['stats']['Speed'] + character['stats']['Skill']) * 0.05 * random.randint(0, 100)
if sneak_chance > 50:
print('You were able to sneak past the snake with no issue.')
else:
print('The snake noticed you and bit you before you could react. You may have been poisoned.')
if coinflip():
character['status'].append('Poisoned')
elif choice == 'shoot' or choice == 's':
shoot_snake_chance = character['stats']['Skill'] * 0.09 + (character['stats']['Skill'] + character['stats']['Strength']) * 0.04 * random.randint(0, 100)
character['inventory']['pistol']['ammo'] = character['inventory']['pistol']['ammo'] - 1
if shoot_snake_chance >= 65:
print(f'You shot snake and killed it. You took a {Color.yellow}snake fang{Color.end} from the snake as a souvenir.')
character['inventory']['snake fang'] = 1
if coinflip():
print(f'The snake was hefty enough that the {Color.yellow}snake meat{Color.end} '
'looks like it could sustain you, so you skinned the snake and took it\'s meat.')
character['inventory']['snake meat'] = 5
else:
print('You missed your shot. Agitated, the snake bit you before you could react. You may have been poisoned.')
print(f'You ripped the snake off your leg. You pulled out the {Color.yellow}snake fang{Color.end} out of your leg and added it to your inventory.')
character['inventory']['snake fang'] = 1
if coinflip():
character['status'].append('Poisoned')
clear(True)
wall_prompt_general = ('After following the path a little while longer, you stumble upon a steep mountain.\n'
'The mountain appears impossible to scale; however, upon further inspection you notice\n'
'a couple odd shaped divets. One divet appears to be vaguely fang shaped and the other\n'
'oval shaped.\n')
wall_prompt_fang_only = (f'Do you want to attempt to {Color.red}Place{Color.end} the {Color.yellow}snake fang{Color.end} or '
f'{Color.red}Call{Color.end} a helicopter to take you home?')
wall_prompt_odd_gem = (f'Do you want to attempt to {Color.red}Place{Color.end} the {Color.yellow}snake fang{Color.end} '
f'and {Color.yellow}odd gem{Color.end} or {Color.red}Call{Color.end} a helicopter to take you home?')
if 'odd gem' in character['inventory']:
choice = action_prompt(wall_prompt_general + wall_prompt_odd_gem, 'Place', 'Call')
if choice == 'place' or choice == 'p':
clear()
print('The ground shakes and the mountainside opens up. Gold, silver, and precious metals lay in '
'in front of you where the mountainside was. You call a helicopter to help transport it home.\n'
'Arriving home with your new riches, you can\'t wait to go exploring again!')
clear(True)
sys.exit(0)
else:
choice = action_prompt(wall_prompt_general + wall_prompt_fang_only, 'Place', 'Call')
if choice == 'place' or choice == 'p':
print('The ground shakes and the mountainside opens up. A large monster pops outside of the mountainside'
', looking to pick a fight.')
clear(True)
battle('Guardian', 20, 7, 5, 4, {'Brute Punch': 5, 'Mega Yeet': 7}, {'Ominous Beam': 9, 'Screech': 3})
print('Gold, silver, and precious metals lay in in front of you where the Guardian was!\n'
'You call a helicopter to help transport it home.\n'
'Arriving home with your new riches, you can\'t wait to go exploring again!')
if choice == 'call' or choice == 'c':
clear()
print(f'You called a helicopter to take you home on your {Color.yellow}satellite phone{Color.end}. '
'You found your trip interesting and are glad to be back home.')
print('The end.')
clear(True)
sys.exit(0)
def battle(name, health, strength, skill, stamina, melee_attacks, special_attacks):
global character
full_health = health
melee_attack_list = []
special_attack_list = []
for m_attack in melee_attacks:
melee_attack_list.append(m_attack)
for s_attack in special_attack_list:
special_attack_list.append(s_attack)
enemy_attack_scope = []
if len(melee_attack_list) > 0:
enemy_attack_scope.append('melee')
if len(special_attack_list) > 0:
enemy_attack_scope.append('special')
while health > 0:
# Make battle HUD
build_hud_1 = (f'{name}\n'
f'{Color.bold}HP:{Color.end} ')
health_bar = ''
if health < full_health:
existing_health_bar = f'{Color.green}█{Color.end}' * int(round(health))
damage_done_bar = f'{Color.red}🮐{Color.end}' * int(round(full_health - health))
health_bar = existing_health_bar + damage_done_bar
else:
health_bar = f'{Color.green}█{Color.end}' * int(round(health))
actions_hud = (f'\n\n{Color.red}')
avail_actions = ['Rest', 'Punch']
if 'rifle' in character['inventory']:
if character['inventory']['ammo box']['ammo'] > 0 and character['inventory']['rifle']['ammo'] < 15:
avail_actions.append('reLoad')
if character['inventory']['rifle']['ammo'] > 0:
avail_actions.append('Shoot')
else:
try:
if character['inventory']['pistol']['ammo'] > 0:
avail_actions.append('Shoot')
except KeyError:
pass
if 'snack' in character['inventory']:
if character['inventory']['snack'] > 0:
avail_actions.append('Eat')
if 'snake meat' in character['inventory']:
if character['inventory']['snack'] > 0:
avail_actions.append('Eat')
for action in avail_actions:
actions_hud = actions_hud + action + f' {Color.end}| {Color.red}'
actions_hud = actions_hud + Color.end
your_health = f"\n\n\n{character['name'].title()}\n{Color.bold}HP: {round(character['stats']['Health'])}{Color.end}"
full_hud = build_hud_1 + health_bar + your_health + actions_hud
battle_turn_act = action_prompt(full_hud, avail_actions)
# Restore a random stat
if battle_turn_act == 'rest' or battle_turn_act == 'r':
restore_stat = random.choice(stat_list)
restore_amount = random.randint(1, 5) / 2
character['stats'][restore_stat] = character['stats'][restore_stat] + restore_amount
print(f'You rested for a little bit and restored {Color.green}{restore_amount} {restore_stat.lower()}{Color.end}!')
clear(True)
# Brute force punch that consumes stamina
elif battle_turn_act == 'punch' or battle_turn_act == 'p':
punch_damage = character['stats']['Strength'] - stamina / random.randint(1, round(int(character['stats']['Strength'])))
health = health - punch_damage
character['stats']['Stamina'] = character['stats']['Stamina'] - 1
print(f'You punched the {name} and dealt {Color.green}{round(punch_damage)} damage{Color.end}!')
clear(True)
# Attack that takes skill and consumes ammo
elif battle_turn_act == 'shoot' or battle_turn_act == 's':
print(f'You took a shot at the {name}.')
if character['ability'] == 'marksman':
character['inventory']['rifle']['ammo'] = character['inventory']['rifle']['ammo'] - 1
gun_damage_modifier = 2
else:
character['inventory']['pistol']['ammo'] = character['inventory']['pistol']['ammo'] - 1
gun_damage_modifier = 1
gun_damage = character['stats']['Skill'] * gun_damage_modifier - skill / random.randint(1, round(int(character['stats']['Skill'])))
health = health - gun_damage
print(f'You dealt {Color.green}{round(gun_damage)} damage{Color.end} with your shot!')
clear(True)
# Determine foode restoration/damage
elif battle_turn_act == 'eat' or battle_turn_act == 'e':
if 'snack' in character['inventory']:
if coinflip():
restore_health = random.randint(0, 3)
else:
restore_health = random.randint(0, 8)
else:
if coinflip():
restore_health = random.randint(-1, 4)
if coinflip():
if 'Poisoned' in character['status']:
character['status'].remove('Poisoned')
print(f'The {Color.yellow}snake meat{Color.end} cured your {Color.green}poison{Color.end}!')
else:
restore_health = random.randint(2, 8)
if coinflip():
if 'Poisoned' not in character['status']:
character['status'].append('Poisoned')
print(f'The {Color.yellow}snake meat{Color.end} {Color.green}poisoned{Color.end} you!')
if restore_health > 0:
print(f'The food restored {Color.green}{restore_health} health{Color.end}!')
clear(True)
else:
print(f'The food caused {Color.green}{restore_health * -1} damage{Color.end} to you!')
clear(True)
character['stats']['Health'] = character['stats']['Health'] + restore_health
# Reload rifle (The pistol cannot be reloaded)
elif battle_turn_act == 'reload' or battle_turn_act == 'l':
potential_reload = 15 - character['inventory']['rifle']['ammo']
if character['inventory']['ammo box']['ammo'] < potential_reload:
character['inventory']['rifle']['ammo'] = character['inventory']['rifle']['ammo'] + character['inventory']['ammo box']['ammo']
character['inventory']['ammo box']['ammo'] = 0
else:
character['inventory']['ammo box']['ammo'] = character['inventory']['ammo box']['ammo'] - potential_reload
character['inventory']['rifle']['ammo'] = 15
print(f'Your {Color.yellow}rifle{Color.end} was reloaded.')
clear(True)
if stamina < 0:
health = stamina + health
print(f'The {name} started to take damage from {Color.green}exhaustion{Color.end}.')
clear(True)
if health <= 0:
break
# The enemy now has a chance to counterattack
next_attack_set = random.choice(enemy_attack_scope)
if next_attack_set == 'melee':
next_attack = random.choice(melee_attack_list)
deal_damage_player = melee_attacks[next_attack] - character['stats']['Stamina'] / random.randint(1, strength)
stamina = stamina - 1
else:
next_attack = random.choice(special_attack_list)
deal_damage_player = special_attacks[next_attack] - character['stats']['Stamina'] / random.randint(1, skill)
rand_enemy_debuff = random.choice([health, strength, skill, stamina])
rand_enemy_debuff_amt = random.randint(0, 2)
deal_damage_player = give_damage(deal_damage_player)
print(f'The {name} used their {next_attack} attack and dealt {Color.green}{round(deal_damage_player)} damage{Color.end} to you!')
clear(True)
clear()
print(f'You defeated the {name}!')
clear(True)
return True
def main():
global danger_health_flag
danger_health_flag = False
# Make character
global character
character = new_game()
# character['name']
# character['gender']
# character['stats']
# Make empty inventory
character['inventory'] = {}
character['ability'] = ''
character['status'] = []
# Initial prompt goes here because it subtly determines the skill
# This prompt also branches the story significantly
shoot_or_explore = ('You have been planning a trip out to the desert for a while;\n'
f'however, you\'re not sure whether you want to go {Color.red}Shooting{Color.end}\n'
f'or simply {Color.red}Explore{Color.end} the area. Which do you prefer?')
result = action_prompt(shoot_or_explore, 'Shooting', 'Explore')
# Pass character attributes over to main game
if result == 'shooting' or result == 's':
character['ability'] = 'marksman'
# Populate inventory
character['inventory']['rifle'] = {'ammo': 15}
# Never actually needed in your inventory
# character['inventory']['target'] = 1
character['inventory']['ammo box'] = {'ammo': 185}
character['inventory']['tannerite'] = 3
character['inventory']['snack'] = 3
print(f'You add your {Color.yellow}rifle{Color.end}, {Color.yellow}ammo box{Color.end}, '
f'a {Color.yellow}target{Color.end}, three {Color.yellow}tannerite{Color.end}, and '
f'some {Color.yellow}snacks{Color.end} to your inventory and head out to the desert.')
clear(True)
shooting_plot()
elif result == 'explore' or result == 'e':
character['ability'] = 'scoutsman'
# Populate inventory
character['inventory']['pistol'] = {'ammo': 7}
character['inventory']['compass'] = 1
character['inventory']['binoculars'] = 1
character['inventory']['satellite phone'] = 1
print(f'You add your {Color.yellow}pistol{Color.end}, {Color.yellow}compass{Color.end}, '
f'{Color.yellow}binoculars{Color.end}, and {Color.yellow}satellite phone{Color.end} '
'to your inventory and head out to the desert.')
clear(True)
explore_plot()
if __name__ == '__main__':
main()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment