scoundrel/game.py
2025-05-13 13:55:07 -04:00

240 lines
8 KiB
Python

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