Stats tracking updated. Work on skull storms. Enemy death sound added for goblins. Various updates and fixes.

This commit is contained in:
Storm Dragon
2025-02-04 00:28:50 -05:00
parent 1d033e067a
commit 4f7f5504d1
12 changed files with 323 additions and 47 deletions

View File

@@ -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:

View File

@@ -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)

View File

@@ -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:

View File

@@ -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 = []

View File

@@ -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
View 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)