New items added..

This commit is contained in:
Storm Dragon
2025-02-06 02:31:57 -05:00
parent c29bcd40b7
commit 8f57069c98
13 changed files with 178 additions and 133 deletions
+11 -4
View File
@@ -8,7 +8,14 @@
}, },
"objects": [ "objects": [
{ {
"x": 5, "x": 2,
"y": 3,
"item": "guts",
"sound": "coffin",
"type": "coffin"
},
{
"x_range": [5, 8],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -85,7 +92,7 @@
"zombie_spawn_chance": 15 "zombie_spawn_chance": 15
}, },
{ {
"x_range": [95, 97], "x_range": [95, 100],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -98,7 +105,7 @@
"type": "coffin" "type": "coffin"
}, },
{ {
"x_range": [120, 122], "x_range": [120, 123],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -122,7 +129,7 @@
], ],
"boundaries": { "boundaries": {
"left": 0, "left": 0,
"right": 160 "right": 165
}, },
"footstep_sound": "footstep_stone" "footstep_sound": "footstep_stone"
} }
+11 -4
View File
@@ -14,7 +14,7 @@
"type": "coffin" "type": "coffin"
}, },
{ {
"x_range": [15, 17], "x_range": [15, 18],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -39,6 +39,13 @@
"static": true, "static": true,
"zombie_spawn_chance": 15 "zombie_spawn_chance": 15
}, },
{
"x_range": [33, 38],
"y": 3,
"sound": "coin",
"collectible": true,
"static": true
},
{ {
"x_range": [45, 60], "x_range": [45, 60],
"y": 12, "y": 12,
@@ -57,7 +64,7 @@
"type": "coffin" "type": "coffin"
}, },
{ {
"x_range": [65, 67], "x_range": [65, 68],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -89,7 +96,7 @@
"zombie_spawn_chance": 20 "zombie_spawn_chance": 20
}, },
{ {
"x_range": [105, 107], "x_range": [105, 108],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -104,7 +111,7 @@
"range": 15 "range": 15
}, },
{ {
"x_range": [130, 160], "x_range": [130, 165],
"y": 15, "y": 15,
"type": "skull_storm", "type": "skull_storm",
"damage": 4, "damage": 4,
+26 -11
View File
@@ -36,13 +36,7 @@
"zombie_spawn_chance": 25 "zombie_spawn_chance": 25
}, },
{ {
"x": 15, "x_range": [25, 28],
"y": 3,
"sound": "coffin",
"type": "coffin"
},
{
"x_range": [25, 27],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -71,7 +65,7 @@
} }
}, },
{ {
"x_range": [42, 44], "x_range": [40, 44],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -97,7 +91,7 @@
} }
}, },
{ {
"x_range": [75, 77], "x_range": [75, 78],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -140,7 +134,7 @@
} }
}, },
{ {
"x_range": [105, 107], "x_range": [105, 115],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
@@ -185,12 +179,19 @@
} }
}, },
{ {
"x_range": [155, 157], "x_range": [155, 158],
"y": 3, "y": 3,
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
"static": true "static": true
}, },
{
"x": 145,
"y": 3,
"item": "hand_of_glory",
"sound": "coffin",
"type": "coffin"
},
{ {
"x_range": [146, 166], "x_range": [146, 166],
"y": 0, "y": 0,
@@ -228,6 +229,20 @@
"sound": "coin", "sound": "coin",
"collectible": true, "collectible": true,
"static": true "static": true
},
{
"x": 185,
"y": 3,
"item": "extra_life",
"sound": "coffin",
"type": "coffin"
},
{
"x_range": [190, 195],
"y": 3,
"sound": "coin",
"collectible": true,
"static": true
} }
], ],
"boundaries": { "boundaries": {
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
+15 -5
View File
@@ -1,11 +1,12 @@
import random
from libstormgames import * from libstormgames import *
from src.item_types import ItemProperties
from src.object import Object from src.object import Object
from src.powerup import PowerUp from src.powerup import PowerUp
import random
class CoffinObject(Object): class CoffinObject(Object):
def __init__(self, x, y, sounds, level): def __init__(self, x, y, sounds, level, item="random"):
super().__init__( super().__init__(
x, y, "coffin", x, y, "coffin",
isStatic=True, isStatic=True,
@@ -13,9 +14,10 @@ class CoffinObject(Object):
isHazard=False isHazard=False
) )
self.sounds = sounds self.sounds = sounds
self.level = level # Store level reference self.level = level
self.is_broken = False self.is_broken = False
self.dropped_item = None self.dropped_item = None
self.specified_item = item
def hit(self, player_pos): def hit(self, player_pos):
"""Handle being hit by the player's weapon""" """Handle being hit by the player's weapon"""
@@ -32,8 +34,16 @@ class CoffinObject(Object):
# Mark coffin as inactive since it's broken # Mark coffin as inactive since it's broken
self.isActive = False self.isActive = False
# Randomly choose item type # Determine item to drop
item_type = random.choice(['hand_of_glory', 'jack_o_lantern']) if self.specified_item == "random":
item_type = ItemProperties.get_random_item()
else:
# Validate specified item
if ItemProperties.is_valid_item(self.specified_item):
item_type = self.specified_item
else:
# Fall back to random if invalid item specified
item_type = ItemProperties.get_random_item()
# Create item 1-2 tiles away in random direction # Create item 1-2 tiles away in random direction
direction = random.choice([-1, 1]) direction = random.choice([-1, 1])
-89
View File
@@ -1,89 +0,0 @@
from libstormgames import *
from src.object import Object
import random
class CoffinObject(Object):
def __init__(self, x, y, sounds):
super().__init__(
x, y, "coffin",
isStatic=True,
isCollectible=False,
isHazard=False
)
self.sounds = sounds
self.is_broken = False
self.dropped_item = None
def hit(self, player_pos):
"""Handle being hit by the player's weapon"""
if not self.is_broken:
self.is_broken = True
self.sounds['coffin_shatter'].play()
# Randomly choose item type
item_type = random.choice(['hand_of_glory', 'jack_o_lantern'])
# Create item 1-2 tiles away in random direction
direction = random.choice([-1, 1])
drop_distance = random.randint(1, 2)
drop_x = self.xPos + (direction * drop_distance)
self.dropped_item = Item(
drop_x,
self.yPos,
item_type,
self.sounds,
direction
)
return True
return False
class Item(Object):
def __init__(self, x, y, item_type, sounds, direction):
super().__init__(
x, y, item_type,
isStatic=False,
isCollectible=True,
isHazard=False
)
self.sounds = sounds
self.direction = direction
self.speed = 0.05 # Base movement speed
self.item_type = item_type
self.channel = None
def update(self, current_time):
"""Update item position"""
if not self.isActive:
return False
# Update position
self._currentX += self.direction * self.speed
# Keep bounce sound playing while moving
if self.channel is None or not self.channel.get_busy():
self.channel = self.sounds['item_bounce'].play(-1)
# Check if item has gone too far (20 tiles)
if abs(self._currentX - self.xRange[0]) > 20:
self.isActive = False
if self.channel:
self.channel.stop()
self.channel = None
return False
return True
def apply_effect(self, player):
"""Apply the item's effect when collected"""
if self.item_type == 'hand_of_glory':
player.start_invincibility()
speak("Hand of Glory makes you invincible!")
elif self.item_type == 'jack_o_lantern':
player.add_projectile('jack_o_lantern')
speak("Gained a Jack-o'-lantern projectile!")
# Stop movement sound when collected
if self.channel:
self.channel.stop()
self.channel = None
+51
View File
@@ -0,0 +1,51 @@
import random
from enum import Enum, auto
class ItemType(Enum):
"""Defines available item types and their properties"""
GUTS = auto()
HAND_OF_GLORY = auto()
JACK_O_LANTERN = auto()
EXTRA_LIFE = auto()
class ItemProperties:
"""Manages item properties and availability"""
# Items that can appear in random drops
RANDOM_ELIGIBLE = {
ItemType.HAND_OF_GLORY: "hand_of_glory",
ItemType.JACK_O_LANTERN: "jack_o_lantern"
}
# All possible items (including special ones)
ALL_ITEMS = {
ItemType.GUTS: "guts",
ItemType.HAND_OF_GLORY: "hand_of_glory",
ItemType.JACK_O_LANTERN: "jack_o_lantern",
ItemType.EXTRA_LIFE: "extra_life"
}
@staticmethod
def get_sound_name(item_type):
"""Convert enum to sound/asset name"""
return ItemProperties.ALL_ITEMS.get(item_type)
@staticmethod
def get_random_item():
"""Get a random item from eligible items"""
item_type = random.choice(list(ItemProperties.RANDOM_ELIGIBLE.keys()))
return ItemProperties.get_sound_name(item_type)
@staticmethod
def is_valid_item(item_name):
"""Check if an item name is valid"""
return item_name in [v for v in ItemProperties.ALL_ITEMS.values()]
@staticmethod
def get_item_type(item_name):
"""Get ItemType enum from string name"""
for item_type, name in ItemProperties.ALL_ITEMS.items():
if name == item_name:
return item_type
return None
+4 -4
View File
@@ -79,7 +79,8 @@ class Level:
xPos[0], xPos[0],
obj["y"], obj["y"],
self.sounds, self.sounds,
self # Pass level reference self, # Pass level reference
item=obj.get("item", "random") # Get item type or default to random
) )
self.objects.append(coffin) self.objects.append(coffin)
# Check if this is an enemy # Check if this is an enemy
@@ -221,7 +222,7 @@ class Level:
if obj.hit(self.player.xPos): if obj.hit(self.player.xPos):
self.bouncing_items.append(obj.dropped_item) self.bouncing_items.append(obj.dropped_item)
speak(f"{obj.dropped_item.item_type} falls out!") #speak(f"{obj.dropped_item.soundName} falls out!")
def handle_collisions(self): def handle_collisions(self):
"""Handle all collision checks and return True if level is complete.""" """Handle all collision checks and return True if level is complete."""
@@ -265,7 +266,6 @@ class Level:
if self.player._coins % 100 == 0: if self.player._coins % 100 == 0:
# Extra life # Extra life
speak("Extra life")
self.player._coins = 0 self.player._coins = 0
self.player._lives += 1 self.player._lives += 1
play_sound(self.sounds['extra_life']) play_sound(self.sounds['extra_life'])
@@ -273,7 +273,7 @@ class Level:
elif obj.isHazard and not self.player.isJumping: elif obj.isHazard and not self.player.isJumping:
if not self.player.isInvincible: if not self.player.isInvincible:
play_sound(self.sounds[obj.soundName]) play_sound(self.sounds[obj.soundName])
speak("You fell in an open grave!") speak("You fell in an open grave! Now, it's yours!")
self.player.set_health(0) self.player.set_health(0)
return False return False
else: else:
+44 -7
View File
@@ -14,6 +14,8 @@ class Player:
self.jumpDuration = 1000 # Jump duration in milliseconds self.jumpDuration = 1000 # Jump duration in milliseconds
self.jumpStartTime = 0 self.jumpStartTime = 0
self.isJumping = False self.isJumping = False
self.isRunning = False
self.runMultiplier = 1.5 # Same multiplier as jumping
self.facingRight = True self.facingRight = True
# Stats and tracking # Stats and tracking
@@ -26,11 +28,14 @@ class Player:
self.sounds = sounds self.sounds = sounds
# Footstep tracking # Footstep tracking
self.baseStepDistance = 0.8
self.baseStepInterval = 250
self.stepDistance = self.baseStepDistance
self.minStepInterval = self.baseStepInterval
self.distanceSinceLastStep = 0 self.distanceSinceLastStep = 0
self.stepDistance = 0.8
self.lastStepTime = 0 self.lastStepTime = 0
self.minStepInterval = 250 # Minimum milliseconds between steps self.isRunning = False
self.footstepSound = "footstep" self.runMultiplier = 1.5
# Inventory system # Inventory system
self.inventory = [] self.inventory = []
@@ -61,8 +66,8 @@ class Player:
def should_play_footstep(self, currentTime): def should_play_footstep(self, currentTime):
"""Check if it's time to play a footstep sound""" """Check if it's time to play a footstep sound"""
return (self.distanceSinceLastStep >= self.stepDistance and return (self.distanceSinceLastStep >= self.get_step_distance() and
currentTime - self.lastStepTime >= self.minStepInterval) currentTime - self.lastStepTime >= self.get_step_interval())
def update(self, currentTime): def update(self, currentTime):
"""Update player state""" """Update player state"""
@@ -76,6 +81,10 @@ class Player:
self.isInvincible = True self.isInvincible = True
self.invincibilityStartTime = pygame.time.get_ticks() self.invincibilityStartTime = pygame.time.get_ticks()
def extra_life(self):
"""Increment lives by 1"""
self._lives += 1
def get_jack_o_lanterns(self): def get_jack_o_lanterns(self):
"""Get number of jack o'lanterns""" """Get number of jack o'lanterns"""
return self._jack_o_lantern_count return self._jack_o_lantern_count
@@ -84,6 +93,10 @@ class Player:
"""Add a jack o'lantern""" """Add a jack o'lantern"""
self._jack_o_lantern_count += 1 self._jack_o_lantern_count += 1
def add_guts(self):
"""Apply guts, increase max_health by 2"""
self._maxHealth += 2
def throw_projectile(self): def throw_projectile(self):
"""Throw a jack o'lantern if we have any""" """Throw a jack o'lantern if we have any"""
if self.get_jack_o_lanterns() <= 0: if self.get_jack_o_lanterns() <= 0:
@@ -96,6 +109,18 @@ class Player:
'direction': 1 if self.facingRight else -1 'direction': 1 if self.facingRight else -1
} }
def get_step_distance(self):
"""Get step distance based on current speed"""
if self.isRunning or self.isJumping:
return self.baseStepDistance / self.runMultiplier
return self.baseStepDistance
def get_step_interval(self):
"""Get minimum time between steps based on current speed"""
if self.isRunning or self.isJumping:
return self.baseStepInterval / self.runMultiplier
return self.baseStepInterval
def get_health(self): def get_health(self):
"""Get current health""" """Get current health"""
return self._health return self._health
@@ -104,6 +129,12 @@ class Player:
"""Get current max health""" """Get current max health"""
return self._maxHealth return self._maxHealth
def get_current_speed(self):
"""Calculate current speed based on state"""
baseSpeed = self.moveSpeed
if self.isJumping or self.isRunning: return baseSpeed * self.runMultiplier
return baseSpeed
def set_footstep_sound(self, soundName): def set_footstep_sound(self, soundName):
"""Set the current footstep sound""" """Set the current footstep sound"""
self.footstepSound = soundName self.footstepSound = soundName
@@ -122,8 +153,7 @@ class Player:
pygame.mixer.stop() pygame.mixer.stop()
cut_scene(self.sounds, 'lose_a_life') cut_scene(self.sounds, 'lose_a_life')
if self._lives > 0: if self._lives > 0:
self._health = self._maxHealth # Reset health if we still have lives self.reset_on_death()
speak(f"{self._lives} lives remaining")
def set_max_health(self, value): def set_max_health(self, value):
"""Set max health""" """Set max health"""
@@ -137,6 +167,13 @@ class Player:
"""Get remaining lives""" """Get remaining lives"""
return self._lives return self._lives
def reset_on_death(self):
"""Reset player state after death"""
self._health = self._maxHealth
self.isJumping = False
self.isRunning = False
self.xPos = 0
def add_weapon(self, weapon): def add_weapon(self, weapon):
"""Add a new weapon to inventory and equip if first weapon""" """Add a new weapon to inventory and equip if first weapon"""
self.weapons.append(weapon) self.weapons.append(weapon)
+4
View File
@@ -44,8 +44,12 @@ class PowerUp(Object):
"""Apply the item's effect when collected""" """Apply the item's effect when collected"""
if self.item_type == 'hand_of_glory': if self.item_type == 'hand_of_glory':
player.start_invincibility() player.start_invincibility()
elif self.item_type == 'guts':
player.add_guts()
elif self.item_type == 'jack_o_lantern': elif self.item_type == 'jack_o_lantern':
player.add_jack_o_lantern() player.add_jack_o_lantern()
elif self.item_type == 'extra_life':
player.extra_life()
# Stop movement sound when collected # Stop movement sound when collected
if self.channel: if self.channel:
+5 -2
View File
@@ -49,8 +49,11 @@ class WickedQuest:
player = self.currentLevel.player player = self.currentLevel.player
currentTime = pygame.time.get_ticks() currentTime = pygame.time.get_ticks()
# Calculate current speed based on jumping state # Update running state
currentSpeed = player.moveSpeed * 1.5 if player.isJumping else player.moveSpeed player.isRunning = keys[pygame.K_SPACE]
# Get current speed (handles both running and jumping)
currentSpeed = player.get_current_speed()
# Track movement distance for this frame # Track movement distance for this frame
movementDistance = 0 movementDistance = 0