Graves basically rewritten.
This commit is contained in:
		| @@ -15,14 +15,14 @@ class CoffinObject(Object): | ||||
|         ) | ||||
|         self.sounds = sounds | ||||
|         self.level = level | ||||
|         self.is_broken = False | ||||
|         self.isBroken = False | ||||
|         self.dropped_item = None | ||||
|         self.specified_item = item | ||||
|          | ||||
|     def hit(self, player_pos): | ||||
|         """Handle being hit by the player's weapon""" | ||||
|         if not self.is_broken: | ||||
|             self.is_broken = True | ||||
|         if not self.isBroken: | ||||
|             self.isBroken = True | ||||
|             play_sound(self.sounds['coffin_shatter']) | ||||
|             self.level.player.stats.update_stat('Coffins broken', 1) | ||||
|              | ||||
|   | ||||
							
								
								
									
										34
									
								
								src/grave.py
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										34
									
								
								src/grave.py
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,34 @@ | ||||
| from libstormgames import * | ||||
| from src.object import Object | ||||
| from src.powerup import PowerUp | ||||
|  | ||||
|  | ||||
| class GraveObject(Object): | ||||
|     def __init__(self, x, y, sounds, item=None, zombieSpawnChance=0): | ||||
|         super().__init__( | ||||
|             x, y, "grave", | ||||
|             isStatic=True, | ||||
|             isCollectible=False, | ||||
|             isHazard=True, | ||||
|             zombieSpawnChance=zombieSpawnChance | ||||
|         ) | ||||
|         self.graveItem = item   | ||||
|         self.isCollected = False  # Renamed to match style of isHazard, isStatic etc | ||||
|         self.sounds = sounds | ||||
|  | ||||
|     def collect_grave_item(self, player): | ||||
|         """Handle collection of items from graves via ducking. | ||||
|      | ||||
|         Returns: | ||||
|             bool: True if item was collected, False if player should die | ||||
|         """ | ||||
|         # If grave has no item or item was already collected, player dies | ||||
|         if not self.graveItem or self.isCollected: | ||||
|             return False | ||||
|  | ||||
|         # Collect the item if player is ducking | ||||
|         if player.isDucking: | ||||
|             self.isCollected = True  # Mark as collected when collection succeeds | ||||
|             return True | ||||
|          | ||||
|         return False | ||||
							
								
								
									
										93
									
								
								src/level.py
									
									
									
									
									
								
							
							
						
						
									
										93
									
								
								src/level.py
									
									
									
									
									
								
							| @@ -4,6 +4,7 @@ from libstormgames import * | ||||
