├── .gitignore ├── __pycache__ ├── objects.cpython-37.pyc └── functions.cpython-37.pyc ├── CONTRIBUTING.md ├── ROADMAP.md ├── asciiart.txt ├── rpg.py ├── LICENSE ├── README.md ├── objects.py └── functions.py /.gitignore: -------------------------------------------------------------------------------- 1 | 2 | *.pyc 3 | __pycache__/functions.cpython-37.pyc 4 | -------------------------------------------------------------------------------- /__pycache__/objects.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kartikcho/Pitchblack-RPG/HEAD/__pycache__/objects.cpython-37.pyc -------------------------------------------------------------------------------- /__pycache__/functions.cpython-37.pyc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/kartikcho/Pitchblack-RPG/HEAD/__pycache__/functions.cpython-37.pyc -------------------------------------------------------------------------------- /CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | ## Contributing 4 | 5 | * Check the issues tab to work on fixes 6 | * For content updates, work on a seperate branch 7 | * If you find a bug while reviewing the code, please report the issue with suitable labels. 8 | * Read the roadmap [here](ROADMAP.md) to work on or know about future planned updates. 9 | 10 | 11 | ### Create pull requests so I can review and add to master. 12 | -------------------------------------------------------------------------------- /ROADMAP.md: -------------------------------------------------------------------------------- 1 | # Currently planned updates 2 | 3 | * A UI Menu on startup 4 | 5 | * A merchant appearing in between battles to buy new weapons or replenish meds. 6 | 7 | * Leaderboard system to save older players on an external file. 8 | 9 | * More variation to scenarios. 10 | 11 | * More procedurally generated content. 12 | 13 | ### If you have any ideas, please open an issue with an enhancement label. 14 | -------------------------------------------------------------------------------- /asciiart.txt: -------------------------------------------------------------------------------- 1 | _____ _____ _ _ _ _ _ _ 2 | / ____| | __ (_) | | | | | | | | | 3 | | | __ ___ _____ | |__) || |_ ___| |__ | |__ | | __ _ ___| | __ 4 | | | / _` \ \ / / _ \ | ___/ | __/ __| '_ \| '_ \| |/ _` |/ __| |/ / 5 | | |___| (_| |\ V / __/ | | | | || (__| | | | |_) | | (_| | (__| < 6 | \_____\__,_| \_/ \___| |_| |_|\__\___|_| |_|_.__/|_|\__,_|\___|_|\_\ 7 | -------------------------------------------------------------------------------- /rpg.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Thu Jun 6 11:42:48 2019 4 | 5 | @author: Kartik 6 | """ 7 | #importing libraries 8 | import os as os 9 | 10 | os.system('cls') #clears screen before displaying ASCII art 11 | 12 | import objects as obj 13 | import functions as func 14 | 15 | os.system('cls') #clears screen again before initiating battle sequence 16 | 17 | 18 | playAgain = "Y" #to run the first instance 19 | 20 | 21 | while playAgain == 'Y' or playAgain == 'y': 22 | func.intro() 23 | func.instance.score = 0 24 | obj.Player.gold = 0 25 | func.instance() 26 | func.store() 27 | func.end() 28 | break 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Kartik Choudhary 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 |

