Actually found a bug with weapon progression. Made survival mode more random. Graves can now have any item from all levels or be empty. Coffins will always have a random item.
This commit is contained in:
@@ -262,9 +262,8 @@ class Enemy(Object):
|
|||||||
if self.enemyType == "witch":
|
if self.enemyType == "witch":
|
||||||
# Determine which item to drop
|
# Determine which item to drop
|
||||||
hasBroom = any(weapon.originalName == "witch_broom" for weapon in self.level.player.weapons)
|
hasBroom = any(weapon.originalName == "witch_broom" for weapon in self.level.player.weapons)
|
||||||
hasNunchucks = any(weapon.originalName == "nunchucks" for weapon in self.level.player.weapons)
|
# Drop witch_broom if player doesn't have it, otherwise drop cauldron
|
||||||
# Drop witch_broom only if player has neither broom nor nunchucks
|
itemType = "witch_broom" if not hasBroom else "cauldron"
|
||||||
itemType = "witch_broom" if not (hasBroom or hasNunchucks) else "cauldron"
|
|
||||||
|
|
||||||
# Create drop 1-2 tiles away in random direction
|
# Create drop 1-2 tiles away in random direction
|
||||||
direction = random.choice([-1, 1])
|
direction = random.choice([-1, 1])
|
||||||
|
|||||||
@@ -18,8 +18,12 @@ class ItemType(Enum):
|
|||||||
class ItemProperties:
|
class ItemProperties:
|
||||||
"""Manages item properties and availability"""
|
"""Manages item properties and availability"""
|
||||||
|
|
||||||
# Items that can appear in random drops
|
# Items that naturally appear in graves and coffins (excluding special items like extra_life, cauldron, witch_broom)
|
||||||
RANDOM_ELIGIBLE = {ItemType.HAND_OF_GLORY: "hand_of_glory", ItemType.JACK_O_LANTERN: "jack_o_lantern"}
|
RANDOM_ELIGIBLE = {
|
||||||
|
ItemType.HAND_OF_GLORY: "hand_of_glory",
|
||||||
|
ItemType.JACK_O_LANTERN: "jack_o_lantern",
|
||||||
|
ItemType.GUTS: "guts"
|
||||||
|
}
|
||||||
|
|
||||||
# All possible items (including special ones)
|
# All possible items (including special ones)
|
||||||
ALL_ITEMS = {
|
ALL_ITEMS = {
|
||||||
|
|||||||
16
src/level.py
16
src/level.py
@@ -13,6 +13,7 @@ from src.player import Player
|
|||||||
from src.projectile import Projectile
|
from src.projectile import Projectile
|
||||||
from src.powerup import PowerUp
|
from src.powerup import PowerUp
|
||||||
from src.skull_storm import SkullStorm
|
from src.skull_storm import SkullStorm
|
||||||
|
from src.item_types import ItemProperties
|
||||||
|
|
||||||
|
|
||||||
class Level:
|
class Level:
|
||||||
@@ -139,11 +140,24 @@ class Level:
|
|||||||
self.objects.append(graspingHands)
|
self.objects.append(graspingHands)
|
||||||
# Check if this is a grave
|
# Check if this is a grave
|
||||||
elif obj.get("type") == "grave":
|
elif obj.get("type") == "grave":
|
||||||
|
# Handle item spawning with chance (for survival mode)
|
||||||
|
grave_item = None
|
||||||
|
if "item_spawn_chance" in obj:
|
||||||
|
# Survival mode: spawn item based on chance (random items already resolved)
|
||||||
|
spawn_chance = obj.get("item_spawn_chance", 0)
|
||||||
|
if random.randint(1, 100) <= spawn_chance:
|
||||||
|
grave_item = obj.get("item")
|
||||||
|
else:
|
||||||
|
# Story mode: use item as specified
|
||||||
|
grave_item = obj.get("item", None)
|
||||||
|
if grave_item == "random":
|
||||||
|
grave_item = ItemProperties.get_random_item()
|
||||||
|
|
||||||
grave = GraveObject(
|
grave = GraveObject(
|
||||||
xPos[0],
|
xPos[0],
|
||||||
obj["y"],
|
obj["y"],
|
||||||
self.sounds,
|
self.sounds,
|
||||||
item=obj.get("item", None),
|
item=grave_item,
|
||||||
zombieSpawnChance=obj.get("zombie_spawn_chance", 0),
|
zombieSpawnChance=obj.get("zombie_spawn_chance", 0),
|
||||||
)
|
)
|
||||||
# Apply sound overrides if specified
|
# Apply sound overrides if specified
|
||||||
|
|||||||
@@ -20,8 +20,11 @@ class SurvivalGenerator:
|
|||||||
self.enemyTemplates = []
|
self.enemyTemplates = []
|
||||||
self.collectibleTemplates = []
|
self.collectibleTemplates = []
|
||||||
self.hazardTemplates = []
|
self.hazardTemplates = []
|
||||||
|
self.graveTemplates = []
|
||||||
self.ambientSounds = []
|
self.ambientSounds = []
|
||||||
self.footstepSounds = []
|
self.footstepSounds = []
|
||||||
|
self.weaponOverrides = {}
|
||||||
|
self.availableItems = set() # Dynamically discovered items from containers
|
||||||
self.loadLevelData()
|
self.loadLevelData()
|
||||||
self.parseTemplates()
|
self.parseTemplates()
|
||||||
|
|
||||||
@@ -54,12 +57,27 @@ class SurvivalGenerator:
|
|||||||
if "footstep_sound" in data and data["footstep_sound"] not in self.footstepSounds:
|
if "footstep_sound" in data and data["footstep_sound"] not in self.footstepSounds:
|
||||||
self.footstepSounds.append(data["footstep_sound"])
|
self.footstepSounds.append(data["footstep_sound"])
|
||||||
|
|
||||||
|
# Collect weapon overrides (merge from all levels, later levels take precedence)
|
||||||
|
if "weapon_sound_overrides" in data:
|
||||||
|
self.weaponOverrides.update(data["weapon_sound_overrides"])
|
||||||
|
|
||||||
# Parse objects
|
# Parse objects
|
||||||
for obj in data.get("objects", []):
|
for obj in data.get("objects", []):
|
||||||
objCopy = copy.deepcopy(obj)
|
objCopy = copy.deepcopy(obj)
|
||||||
# Add source level information to track difficulty progression
|
# Add source level information to track difficulty progression
|
||||||
objCopy["source_level"] = levelNum
|
objCopy["source_level"] = levelNum
|
||||||
|
|
||||||
|
# Discover items from containers (graves and coffins)
|
||||||
|
if obj.get("type") in ["grave", "coffin"] and "item" in obj:
|
||||||
|
item_name = obj["item"]
|
||||||
|
# Check for sound override (themed equivalent)
|
||||||
|
if "sound_overrides" in obj and "item" in obj["sound_overrides"]:
|
||||||
|
item_name = obj["sound_overrides"]["item"]
|
||||||
|
|
||||||
|
# Exclude special items that should remain rare/exclusive
|
||||||
|
if item_name and item_name != "random" and item_name not in ["extra_life"]:
|
||||||
|
self.availableItems.add(item_name)
|
||||||
|
|
||||||
# Categorize objects
|
# Categorize objects
|
||||||
if "enemy_type" in obj:
|
if "enemy_type" in obj:
|
||||||
self.enemyTemplates.append(objCopy)
|
self.enemyTemplates.append(objCopy)
|
||||||
@@ -67,9 +85,18 @@ class SurvivalGenerator:
|
|||||||
self.collectibleTemplates.append(objCopy)
|
self.collectibleTemplates.append(objCopy)
|
||||||
elif obj.get("type") in ["skull_storm", "catapult", "grasping_hands"]:
|
elif obj.get("type") in ["skull_storm", "catapult", "grasping_hands"]:
|
||||||
self.hazardTemplates.append(objCopy)
|
self.hazardTemplates.append(objCopy)
|
||||||
|
elif obj.get("type") == "grave":
|
||||||
|
self.graveTemplates.append(objCopy)
|
||||||
else:
|
else:
|
||||||
self.objectTemplates.append(objCopy)
|
self.objectTemplates.append(objCopy)
|
||||||
|
|
||||||
|
def get_random_container_item(self):
|
||||||
|
"""Get a random item from items discovered in containers."""
|
||||||
|
if not self.availableItems:
|
||||||
|
# Fallback to original hardcoded items if no items discovered
|
||||||
|
return random.choice(["hand_of_glory", "jack_o_lantern", "guts"])
|
||||||
|
return random.choice(list(self.availableItems))
|
||||||
|
|
||||||
def generate_survival_level(self, difficultyLevel=1, segmentLength=100):
|
def generate_survival_level(self, difficultyLevel=1, segmentLength=100):
|
||||||
"""Generate an endless survival level segment.
|
"""Generate an endless survival level segment.
|
||||||
|
|
||||||
@@ -99,10 +126,15 @@ class SurvivalGenerator:
|
|||||||
if self.footstepSounds:
|
if self.footstepSounds:
|
||||||
levelData["footstep_sound"] = random.choice(self.footstepSounds)
|
levelData["footstep_sound"] = random.choice(self.footstepSounds)
|
||||||
|
|
||||||
|
# Include weapon overrides if any were found
|
||||||
|
if self.weaponOverrides:
|
||||||
|
levelData["weapon_sound_overrides"] = self.weaponOverrides
|
||||||
|
|
||||||
# Calculate spawn rates based on difficulty
|
# Calculate spawn rates based on difficulty
|
||||||
collectibleDensity = max(0.1, 0.3 - (difficultyLevel * 0.02)) # Fewer collectibles over time
|
collectibleDensity = max(0.1, 0.3 - (difficultyLevel * 0.02)) # Fewer collectibles over time
|
||||||
enemyDensity = min(0.8, 0.2 + (difficultyLevel * 0.05)) # More enemies over time
|
enemyDensity = min(0.8, 0.2 + (difficultyLevel * 0.05)) # More enemies over time
|
||||||
hazardDensity = min(0.4, 0.1 + (difficultyLevel * 0.03)) # More hazards over time
|
hazardDensity = min(0.4, 0.1 + (difficultyLevel * 0.03)) # More hazards over time
|
||||||
|
graveDensity = max(0.15, 0.25 - (difficultyLevel * 0.01)) # Moderate grave density, slight decrease over time
|
||||||
objectDensity = max(0.1, 0.2 - (difficultyLevel * 0.01)) # Fewer misc objects over time
|
objectDensity = max(0.1, 0.2 - (difficultyLevel * 0.01)) # Fewer misc objects over time
|
||||||
|
|
||||||
# Generate objects across the segment with buffer zones
|
# Generate objects across the segment with buffer zones
|
||||||
@@ -123,7 +155,10 @@ class SurvivalGenerator:
|
|||||||
elif rand < collectibleDensity + enemyDensity + hazardDensity and self.hazardTemplates:
|
elif rand < collectibleDensity + enemyDensity + hazardDensity and self.hazardTemplates:
|
||||||
obj = self.place_hazard(currentX, difficultyLevel)
|
obj = self.place_hazard(currentX, difficultyLevel)
|
||||||
currentX += random.randint(20, 35)
|
currentX += random.randint(20, 35)
|
||||||
elif rand < collectibleDensity + enemyDensity + hazardDensity + objectDensity and self.objectTemplates:
|
elif rand < collectibleDensity + enemyDensity + hazardDensity + graveDensity and self.graveTemplates:
|
||||||
|
obj = self.place_grave(currentX, difficultyLevel)
|
||||||
|
currentX += random.randint(12, 20)
|
||||||
|
elif rand < collectibleDensity + enemyDensity + hazardDensity + graveDensity + objectDensity and self.objectTemplates:
|
||||||
obj = self.place_object(currentX, difficultyLevel)
|
obj = self.place_object(currentX, difficultyLevel)
|
||||||
currentX += random.randint(12, 20)
|
currentX += random.randint(12, 20)
|
||||||
else:
|
else:
|
||||||
@@ -141,6 +176,11 @@ class SurvivalGenerator:
|
|||||||
}
|
}
|
||||||
levelData["objects"].append(endMarker)
|
levelData["objects"].append(endMarker)
|
||||||
|
|
||||||
|
# Post-process all objects to resolve "random" items to specific items
|
||||||
|
for obj in levelData["objects"]:
|
||||||
|
if obj.get("item") == "random":
|
||||||
|
obj["item"] = self.get_random_container_item()
|
||||||
|
|
||||||
return levelData
|
return levelData
|
||||||
|
|
||||||
def place_collectible(self, xPos, difficultyLevel):
|
def place_collectible(self, xPos, difficultyLevel):
|
||||||
@@ -221,16 +261,34 @@ class SurvivalGenerator:
|
|||||||
|
|
||||||
return obj
|
return obj
|
||||||
|
|
||||||
|
def place_grave(self, xPos, difficultyLevel):
|
||||||
|
"""Place a grave at the given position with scaled difficulty."""
|
||||||
|
template = random.choice(self.graveTemplates)
|
||||||
|
obj = copy.deepcopy(template)
|
||||||
|
|
||||||
|
# Increase zombie spawn chance with difficulty for graves
|
||||||
|
baseChance = obj.get("zombie_spawn_chance", 0)
|
||||||
|
obj["zombie_spawn_chance"] = min(50, baseChance + (difficultyLevel * 2))
|
||||||
|
|
||||||
|
# Add item spawn chance that scales with difficulty (more items later when you need them)
|
||||||
|
baseItemChance = 30 # 30% base chance
|
||||||
|
obj["item_spawn_chance"] = min(70, baseItemChance + (difficultyLevel * 3))
|
||||||
|
obj["item"] = "random" # Will be resolved to specific item in level generation
|
||||||
|
|
||||||
|
# Handle x_range vs single x
|
||||||
|
if "x_range" in obj:
|
||||||
|
rangeSize = obj["x_range"][1] - obj["x_range"][0]
|
||||||
|
obj["x_range"] = [xPos, xPos + rangeSize]
|
||||||
|
else:
|
||||||
|
obj["x"] = xPos
|
||||||
|
|
||||||
|
return obj
|
||||||
|
|
||||||
def place_object(self, xPos, difficultyLevel):
|
def place_object(self, xPos, difficultyLevel):
|
||||||
"""Place a misc object at the given position."""
|
"""Place a misc object at the given position."""
|
||||||
template = random.choice(self.objectTemplates)
|
template = random.choice(self.objectTemplates)
|
||||||
obj = copy.deepcopy(template)
|
obj = copy.deepcopy(template)
|
||||||
|
|
||||||
# Handle graves - increase zombie spawn chance with difficulty
|
|
||||||
if obj.get("type") == "grave":
|
|
||||||
baseChance = obj.get("zombie_spawn_chance", 0)
|
|
||||||
obj["zombie_spawn_chance"] = min(50, baseChance + (difficultyLevel * 2))
|
|
||||||
|
|
||||||
# Handle coffins - make all items random in survival mode
|
# Handle coffins - make all items random in survival mode
|
||||||
if obj.get("type") == "coffin":
|
if obj.get("type") == "coffin":
|
||||||
obj["item"] = "random" # Override any specified item
|
obj["item"] = "random" # Override any specified item
|
||||||
|
|||||||
Reference in New Issue
Block a user