New items added..
This commit is contained in:
@@ -8,7 +8,14 @@
|
||||
},
|
||||
"objects": [
|
||||
{
|
||||
"x": 5,
|
||||
"x": 2,
|
||||
"y": 3,
|
||||
"item": "guts",
|
||||
"sound": "coffin",
|
||||
"type": "coffin"
|
||||
},
|
||||
{
|
||||
"x_range": [5, 8],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -85,7 +92,7 @@
|
||||
"zombie_spawn_chance": 15
|
||||
},
|
||||
{
|
||||
"x_range": [95, 97],
|
||||
"x_range": [95, 100],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -98,7 +105,7 @@
|
||||
"type": "coffin"
|
||||
},
|
||||
{
|
||||
"x_range": [120, 122],
|
||||
"x_range": [120, 123],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -122,7 +129,7 @@
|
||||
],
|
||||
"boundaries": {
|
||||
"left": 0,
|
||||
"right": 160
|
||||
"right": 165
|
||||
},
|
||||
"footstep_sound": "footstep_stone"
|
||||
}
|
||||
|
@@ -14,7 +14,7 @@
|
||||
"type": "coffin"
|
||||
},
|
||||
{
|
||||
"x_range": [15, 17],
|
||||
"x_range": [15, 18],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -39,6 +39,13 @@
|
||||
"static": true,
|
||||
"zombie_spawn_chance": 15
|
||||
},
|
||||
{
|
||||
"x_range": [33, 38],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
"static": true
|
||||
},
|
||||
{
|
||||
"x_range": [45, 60],
|
||||
"y": 12,
|
||||
@@ -57,7 +64,7 @@
|
||||
"type": "coffin"
|
||||
},
|
||||
{
|
||||
"x_range": [65, 67],
|
||||
"x_range": [65, 68],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -89,7 +96,7 @@
|
||||
"zombie_spawn_chance": 20
|
||||
},
|
||||
{
|
||||
"x_range": [105, 107],
|
||||
"x_range": [105, 108],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -104,7 +111,7 @@
|
||||
"range": 15
|
||||
},
|
||||
{
|
||||
"x_range": [130, 160],
|
||||
"x_range": [130, 165],
|
||||
"y": 15,
|
||||
"type": "skull_storm",
|
||||
"damage": 4,
|
||||
|
@@ -36,13 +36,7 @@
|
||||
"zombie_spawn_chance": 25
|
||||
},
|
||||
{
|
||||
"x": 15,
|
||||
"y": 3,
|
||||
"sound": "coffin",
|
||||
"type": "coffin"
|
||||
},
|
||||
{
|
||||
"x_range": [25, 27],
|
||||
"x_range": [25, 28],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -71,7 +65,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"x_range": [42, 44],
|
||||
"x_range": [40, 44],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -97,7 +91,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"x_range": [75, 77],
|
||||
"x_range": [75, 78],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -140,7 +134,7 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"x_range": [105, 107],
|
||||
"x_range": [105, 115],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
@@ -185,12 +179,19 @@
|
||||
}
|
||||
},
|
||||
{
|
||||
"x_range": [155, 157],
|
||||
"x_range": [155, 158],
|
||||
"y": 3,
|
||||
"sound": "coin",
|
||||
"collectible": true,
|
||||
"static": true
|
||||
},
|
||||
{
|
||||
"x": 145,
|
||||
"y": 3,
|
||||
"item": "hand_of_glory",
|
||||
"sound": "coffin",
|
||||
"type": "coffin"
|
||||
},
|
||||
{
|
||||
"x_range": [146, 166],
|
||||
"y": 0,
|
||||
@@ -228,6 +229,20 @@
|
||||
"sound": "coin",
|
||||
"collectible": 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": {
|
||||
|
BIN
sounds/extra_life.ogg
(Stored with Git LFS)
BIN
sounds/extra_life.ogg
(Stored with Git LFS)
Binary file not shown.
BIN
sounds/get_guts.ogg
(Stored with Git LFS)
Normal file
BIN
sounds/get_guts.ogg
(Stored with Git LFS)
Normal file
Binary file not shown.
@@ -1,11 +1,12 @@
|
||||
import random
|
||||
from libstormgames import *
|
||||
from src.item_types import ItemProperties
|
||||
from src.object import Object
|
||||
from src.powerup import PowerUp
|
||||
import random
|
||||
|
||||
|
||||
class CoffinObject(Object):
|
||||
def __init__(self, x, y, sounds, level):
|
||||
def __init__(self, x, y, sounds, level, item="random"):
|
||||
super().__init__(
|
||||
x, y, "coffin",
|
||||
isStatic=True,
|
||||
@@ -13,9 +14,10 @@ class CoffinObject(Object):
|
||||
isHazard=False
|
||||
)
|
||||
self.sounds = sounds
|
||||
self.level = level # Store level reference
|
||||
self.level = level
|
||||
self.is_broken = False
|
||||
self.dropped_item = None
|
||||
self.specified_item = item
|
||||
|
||||
def hit(self, player_pos):
|
||||
"""Handle being hit by the player's weapon"""
|
||||
@@ -23,23 +25,31 @@ class CoffinObject(Object):
|
||||
self.is_broken = True
|
||||
play_sound(self.sounds['coffin_shatter'])
|
||||
self.level.player.stats.update_stat('Coffins broken', 1)
|
||||
|
||||
|
||||
# Stop the ongoing coffin sound
|
||||
if self.channel:
|
||||
obj_stop(self.channel)
|
||||
self.channel = None
|
||||
|
||||
|
||||
# Mark coffin as inactive since it's broken
|
||||
self.isActive = False
|
||||
|
||||
# Randomly choose item type
|
||||
item_type = random.choice(['hand_of_glory', 'jack_o_lantern'])
|
||||
|
||||
# Determine item to drop
|
||||
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
|
||||
direction = random.choice([-1, 1])
|
||||
drop_distance = random.randint(1, 2)
|
||||
drop_x = self.xPos + (direction * drop_distance)
|
||||
|
||||
|
||||
self.dropped_item = PowerUp(
|
||||
drop_x,
|
||||
self.yPos,
|
||||
|
89
src/item.py
89
src/item.py
@@ -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
src/item_types.py
Normal file
51
src/item_types.py
Normal 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
|
@@ -79,7 +79,8 @@ class Level:
|
||||
xPos[0],
|
||||
obj["y"],
|
||||
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)
|
||||
# Check if this is an enemy
|
||||
@@ -221,7 +222,7 @@ class Level:
|
||||
|
||||
if obj.hit(self.player.xPos):
|
||||
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):
|
||||
"""Handle all collision checks and return True if level is complete."""
|
||||
@@ -265,7 +266,6 @@ class Level:
|
||||
|
||||
if self.player._coins % 100 == 0:
|
||||
# Extra life
|
||||
speak("Extra life")
|
||||
self.player._coins = 0
|
||||
self.player._lives += 1
|
||||
play_sound(self.sounds['extra_life'])
|
||||
@@ -273,7 +273,7 @@ class Level:
|
||||
elif obj.isHazard and not self.player.isJumping:
|
||||
if not self.player.isInvincible:
|
||||
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)
|
||||
return False
|
||||
else:
|
||||
|
@@ -14,6 +14,8 @@ class Player:
|
||||
self.jumpDuration = 1000 # Jump duration in milliseconds
|
||||
self.jumpStartTime = 0
|
||||
self.isJumping = False
|
||||
self.isRunning = False
|
||||
self.runMultiplier = 1.5 # Same multiplier as jumping
|
||||
self.facingRight = True
|
||||
|
||||
# Stats and tracking
|
||||
@@ -26,11 +28,14 @@ class Player:
|
||||
self.sounds = sounds
|
||||
|
||||
# Footstep tracking
|
||||
self.baseStepDistance = 0.8
|
||||
self.baseStepInterval = 250
|
||||
self.stepDistance = self.baseStepDistance
|
||||
self.minStepInterval = self.baseStepInterval
|
||||
self.distanceSinceLastStep = 0
|
||||
self.stepDistance = 0.8
|
||||
self.lastStepTime = 0
|
||||
self.minStepInterval = 250 # Minimum milliseconds between steps
|
||||
self.footstepSound = "footstep"
|
||||
self.isRunning = False
|
||||
self.runMultiplier = 1.5
|
||||
|
||||
# Inventory system
|
||||
self.inventory = []
|
||||
@@ -61,8 +66,8 @@ class Player:
|
||||
|
||||
def should_play_footstep(self, currentTime):
|
||||
"""Check if it's time to play a footstep sound"""
|
||||
return (self.distanceSinceLastStep >= self.stepDistance and
|
||||
currentTime - self.lastStepTime >= self.minStepInterval)
|
||||
return (self.distanceSinceLastStep >= self.get_step_distance() and
|
||||
currentTime - self.lastStepTime >= self.get_step_interval())
|
||||
|
||||
def update(self, currentTime):
|
||||
"""Update player state"""
|
||||
@@ -76,6 +81,10 @@ class Player:
|
||||
self.isInvincible = True
|
||||
self.invincibilityStartTime = pygame.time.get_ticks()
|
||||
|
||||
def extra_life(self):
|
||||
"""Increment lives by 1"""
|
||||
self._lives += 1
|
||||
|
||||
def get_jack_o_lanterns(self):
|
||||
"""Get number of jack o'lanterns"""
|
||||
return self._jack_o_lantern_count
|
||||
@@ -84,6 +93,10 @@ class Player:
|
||||
"""Add a jack o'lantern"""
|
||||
self._jack_o_lantern_count += 1
|
||||
|
||||
def add_guts(self):
|
||||
"""Apply guts, increase max_health by 2"""
|
||||
self._maxHealth += 2
|
||||
|
||||
def throw_projectile(self):
|
||||
"""Throw a jack o'lantern if we have any"""
|
||||
if self.get_jack_o_lanterns() <= 0:
|
||||
@@ -96,6 +109,18 @@ class Player:
|
||||
'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):
|
||||
"""Get current health"""
|
||||
return self._health
|
||||
@@ -104,6 +129,12 @@ class Player:
|
||||
"""Get current max health"""
|
||||
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):
|
||||
"""Set the current footstep sound"""
|
||||
self.footstepSound = soundName
|
||||
@@ -122,8 +153,7 @@ class Player:
|
||||
pygame.mixer.stop()
|
||||
cut_scene(self.sounds, 'lose_a_life')
|
||||
if self._lives > 0:
|
||||
self._health = self._maxHealth # Reset health if we still have lives
|
||||
speak(f"{self._lives} lives remaining")
|
||||
self.reset_on_death()
|
||||
|
||||
def set_max_health(self, value):
|
||||
"""Set max health"""
|
||||
@@ -137,6 +167,13 @@ class Player:
|
||||
"""Get remaining 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):
|
||||
"""Add a new weapon to inventory and equip if first weapon"""
|
||||
self.weapons.append(weapon)
|
||||
|
@@ -44,8 +44,12 @@ class PowerUp(Object):
|
||||
"""Apply the item's effect when collected"""
|
||||
if self.item_type == 'hand_of_glory':
|
||||
player.start_invincibility()
|
||||
elif self.item_type == 'guts':
|
||||
player.add_guts()
|
||||
elif self.item_type == 'jack_o_lantern':
|
||||
player.add_jack_o_lantern()
|
||||
elif self.item_type == 'extra_life':
|
||||
player.extra_life()
|
||||
|
||||
# Stop movement sound when collected
|
||||
if self.channel:
|
||||
|
@@ -49,9 +49,12 @@ class WickedQuest:
|
||||
player = self.currentLevel.player
|
||||
currentTime = pygame.time.get_ticks()
|
||||
|
||||
# Calculate current speed based on jumping state
|
||||
currentSpeed = player.moveSpeed * 1.5 if player.isJumping else player.moveSpeed
|
||||
# Update running state
|
||||
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
|
||||
movementDistance = 0
|
||||
|
||||
|
Reference in New Issue
Block a user