Spiderweb obstacles added. Latest libstormgames module update. Level 4 created, needs adjustment, currently way too hard.
This commit is contained in:
		| @@ -41,6 +41,11 @@ class Enemy(Object): | ||||
|             self.damage = level.player.get_max_health()  # Instant death | ||||
|             self.health = 1  # Easy to kill | ||||
|             self.attackCooldown = 1500  # Slower attack rate | ||||
|         elif enemyType == "spider": | ||||
|             speedMultiplier = kwargs.get('speed_multiplier', 2.0) | ||||
|             self.movementSpeed *= speedMultiplier  # Spiders are faster | ||||
|             self.attackPattern = {'type': 'hunter'}  # Spiders actively hunt the player | ||||
|             self.turnThreshold = 3  # Spiders turn around quickly to chase player | ||||
|              | ||||
|     @property | ||||
|     def xPos(self): | ||||
|   | ||||
							
								
								
									
										161
									
								
								src/level.py
									
									
									
									
									
								
							
							
						
						
									
										161
									
								
								src/level.py
									
									
									
									
									
								
							| @@ -95,6 +95,27 @@ class Level: | ||||
|                     item=obj.get("item", "random")  # Get item type or default to random | ||||
|                 ) | ||||
|                 self.objects.append(coffin) | ||||
|             # Check if this is a spider web | ||||
|             elif obj.get("type") == "spider_web": | ||||
|                 # Check distance from graves | ||||
|                 isValidPosition = True | ||||
|                 for existingObj in self.objects: | ||||
|                     if (existingObj.soundName == "grave" and | ||||
|                         not hasattr(existingObj, 'graveItem')): | ||||
|                         distance = abs(obj["x"] - existingObj.xPos) | ||||
|                         if distance < 3: | ||||
|                             isValidPosition = False | ||||
|                             break | ||||
|  | ||||
|                 if isValidPosition: | ||||
|                     web = Object( | ||||
|                         obj["x"],  # Just pass the single x value | ||||
|                         obj["y"], | ||||
|                         "spiderweb", | ||||
|                         isStatic=True, | ||||
|                         isCollectible=False, | ||||
|                     ) | ||||
|                     self.objects.append(web) | ||||
|             # Check if this is an enemy | ||||
|             elif "enemy_type" in obj: | ||||
|                 enemy = Enemy( | ||||
| @@ -229,7 +250,21 @@ class Level: | ||||
|                      | ||||
|                         if obj.hit(self.player.xPos): | ||||
|                             self.bouncing_items.append(obj.dropped_item) | ||||
|                             #speak(f"{obj.dropped_item.soundName} falls out!") | ||||
|  | ||||
|     def spawn_spider(self, xPos, yPos): | ||||
|         """Spawn a spider at the given position""" | ||||
|         spider = Enemy( | ||||
|             [xPos - 5, xPos + 5],  # Give spider a patrol range | ||||
|             yPos, | ||||
|             "spider", | ||||
|             self.sounds, | ||||
|             self, | ||||
|             health=8, | ||||
|             damage=8, | ||||
|             attack_range=1, | ||||
|             speed_multiplier=2.0 | ||||
|         ) | ||||
|         self.enemies.append(spider) | ||||
|  | ||||
|     def handle_collisions(self): | ||||
|         """Handle all collision checks and return True if level is complete.""" | ||||
| @@ -243,7 +278,7 @@ class Level: | ||||
|                 continue | ||||
|  | ||||
|             # Handle grave edge warnings | ||||
|             if obj.isHazard: | ||||
|             if obj.isHazard and obj.soundName != "spiderweb":  # Explicitly exclude spiderwebs | ||||
|                 distance = abs(self.player.xPos - obj.xPos) | ||||
|                 currentTime = pygame.time.get_ticks() | ||||
|                 if (distance <= 2 and not self.player.isJumping and not self.player.isInvincible  | ||||
| @@ -254,56 +289,80 @@ class Level: | ||||
|                         play_sound(self.sounds['edge']) | ||||
|                     self.lastWarningTime = currentTime | ||||
|  | ||||
|             if obj.is_in_range(self.player.xPos): | ||||
|                 if obj.isCollectible and self.player.isJumping: | ||||
|                     currentPos = round(self.player.xPos) | ||||
|                     if currentPos not in obj.collectedPositions: | ||||
|                         play_sound(self.sounds[f'get_{obj.soundName}']) | ||||
|                         obj.collect_at_position(currentPos) | ||||
|                         self.player.collectedItems.append(obj.soundName) | ||||
|             if not obj.is_in_range(self.player.xPos): | ||||
|                 continue | ||||
|  | ||||
|             # Handle collectibles | ||||
|             if obj.isCollectible and self.player.isJumping: | ||||
|                 currentPos = round(self.player.xPos) | ||||
|                 if currentPos not in obj.collectedPositions: | ||||
|                     play_sound(self.sounds[f'get_{obj.soundName}']) | ||||
|                     obj.collect_at_position(currentPos) | ||||
|                     self.player.collectedItems.append(obj.soundName) | ||||
|                     self.player.stats.update_stat('Items collected', 1) | ||||
|                     if obj.soundName == "coin": | ||||
|                         self.player._coins += 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 | ||||
|                                 self.player._coins = 0 | ||||
|                                 self.player._lives += 1 | ||||
|                                 play_sound(self.sounds['get_extra_life']) | ||||
|                 continue | ||||
|  | ||||
|             # Handle spiderweb - this should trigger for both walking and jumping if not ducking | ||||
|             if obj.soundName == "spiderweb" and not self.player.isDucking: | ||||
|                 # Create and apply web effect | ||||
|                 webEffect = PowerUp( | ||||
|                     obj.xPos, | ||||
|                     obj.yPos, | ||||
|                     'spiderweb', | ||||
|                     self.sounds, | ||||
|                     0  # No direction needed since it's just for effect | ||||
|                 ) | ||||
|                 webEffect.level = self  # Pass level reference for spider spawning | ||||
|                 play_sound(self.sounds['hit_spiderweb']) | ||||
|                 webEffect.apply_effect(self.player) | ||||
|  | ||||
|                 # Deactivate web | ||||
|                 obj.isActive = False | ||||
|                 obj.channel = obj_stop(obj.channel) | ||||
|                 continue | ||||
|  | ||||
|             # Handle graves and other hazards | ||||
|             if obj.isHazard and not self.player.isJumping: | ||||
|                 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) | ||||
|                         if obj.soundName == "coin": | ||||
|                             self.player._coins += 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 | ||||
|                                     self.player._coins = 0 | ||||
|                                     self.player._lives += 1 | ||||
|                                     play_sound(self.sounds['get_extra_life']) | ||||
|  | ||||
|                 elif obj.isHazard and not self.player.isJumping: | ||||
|                     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 | ||||
|                         # 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: | ||||
|   | ||||
| @@ -86,6 +86,13 @@ class Player: | ||||
|  | ||||
|     def update(self, currentTime): | ||||
|         """Update player state""" | ||||
|         if hasattr(self, 'webPenaltyEndTime'): | ||||
|             if currentTime >= self.webPenaltyEndTime: | ||||
|                 self.moveSpeed *= 2  # Restore speed | ||||
|                 if self.currentWeapon: | ||||
|                     self.currentWeapon.attackDuration *= 0.5  # Restore attack speed | ||||
|                 del self.webPenaltyEndTime | ||||
|  | ||||
|         # Check if invincibility has expired | ||||
|         if self.isInvincible and currentTime - self.invincibilityStartTime >= self.invincibilityDuration: | ||||
|             self.isInvincible = False | ||||
|   | ||||
| @@ -57,6 +57,22 @@ class PowerUp(Object): | ||||
|             broomWeapon = Weapon.create_witch_broom() | ||||
|             player.add_weapon(broomWeapon) | ||||
|             player.equip_weapon(broomWeapon) | ||||
|         elif self.item_type == 'spiderweb': | ||||
|             # Bounce player back (happens even if invincible) | ||||
|             player.xPos -= 3 if player.xPos > self.xPos else -3 | ||||
|  | ||||
|             # Only apply debuffs if not invincible | ||||
|             if not player.isInvincible: | ||||
|                 # Half speed and double attack time for 15 seconds | ||||
|                 player.moveSpeed *= 0.5 | ||||
|                 if player.currentWeapon: | ||||
|                     player.currentWeapon.attackDuration *= 2 | ||||
|                 # Set timer for penalty removal | ||||
|                 player.webPenaltyEndTime = pygame.time.get_ticks() + 15000 | ||||
|  | ||||
|             # Tell level to spawn a spider | ||||
|             if hasattr(self, 'level'): | ||||
|                 self.level.spawn_spider(self.xPos, self.yPos) | ||||
|          | ||||
|         # Stop movement sound when collected | ||||
|         if self.channel: | ||||
|   | ||||
		Reference in New Issue
	
	Block a user