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
.gitattributes vendored Normal file
View File

@@ -0,0 +1 @@
*.ogg filter=lfs diff=lfs merge=lfs -text

5
.gitignore vendored Normal file
View File

@@ -0,0 +1,5 @@
__pycache__/
*\.pyc
sounds/rec.sh
*.flac
*.wav

3
.gitmodules vendored Normal file
View File

@@ -0,0 +1,3 @@
[submodule "libstormgames"]
path = libstormgames
url = https://git.stormux.org/storm/libstormgames

36
levels/1.json Normal file
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
}
}

1
libstormgames Submodule

Submodule libstormgames added at 9f03de15b8

BIN
sounds/coin.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
sounds/footstep.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
sounds/game-intro.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
sounds/get_coin.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
sounds/goblin.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
sounds/grave.ogg (Stored with Git LFS) Normal file

Binary file not shown.

BIN
sounds/jump.ogg (Stored with Git LFS) Normal file

Binary file not shown.

0
src/__init__.py Normal file
View File

76
src/level.py Normal file
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
src/object.py Normal file
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
src/player.py Normal file
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
wicked_quest.py Normal file
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()