Stats tracking updated. Work on skull storms. Enemy death sound added for goblins. Various updates and fixes.
This commit is contained in:
131
wicked_quest.py
131
wicked_quest.py
@@ -9,22 +9,42 @@ from src.player import Player
|
||||
|
||||
class WickedQuest:
|
||||
def __init__(self):
|
||||
"""Initialize game and load sounds."""
|
||||
self.sounds = initialize_gui("Wicked Quest")
|
||||
self.currentLevel = None
|
||||
self.lastThrowTime = 0
|
||||
self.throwDelay = 250
|
||||
self.player = None # Will be initialized when first level loads
|
||||
|
||||
def load_level(self, levelNumber):
|
||||
"""Load a level from its JSON file."""
|
||||
levelFile = f"levels/{levelNumber}.json"
|
||||
try:
|
||||
with open(levelFile, 'r') as f:
|
||||
levelData = json.load(f)
|
||||
self.currentLevel = Level(levelData, self.sounds)
|
||||
speak(f"Level {levelNumber} loaded")
|
||||
|
||||
# Create player if this is the first level
|
||||
if self.player is None:
|
||||
self.player = Player(levelData["player_start"]["x"], levelData["player_start"]["y"], self.sounds)
|
||||
else:
|
||||
# Just update player position for new level
|
||||
self.player.xPos = levelData["player_start"]["x"]
|
||||
self.player.yPos = levelData["player_start"]["y"]
|
||||
|
||||
# Pass existing player to new level
|
||||
self.currentLevel = Level(levelData, self.sounds, self.player)
|
||||
|
||||
# Announce level details
|
||||
levelIntro = f"Level {levelData['level_id']}, {levelData['name']}. {levelData['description']}"
|
||||
messagebox(levelIntro)
|
||||
|
||||
return True
|
||||
except FileNotFoundError:
|
||||
speak("Level not found")
|
||||
return False
|
||||
return True
|
||||
|
||||
def handle_input(self):
|
||||
"""Process keyboard input for player actions."""
|
||||
keys = pygame.key.get_pressed()
|
||||
player = self.currentLevel.player
|
||||
currentTime = pygame.time.get_ticks()
|
||||
@@ -45,17 +65,20 @@ class WickedQuest:
|
||||
player.xPos += currentSpeed
|
||||
player.facingRight = True
|
||||
|
||||
# Status queries
|
||||
if keys[pygame.K_c]:
|
||||
speak(f"{player.get_coins()} coins")
|
||||
|
||||
if keys[pygame.K_h]:
|
||||
speak(f"{player.get_health()} HP")
|
||||
|
||||
if keys[pygame.K_l]:
|
||||
speak(f"{player.get_lives()} lives")
|
||||
|
||||
if keys[pygame.K_f]: # Throw projectile
|
||||
self.currentLevel.throw_projectile()
|
||||
if keys[pygame.K_j]: # Check jack o'lanterns
|
||||
speak(f"{player.get_jack_o_lanterns()} jack o'lanterns")
|
||||
if keys[pygame.K_f]:
|
||||
currentTime = pygame.time.get_ticks()
|
||||
if currentTime - self.lastThrowTime >= self.throwDelay:
|
||||
self.currentLevel.throw_projectile()
|
||||
self.lastThrowTime = currentTime
|
||||
|
||||
# Handle attack with either CTRL key
|
||||
if (keys[pygame.K_LCTRL] or keys[pygame.K_RCTRL]) and player.start_attack(currentTime):
|
||||
@@ -81,45 +104,103 @@ class WickedQuest:
|
||||
# Reset step distance tracking after landing
|
||||
player.distanceSinceLastStep = 0
|
||||
|
||||
def display_level_stats(self, timeTaken):
|
||||
"""Display level completion statistics."""
|
||||
# Convert time from milliseconds to minutes:seconds
|
||||
minutes = timeTaken // 60000
|
||||
seconds = (timeTaken % 60000) // 1000
|
||||
|
||||
# Update time in stats
|
||||
self.currentLevel.player.stats.update_stat('Total time', timeTaken, levelOnly=True)
|
||||
|
||||
report = [f"Level {self.currentLevel.levelId} Complete!"]
|
||||
report.append(f"Time taken: {minutes} minutes and {seconds} seconds")
|
||||
|
||||
# Add all level stats
|
||||
for key in self.currentLevel.player.stats.level:
|
||||
if key != 'Total time': # Skip time since we already displayed it
|
||||
report.append(f"{key}: {self.currentLevel.player.stats.get_level_stat(key)}")
|
||||
|
||||
pygame.mixer.stop()
|
||||
display_text(report)
|
||||
self.currentLevel.player.stats.reset_level()
|
||||
|
||||
def display_game_over(self, timeTaken):
|
||||
"""Display game over screen with statistics."""
|
||||
minutes = timeTaken // 60000
|
||||
seconds = (timeTaken % 60000) // 1000
|
||||
|
||||
report = ["Game Over!"]
|
||||
report.append(f"Time taken: {minutes} minutes and {seconds} seconds")
|
||||
|
||||
# Add all total stats
|
||||
for key in self.currentLevel.player.stats.total:
|
||||
if key not in ['Total time', 'levelsCompleted']: # Skip these
|
||||
report.append(f"Total {key}: {self.currentLevel.player.stats.get_total_stat(key)}")
|
||||
|
||||
display_text(report)
|
||||
|
||||
def game_loop(self):
|
||||
"""Main game loop handling updates and state changes."""
|
||||
clock = pygame.time.Clock()
|
||||
|
||||
while self.currentLevel.player.get_health() > 0 and self.currentLevel.player.get_lives() > 0:
|
||||
startTime = pygame.time.get_ticks()
|
||||
currentLevelNum = 1
|
||||
|
||||
while True:
|
||||
currentTime = pygame.time.get_ticks()
|
||||
|
||||
|
||||
if check_for_exit():
|
||||
return
|
||||
|
||||
# Update player state (including power-ups)
|
||||
|
||||
# Update game state
|
||||
self.currentLevel.player.update(currentTime)
|
||||
|
||||
self.handle_input()
|
||||
|
||||
# Update audio positioning and handle collisions
|
||||
self.currentLevel.update_audio()
|
||||
self.currentLevel.handle_collisions()
|
||||
|
||||
# Handle combat interactions
|
||||
|
||||
# Handle combat and projectiles
|
||||
self.currentLevel.handle_combat(currentTime)
|
||||
|
||||
# Update projectiles
|
||||
self.currentLevel.handle_projectiles(currentTime)
|
||||
|
||||
|
||||
# Check for death first
|
||||
if self.currentLevel.player.get_health() <= 0:
|
||||
if self.currentLevel.player.get_lives() <= 0:
|
||||
# Game over
|
||||
pygame.mixer.stop()
|
||||
self.display_game_over(pygame.time.get_ticks() - startTime)
|
||||
return
|
||||
|
||||
# Handle collisions and check level completion
|
||||
if self.currentLevel.handle_collisions(): # Changed from elif to if
|
||||
# Level completed
|
||||
self.display_level_stats(pygame.time.get_ticks() - startTime)
|
||||
|
||||
# Try to load next level
|
||||
currentLevelNum += 1
|
||||
if self.load_level(currentLevelNum):
|
||||
# Reset timer for new level
|
||||
startTime = pygame.time.get_ticks()
|
||||
continue
|
||||
else:
|
||||
# No more levels - game complete!
|
||||
messagebox("Congratulations! You've completed all available levels!")
|
||||
self.display_game_over(pygame.time.get_ticks() - startTime)
|
||||
return
|
||||
|
||||
clock.tick(60) # 60 FPS
|
||||
|
||||
# Player died or ran out of lives
|
||||
speak("Game Over")
|
||||
|
||||
def run(self):
|
||||
"""Main game loop with menu system."""
|
||||
while True:
|
||||
choice = game_menu(self.sounds, "play", "instructions", "learn_sounds", "credits", "donate", "exit")
|
||||
|
||||
if choice == "exit":
|
||||
exit_game()
|
||||
elif choice == "play":
|
||||
self.player = None # Reset player for new game
|
||||
if self.load_level(1):
|
||||
self.game_loop()
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
game = WickedQuest()
|
||||
game.run()
|
||||
|
Reference in New Issue
Block a user