init
This commit is contained in:
		
						commit
						53728db742
					
				
					 9 changed files with 755 additions and 0 deletions
				
			
		
							
								
								
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										3
									
								
								.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							|  | @ -0,0 +1,3 @@ | |||
| __pycache__/ | ||||
| save.pickle | ||||
| venv/ | ||||
							
								
								
									
										117
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										117
									
								
								README.md
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,117 @@ | |||
| # Scoundrel | ||||
| 
 | ||||
| This is a terminal port of the rogue-lite card game Scoundrel. I got really into Balatro for a week | ||||
| and immediately started wanting to code a game. I stumbled upon a youtube video for a rogue-lite | ||||
| card game you can play with just a deck of cards and decided to port it to the terminal as a preliminary exercise before I begin to write a new game (which may never happen, I have 5 other pressing projects that take priority over game development). | ||||
| 
 | ||||
| # Installation | ||||
| 
 | ||||
| You must have python installed on your machine... | ||||
| 
 | ||||
| 1. clone the repository | ||||
| 2. cd into the repository and create a virtual environment `python3 -m venv venv` | ||||
| 3. activate the virtual environment `source venv/bin/activate` | ||||
| 4. install requirements `pip install -r requirements.txt` | ||||
| 5. run the game `python3 main.py` | ||||
| 
 | ||||
| # Rules  | ||||
| ### 1. INTRODUCTION: | ||||
| 
 | ||||
| Welcome to Scoundrel! The solo rogue-lite dungeon crawler card game! | ||||
| This is the unneccessary terminal port of the game by Dominic DiTaranto. | ||||
| If you enjoy this port, check out my website for other cool stuff | ||||
| https://www.domdit.com | ||||
| 
 | ||||
| Table Of Contents: | ||||
| 1. INTRODUCTION | ||||
| 3. CONTROLS | ||||
| 2. RULES | ||||
| 
 | ||||
| ### 2. CONTROLS | ||||
| 
 | ||||
| Arrow Keys    -  Select a Card | ||||
| 
 | ||||
| Enter Button  -  Engage with a Card | ||||
| 
 | ||||
| s             -  Skip a Room | ||||
| 
 | ||||
| b             -  Fight Barehanded | ||||
| 
 | ||||
| p             -  Pause/Unpause | ||||
| 
 | ||||
| h             -  See High Scores (from start menu) | ||||
| 
 | ||||
| u             -  Change User Name (from start menu) | ||||
| 
 | ||||
| Esc           -  Exit Game | ||||
| 
 | ||||
| ?             -  Takes you to this help page. | ||||
| 
 | ||||
| ### 3.a RULES - Setup and Rules | ||||
| 
 | ||||
| You are a dungeon explorer making your way through a series of rooms. | ||||
| A room is made up of 4 cards. | ||||
| 
 | ||||
| In each room you may encounter: | ||||
| - Equippable Weapons (Diamond Suit Cards) | ||||
| - Health Potions (Heart Suit Cards) | ||||
| - Enemies (Spade and Club Suit Cards) | ||||
| - Merchants (Joker Cards) [Not Yet Implemented] | ||||
| 
 | ||||
| Your goal is to traverse the rooms until the deck runs out of cards. | ||||
| 
 | ||||
| ### 3.b RULES - Selecting a Card | ||||
| 
 | ||||
| When you enter a room, select a card by navigating to it with the arrow keys | ||||
| and pressing Enter. | ||||
| 
 | ||||
| If the card is a weapon, you equip that weapon. Each weapon does as much damage | ||||
| as its value. Picking up a weapon will automatically discard your currently equipped weapon. | ||||
| 
 | ||||
| If the card is a health potion, you will gain life equal to the value of the card. | ||||
| Your life may not exceed 20.  | ||||
| 
 | ||||
| You can skip a room by pressing s, but you cannot skip two rooms in a row. the room  | ||||
| that you skip gets moved to the bottom of the deck to be traversed through later. | ||||
| 
 | ||||
| ### 3.c RULES - Combat | ||||
| 
 | ||||
| If you select an enemy, you enter the combat phase. | ||||
| 
 | ||||
| If you do not have a weapon equipped you will take damage to your life points | ||||
| equal to the value of the enemy card. This is called barehanded combat. | ||||
| 
 | ||||
| If you have an equipped weapon and the value of the weapon is greater than the enemy value | ||||
| You do not take any damage to your health. Your weapon becomes damaged and you can only  | ||||
| attack enemies with a value lower than the previous enemy's value. This is the weapons damage rating. | ||||
| 
 | ||||
