diff --git a/levels/Wicked Quest/12.json b/levels/Wicked Quest/12.json index a5cc8ce..f57bf27 100644 --- a/levels/Wicked Quest/12.json +++ b/levels/Wicked Quest/12.json @@ -1,7 +1,7 @@ { "level_id": 12, "name": "Pumpkin Run", - "description": "Angry at the way you just blew through their defenses like that, monsters have decided to man... er monster the catapults. Good luck." + "description": "Angry at the way you just blew through their defenses like that, monsters have decided to man... er monster the catapults. Good luck.", "player_start": { "x": 0, "y": 0 @@ -26,7 +26,7 @@ "y": 0, "type": "catapult", "fire_interval": 3000, - "range": 50 + "range": 40 }, { "x_range": [55, 60], @@ -56,7 +56,7 @@ "y": 0, "type": "catapult", "fire_interval": 3000, - "range": 50 + "range": 40 }, { "x_range": [105, 110], @@ -86,14 +86,14 @@ "y": 0, "type": "catapult", "fire_interval": 3000, - "range": 50 + "range": 40 }, { "x_range": [145, 165], "y": 15, "type": "skull_storm", "damage": 4, - "maximum_skulls": 3, + "maximum_skulls": 5, "frequency": { "min": 1, "max": 3 @@ -117,7 +117,7 @@ "y": 0, "type": "catapult", "fire_interval": 3000, - "range": 50 + "range": 40 }, { "x_range": [185, 195], @@ -148,7 +148,7 @@ "y": 0, "type": "catapult", "fire_interval": 3000, - "range": 50 + "range": 40 }, { "x_range": [235, 240], @@ -169,7 +169,7 @@ "y": 0, "type": "catapult", "fire_interval": 3000, - "range": 50 + "range": 40 }, { "x_range": [265, 285], @@ -179,7 +179,7 @@ "maximum_skulls": 3, "frequency": { "min": 1, - "max": 3 + "max": 5 } }, { @@ -194,7 +194,7 @@ "y": 0, "type": "catapult", "fire_interval": 3000, - "range": 50 + "range": 40 }, { "x_range": [305, 315], @@ -220,17 +220,17 @@ "y": 0, "type": "catapult", "fire_interval": 3000, - "range": 50 + "range": 40 }, { "x_range": [355, 375], "y": 15, "type": "skull_storm", "damage": 4, - "maximum_skulls": 3, + "maximum_skulls": 5, "frequency": { "min": 1, - "max": 3 + "max": 5 } }, { diff --git a/levels/Wicked Quest/13.json b/levels/Wicked Quest/13.json index 48adb74..5758efc 100644 --- a/levels/Wicked Quest/13.json +++ b/levels/Wicked Quest/13.json @@ -2,6 +2,7 @@ "level_id": 13, "name": "Trick or Treat", "description": "The end of your journey lies ahead, but the monsters have prepared a special welcome. The air crackles with dark magic, and something massive stirs in the darkness.", + "locked": true, "player_start": { "x": 0, "y": 0 diff --git a/sounds/coffin.ogg b/sounds/coffin.ogg index 80370cb..e4f82db 100644 --- a/sounds/coffin.ogg +++ b/sounds/coffin.ogg @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b70b98de7ceca8036143357dee7b2c98c9c7c4bf0c08bdef41addbe29e4a7765 -size 60273 +oid sha256:bb3d9ddad96a134c774157e6dd777d8352aa8bb7ed81ae30189ebc92ad93bc2e +size 61691 diff --git a/sounds/locked.ogg b/sounds/locked.ogg new file mode 100644 index 0000000..88f0300 --- /dev/null +++ b/sounds/locked.ogg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ee6b45bc10bdc8342f2a3475af02eed29f3f937778c3ee478a65e9e97ecf0b72 +size 42532 diff --git a/src/enemy.py b/src/enemy.py index 7eeab3f..8c7f5eb 100644 --- a/src/enemy.py +++ b/src/enemy.py @@ -53,47 +53,11 @@ class Enemy(Object): return self._currentX @xPos.setter + def xPos(self, value): """Set current x position""" self._currentX = value - def update_movement(self, player): - """Update enemy movement based on attack pattern""" - if self.attackPattern['type'] == 'hunter': - # Calculate distance to player - distanceToPlayer = player.xPos - self.xPos - - if abs(distanceToPlayer) <= (self.patrolEnd - self.patrolStart): # Use full range - # Player is within movement range - if self.movingRight: - # Moving right - if distanceToPlayer < -self.turnThreshold: - # Player is too far behind us, turn around - self.movingRight = False - else: - self.xPos += self.movementSpeed - else: - # Moving left - if distanceToPlayer > self.turnThreshold: - # Player is too far ahead of us, turn around - self.movingRight = True - else: - self.xPos -= self.movementSpeed - - # Ensure we stay within our range - if self.xPos <= self.patrolStart: - self.xPos = self.patrolStart - self.movingRight = True - elif self.xPos >= self.patrolEnd: - self.xPos = self.patrolEnd - self.movingRight = False - else: - # Player out of range, return to normal patrol - self.patrol_movement() - else: - # Default patrol behavior - self.patrol_movement() - def patrol_movement(self): """Standard back-and-forth patrol movement""" if self.movingRight: @@ -109,20 +73,28 @@ class Enemy(Object): """Update enemy position and handle attacks""" if not self.isActive or self.health <= 0: return - - # Handle movement based on enemy type - if self.enemyType == "zombie": - # Zombies always chase player + + # Handle movement based on enemy type and pattern + if self.enemyType == "zombie" or self.attackPattern['type'] == 'hunter': + # Direct chase behavior for zombies and hunters if player.xPos > self.xPos: self.movingRight = True self.xPos += self.movementSpeed else: self.movingRight = False self.xPos -= self.movementSpeed + + # Only enforce level boundaries, not patrol boundaries + if self.xPos < self.level.leftBoundary: + self.xPos = self.level.leftBoundary + self.movingRight = True + elif self.xPos > self.level.rightBoundary: + self.xPos = self.level.rightBoundary + self.movingRight = False else: - # Other enemies use their attack pattern - self.update_movement(player) - + # Other enemies use patrol pattern + self.patrol_movement() + # Check for attack opportunity if self.can_attack(currentTime, player): self.attack(currentTime, player) diff --git a/src/level.py b/src/level.py index 9a89dd0..d60e184 100644 --- a/src/level.py +++ b/src/level.py @@ -22,10 +22,11 @@ class Level: self.player = player 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"] + self.isLocked = levelData.get("locked", False) # Default to False if not specified self.levelId = levelData["level_id"] # Get footstep sound for this level, default to 'footstep' if not specified @@ -143,7 +144,8 @@ class Level: health=obj.get("health", 5), damage=obj.get("damage", 1), attack_range=obj.get("attack_range", 1), - movement_range=obj.get("movement_range", 5) + movement_range=obj.get("movement_range", 5), + attack_pattern=obj.get("attack_pattern", {'type': 'patrol'}) # Add this line ) self.enemies.append(enemy) else: @@ -394,7 +396,15 @@ class Level: if obj.soundName == "end_of_level": # Check if player has reached or passed the end marker if self.player.xPos >= obj.xPos: - # Stop all current sounds and play end level sound + # If level is locked, check for remaining enemies + if self.isLocked and any(enemy.isActive for enemy in self.enemies): + speak("You must defeat all enemies before proceeding!") + play_sound(self.sounds['locked']) + # Push player back a bit + self.player.xPos -= 1 + return False + + # Level complete pygame.mixer.stop() play_sound(self.sounds['end_of_level']) return True diff --git a/wicked_quest.py b/wicked_quest.py index 2d8950d..1c01ebb 100644 --- a/wicked_quest.py +++ b/wicked_quest.py @@ -90,7 +90,7 @@ class WickedQuest: if keys[pygame.K_c]: speak(f"{player.get_coins()} gbone dust") if keys[pygame.K_h]: - speak(f"{player.get_health()} HP") + speak(f"{player.get_health()} health of {player.get_max_health()}") if keys[pygame.K_l]: speak(f"{player.get_lives()} lives") if keys[pygame.K_j]: # Check jack o'lanterns