Extra life added, fixed sounds to use the new functions for volume control Other various improvements.
This commit is contained in:
		 Submodule libstormgames updated: 80fe2caff3...68e72f5d81
									
								
							
							
								
								
									
										
											BIN
										
									
								
								sounds/extra_life.ogg
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										
											BIN
										
									
								
								sounds/extra_life.ogg
									 (Stored with Git LFS)
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| @@ -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]) | ||||||
|   | |||||||
| @@ -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) | ||||||
|          |          | ||||||
|   | |||||||
							
								
								
									
										38
									
								
								src/level.py
									
									
									
									
									
								
							
							
						
						
									
										38
									
								
								src/level.py
									
									
									
									
									
								
							| @@ -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']) | ||||||
|   | |||||||
| @@ -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( | ||||||
|   | |||||||
| @@ -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: | ||||||
|   | |||||||
| @@ -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 | ||||||
|   | |||||||
| @@ -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() | ||||||
|   | |||||||
		Reference in New Issue
	
	Block a user