| If you attack an enemy with a weapon that has a value lower than the enemy's value, you | ||||
| take damage equal to the enemy value - the weapon value. Example: if your weapon is a 5  | ||||
| and the enemy is an 8, you will take 3 damage. | ||||
| 
 | ||||
| ### 3.d RULES - Combat Continued | ||||
| 
 | ||||
| If you attack an enemy with a value higher than the weapon's damage rating, | ||||
| you take all of that damage as if it were barehanded. You will lose life equal  | ||||
| to the value of the enemy. | ||||
| 
 | ||||
| You should only attack enemies with a weapon that has a damage rating above or equal | ||||
| to the enemy's value. There will be situations where you have no choice but to take | ||||
| the barehanded damage combat. This is part of the strategy element. | ||||
| 
 | ||||
| Your Weapon's damage rating is shown in the brackets next to the weapon. | ||||
| 
 | ||||
| When a room only has 1 card left, you move on to the next room. That card follows you | ||||
| into the next room | ||||
| 
 | ||||
| ### 3.e RULES - Scoring | ||||
| 
 | ||||
| If you die, the remaining monster's values are subtracted from your score.  | ||||
| The negative value is your score. | ||||
| 
 | ||||
| If you beat the whole dungeon, your score is your positive life points. | ||||
| 
 | ||||
| 
 | ||||
| # Future Updates | ||||
| - Endless mode: reshuffle the deck and keep playing | ||||
| - Jokers as Merchants: Add jokers back to the deck and have them either buff you or hurt you based on RNG. | ||||
							
								
								
									
										41
									
								
								assets/ascii_art.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								assets/ascii_art.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,41 @@ | |||
| START_SCREEN = ''' | ||||
|    ▄████████  ▄████████  ▄██████▄  ███    █▄  ███▄▄▄▄   ████████▄     ▄████████    ▄████████  ▄█        | ||||
|   ███    ███ ███    ███ ███    ███ ███    ███ ███▀▀▀██▄ ███   ▀███   ███    ███   ███    ███ ███        | ||||
|   ███    █▀  ███    █▀  ███    ███ ███    ███ ███   ███ ███    ███   ███    ███   ███    █▀  ███        | ||||
|   ███        ███        ███    ███ ███    ███ ███   ███ ███    ███  ▄███▄▄▄▄██▀  ▄███▄▄▄     ███        | ||||
| ▀███████████ ███        ███    ███ ███    ███ ███   ███ ███    ███ ▀▀███▀▀▀▀▀   ▀▀███▀▀▀     ███        | ||||
|          ███ ███    █▄  ███    ███ ███    ███ ███   ███ ███    ███ ▀███████████   ███    █▄  ███        | ||||
|    ▄█    ███ ███    ███ ███    ███ ███    ███ ███   ███ ███   ▄███   ███    ███   ███    ███ ███▌    ▄  | ||||
|  ▄████████▀  ████████▀   ▀██████▀  ████████▀   ▀█   █▀  ████████▀    ███    ███   ██████████ █████▄▄██  | ||||
|                                                                      ███    ███              ▀          | ||||
|     Port by Dominic Ditaranto (https://www.domdit.com)                                          v1.0.0 | ||||
|     Press ? for Rules and Controls | Press Enter to Start | ||||
|     Press u to Set Your Username! (Currently: {username}) | ||||
|     Press h to See High Score List! | ||||
| 
 | ||||
|                                          | ||||
|      | ||||
| ''' | ||||
| 
 | ||||
| GAME_OVER = ''' | ||||
|                 SCORE: {score} | ||||
|    ▄██████▄     ▄████████   ▄▄▄▄███▄▄▄▄      ▄████████  | ||||
|   ███    ███   ███    ███ ▄██▀▀▀███▀▀▀██▄   ███    ███  | ||||
|   ███    █▀    ███    ███ ███   ███   ███   ███    █▀   | ||||
|  ▄███          ███    ███ ███   ███   ███  ▄███▄▄▄      | ||||
| ▀▀███ ████▄  ▀███████████ ███   ███   ███ ▀▀███▀▀▀      | ||||
|   ███    ███   ███    ███ ███   ███   ███   ███    █▄   | ||||
|   ███    ███   ███    ███ ███   ███   ███   ███    ███  | ||||
|   ████████▀    ███    █▀   ▀█   ███   █▀    ██████████  | ||||
|                                                         | ||||
|  ▄██████▄   ▄█    █▄     ▄████████    ▄████████         | ||||
| ███    ███ ███    ███   ███    ███   ███    ███         | ||||
| ███    ███ ███    ███   ███    █▀    ███    ███         | ||||
| ███    ███ ███    ███  ▄███▄▄▄      ▄███▄▄▄▄██▀         | ||||
| ███    ███ ███    ███ ▀▀███▀▀▀     ▀▀███▀▀▀▀▀           | ||||
| ███    ███ ███    ███   ███    █▄  ▀███████████         | ||||
| ███    ███ ███    ███   ███    ███   ███    ███         | ||||
|  ▀██████▀   ▀██████▀    ██████████   ███    ███         | ||||
|                                      ███    ███         | ||||
| Press Enter To Return To Start Page | Press Esc to Quit | ||||
| ''' | ||||
							
								
								
									
										116
									
								
								assets/help.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										116
									
								
								assets/help.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,116 @@ | |||
