Extra life added, fixed sounds to use the new functions for volume control Other various improvements.

This commit is contained in:
Storm Dragon
2025-02-04 07:12:12 -05:00
parent 4f7f5504d1
commit 883dafaac0
9 changed files with 61 additions and 34 deletions

BIN
sounds/extra_life.ogg (Stored with Git LFS) Normal file

Binary file not shown.

View File

@@ -37,9 +37,7 @@ class Pumpkin:
# Calculate volume and pan for splat sound based on final position # Calculate volume and pan for splat sound based on final position
volume, left, right = calculate_volume_and_pan(playerX, self.x) volume, left, right = calculate_volume_and_pan(playerX, self.x)
if volume > 0: # Only play if within audible range if volume > 0: # Only play if within audible range
channel = sounds["pumpkin_splat"].play() obj_play(sounds, 'pumpkin_splat', playerX, self.x, loop=False)
if channel:
channel.set_volume(volume * left, volume * right)
def check_collision(self, player): def check_collision(self, player):
"""Check if pumpkin hits player""" """Check if pumpkin hits player"""
@@ -78,7 +76,7 @@ class Catapult(Object):
self.lastFireTime = currentTime self.lastFireTime = currentTime
# Play launch sound # Play launch sound
self.sounds['catapult_launch'].play() play_sound(self.sounds['catapult_launch'])
# Set up pending pumpkin # Set up pending pumpkin
isHigh = random.choice([True, False]) isHigh = random.choice([True, False])

View File

@@ -21,7 +21,7 @@ class CoffinObject(Object):
"""Handle being hit by the player's weapon""" """Handle being hit by the player's weapon"""
if not self.is_broken: if not self.is_broken:
self.is_broken = True self.is_broken = True
self.sounds['coffin_shatter'].play() play_sound(self.sounds['coffin_shatter'])
self.level.player.stats.update_stat('Coffins broken', 1) self.level.player.stats.update_stat('Coffins broken', 1)
self.level.player.stats.update_stat('Coffins remaining', -1) self.level.player.stats.update_stat('Coffins remaining', -1)

View File