3 | 4 | ### Sent by the king himself, you must clear out the dungeon bothering the townsfolk, or die trying... 5 | 6 | # Features 7 | * Procedurally generated content, making every game different than the one before (and sometimes wacky as heck too). 8 | * Strategic resource managment to survive longer. 9 | * Enemies level up too as you go deeper so you stop spamming attack and actually think in fights. 10 | * Next-gen economy simulator, involves trading and saving money. 11 | * More content on the way by our team of skilled hardworking devs working day and night to give you the best experience of your life. 12 | 13 | ## DnD style gameplay 14 | An interactive text adventure with a dice rolling to determine enemy's stats. 15 | Also involves multiple stats for the player like HP, AP and itembonuses. 16 | 17 | ## Requirements 18 | 19 | * Python3 20 | 21 | ## To run program: 22 | Run rpg.py to start the game. 23 | 24 | ```bash 25 | cd [[location of the file "rpg.py"]] 26 | python rpg.py 27 | ``` 28 | 29 | ### To see how you can contribute, see [here](CONTRIBUTING.md). 30 | 31 | ### To know about future planned updates, see [here](ROADMAP.md). 32 | 33 | -------------------------------------------------------------------------------- /objects.py: -------------------------------------------------------------------------------- 1 | #importing libraries 2 | import random 3 | import re 4 | import functions as func 5 | 6 | #displays Cave Pitchblack ascii art 7 | f = open('asciiart.txt', 'r') 8 | data = f.read() # reads asciiart.txt 9 | f.close() 10 | print (data) 11 | 12 | #randomly generates player and enemy stats 13 | class Settings: 14 | PLAYER_ATTACK = random.randint(5, 10) 15 | MAX_ENEMY_STRENGTH = 15 16 | MIN_ENEMY_STRENGTH = 5 17 | ENEMIES = ['behemoth', 'goblin', 'hellstep', 'orc', 'golem', 'zombie', 'undead mermaid','brinebrute', 'soulcreep','murkmutant'] 18 | ENEMY_PREFIX = ['big', 'giant', 'ugly', 'fat', 'angry', 'vicious', 'murderous', 'vile', 'fat', 'dyslexic', 'terribly anorexic'] 19 | ENEMY_WEAPON = ['sword', 'warhammer', 'charming smile', 'axe', 'hammer', 'club', 'giant bone', 'mace', 'dagger', 'terrible case of body odor', 'shiny gauntlet from a dead city soldier'] 20 | PLAYER_WEAPON = {"sword": 2, "axe": 3, "bow": 2} 21 | PLAYER_HEAL = 5 22 | 23 | #randomly generates enemy type 24 | class Enemy: 25 | name = ( 26 | random.choice(Settings.ENEMY_PREFIX) 27 | + " " 28 | + random.choice(Settings.ENEMIES) 29 | ) 30 | weapon = random.choice(Settings.ENEMY_WEAPON) 31 | attack = random.randint(Settings.MIN_ENEMY_STRENGTH, Settings.MAX_ENEMY_STRENGTH) 32 | health = random.randint(10, 40) 33 | 34 | #uses player input to create a character 35 | class Player: 36 | 37 | 38 | name = input('What is your name traveller? ') 39 | 40 | number = re.compile(r'[1,2,3]+') #characters allowed 41 | weapon_choice = input('Choose your weapon: 1. Sword, 2.Battle Axe, 3. Recurve Bow ') #while loop that executes till the character entered is valid 42 | 43 | while not number.match(weapon_choice): #compares the character entered 44 | print ("Please enter a valid response") #executes if character entered is invalid 45 | weapon_choice = input('Choose your weapon: 1. Sword, 2. Battle Axe, 3. Recurve Bow ') 46 | if weapon_choice == '1': 47 | weapon_bonus = 2 48 | weapon = "sword" 49 | elif weapon_choice == "2": 50 | weapon_bonus = 3 51 | weapon = "axe" 52 | elif weapon_choice == "3": 53 | weapon_bonus = 2 54 | weapon = "bow" 55 | else: 56 | print("You did not choose a weapon, restarting game...") 57 | 58 | attack = Settings.PLAYER_ATTACK + weapon_bonus 59 | health = 100 60 | gold = 0 61 | -------------------------------------------------------------------------------- /functions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Created on Mon Jun 17 13:42:48 2019 4 | 5 | @author: Kartik 6 | """ 7 | #importing libraries 8 | import random 9 | import time 10 | import sys 11 | import re 12 | import objects as obj 13 | 14 | 15 | #text output speed 16 | def say(text): 17 | for char in text: 18 | print(char, end="") 19 | time.sleep(0.04) 20 | print("") 21 | time.sleep(0.3) 22 | 23 | #uses all the stats to start story 24 | def intro(): 25 | say(f"Greetings, {obj.Player.name}.") 26 | if obj.Player.weapon == "sword": 27 | say("You have a sword in your hand. Fast and swift.") 28 | elif obj.Player.weapon == "axe": 29 | say("You have an axe by your side. Slow, but strong.") 30 | elif obj.Player.weapon == "bow": 31 | say("You picked the bow. Silent but deadly.") 32 | say("You were sent to clear out Cave Pitchblack by the kingdom.") 33 | say("You reach your destination, the cave dark as the night as you enter.") 34 | 35 | #procedurally generates a battle instance 36 | def instance(): 37 | say(f"You have encountered a {obj.Enemy.name} wielding a {obj.Enemy.weapon}.") 38 | say(f"Its attack is {obj.Enemy.attack} and it has {obj.Enemy.health} health.") 39 | say( 40 | f"Your attack would do {obj.Player.attack} damage. You have {obj.Player.health} health left." 41 | ) 42 | say(f"You choose to:") 43 | say(f"1. Attack, 2. Run") 44 | 45 | number = re.compile(r'[1,2]+') #characters allowed 46 | choice = input() #while loop that executes till the entered character entered is valid 47 | 48 | while not number.match(choice): #compares the character entered 49 | print ("Please enter a valid response") 50 | choice = input() 51 | if choice == '1': 52 | battle() 53 | elif choice == '2': 54 | end() 55 | 56 | #simulates the fight 57 | def battle(): 58 | while obj.Enemy.health > 0: 59 | say(f"You attack with your {obj.Player.weapon}.") 60 | obj.Enemy.health = obj.Enemy.health - obj.Player.attack 61 | if obj.Enemy.health <= 0: 62 | say(f"Your attack did {obj.Player.attack} damage. The {obj.Enemy.name} falls.") 63 | victory() 64 | 65 | say( 66 | f"Your attack did {obj.Player.attack} damage. The {obj.Enemy.name} now has {obj.Enemy.health} health." 67 | ) 68 | 69 | obj.Player.health = obj.Player.health - obj.Enemy.attack 70 | say( 71 | f"The {obj.Enemy.name} attacks back. You take {obj.Enemy.attack} damage. Your health is now {obj.Player.health}." 72 | ) 73 | if obj.Player.health > 0 and obj.Enemy.health <= 0: 74 | victory() 75 | if obj.Player.health <= 0: 76 | sys.exit("You died. Game Over.") 77 | 78 | #generates new enemy strength and stats to increase difficulty and levels up character after fight 79 | def difficulty(): 80 | instance.score = instance.score + 1 81 | obj.Player.attack = obj.Player.attack + random.randint(1, 3) * instance.score 82 | obj.Player.health = obj.Player.health + random.randint(1, 3) * instance.score 83 | obj.Enemy.name = ( 84 | random.choice(obj.Settings.ENEMY_PREFIX) 85 | + " " 86 | + random.choice(obj.Settings.ENEMIES) 87 | ) 88 | obj.Enemy.weapon = random.choice(obj.Settings.ENEMY_WEAPON) 89 | obj.Enemy.attack = obj.Enemy.attack + random.randint(1, 3) * instance.score 90 | obj.Enemy.health = random.randint(1, 20) + random.randint(1, 3) * instance.score 91 | obj.Player.gold = obj.Player.gold + random.randint(5,15) * instance.score 92 | 93 | #generates victory and the loot after battle 94 | def victory(): 95 | say(f"You defeated the {obj.Enemy.name}.") 96 | difficulty() 97 | say(f"You find some gold while looting and now have {obj.Player.gold} coins.") 98 | say(f"Your attack goes up to {obj.Player.attack} and your health to {obj.Player.health}") 99 | if obj.Settings.PLAYER_HEAL > 0: 100 | say(f"You have {obj.Settings.PLAYER_HEAL} meds left. Use them wisely.") 101 | say("Would you like to use one? Y/N") 102 | 103 | value = re.compile(r'[y,Y,n,N]+') #characters allowed 104 | choice = input() 105 | while not value.match(choice): #while loop that executes till the entered character entered is valid 106 | print ("Please enter a valid response") 107 | choice = input() 108 | if choice == 'Y' or choice == 'y': 109 | obj.Player.health = obj.Player.health + (random.randint(5, 10) * instance.score) 110 | obj.Settings.PLAYER_HEAL = obj.Settings.PLAYER_HEAL - 1 111 | say(f"You mend your wounds and your health goes up to {obj.Player.health}. You have {obj.Settings.PLAYER_HEAL} meds left.") 112 | else: 113 | say(f"You still have {obj.Settings.PLAYER_HEAL} meds left.") 114 | 115 | if obj.Settings.PLAYER_HEAL == 0: 116 | say("You are out of meds. Good luck.") 117 | say("Go deeper into the cave? Y/N") 118 | value = re.compile(r'[y,Y,n,N]+') 119 | choice = input() 120 | 121 | while not value.match(choice): 122 | print ("Please enter a valid response") 123 | choice = input() 124 | 125 | if choice == 'Y' or choice == 'y': 126 | say('You march forward...') 127 | num = random.randint(1, 10) 128 | if num < 5: 129 | store() 130 | instance() 131 | else: 132 | instance() 133 | if choice == "N" or choice == "n": 134 | end() 135 | 136 | #end game if chosen to quit 137 | def end(): 138 | say("You decide to be smart and retreat...") 139 | say(f"You defeated {instance.score} monsters.") 140 | say(f"Thank you for playing.") 141 | say(f"Made by Kartik Choudhary") #Star me on Github lol (kartikch918) 142 | sys.exit("Exiting game ...") 143 | 144 | #merchant uses Player.gold 145 | def store(): 146 | say(f"You see a strange merchant waiting in the shadows with blue flames in his lamp.") 147 | say(f"\nYou approach him.\n") 148 | say(f"\n'What are you buying stranger?'\n") 149 | say(f"You check your pockets and see you have {obj.Player.gold} coins left.") 150 | print ("1. Flame Sword [5 DMG] --> 100 gold coins") 151 | print ("2. Enchanted Dagger [5 DMG] --> 40 gold coins") 152 | print ("3. Stealth Bow [5 DMG] --> 70 gold coins") 153 | print ("4. Meds [1 MED] --> 20 gold coins") 154 | print ("5. back") 155 | print (" ") 156 | 157 | merch_number = re.compile(r'[1,2,3,4,5]+') #characters allowed 158 | store.choice = input() #while loop that executes till the entered character entered is valid 159 | 160 | 161 | while not merch_number.match(store.choice): #compares the character entered 162 | print ("Please enter a valid response") 163 | store.choice = input() 164 | 165 | if store.choice == '1': 166 | if obj.Player.gold < 0: 167 | say("Not enough gold") 168 | instance() 169 | else: 170 | obj.Player.weapon_bonus = 6 171 | obj.Player.gold = obj.Player.gold-100 172 | say("Purchased successfully") 173 | say("The merchant grins as you leave and go forward.") 174 | instance() 175 | 176 | elif store.choice == '2': 177 | if obj.Player.gold < 0: 178 | say("Not enough gold") 179 | instance() 180 | else: 181 | obj.Player.weapon_bonus = 4 182 | obj.Player.gold = obj.Player.gold-40 183 | say("Purchased successfully") 184 | say("The merchant grins as you leave and go forward.") 185 | instance() 186 | 187 | elif store.choice == '3': 188 | if obj.Player.gold < 0: 189 | say("Not enough gold") 190 | instance() 191 | else: 192 | obj.Player.weapon_bonus = 5 193 | obj.Player.gold = obj.Player.gold-70 194 | say("Purchased successfully") 195 | say("The merchant grins as you leave and go forward.") 196 | instance() 197 | 198 | elif store.choice == '4': 199 | if obj.Player.gold < 0: 200 | say("Not enough gold") 201 | instance() 202 | else: 203 | obj.Settings.PLAYER_HEAL = obj.Settings.PLAYER_HEAL + 1 204 | obj.Player.gold = obj.Player.gold-20 205 | say("Purchased successfully") 206 | say("The merchant grins as you leave and go forward.") 207 | instance() 208 | elif store.choice == '5': 209 | say("\"You will come again stranger\", he exclaims") 210 | instance() 211 | 212 | --------------------------------------------------------------------------------