| PAGE_ONE = ''' | ||||
| 1. INTRODUCTION: | ||||
| 
 | ||||
| Welcome to Scoundrel! The solo rogue-lite dungeon crawler card game! | ||||
| This is the unneccessary terminal port of the game by Dominic DiTaranto. | ||||
| If you enjoy this port, check out my website for other cool stuff | ||||
| https://www.domdit.com | ||||
| 
 | ||||
| Table Of Contents: | ||||
| 1. INTRODUCTION | ||||
| 3. CONTROLS | ||||
| 2. RULES | ||||
| 
 | ||||
| Use the up and down arrow keys to scroll through the help pages.. | ||||
| 
 | ||||
|                                 1 | ||||
| ''' | ||||
| 
 | ||||
| PAGE_TWO = ''' | ||||
| 2. CONTROLS | ||||
| 
 | ||||
| Arrow Keys      Select a Card | ||||
| Enter Button    Engage with a Card | ||||
| s               Skip a Room | ||||
| b               Fight Barehanded | ||||
| p               Pause/Unpause | ||||
| h               See High Scores (from start menu) | ||||
| u               Change User Name (from start menu) | ||||
| Esc             Exit Game | ||||
| ?               Takes you to this help page. | ||||
|                                 2 | ||||
| ''' | ||||
| 
 | ||||
| 
 | ||||
| PAGE_THREE = ''' | ||||
| 3.a RULES - Setup and Rules | ||||
| 
 | ||||
| You are a dungeon explorer making your way through a series of rooms. | ||||
| A room is made up of 4 cards. | ||||
| 
 | ||||
| In each room you may encounter: | ||||
| - Equippable Weapons (Diamond Suit Cards) | ||||
| - Health Potions (Heart Suit Cards) | ||||
| - Enemies (Spade and Club Suit Cards) | ||||
| - Merchants (Joker Cards) [Not Yet Implemented] | ||||
| 
 | ||||
| Your goal is to traverse the rooms until the deck runs out of cards. | ||||
|                                 3 | ||||
| ''' | ||||
| 
 | ||||
| PAGE_FOUR = ''' | ||||
| 3.b RULES - Selecting a Card | ||||
| 
 | ||||
| When you enter a room, select a card by navigating to it with the arrow keys | ||||
| and pressing Enter. | ||||
| 
 | ||||
| If the card is a weapon, you equip that weapon. Each weapon does as much damage | ||||
| as its value. Picking up a weapon will automatically discard your currently equipped weapon. | ||||
| 
 | ||||
| If the card is a health potion, you will gain life equal to the value of the card. | ||||
| Your life may not exceed 20.  | ||||
| 
 | ||||
| You can skip a room by pressing s, but you cannot skip two rooms in a row. the room  | ||||
| that you skip gets moved to the bottom of the deck to be traversed through later. | ||||
|                                 4 | ||||
| ''' | ||||
| 
 | ||||
| PAGE_FIVE = ''' | ||||
| 3.c RULES - Combat | ||||
| 
 | ||||
| If you select an enemy, you enter the combat phase. | ||||
| 
 | ||||
| If you do not have a weapon equipped you will take damage to your life points | ||||
| equal to the value of the enemy card. This is called barehanded combat. | ||||
| 
 | ||||
| If you have an equipped weapon and the value of the weapon is greater than the enemy value | ||||
| You do not take any damage to your health. Your weapon becomes damaged and you can only  | ||||
| attack enemies with a value lower than the previous enemy's value. This is the weapons damage rating. | ||||
| 
 | ||||
| If you attack an enemy with a weapon that has a value lower than the enemy's value, you | ||||
| take damage equal to the enemy value - the weapon value. Example: if your weapon is a 5  | ||||
| and the enemy is an 8, you will take 3 damage. | ||||
|                                 5 | ||||
| ''' | ||||
| 
 | ||||