@@ -181,20 +181,23 @@ class Level:
# Check for item collection # Check for item collection
if abs(item.xPos - self.player.xPos) < 1 and self.player.isJumping: if abs(item.xPos - self.player.xPos) < 1 and self.player.isJumping:
self.sounds[f'get_{item.soundName}'].play() play_sound(self.sounds[f'get_{item.soundName}'])
item.apply_effect(self.player) item.apply_effect(self.player)
item.isActive = False item.isActive = False
self.bouncing_items.remove(item) self.bouncing_items.remove(item)
def handle_combat(self, currentTime): def handle_combat(self, currentTime):
"""Handle combat interactions between player and enemies""" """Handle combat interactions between player and enemies"""
attackRange = self.player.get_attack_range(currentTime) # Only get attack range if attack is active
if attackRange: if self.player.currentWeapon and self.player.currentWeapon.is_attack_active(currentTime):
attackRange = self.player.currentWeapon.get_attack_range(self.player.xPos, self.player.facingRight)
# Check for enemy hits # Check for enemy hits
for enemy in self.enemies: for enemy in self.enemies:
if enemy.isActive and enemy.xPos >= attackRange[0] and enemy.xPos <= attackRange[1]: if enemy.isActive and enemy.xPos >= attackRange[0] and enemy.xPos <= attackRange[1]:
if self.weapon_hit_channel is None or not self.weapon_hit_channel.get_busy(): if self.weapon_hit_channel is None or not self.weapon_hit_channel.get_busy():
self.weapon_hit_channel = self.sounds[self.player.currentWeapon.hitSound].play() self.weapon_hit_channel = self.sounds[self.player.currentWeapon.hitSound].play()
self.weapon_hit_channel = play_sound(self.sounds[self.player.currentWeapon.hitSound])
enemy.take_damage(self.player.currentWeapon.damage) enemy.take_damage(self.player.currentWeapon.damage)
else: else:
@@ -230,7 +233,7 @@ class Level:
distance = abs(self.player.xPos - obj.xPos) distance = abs(self.player.xPos - obj.xPos)
if distance <= 2 and not self.player.isJumping: if distance <= 2 and not self.player.isJumping:
if self.edge_warning_channel is None or not self.edge_warning_channel.get_busy(): if self.edge_warning_channel is None or not self.edge_warning_channel.get_busy():
self.edge_warning_channel = self.sounds['edge'].play() self.edge_warning_channel = play_sound(self.sounds['edge'])
else: else:
if self.edge_warning_channel is not None and not self.edge_warning_channel.get_busy(): if self.edge_warning_channel is not None and not self.edge_warning_channel.get_busy():
self.edge_warning_channel = None self.edge_warning_channel = None
@@ -239,16 +242,31 @@ class Level:
if obj.isCollectible and self.player.isJumping: if obj.isCollectible and self.player.isJumping:
currentPos = round(self.player.xPos) currentPos = round(self.player.xPos)
if currentPos not in obj.collectedPositions: if currentPos not in obj.collectedPositions:
self.sounds[f'get_{obj.soundName}'].play() play_sound(self.sounds[f'get_{obj.soundName}'])
obj.collect_at_position(currentPos) obj.collect_at_position(currentPos)
self.player.collectedItems.append(obj.soundName) self.player.collectedItems.append(obj.soundName)
self.player.stats.update_stat('Items collected', 1) self.player.stats.update_stat('Items collected', 1)
if obj.soundName == "coin": if obj.soundName == "coin":
self.player._coins += 1 self.player._coins += 1
self.player.stats.update_stat('Bone dust', 1) self.player.stats.update_stat('Bone dust', 1)
if self.player._coins % 5 == 0:
# Only heal if below max health
if self.player.get_health() < self.player.get_max_health():
self.player.set_health(min(
self.player.get_health() + 1,
self.player.get_max_health()
))
if self.player._coins % 100 == 0:
# Extra life
speak("Extra life")
self.player._coins = 0
self.player._lives += 1
play_sound(self.sounds['extra_life'])
elif obj.isHazard and not self.player.isJumping: elif obj.isHazard and not self.player.isJumping:
if not self.player.isInvincible: if not self.player.isInvincible:
self.sounds[obj.soundName].play() play_sound(self.sounds[obj.soundName])
speak("You fell in an open grave!") speak("You fell in an open grave!")
self.player.set_health(0) self.player.set_health(0)
return False return False
@@ -269,7 +287,7 @@ class Level:
if self.player.xPos >= obj.xPos: if self.player.xPos >= obj.xPos:
# Stop all current sounds and play end level sound # Stop all current sounds and play end level sound
pygame.mixer.stop() pygame.mixer.stop()
self.sounds["end_of_level"].play() play_sound(self.sounds['end_of_level'])
return True return True
return False return False
@@ -289,9 +307,7 @@ class Level:
# Calculate volume and pan for splat sound based on final position # Calculate volume and pan for splat sound based on final position
volume, left, right = calculate_volume_and_pan(self.player.xPos, proj.x) volume, left, right = calculate_volume_and_pan(self.player.xPos, proj.x)
if volume > 0: # Only play if within audible range if volume > 0: # Only play if within audible range
channel = self.sounds["pumpkin_splat"].play() obj_play(self.sounds, 'pumpkin_splat', self.player.xPos, proj.x, loop=False)
if channel:
channel.set_volume(volume * left, volume * right)
break break
def throw_projectile(self): def throw_projectile(self):
@@ -307,4 +323,4 @@ class Level:
proj_info['direction'] proj_info['direction']
)) ))
# Play throw sound # Play throw sound
self.sounds['throw_jack_o_lantern'].play() play_sound(self.sounds['throw_jack_o_lantern'])

View File

