Initial commit.

This commit is contained in:
Storm Dragon
2025-01-30 01:17:52 -05:00
commit 0d115b2bef
17 changed files with 260 additions and 0 deletions
+1
View File
@@ -0,0 +1 @@
*.ogg filter=lfs diff=lfs merge=lfs -text
+5
View File
@@ -0,0 +1,5 @@
__pycache__/
*\.pyc
sounds/rec.sh
*.flac
*.wav
+3
View File
@@ -0,0 +1,3 @@
[submodule "libstormgames"]
path = libstormgames
url = https://git.stormux.org/storm/libstormgames
+36
View File
@@ -0,0 +1,36 @@
{
"level_id": 1,
"name": "The Mausoleum",
"description": "After years of existing as a pile of bones, someone was crazy enough to assemble your skeleton. Time to reak some havoc!",
"player_start": {
"x": 0,
"y": 0
},
"objects": [
{
"x": 5,
"y": 3,
"sound": "coin",
"collectible": true,
"static": true
},
{
"x": 25,
"y": 0,
"sound": "goblin",
"hazard": true,
"static": false
},
{
"x": 50,
"y": 0,
"hazard": true,
"sound": "grave",
"static": true
}
],
"boundaries": {
"left": 0,
"right": 500
}
}
Submodule
+1
Submodule libstormgames added at 9f03de15b8
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
BIN
View File
Binary file not shown.
View File
+76
View File
@@ -0,0 +1,76 @@
from libstormgames import *
from src.player import Player
from src.object import Object
class Level:
def __init__(self, levelData, sounds):
self.sounds = sounds
self.objects = []
self.player = Player(levelData["player_start"]["x"], levelData["player_start"]["y"])
# Load objects from level data
for obj in levelData["objects"]:
gameObject = Object(
obj["x"],
obj["y"],
obj["sound"],
isStatic=obj.get("static", True),
isCollectible=obj.get("collectible", False),
isHazard=obj.get("hazard", False)
)
self.objects.append(gameObject)
def update_audio(self):
# Update all object sounds based on player position
for obj in self.objects:
if not obj.isActive:
continue
# For non-static objects like goblins, ensure continuous sound
if not obj.isStatic:
# If channel doesn't exist or sound stopped playing, restart it
if obj.channel is None or not obj.channel.get_busy():
obj.channel = obj_play(self.sounds, obj.soundName, self.player.xPos, obj.xPos)
else:
# Original logic for static objects
if obj.channel is None:
obj.channel = obj_play(self.sounds, obj.soundName, self.player.xPos, obj.xPos)
# Update position-based audio for all objects
if obj.channel is not None:
obj.channel = obj_update(obj.channel, self.player.xPos, obj.xPos)
def handle_collisions(self):
for obj in self.objects:
if not obj.isActive:
continue
# Single-tile collision detection (more precise)
collision_threshold = 0.5 # Half a tile width from center
distance = abs(self.player.xPos - obj.xPos)
if distance <= collision_threshold:
if obj.isCollectible:
# Coins must be collected while jumping
if self.player.isJumping:
self.sounds[f'get_{obj.soundName}'].play()
speak(f"Collected {obj.soundName}")
obj.isActive = False
obj_stop(obj.channel)
self.player.collectedItems.append(obj.soundName)
elif obj.isHazard:
# Only affect player if they're not jumping (for ground-based hazards)
if not self.player.isJumping:
if obj.soundName == "grave":
self.sounds['grave'].play()
speak("You fell into a pit!")
elif obj.soundName == "goblin":
self.sounds['goblin'].play()
speak("A goblin got you!")
else: # Other hazards
self.sounds[obj.soundName].play()
speak(f"A {obj.soundName} got you!")
# Apply knockback for any hazard hit
knockback = 2
self.player.xPos = self.player.xPos - knockback if self.player.facingRight else self.player.xPos + knockback
+10
View File
@@ -0,0 +1,10 @@
class Object:
def __init__(self, xPos, yPos, soundName, isStatic=True, isCollectible=False, isHazard=False):
self.xPos = xPos
self.yPos = yPos
self.soundName = soundName
self.isStatic = isStatic
self.isCollectible = isCollectible
self.isHazard = isHazard
self.channel = None # For tracking the sound channel
self.isActive = True
+13
View File
@@ -0,0 +1,13 @@
class Player:
def __init__(self, xPos, yPos):
self.xPos = xPos
self.yPos = yPos
self.moveSpeed = 0.05
self.jumpDuration = 1000 # Jump duration in milliseconds
self.jumpStartTime = 0
self.isJumping = False
self.facingRight = True
self.collectedItems = []
# Track distance for footsteps
self.distanceSinceLastStep = 0
self.stepDistance = 0.5 # Play a step sound every 0.5 units moved
+94
View File
@@ -0,0 +1,94 @@
#!/usr/bin/env python3
import json
import os
from libstormgames import *
from src.level import Level
from src.object import Object
from src.player import Player
class WickedQuest:
def __init__(self):
self.sounds = initialize_gui("Wicked Quest")
self.currentLevel = None
def load_level(self, levelNumber):
levelFile = f"levels/{levelNumber}.json"
try:
with open(levelFile, 'r') as f:
levelData = json.load(f)
self.currentLevel = Level(levelData, self.sounds)
speak(f"Level {levelNumber} loaded")
except FileNotFoundError:
speak("Level not found")
return False
return True
def handle_input(self):
keys = pygame.key.get_pressed()
player = self.currentLevel.player
# Calculate current speed based on jumping state
currentSpeed = player.moveSpeed * 1.5 if player.isJumping else player.moveSpeed
# Track movement distance for this frame
movement = 0
# Horizontal movement
if keys[pygame.K_a]: # Left
movement = currentSpeed
player.xPos -= currentSpeed
player.facingRight = False
elif keys[pygame.K_d]: # Right
movement = currentSpeed
player.xPos += currentSpeed
player.facingRight = True
# Play footstep sounds if moving and not jumping
if movement > 0 and not player.isJumping:
player.distanceSinceLastStep += movement
if player.distanceSinceLastStep >= player.stepDistance:
self.sounds['footstep'].play()
player.distanceSinceLastStep = 0
# Handle jumping
currentTime = pygame.time.get_ticks()
# Start jump
if keys[pygame.K_w] and not player.isJumping:
player.isJumping = True
player.jumpStartTime = currentTime
self.sounds['jump'].play()
# Check if jump should end
if player.isJumping and currentTime - player.jumpStartTime >= player.jumpDuration:
player.isJumping = False
# Reset step distance tracking after landing
player.distanceSinceLastStep = 0
def game_loop(self):
clock = pygame.time.Clock()
while True:
if check_for_exit():
return
self.handle_input()
# Update audio positioning and handle collisions
self.currentLevel.update_audio()
self.currentLevel.handle_collisions()
clock.tick(60) # 60 FPS
def run(self):
while True:
choice = game_menu(self.sounds, "play", "instructions", "learn_sounds", "credits", "donate")
if choice == "play":
if self.load_level(1):
self.game_loop()
if __name__ == "__main__":
game = WickedQuest()
game.run()