| PAGE_SIX = ''' | ||||
| 3.d RULES - Combat Continued | ||||
| 
 | ||||
| If you attack an enemy with a value higher than the weapon's damage rating, | ||||
| you take all of that damage as if it were barehanded. You will lose life equal  | ||||
| to the value of the enemy. | ||||
| 
 | ||||
| You should only attack enemies with a weapon that has a damage rating above or equal | ||||
| to the enemy's value. There will be situations where you have no choice but to take | ||||
| the barehanded damage combat. This is part of the strategy element. | ||||
| 
 | ||||
| Your Weapon's damage rating is shown in the brackets next to the weapon. | ||||
| 
 | ||||
| When a room only has 1 card left, you move on to the next room. That card follows you | ||||
| into the next room | ||||
|                                 6 | ||||
| ''' | ||||
| 
 | ||||
| PAGE_SEVEN = ''' | ||||
| 3.e RULES - Scoring | ||||
| 
 | ||||
| If you die, the remaining monster's values are subtracted from your score.  | ||||
| The negative value is your score. | ||||
| 
 | ||||
| If you beat the whole dungeon, your score is your positive life points. | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
|                                 7 | ||||
| ''' | ||||
							
								
								
									
										38
									
								
								card.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								card.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,38 @@ | |||
| from colorama import Fore, Back, Style | ||||
| 
 | ||||
| 
 | ||||
| class Card: | ||||
|     def __init__(self, value, suit): | ||||
|         self.value = value | ||||
|         self.suit = suit | ||||
|         self.selected = False | ||||
| 
 | ||||
|         self.suit_map = { | ||||
|             0: '♠', | ||||
|             1: '❤', | ||||
|             2: '♣', | ||||
|             3: '♦' | ||||
|         } | ||||
| 
 | ||||
|         self.value_map = { | ||||
|             1: 'A', | ||||
|             11: 'J', | ||||
|             12: 'Q', | ||||
|             13: 'K' | ||||
|         } | ||||
| 
 | ||||
|     def display_card(self): | ||||
|         return f"{Back.WHITE}{Fore.RED if self.suit in [1,3] else Fore.BLUE}{self.value_map.get(self.value, self.value)}{self.suit_map[self.suit]} {Style.RESET_ALL}" | ||||
| 
 | ||||
|     def __repr__(self): | ||||
|         s = Back.WHITE if not self.selected else Back.GREEN | ||||
|         return f"{s}{Fore.RED if self.suit in [1,3] else Fore.BLUE}{self.value_map.get(self.value, self.value)}{self.suit_map[self.suit]} {Style.RESET_ALL}" | ||||
| 
 | ||||
|     def help_text(self, weapon=None): | ||||
|         if self.suit in [0, 2]: | ||||
|             return f'Attack {self.display_card()} {"barehanded?" if not weapon else "with {}? [b]".format(weapon)}' | ||||
|         elif self.suit == 1: | ||||
|             return f"Use {self.display_card()} as a health potion?" | ||||
|         elif self.suit == 3: | ||||
|             return f"Equip {self.display_card()} as a weapon?" | ||||
|      | ||||
							
								
								
									
										29
									
								
								deck.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								deck.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,29 @@ | |||
| import random | ||||
| from collections import deque | ||||
| 
 | ||||
| from card import Card | ||||
| 
 | ||||
| 
 | ||||
| class Deck: | ||||
|     def __init__(self): | ||||
|         self.deck = deque() | ||||
| 
 | ||||
|     def generate_deck(self): | ||||
|         for suit in range(4): | ||||
|             if suit in [0, 2]: | ||||
|                 for i in range(1, 14): | ||||
|                     c = Card(i, suit) | ||||
|                     self.deck.append(c) | ||||
|             elif suit in [1, 3]: | ||||
|                 for i in range(2, 11): | ||||
|                     c = Card(i, suit) | ||||
|                     self.deck.append(c) | ||||
| 
 | ||||
| 
 | ||||
|     def shuffle(self): | ||||
|         random.shuffle(self.deck) | ||||
| 
 | ||||
|     def draw(self): | ||||
|         if len(self.deck) > 0: | ||||
|             return self.deck.popleft() | ||||
| 
 | ||||
							
								
								
									
										240
									
								
								game.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										240
									
								
								game.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,240 @@ | |||
| import os | ||||
| import pickle | ||||
| import sys | ||||
| import time | ||||
| 
 | ||||
