Weapons now do different things. Shovels fill in graves, broom gives a speed and jump bonus and nunchucks just thwack things real hard and have best reach.

This commit is contained in:
Storm Dragon
2025-09-07 13:20:49 -04:00
parent cf3f27d9b8
commit 56a78aa4ff
6 changed files with 88 additions and 16 deletions
+30 -2
View File
@@ -16,6 +16,7 @@ class GraveObject(Object):
) )
self.graveItem = item self.graveItem = item
self.isCollected = False # Renamed to match style of isHazard, isStatic etc self.isCollected = False # Renamed to match style of isHazard, isStatic etc
self.isFilled = False # Track if grave has been filled with shovel
self.sounds = sounds self.sounds = sounds
def collect_grave_item(self, player): def collect_grave_item(self, player):
@@ -28,11 +29,38 @@ class GraveObject(Object):
if not self.graveItem or self.isCollected: if not self.graveItem or self.isCollected:
return False return False
# Collect the item if player is ducking # Collect the item if player is ducking, walking (not running), and wielding shovel
if player.isDucking: if (player.isDucking and not player.isRunning and
player.currentWeapon and player.currentWeapon.name == "rusty_shovel"):
self.isCollected = True # Mark as collected when collection succeeds self.isCollected = True # Mark as collected when collection succeeds
return True return True
return False return False
def can_fill_grave(self, player):
"""Check if grave can be filled with shovel.
Returns:
bool: True if grave can be filled, False otherwise
"""
# Can only fill empty graves (no item) that haven't been filled yet
if self.graveItem or self.isFilled:
return False
# Must be ducking, walking (not running), and wielding shovel
return (player.isDucking and not player.isRunning and
player.currentWeapon and player.currentWeapon.name == "rusty_shovel")
def fill_grave(self, player):
"""Fill the grave with dirt using shovel.
Returns:
bool: True if grave was filled successfully
"""
if self.can_fill_grave(player):
self.isFilled = True
self.isHazard = False # No longer a hazard once filled
return True
return False
+12 -1
View File
@@ -417,9 +417,10 @@ class Level:
if obj.isHazard and not self.player.isJumping: if obj.isHazard and not self.player.isJumping:
if isinstance(obj, GraveObject): if isinstance(obj, GraveObject):
can_collect = obj.collect_grave_item(self.player) can_collect = obj.collect_grave_item(self.player)
can_fill = obj.can_fill_grave(self.player)
if can_collect: if can_collect:
# Successfully collected item while ducking # Successfully collected item while ducking with shovel
play_sound(self.sounds[f'get_{obj.graveItem}']) play_sound(self.sounds[f'get_{obj.graveItem}'])
self.player.stats.update_stat('Items collected', 1) self.player.stats.update_stat('Items collected', 1)
# Create PowerUp to handle the item effect # Create PowerUp to handle the item effect
@@ -434,6 +435,16 @@ class Level:
obj.channel = None obj.channel = None
obj.isActive = False # Mark the grave as inactive after collection obj.isActive = False # Mark the grave as inactive after collection
continue continue
elif can_fill and obj.fill_grave(self.player):
# Successfully filled empty grave with shovel
play_sound(self.sounds.get('shovel_dig', obj.soundName)) # Use dig sound if available
self.player.stats.update_stat('Graves filled', 1)
# Stop grave's current audio channel
if obj.channel:
obj_stop(obj.channel)
obj.channel = None
obj.isActive = False # Mark grave as inactive after filling
continue
elif not self.player.isInvincible: elif not self.player.isInvincible:
# Kill player for normal graves or non-ducking collision # Kill player for normal graves or non-ducking collision
play_sound(self.sounds[obj.soundName]) play_sound(self.sounds[obj.soundName])
+24 -8
View File
@@ -158,15 +158,23 @@ class Player:
def get_step_distance(self): def get_step_distance(self):
"""Get step distance based on current speed""" """Get step distance based on current speed"""
weaponBonus = self.currentWeapon.speedBonus if self.currentWeapon else 1.0
totalMultiplier = weaponBonus
if self.isRunning or self.isJumping: if self.isRunning or self.isJumping:
return self.baseStepDistance / self.runMultiplier totalMultiplier *= self.runMultiplier
return self.baseStepDistance
return self.baseStepDistance / totalMultiplier
def get_step_interval(self): def get_step_interval(self):
"""Get minimum time between steps based on current speed""" """Get minimum time between steps based on current speed"""
weaponBonus = self.currentWeapon.speedBonus if self.currentWeapon else 1.0
totalMultiplier = weaponBonus
if self.isRunning or self.isJumping: if self.isRunning or self.isJumping:
return self.baseStepInterval / self.runMultiplier totalMultiplier *= self.runMultiplier
return self.baseStepInterval
return self.baseStepInterval / totalMultiplier
def get_health(self): def get_health(self):
"""Get current health""" """Get current health"""
@@ -181,10 +189,18 @@ class Player:
self._health = self._maxHealth self._health = self._maxHealth
def get_current_speed(self): def get_current_speed(self):
"""Calculate current speed based on state""" """Calculate current speed based on state and weapon"""
baseSpeed = self.moveSpeed baseSpeed = self.moveSpeed
if self.isJumping or self.isRunning: return baseSpeed * self.runMultiplier weaponBonus = self.currentWeapon.speedBonus if self.currentWeapon else 1.0
return baseSpeed
if self.isJumping or self.isRunning:
return baseSpeed * self.runMultiplier * weaponBonus
return baseSpeed * weaponBonus
def get_current_jump_duration(self):
"""Calculate current jump duration based on weapon bonus"""
weaponBonus = self.currentWeapon.jumpDurationBonus if self.currentWeapon else 1.0
return int(self.jumpDuration * weaponBonus)
def set_footstep_sound(self, soundName): def set_footstep_sound(self, soundName):
"""Set the current footstep sound""" """Set the current footstep sound"""
@@ -269,7 +285,7 @@ class Player:
for weapon in self.weapons: for weapon in self.weapons:
if weapon.name == targetWeaponName: if weapon.name == targetWeaponName:
self.equip_weapon(weapon) self.equip_weapon(weapon)
speak(f"Switched to {weapon.name.replace('_', ' ')}") speak(weapon.name.replace('_', ' '))
return True return True
# Weapon not found in inventory # Weapon not found in inventory
+15 -2
View File
@@ -100,7 +100,9 @@ class SaveManager:
'range': weapon.range, 'range': weapon.range,
'attackSound': weapon.attackSound, 'attackSound': weapon.attackSound,
'hitSound': weapon.hitSound, 'hitSound': weapon.hitSound,
'attackDuration': weapon.attackDuration 'attackDuration': weapon.attackDuration,
'speedBonus': getattr(weapon, 'speedBonus', 1.0),
'jumpDurationBonus': getattr(weapon, 'jumpDurationBonus', 1.0)
}) })
return serialized return serialized
@@ -109,13 +111,24 @@ class SaveManager:
from src.weapon import Weapon from src.weapon import Weapon
weapons = [] weapons = []
for data in weapon_data: for data in weapon_data:
# Handle backward compatibility for old saves
speedBonus = data.get('speedBonus', 1.0)
jumpDurationBonus = data.get('jumpDurationBonus', 1.0)
# For old saves, restore proper bonuses for specific weapons
if data['name'] == 'witch_broom' and speedBonus == 1.0:
speedBonus = 1.17
jumpDurationBonus = 1.25
weapon = Weapon( weapon = Weapon(
name=data['name'], name=data['name'],
damage=data['damage'], damage=data['damage'],
range=data['range'], range=data['range'],
attackSound=data['attackSound'], attackSound=data['attackSound'],
hitSound=data['hitSound'], hitSound=data['hitSound'],
attackDuration=data['attackDuration'] attackDuration=data['attackDuration'],
speedBonus=speedBonus,
jumpDurationBonus=jumpDurationBonus
) )
weapons.append(weapon) weapons.append(weapon)
return weapons return weapons
+6 -2
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
class Weapon: class Weapon:
def __init__(self, name, damage, range, attackSound, hitSound, cooldown=500, attackDuration=200): def __init__(self, name, damage, range, attackSound, hitSound, cooldown=500, attackDuration=200, speedBonus=1.0, jumpDurationBonus=1.0):
self.name = name self.name = name
self.damage = damage self.damage = damage
self.range = range # Range in tiles self.range = range # Range in tiles
@@ -9,6 +9,8 @@ class Weapon:
self.hitSound = hitSound self.hitSound = hitSound
self.cooldown = cooldown # Milliseconds between attacks self.cooldown = cooldown # Milliseconds between attacks
self.attackDuration = attackDuration # Milliseconds the attack is active self.attackDuration = attackDuration # Milliseconds the attack is active
self.speedBonus = speedBonus # Speed multiplier when wielding this weapon
self.jumpDurationBonus = jumpDurationBonus # Jump duration multiplier when wielding this weapon
self.lastAttackTime = 0 self.lastAttackTime = 0
self.hitEnemies = set() self.hitEnemies = set()
@@ -35,7 +37,9 @@ class Weapon:
attackSound="player_broom_attack", attackSound="player_broom_attack",
hitSound="player_broom_hit", hitSound="player_broom_hit",
cooldown=500, cooldown=500,
attackDuration=200 attackDuration=200,
speedBonus=1.17, # 17% speed bonus when wielding the broom
jumpDurationBonus=1.25 # 25% longer jump duration for better traversal
) )
def can_attack(self, currentTime): def can_attack(self, currentTime):
+1 -1
View File
@@ -242,7 +242,7 @@ class WickedQuest:
play_sound(self.sounds['jump']) play_sound(self.sounds['jump'])
# Check if jump should end # Check if jump should end
if player.isJumping and currentTime - player.jumpStartTime >= player.jumpDuration: if player.isJumping and currentTime - player.jumpStartTime >= player.get_current_jump_duration():
player.isJumping = False player.isJumping = False
play_sound(self.sounds[player.footstepSound]) # Landing sound play_sound(self.sounds[player.footstepSound]) # Landing sound
# Reset step distance tracking after landing # Reset step distance tracking after landing