@@ -39,7 +39,7 @@ class Player:
# Power-up states # Power-up states
self.isInvincible = False self.isInvincible = False
self.invincibilityStartTime = 0 self.invincibilityStartTime = 0
self.invincibilityDuration = 5000 # 5 seconds of invincibility self.invincibilityDuration = 10000 # 10 seconds of invincibility
# Initialize starting weapon (rusty shovel) # Initialize starting weapon (rusty shovel)
self.add_weapon(Weapon( self.add_weapon(Weapon(

View File

@@ -44,10 +44,8 @@ class PowerUp(Object):
"""Apply the item's effect when collected""" """Apply the item's effect when collected"""
if self.item_type == 'hand_of_glory': if self.item_type == 'hand_of_glory':
player.start_invincibility() player.start_invincibility()
speak("Hand of Glory makes you invincible!")
elif self.item_type == 'jack_o_lantern': elif self.item_type == 'jack_o_lantern':
player.add_jack_o_lantern() player.add_jack_o_lantern()
speak("Gained a Jack-o'-lantern!")
# Stop movement sound when collected # Stop movement sound when collected
if self.channel: if self.channel:

View File

@@ -33,7 +33,7 @@ class SkullStorm(Object):
inRange = self.xRange[0] <= player.xPos <= self.xRange[1] inRange = self.xRange[0] <= player.xPos <= self.xRange[1]
if inRange and not self.playerInRange: if inRange and not self.playerInRange:
# Player just entered range - play the warning sound # Player just entered range - play the warning sound
self.sounds['skull_storm'].play() play_sound(self.sounds['skull_storm'])
self.playerInRange = True self.playerInRange = True
elif not inRange and self.playerInRange: # Only speak when actually leaving range elif not inRange and self.playerInRange: # Only speak when actually leaving range
# Player just left range # Player just left range
@@ -62,7 +62,7 @@ class SkullStorm(Object):
skull['x'], skull['x'],
self.yPos, self.yPos,
currentY, currentY,
existingChannel=skull['channel'] existing_channel=skull['channel']
) )
# Check if we should spawn a new skull # Check if we should spawn a new skull
@@ -100,10 +100,7 @@ class SkullStorm(Object):
channel = pygame.mixer.find_channel(True) # Find an available channel channel = pygame.mixer.find_channel(True) # Find an available channel
if channel: if channel:
soundObj = self.sounds['skull_lands'] soundObj = self.sounds['skull_lands']
channel.play(soundObj, 0) # Play once (0 = no loops) obj_play(self.sounds, 'skull_lands', player.xPos, skull['x'], loop=False)
# Apply positional audio
volume, left, right = calculate_volume_and_pan(player.xPos, skull['x'])
channel.set_volume(volume * left, volume * right)
# Check if player was hit # Check if player was hit
if abs(player.xPos - skull['x']) < 1: # Within 1 tile if abs(player.xPos - skull['x']) < 1: # Within 1 tile

View File

@@ -67,7 +67,7 @@ class WickedQuest:
# Status queries # Status queries
if keys[pygame.K_c]: if keys[pygame.K_c]:
speak(f"{player.get_coins()} coins") speak(f"{player.get_coins()} gbone dust")
if keys[pygame.K_h]: if keys[pygame.K_h]:
speak(f"{player.get_health()} HP") speak(f"{player.get_health()} HP")
if keys[pygame.K_l]: if keys[pygame.K_l]:
@@ -82,25 +82,25 @@ class WickedQuest:
# Handle attack with either CTRL key # Handle attack with either CTRL key
if (keys[pygame.K_LCTRL] or keys[pygame.K_RCTRL]) and player.start_attack(currentTime): if (keys[pygame.K_LCTRL] or keys[pygame.K_RCTRL]) and player.start_attack(currentTime):
self.sounds[player.currentWeapon.attackSound].play() play_sound(self.sounds[player.currentWeapon.attackSound])
# Play footstep sounds if moving and not jumping # Play footstep sounds if moving and not jumping
if movementDistance > 0 and not player.isJumping: if movementDistance > 0 and not player.isJumping:
player.distanceSinceLastStep += movementDistance player.distanceSinceLastStep += movementDistance
if player.distanceSinceLastStep >= player.stepDistance: if player.distanceSinceLastStep >= player.stepDistance:
self.sounds['footstep'].play() play_sound(self.sounds['footstep'])
player.distanceSinceLastStep = 0 player.distanceSinceLastStep = 0
# Handle jumping # Handle jumping
if keys[pygame.K_w] and not player.isJumping: if keys[pygame.K_w] and not player.isJumping:
player.isJumping = True player.isJumping = True
player.jumpStartTime = currentTime player.jumpStartTime = currentTime
self.sounds['jump'].play() play_sound(self.sounds['jump'])
# Check if jump should end # Check if jump should end
if player.isJumping and currentTime - player.jumpStartTime >= player.jumpDuration: if player.isJumping and currentTime - player.jumpStartTime >= player.jumpDuration:
player.isJumping = False player.isJumping = False
self.sounds['footstep'].play() play_sound(self.sounds['footstep'])
# Reset step distance tracking after landing # Reset step distance tracking after landing
player.distanceSinceLastStep = 0 player.distanceSinceLastStep = 0
@@ -149,9 +149,24 @@ class WickedQuest:
while True: while True:
currentTime = pygame.time.get_ticks() currentTime = pygame.time.get_ticks()
if check_for_exit(): # Game volume controls
return for event in pygame.event.get():
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE:
return
if event.key == pygame.K_PAGEUP:
adjust_master_volume(0.1)
elif event.key == pygame.K_PAGEDOWN:
adjust_master_volume(-0.1)
elif event.key == pygame.K_HOME:
adjust_bgm_volume(0.1)
elif event.key == pygame.K_END:
adjust_bgm_volume(-0.1)
elif event.key == pygame.K_INSERT:
adjust_sfx_volume(0.1)
elif event.key == pygame.K_DELETE:
adjust_sfx_volume(-0.1)
# Update game state # Update game state
self.currentLevel.player.update(currentTime) self.currentLevel.player.update(currentTime)
self.handle_input() self.handle_input()