| from pynput.keyboard import Key, Listener, KeyCode | ||||
| 
 | ||||
| from assets.help import PAGE_ONE, PAGE_TWO, PAGE_THREE, PAGE_FOUR, PAGE_FIVE, PAGE_SIX, PAGE_SEVEN | ||||
| from deck import Deck | ||||
| 
 | ||||
| 
 | ||||
| class Game: | ||||
|     def __init__(self, username='Wayne Skyler'): | ||||
|         self.username = username | ||||
| 
 | ||||
|         self.deck = Deck() | ||||
|         self.current_room_cards = [] | ||||
|         self.selected_card = 0 | ||||
|         self.graveyard = [] | ||||
| 
 | ||||
|         self.paused = False | ||||
| 
 | ||||
|         self.room = 1 | ||||
|         self.block_skip = False | ||||
| 
 | ||||
|         self.weapon = None | ||||
|         self.defeated = [] | ||||
| 
 | ||||
|         self.max_health = 20 | ||||
|         self.health = 20 | ||||
| 
 | ||||
|         self.history = [] | ||||
| 
 | ||||
|         self.help_screens = [PAGE_ONE, PAGE_TWO, PAGE_THREE, PAGE_FOUR, PAGE_FIVE, PAGE_SIX, PAGE_SEVEN] | ||||
|         self.current_help_screen = 0 | ||||
|         self.on_help_screen = False | ||||
|         self.from_screen = None | ||||
| 
 | ||||
| 
 | ||||
|         self.score = len(self.deck.deck) * -1 | ||||
|         self.save_file = 'save.pickle' | ||||
| 
 | ||||
|     @property | ||||
|     def current_card(self): | ||||
|         return self.current_room_cards[self.selected_card] | ||||
| 
 | ||||
|     def initialize(self): | ||||
|         self.deck = Deck() | ||||
|         self.deck.generate_deck() | ||||
|         self.deck.shuffle() | ||||
|          | ||||
|         while len(self.current_room_cards) < 4 and len(self.deck.deck) > 0: | ||||
|             self.current_room_cards.append(self.deck.draw()) | ||||
| 
 | ||||
|         self.current_room_cards[0].selected = True | ||||
| 
 | ||||
|     def display(self): | ||||
|         os.system('clear') | ||||
|         print(f"Current Room: {self.room} | Health: {self.health}/{self.max_health} | ? for Rules & Controls") | ||||
|         print('\t'.join([str(x) for x in self.current_room_cards])) | ||||
|         print('\n') | ||||
|         print('\n') | ||||
|         print(f"Weapon: {self.weapon if self.weapon else 'None'} {'[{}]'.format(' '.join([str(x) for x in self.defeated]) if self.graveyard else None)}") | ||||
|         print(f"{self.current_card.help_text(self.weapon)} [Enter]") | ||||
| 
 | ||||
|     def flash_message(self, msg): | ||||
|         for i in reversed(range(3)): | ||||
|             os.system('clear') | ||||
|             print(msg) | ||||
|             print(f'\n\tWait {str(i+1)} Seconds...') | ||||
|             time.sleep(1) | ||||
| 
 | ||||
|     def toggle_pause(self): | ||||
|         self.paused = True if not self.paused else False | ||||
| 
 | ||||
|     def input(self): | ||||
| 
 | ||||
|         def on_press(key): | ||||
|             self.history.append(key) | ||||
| 
 | ||||
|             if self.paused and key != KeyCode.from_char('p'): | ||||
|                 return False | ||||
| 
 | ||||
|             if key == Key.right: | ||||
|                 self.change_selected_card() | ||||
|             elif key == Key.left: | ||||
|                 self.change_selected_card(False) | ||||
|             elif key == Key.enter: | ||||
|                 if self.current_card.suit in [0, 2]: # Interact with selected card | ||||
|                     self.attack() | ||||
|                 elif self.current_card.suit == 1: | ||||
|                     self.health_potion() | ||||
|                 elif self.current_card.suit == 3: | ||||
|                     self.equip_weapon() | ||||
|             elif key == KeyCode.from_char('s'): # Skip Room | ||||
|                 self.skip_room() | ||||
|             elif key == KeyCode.from_char('b'): # Attack Barehanded | ||||
|                 weapon_copy = self.weapon | ||||
|                 self.weapon = None | ||||
|                 self.attack() | ||||
|                 self.weapon = weapon_copy | ||||
|             elif key == KeyCode.from_char('p'): | ||||
|                 self.toggle_pause() | ||||
|             elif key == Key.esc: # Quit The Game | ||||
|                 self.store_high_score() | ||||
|                 sys.exit() | ||||
|             if key == KeyCode.from_char('?'): | ||||
|                 self.on_help_screen = True if not self.on_help_screen else False | ||||
| 
 | ||||
