Stats tracking updated. Work on skull storms. Enemy death sound added for goblins. Various updates and fixes.
This commit is contained in:
@@ -3,8 +3,9 @@ from src.object import Object
|
||||
from src.powerup import PowerUp
|
||||
import random
|
||||
|
||||
|
||||
class CoffinObject(Object):
|
||||
def __init__(self, x, y, sounds):
|
||||
def __init__(self, x, y, sounds, level):
|
||||
super().__init__(
|
||||
x, y, "coffin",
|
||||
isStatic=True,
|
||||
@@ -12,6 +13,7 @@ class CoffinObject(Object):
|
||||
isHazard=False
|
||||
)
|
||||
self.sounds = sounds
|
||||
self.level = level # Store level reference
|
||||
self.is_broken = False
|
||||
self.dropped_item = None
|
||||
|
||||
@@ -20,6 +22,8 @@ class CoffinObject(Object):
|
||||
if not self.is_broken:
|
||||
self.is_broken = True
|
||||
self.sounds['coffin_shatter'].play()
|
||||
self.level.player.stats.update_stat('Coffins broken', 1)
|
||||
self.level.player.stats.update_stat('Coffins remaining', -1)
|
||||
|
||||
# Stop the ongoing coffin sound
|
||||
if self.channel:
|
||||
|
17
src/enemy.py
17
src/enemy.py
@@ -4,18 +4,19 @@ import pygame
|
||||
|
||||
|
||||
class Enemy(Object):
|
||||
def __init__(self, xRange, y, enemyType, sounds, **kwargs):
|
||||
def __init__(self, xRange, y, enemyType, sounds, level, **kwargs):
|
||||
# Initialize base object properties
|
||||
super().__init__(
|
||||
xRange,
|
||||
y,
|
||||
f"{enemyType}", # Base sound for ambient noise
|
||||
f"{enemyType}", # Base sound
|
||||
isStatic=False,
|
||||
isHazard=True
|
||||
)
|
||||
|
||||
# Enemy specific properties
|
||||
self.enemyType = enemyType
|
||||
self.level = level
|
||||
self.health = kwargs.get('health', 5) # Default 5 HP
|
||||
self.damage = kwargs.get('damage', 1) # Default 1 damage
|
||||
self.attackRange = kwargs.get('attack_range', 1) # Default 1 tile range
|
||||
@@ -106,7 +107,7 @@ class Enemy(Object):
|
||||
self.sounds[attackSound].play()
|
||||
# Deal damage to player
|
||||
player.set_health(player.get_health() - self.damage)
|
||||
speak(f"The {self.enemyType} hits you!")
|
||||
self.sounds['player_takes_damage'].play()
|
||||
|
||||
def take_damage(self, amount):
|
||||
"""Handle enemy taking damage"""
|
||||
@@ -120,7 +121,11 @@ class Enemy(Object):
|
||||
if self.channel:
|
||||
obj_stop(self.channel)
|
||||
self.channel = None
|
||||
# Play death sound if available
|
||||
deathSound = f"{self.enemyType}_death"
|
||||
# Play death sound if available using positional audio
|
||||
deathSound = f"{self.enemyType}_dies"
|
||||
if deathSound in self.sounds:
|
||||
self.sounds[deathSound].play()
|
||||
self.channel = obj_play(self.sounds, deathSound, self.level.player.xPos, self.xPos, loop=False)
|
||||
|
||||
# Update stats
|
||||
self.level.player.stats.update_stat('Enemies killed', 1)
|
||||
self.level.player.stats.update_stat('Enemies remaining', -1)
|
||||
|
23
src/level.py
23
src/level.py
@@ -72,7 +72,8 @@ class Level:
|
||||
coffin = CoffinObject(
|
||||
xPos[0],
|
||||
obj["y"],
|
||||
self.sounds
|
||||
self.sounds,
|
||||
self # Pass level reference
|
||||
)
|
||||
self.objects.append(coffin)
|
||||
# Check if this is an enemy
|
||||
@@ -82,6 +83,7 @@ class Level:
|
||||
obj["y"],
|
||||
obj["enemy_type"],
|
||||
self.sounds,
|
||||
self, # Pass level reference
|
||||
health=obj.get("health", 5),
|
||||
damage=obj.get("damage", 1),
|
||||
attack_range=obj.get("attack_range", 1),
|
||||
@@ -99,6 +101,10 @@ class Level:
|
||||
zombie_spawn_chance=obj.get("zombie_spawn_chance", 0)
|
||||
)
|
||||
self.objects.append(gameObject)
|
||||
enemyCount = len(self.enemies)
|
||||
coffinCount = sum(1 for obj in self.objects if hasattr(obj, 'is_broken'))
|
||||
player.stats.update_stat('Enemies remaining', enemyCount)
|
||||
player.stats.update_stat('Coffins remaining', coffinCount)
|
||||
|
||||
def update_audio(self):
|
||||
"""Update all audio and entity state."""
|
||||
@@ -126,6 +132,7 @@ class Level:
|
||||
obj.yPos,
|
||||
"zombie",
|
||||
self.sounds,
|
||||
self, # Pass the level reference
|
||||
health=3,
|
||||
damage=10,
|
||||
attack_range=1
|
||||
@@ -235,13 +242,19 @@ class Level:
|
||||
self.sounds[f'get_{obj.soundName}'].play()
|
||||
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)
|
||||
elif obj.isHazard and not self.player.isJumping:
|
||||
self.sounds[obj.soundName].play()
|
||||
speak("You fell in an open grave!")
|
||||
self.player.set_health(0)
|
||||
return False
|
||||
if not self.player.isInvincible:
|
||||
self.sounds[obj.soundName].play()
|
||||
speak("You fell in an open grave!")
|
||||
self.player.set_health(0)
|
||||
return False
|
||||
else:
|
||||
# When invincible, treat it like a successful jump over the grave
|
||||
pass
|
||||
|
||||
# Handle boundaries
|
||||
if self.player.xPos < self.leftBoundary:
|
||||
|
@@ -1,5 +1,6 @@
|
||||
import pygame
|
||||
from libstormgames import *
|
||||
from src.stat_tracker import StatTracker
|
||||
from src.weapon import Weapon
|
||||
|
||||
|
||||
@@ -21,6 +22,7 @@ class Player:
|
||||
self._lives = 1
|
||||
self.distanceSinceLastStep = 0
|
||||
self.stepDistance = 0.5
|
||||
self.stats = StatTracker()
|
||||
|
||||
# Inventory system
|
||||
self.inventory = []
|
||||
|
@@ -55,15 +55,15 @@ class SkullStorm(Object):
|
||||
fallProgress = timeElapsed / skull['fall_duration']
|
||||
currentY = self.yPos * (1 - fallProgress)
|
||||
|
||||
if skull['channel'] is None or not skull['channel'].get_busy():
|
||||
skull['channel'] = play_random_falling(
|
||||
self.sounds,
|
||||
'falling_skull',
|
||||
player.xPos,
|
||||
skull['x'],
|
||||
self.yPos,
|
||||
currentY
|
||||
)
|
||||
skull['channel'] = play_random_falling(
|
||||
self.sounds,
|
||||
'falling_skull',
|
||||
player.xPos,
|
||||
skull['x'],
|
||||
self.yPos,
|
||||
currentY,
|
||||
existingChannel=skull['channel']
|
||||
)
|
||||
|
||||
# Check if we should spawn a new skull
|
||||
if (len(self.activeSkulls) < self.maxSkulls and
|
||||
|
44
src/stat_tracker.py
Normal file
44
src/stat_tracker.py
Normal file
@@ -0,0 +1,44 @@
|
||||
class StatTracker:
|
||||
def __init__(self):
|
||||
# Base dictionary for tracking stats
|
||||
self.total = {
|
||||
'Bone dust': 0,
|
||||
'Enemies killed': 0,
|
||||
'Enemies remaining': 0,
|
||||
'Coffins broken': 0,
|
||||
'Coffins remaining': 0,
|
||||
'Items collected': 0,
|
||||
'Total time': 0
|
||||
}
|
||||
|
||||
# Create level stats from total (shallow copy is fine here)
|
||||
self.level = self.total.copy()
|
||||
|
||||
self.total['levelsCompleted'] = 0
|
||||
|
||||
def reset_level(self):
|
||||
"""Reset level stats based on variable type"""
|
||||
for key in self.level:
|
||||
if isinstance(self.level[key], (int, float)):
|
||||
self.level[key] = 0
|
||||
elif isinstance(self.level[key], str):
|
||||
self.level[key] = ""
|
||||
elif isinstance(self.level[key], list):
|
||||
self.level[key] = []
|
||||
elif self.level[key] is None:
|
||||
self.level[key] = None
|
||||
|
||||
def update_stat(self, statName, value=1, levelOnly=False):
|
||||
"""Update a stat in both level and total (unless levelOnly is True)"""
|
||||
if statName in self.level:
|
||||
self.level[statName] += value
|
||||
if not levelOnly and statName in self.total:
|
||||
self.total[statName] += value
|
||||
|
||||
def get_level_stat(self, statName):
|
||||
"""Get a level stat"""
|
||||
return self.level.get(statName, 0)
|
||||
|
||||
def get_total_stat(self, statName):
|
||||
"""Get a total stat"""
|
||||
return self.total.get(statName, 0)
|
Reference in New Issue
Block a user