├── .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 |
--------------------------------------------------------------------------------