|             if key == Key.up: | ||||
|                 if self.current_help_screen != 0: | ||||
|                     self.current_help_screen -= 1 | ||||
|                     self.help_screen() | ||||
|             if key == Key.down: | ||||
|                 if self.current_help_screen < len(self.help_screens) - 1: | ||||
|                     self.current_help_screen += 1 | ||||
|                     self.help_screen() | ||||
| 
 | ||||
|             return False | ||||
| 
 | ||||
|         with Listener(on_press=on_press) as listener: | ||||
|             listener.join() | ||||
| 
 | ||||
|     def help_screen(self): | ||||
|         os.system('clear') | ||||
|         print(self.help_screens[self.current_help_screen]) | ||||
| 
 | ||||
|     def change_selected_card(self, right=True): | ||||
|         self.current_card.selected = False | ||||
|         if right: | ||||
|             if self.selected_card != len(self.current_room_cards) - 1: | ||||
|                 self.selected_card += 1 | ||||
|         else: | ||||
|             if self.selected_card > 0: | ||||
|                 self.selected_card -= 1 | ||||
|         self.current_card.selected = True | ||||
| 
 | ||||
|     def attack(self): | ||||
|         if self.current_card.suit not in [0, 2]: | ||||
|             self.flash_message('\n\n\n\tSelected card is not an enemy!') | ||||
|             return | ||||
| 
 | ||||
|         if not self.weapon: | ||||
|             self.health -= self.current_card.value | ||||
|              | ||||
|             if self.health > 0: | ||||
|                 self.send_selected_to_grave() | ||||
|         else: | ||||
|             if self.defeated and self.defeated[-1].value < self.current_card.value: | ||||
|                 self.health -= self.current_card.value | ||||
|                 self.flash_message('\n\n\n\tYou should not have done that! \n\tYour weapon was not strong enough; causing you to take all of the damage!' ) | ||||
|                 self.send_selected_to_grave() | ||||
|                 return | ||||
|             if self.weapon.value < self.current_card.value: | ||||
|                 damage = self.current_card.value - self.weapon.value | ||||
|                 self.health -= damage | ||||
|                 if self.health <= 0: | ||||
|                     pass | ||||
|             self.defeated.append(self.current_card) | ||||
|             self.send_selected_to_grave() | ||||
|      | ||||
|     def send_selected_to_grave(self): | ||||
|         self.graveyard.append(self.current_room_cards.pop(self.selected_card)) | ||||
|         self.check_win() | ||||
|         self.selected_card = 0 | ||||
|         if len(self.current_room_cards) == 1: | ||||
|             self.advance_room() | ||||
|         if len(self.current_room_cards) > 0: | ||||
|             self.current_card.selected = True | ||||
|         self.deselect_defeated() | ||||
| 
 | ||||
|     def health_potion(self): | ||||
|         self.health += self.current_card.value | ||||
|         if self.health > 20: | ||||
|             self.health = 20 | ||||
|         self.send_selected_to_grave() | ||||
| 
 | ||||
|     def equip_weapon(self): | ||||
|         self.defeated = [] | ||||
|         self.weapon = self.current_card | ||||
|         self.current_card.selected = False | ||||
|         self.send_selected_to_grave() | ||||
| 
 | ||||
|     def deselect_defeated(self): | ||||
|         for i in self.defeated: | ||||
|             i.selected = False | ||||
| 
 | ||||
|     def advance_room(self): | ||||
|         self.block_skip = False | ||||
|         self.room += 1 | ||||
|          | ||||
|         # TODO: This can be simplified with initialize room func | ||||
|         while len(self.current_room_cards) < 4: | ||||
|             self.current_room_cards.append(self.deck.draw()) | ||||
|         self.current_room_cards[0].selected = True | ||||
| 
 | ||||
|     def skip_room(self): | ||||
|         if self.block_skip: | ||||
|             self.flash_message('\n\n\n\tYou cannot run away!') | ||||
|         else: | ||||
|             for card in self.current_room_cards: | ||||
|                 card.selected = False | ||||
|                 self.deck.deck.append(card) | ||||
|             self.current_room_cards = [] | ||||
|             self.advance_room() | ||||
|             self.block_skip = True | ||||
|             self.flash_message('\n\n\n\tRun Away, Coward!! 🤡') | ||||
| 
 | ||||
