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