| from src.catapult import Catapult | ||||
| from src.coffin import CoffinObject | ||||
| from src.enemy import Enemy | ||||
| from src.grave import GraveObject | ||||
| from src.object import Object | ||||
| from src.player import Player | ||||
| from src.projectile import Projectile | ||||
| @@ -19,7 +20,9 @@ class Level: | ||||
|         self.bouncing_items = [] | ||||
|         self.projectiles = []  # Track active projectiles | ||||
|         self.player = player | ||||
|         self.edge_warning_channel = None | ||||
|         self.lastWarningTime = 0 | ||||
|         self.warningInterval = int(self.sounds['edge'].get_length() * 1000)  # Convert seconds to milliseconds | ||||
|  | ||||
|         self.weapon_hit_channel = None | ||||
|         self.leftBoundary = levelData["boundaries"]["left"] | ||||
|         self.rightBoundary = levelData["boundaries"]["right"] | ||||
| @@ -61,6 +64,16 @@ class Level: | ||||
|                     firingRange=obj.get("range", 20) | ||||
|                 ) | ||||
|                 self.objects.append(catapult) | ||||
|             # Check if this is a grave | ||||
|             elif obj.get("type") == "grave": | ||||
|                 grave = GraveObject( | ||||
|                     xPos[0], | ||||
|                     obj["y"], | ||||
|                     self.sounds, | ||||
|                     item=obj.get("item", None), | ||||
|                     zombieSpawnChance=obj.get("zombie_spawn_chance", 0) | ||||
|                 ) | ||||
|                 self.objects.append(grave) | ||||
|             # Check if this is a skull storm | ||||
|             elif obj.get("type") == "skull_storm": | ||||
|                 skullStorm = SkullStorm( | ||||
| @@ -105,11 +118,11 @@ class Level: | ||||
|                     isStatic=obj.get("static", True), | ||||
|                     isCollectible=obj.get("collectible", False), | ||||
|                     isHazard=obj.get("hazard", False), | ||||
|                     zombie_spawn_chance=obj.get("zombie_spawn_chance", 0) | ||||
|                     zombieSpawnChance=obj.get("zombieSpawnChance", 0) | ||||
|                 ) | ||||
|                 self.objects.append(gameObject) | ||||
|         enemyCount = len(self.enemies) | ||||
|         coffinCount = sum(1 for obj in self.objects if hasattr(obj, 'is_broken')) | ||||
|         coffinCount = sum(1 for obj in self.objects if hasattr(obj, 'isBroken')) | ||||
|         player.stats.update_stat('Enemies remaining', enemyCount) | ||||
|         player.stats.update_stat('Coffins remaining', coffinCount) | ||||
|  | ||||
| @@ -124,16 +137,16 @@ class Level: | ||||
|                  | ||||
|             # Check for potential zombie spawn from graves | ||||
|             if (obj.soundName == "grave" and  | ||||
|                 obj.zombie_spawn_chance > 0 and  | ||||
|                 not obj.has_spawned): | ||||
|                 obj.zombieSpawnChance > 0 and  | ||||
|                 not obj.hasSpawned): | ||||
|                  | ||||
|                 distance = abs(self.player.xPos - obj.xPos) | ||||
|                 if distance < 6:  # Within 6 tiles | ||||
|                     # Mark as checked before doing anything else to prevent multiple checks | ||||
|                     obj.has_spawned = True | ||||
|                     obj.hasSpawned = True | ||||
|                      | ||||
|                     roll = random.randint(1, 100) | ||||
|                     if roll <= obj.zombie_spawn_chance: | ||||
|                     if roll <= obj.zombieSpawnChance: | ||||
|                         zombie = Enemy( | ||||
|                             [obj.xPos, obj.xPos], | ||||
|                             obj.yPos, | ||||
| @@ -209,8 +222,8 @@ class Level: | ||||
|  | ||||
|             # Check for coffin hits | ||||
|             for obj in self.objects: | ||||
|                 if hasattr(obj, 'is_broken'):  # Check if it's a coffin without using isinstance | ||||
|                     if (not obj.is_broken and  | ||||
|                 if hasattr(obj, 'isBroken'):  # Check if it's a coffin without using isinstance | ||||
|                     if (not obj.isBroken and  | ||||
|                         obj.xPos >= attackRange[0] and  | ||||
|                         obj.xPos <= attackRange[1] and | ||||
|                         self.player.isJumping):  # Must be jumping to hit floating coffins | ||||
| @@ -229,16 +242,18 @@ class Level: | ||||
|         for obj in self.objects: | ||||
|             if not obj.isActive: | ||||
|                 continue | ||||
|          | ||||
|  | ||||
|             # Handle grave edge warnings | ||||
|             if obj.isHazard: | ||||
|                 distance = abs(self.player.xPos - obj.xPos) | ||||
|                 if distance <= 2 and not self.player.isJumping and not self.player.isInvincible: | ||||
|                     if self.edge_warning_channel is None or not self.edge_warning_channel.get_busy(): | ||||
|                         self.edge_warning_channel = play_sound(self.sounds['edge']) | ||||
|             else: | ||||
|                 if self.edge_warning_channel is not None and not self.edge_warning_channel.get_busy(): | ||||
|                     self.edge_warning_channel = None | ||||
|                 currentTime = pygame.time.get_ticks() | ||||
|                 if (distance <= 2 and not self.player.isJumping and not self.player.isInvincible  | ||||
|                         and currentTime - self.lastWarningTime >= self.warningInterval): | ||||
|                     if isinstance(obj, GraveObject) and obj.graveItem and not obj.isCollected: | ||||
|                         play_sound(self.sounds['_edge']) | ||||
|                     else: | ||||
|                         play_sound(self.sounds['edge']) | ||||
|                     self.lastWarningTime = currentTime | ||||
|  | ||||
|             if obj.is_in_range(self.player.xPos): | ||||
|                 if obj.isCollectible and self.player.isJumping: | ||||
| @@ -255,25 +270,41 @@ class Level: | ||||
|                                 # 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() | ||||
|                                         self.player.get_health() + 1, | ||||
|                                         self.player.get_max_health() | ||||
|                                     )) | ||||
|  | ||||
|                             if self.player._coins % 100 == 0: | ||||
|                                 # Extra life | ||||
|                                 self.player._coins = 0 | ||||
|                                 self.player._lives += 1 | ||||
|                                 play_sound(self.sounds['get_extra_life']) | ||||
|                                 if self.player._coins % 100 == 0: | ||||
|                                     # Extra life | ||||
|                                     self.player._coins = 0 | ||||
|                                     self.player._lives += 1 | ||||
|                                     play_sound(self.sounds['get_extra_life']) | ||||
|  | ||||
|                 elif obj.isHazard and not self.player.isJumping: | ||||
|                     if not self.player.isInvincible: | ||||
|                         play_sound(self.sounds[obj.soundName]) | ||||
|                         speak("You fell in an open grave! Now, it's yours!") | ||||
|                         self.player.set_health(0) | ||||
|                         return False | ||||
|                     else: | ||||
|                         # When invincible, treat it like a successful jump over the grave | ||||
|                         pass | ||||
|                     if isinstance(obj, GraveObject): | ||||
|                         can_collect = obj.collect_grave_item(self.player) | ||||
|      | ||||
|                         if can_collect: | ||||
|                             # Successfully collected item while ducking | ||||
|                             play_sound(self.sounds[f'get_{obj.graveItem}']) | ||||
|                             self.player.stats.update_stat('Items collected', 1) | ||||
|                             # Create PowerUp to handle the item effect | ||||
|                             item = PowerUp(obj.xPos, obj.yPos, obj.graveItem, self.sounds, 1) | ||||
|                             item.apply_effect(self.player) | ||||
|                             # Stop grave's current audio channel | ||||
|                             if obj.channel: | ||||
|                                 obj_stop(obj.channel) | ||||
|                             # Remove the grave | ||||
|                             obj.graveItem = None | ||||
|                             obj.channel = None | ||||
|                             obj.isActive = False  # Mark the grave as inactive after collection | ||||
|                             continue | ||||
|                         elif not self.player.isInvincible: | ||||
|                             # Kill player for normal graves or non-ducking collision | ||||
|                             play_sound(self.sounds[obj.soundName]) | ||||
|                             speak("You fell in an open grave! Now, it's yours!") | ||||
|                             self.player.set_health(0) | ||||
|                             return False | ||||
|  | ||||
|         # Handle boundaries | ||||
|         if self.player.xPos < self.leftBoundary: | ||||
|   | ||||
| @@ -1,7 +1,7 @@ | ||||
| from libstormgames import * | ||||
|  | ||||
| class Object: | ||||
|     def __init__(self, x, yPos, soundName, isStatic=True, isCollectible=False, isHazard=False, zombie_spawn_chance=0): | ||||
|     def __init__(self, x, yPos, soundName, isStatic=True, isCollectible=False, isHazard=False, zombieSpawnChance=0): | ||||
|         # x can be either a single position or a range [start, end] | ||||
|         self.xRange = [x, x] if isinstance(x, (int, float)) else x | ||||
|         self.yPos = yPos | ||||
| @@ -9,8 +9,8 @@ class Object: | ||||
|         self.isStatic = isStatic | ||||
|         self.isCollectible = isCollectible | ||||
|         self.isHazard = isHazard | ||||
|         self.zombie_spawn_chance = zombie_spawn_chance | ||||
|         self.has_spawned = False  # Track if this object has spawned a zombie | ||||
|         self.zombieSpawnChance = zombieSpawnChance | ||||
|         self.hasSpawned = False | ||||
|         self.channel = None  # For tracking the sound channel | ||||
|         self.isActive = True | ||||
|         # For collectibles in a range, track which positions have been collected | ||||
|   | ||||
| @@ -13,6 +13,7 @@ class Player: | ||||
|         self.moveSpeed = 0.05 | ||||
|         self.jumpDuration = 1000  # Jump duration in milliseconds | ||||
|         self.jumpStartTime = 0 | ||||
|         self.isDucking = False | ||||
|         self.isJumping = False | ||||
|         self.isRunning = False | ||||
|         self.runMultiplier = 1.5  # Same multiplier as jumping | ||||
| @@ -69,6 +70,20 @@ class Player: | ||||
|         return (self.distanceSinceLastStep >= self.get_step_distance() and  | ||||
|                 currentTime - self.lastStepTime >= self.get_step_interval()) | ||||
|  | ||||
|     def duck(self): | ||||
|         """Start ducking""" | ||||
|         if not self.isDucking and not self.isJumping:  # Can't duck while jumping | ||||
|             self.isDucking = True | ||||
|             play_sound(self.sounds['duck']) | ||||
|             return True | ||||
|         return False | ||||
|  | ||||
|     def stand(self): | ||||
|         """Stop ducking state and play sound""" | ||||
|         if self.isDucking: | ||||
|             self.isDucking = False | ||||
|             play_sound(self.sounds['stand']) | ||||
|  | ||||
|     def update(self, currentTime): | ||||
|         """Update player state""" | ||||
|         # Check if invincibility has expired | ||||
|   | ||||
		Reference in New Issue
	
	Block a user