|     def cleanup(self): | ||||
|         self.current_room_cards = [x for x in self.current_room_cards if x is not None] | ||||
| 
 | ||||
|     def store_high_score(self): | ||||
|         self.calculate_score() | ||||
|         with open(self.save_file, 'rb') as f: | ||||
|             save_data = pickle.load(f) | ||||
|             save_data['high_scores'].append((self.username, self.score)) | ||||
|             sorted_high_scores = sorted(save_data['high_scores'], key=lambda x: x[1], reverse=True)[:9] | ||||
|             save_data['high_scores'] = sorted_high_scores | ||||
| 
 | ||||
|         with open(self.save_file, 'wb') as f: | ||||
|             pickle.dump(save_data, f) | ||||
| 
 | ||||
|     def calculate_score(self): | ||||
|         self.score = 0 | ||||
|         for card in self.current_room_cards + list(self.deck.deck): | ||||
|             if card.suit in [0, 2]: | ||||
|                 self.score -= card.value | ||||
|          | ||||
|         if self.score == 0: | ||||
|             self.score += self.health | ||||
|             for card in self.current_room_cards + list(self.deck.deck): | ||||
|                 if card.suit == 1: | ||||
|                     self.score += card.value | ||||
| 
 | ||||
|     def check_win(self): | ||||
|         if len(self.deck.deck) <= 0 and len(self.current_room_cards) <= 0: | ||||
|             self.calculate_score() | ||||
|             self.store_high_score() | ||||
|             return True | ||||
| 
 | ||||
							
								
								
									
										163
									
								
								main.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										163
									
								
								main.py
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,163 @@ | |||
| import os | ||||
| import pickle | ||||
| import sys | ||||
| import termios | ||||
| 
 | ||||
| from game import Game | ||||
| from assets.ascii_art import START_SCREEN, GAME_OVER | ||||
| from assets.help import PAGE_ONE, PAGE_TWO, PAGE_THREE, PAGE_FOUR, PAGE_FIVE, PAGE_SIX, PAGE_SEVEN | ||||
| 
 | ||||
| from pynput.keyboard import Key, Listener, KeyCode | ||||
| 
 | ||||
| 
 | ||||
| class Main: | ||||
|     def __init__(self): | ||||
|         self.screen_mode = True | ||||
|         self.game = None | ||||
|         self.username = 'Wayne Skyler' | ||||
| 
 | ||||
|         self.save_file = 'save.pickle' | ||||
|         self.save_data = None | ||||
| 
 | ||||
|         self.help_screens = [PAGE_ONE, PAGE_TWO, PAGE_THREE, PAGE_FOUR, PAGE_FIVE, PAGE_SIX, PAGE_SEVEN] | ||||
|         self.current_help_screen = 0 | ||||
|         self.on_help_screen = False | ||||
|         self.from_screen = None | ||||
| 
 | ||||
|         if not os.path.isfile(self.save_file): | ||||
| 
 | ||||
|             with open(self.save_file, 'wb') as f: | ||||
|                 save_data = { | ||||
|                     'username': self.username, | ||||
|                     'high_scores': [] | ||||
|                 } | ||||
| 
 | ||||
|                 pickle.dump(save_data, f) | ||||
| 
 | ||||
|         else: | ||||
|             with open(self.save_file, 'rb') as f: | ||||
|                 self.save_data = pickle.load(f) | ||||
|                 self.username = self.save_data['username'] | ||||
| 
 | ||||
|     def main(self): | ||||
|         self.screens() | ||||
| 
 | ||||
|     def screens(self, mode=None): | ||||
|         while self.screen_mode: | ||||
|             if self.game and mode != 'win': | ||||
|                 if self.game.health <= 0: | ||||
|                     os.system('clear') | ||||
|                     self.game.store_high_score() | ||||
|                     print(GAME_OVER.format(score=self.game.score)) | ||||
|                     self.input(mode='game_over') | ||||
|             else: | ||||
|                 os.system('clear') | ||||
|                 if mode == 'win': | ||||
|                     self.game.health = 0 | ||||
|                     self.game.flash_message(f'\n\n\n\twin. Congratulashon. {self.game.score}') | ||||
|                     self.game = None | ||||
|                     self.screens(mode=None) | ||||
|                 else:  | ||||
|                     print(START_SCREEN.format(username=self.username)) | ||||
|                     self.input(mode='start') | ||||
| 
 | ||||
|     def gameplay(self): | ||||
|         self.game = Game(username=self.username) | ||||
|         self.game.initialize() | ||||
|         while self.game.health > 0: | ||||
|             if not self.game.paused and not self.game.on_help_screen: | ||||
|                 self.game.cleanup() | ||||
|                 if self.game.check_win(): | ||||
|                     self.screen_mode = True | ||||
|                     self.screens(mode='win') | ||||
|                 if None in self.game.current_room_cards: | ||||
|                     breakpoint() | ||||
|                     self.game = None | ||||
|                 self.game.display() | ||||
|                 self.game.input() | ||||
|             else: | ||||
|                 if self.game.paused: | ||||
|                     self.pause_game() | ||||
|                     self.game.input() | ||||
|                 elif self.game.on_help_screen: | ||||
|                     self.game.help_screen() | ||||
|                     self.game.input() | ||||
| 
 | ||||
|         self.screen_mode = True | ||||
|         self.screens() | ||||
| 
 | ||||
|     def pause_game(self): | ||||
|         os.system('clear') | ||||
|         print('\n\n\t PAUSED') | ||||
|         print('\t Press p to unpause...') | ||||
| 
 | ||||
|     def high_scores(self): | ||||
|         with open(self.save_file, 'rb') as f: | ||||
|             save_data = pickle.load(f) | ||||
| 
 | ||||
|         os.system('clear') | ||||
|         print('\t\tHIGH SCORES\n') | ||||
|         for score in save_data['high_scores']: | ||||
|             print(f"\t{score[0]}\t{score[1]}") | ||||
| 
 | ||||
|         print('\n\tPress Enter to Return to Start Screen \n') | ||||
| 
 | ||||
|         self.input('game_over') | ||||
| 
 | ||||
|     def help_screen(self): | ||||
|         os.system('clear') | ||||
|         print(self.help_screens[self.current_help_screen]) | ||||
| 
 | ||||
|     def input(self, mode='start'): | ||||
|         def on_press(key): | ||||
|             termios.tcflush(sys.stdin, termios.TCIOFLUSH) | ||||
|             if key == Key.enter: | ||||
|                 if mode == 'start': | ||||
|                     self.screen_mode = False | ||||
|                     self.gameplay() | ||||
|                 if mode == 'game_over': | ||||
|                     self.game = None | ||||
|                     self.screen_mode = True | ||||
|                     self.screens() | ||||
|             if key == Key.esc: | ||||
|                 sys.exit() | ||||
|             if key == KeyCode.from_char('h'): | ||||
|                 self.high_scores() | ||||
|             if key == KeyCode.from_char('u'): | ||||
|                 self.username = input('Input Your Username: ') | ||||
|                 with open(self.save_file, 'rb') as f: | ||||
|                     self.save_data = pickle.load(f) | ||||
| 
 | ||||
|                 self.save_data['username'] = self.username | ||||
| 
 | ||||
|                 with open(self.save_file, 'wb') as f: | ||||
|                     pickle.dump(self.save_data, f) | ||||
| 
 | ||||
|                 self.screens() | ||||
|             if key == KeyCode.from_char('?'): | ||||
|                 if mode != 'game_help': | ||||
|                     self.on_help_screen = True if not self.on_help_screen else False | ||||
|                     if self.on_help_screen: | ||||
|                         self.help_screen() | ||||
|                     else: | ||||
|                         self.screens() | ||||
|                 elif mode == 'game_help': | ||||
|                     self.game.on_help_screen = True if not self.game.on_help_screen else False | ||||
| 
 | ||||
|             if key == Key.up: | ||||
|                 if self.current_help_screen != 0: | ||||
|                     self.current_help_screen -= 1 | ||||
|                     self.help_screen() | ||||
|             if key == Key.down: | ||||
|                 if self.current_help_screen < len(self.help_screens) - 1: | ||||
|                     self.current_help_screen += 1 | ||||
|                     self.help_screen() | ||||
| 
 | ||||
| 
 | ||||
|         with Listener(on_press=on_press) as listener: | ||||
|             listener.join() | ||||
| 
 | ||||
| 
 | ||||
| if __name__ == '__main__': | ||||
|     main = Main() | ||||
|     main.main() | ||||
							
								
								
									
										8
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								requirements.txt
									
									
									
									
									
										Normal file
									
								
							|  | @ -0,0 +1,8 @@ | |||
| colorama==0.4.6 | ||||
| evdev==1.9.1 | ||||
| keyboard==0.13.5 | ||||
| pynput==1.8.0 | ||||
| PyRect==0.2.0 | ||||
| python-xlib==0.33 | ||||
| six==1.17.0 | ||||
| wheel==0.45.1 | ||||
		Loading…
	
		Reference in a new issue