Files

Creating Custom Levels for Wicked Quest

Want to add your own levels? It's simple! Every level is a JSON file, and you can create as many as you want up to 998. Level 999 is reserved for survival mode.

Getting Started

  1. Create a directory under levels/ with your level pack name:

    levels/My Cool Levels/
    
  2. Start with 1.json in your new directory. Each level after that is numbered in order: 2.json, 3.json, etc. You can also add instructions.txt and credits.txt to the level pack. These items will be shown in the menu for the level pack, e.g. Story Mode, Survival Mode, Instructions, Credits.

Basic Level Structure

Every level needs these essential properties:

{
    "level_id": 1,
    "name": "My Level",
    "description": "Set the scene for your level.",
    "locked": false,
    "player_start": {
        "x": 0,
        "y": 0
    },
    "boundaries": {
        "left": 0,
        "right": 200
    },
    "ambience": "Graveyard Blitz.ogg",
    "footstep_sound": "footstep_stone"
}

If you set locked to true, the player cannot leave the level until all enemies have been defeated. Drop custom ambience files (e.g., music or creepy soundtracks) in sounds/ambience/. Add custom footstep sounds into the sounds/ directory.

Dialogue System

Instead of using a simple "description" field, levels can now include interactive dialogue sequences with the new "dialog" property. This creates immersive story-driven introductions with character conversations:

{
    "level_id": 1,
    "name": "Story Level",
    "dialog": {
        "allow_skip": true,
        "entries": [
            {
                "speaker": "Character Name",
                "text": "This is what the character says."
            },
            {
                "speaker": "Billy Bones",
                "text": "This is the player character's response."
            },
            {
                "text": "A narrative description of what happens.",
                "narrative": true
            },
            {
                "speaker": "Character Name",
                "text": "More dialogue with optional sound effect.",
                "sound": "character_sound"
            }
        ]
    },
    "player_start": {
        "x": 0,
        "y": 0
    }
}

Dialogue Properties:

  • allow_skip: Set to true to let players skip the dialogue sequence
  • entries: Array of dialogue entries that play in sequence
  • speaker: Name of the character speaking (optional for narrative entries)
  • text: The dialogue text to be spoken
  • narrative: Set to true for descriptive text entries (no speaker)
  • sound: Optional sound file to play with this dialogue entry. If no sound is specified, the system will automatically play sounds/dialogue.ogg if it exists.

Note: Levels can include both "description" and "dialog". When both are present, the dialogue plays first, followed by the standard level description message format ("Level X, Name. Description.").

Adding Objects

All objects go in an "objects" list. Here are examples of what you can add:

Object Positioning

Objects can be positioned using either:

  • "x": 15 - Single position for objects like coffins, graves, catapults
  • "x_range": [10, 20] - Range for objects that span multiple positions like bone dust collections, enemy patrol areas, or hazards

The y coordinate determines the vertical layer:

  • y: 0 - Ground level (enemies, graves, catapults)
  • y: 3 - Elevated level (bone dust, coffins)
  • y: 12 - High level (skull storms)

Collectibles

Bone Dust

{
    "x_range": [5, 8],
    "y": 3,
    "sound": "bone_dust",
    "collectible": true,
    "static": true
}

The static property means objects don't move - they stay in their fixed positions. Static objects like bone dust and graves remain stationary, while enemies without this property can move and patrol.

Interactive Objects

Coffins

{
    "x": 15,
    "y": 3,
    "sound": "coffin",
    "type": "coffin",
    "item": "extra_life"
}

Items available for coffins:

  • "extra_life" - Grants an extra life
  • "hand_of_glory" - Provides temporary invincibility
  • "jack_o_lantern" - Throwable projectile
  • "guts" - Increases max health or restores health if at max
  • "cauldron" - Special item
  • "witch_broom" - Weapon upgrade
  • "shin_bone" - Currency for extra lives (100 needed)
  • "guts" - Health upgrade/restoration
  • "random" - Randomly selects from eligible items (default if not specified)

Coffin Behavior: When broken with any weapon, coffins drop their specified item 1-2 tiles away in a random direction. The item bounces and can be collected by walking over it.

Graves

{
    "x": 35,
    "y": 0,
    "type": "grave",
    "sound": "grave",
    "static": true,
    "zombie_spawn_chance": 20,
    "item": "shin_bone"
}

Grave items available:

  • Any item available for coffins

Grave behaviors:

  • zombie_spawn_chance: 0-100, higher means more zombies spawn when walked over
  • Item collection: Duck while walking (not running) with the rusty shovel equipped to safely collect items
  • Grave filling: Duck with shovel over empty graves (no item) to fill them and remove the hazard

Enemies

{
    "x_range": [20, 35],
    "y": 0,
    "enemy_type": "goblin",
    "health": 4,
    "damage": 2,
    "attack_range": 1.5,
    "attack_pattern": {
        "type": "hunter",
        "turn_threshold": 5
    }
}

Attack patterns:

  • "patrol": Enemy moves back and forth within their x_range
  • "hunter": Enemy will leave their area to pursue the player once entered
    • turn_threshold: How quickly hunting enemies turn around to attack (lower = more aggressive)

Advanced Enemy Behaviors

Vulnerability System (Ghost-like Enemies)
{
    "x_range": [400, 415],
    "y": 0,
    "enemy_type": "ghost",
    "health": 60,
    "damage": 2,
    "attack_range": 1,
    "has_vulnerability": true,
    "is_vulnerable": false,
    "vulnerability_duration": 3000,
    "invulnerability_duration": 5000,
    "speed_multiplier": 0.8,
    "attack_cooldown": 1200,
    "attack_pattern": {
        "type": "hunter",
        "turn_threshold": 2
    }
}

Vulnerability system: Enemy alternates between vulnerable and invulnerable states. They can only be damaged when vulnerable (plays enemy_is_vulnerable.ogg sound).

Enemy Spawning System
{
    "x_range": [420, 470],
    "y": 0,
    "enemy_type": "revenant",
    "health": 80,
    "damage": 1,
    "attack_range": 1,
    "attack_pattern": {
        "type": "patrol"
    },
    "can_spawn": true,
    "spawn_type": "zombie",
    "spawn_cooldown": 2500,
    "spawn_chance": 75,
    "spawn_distance": 5
}

Spawning properties:

  • can_spawn: Enable spawning behavior
  • spawn_type: Type of enemy to spawn (e.g., "zombie", "black_cat")
  • spawn_cooldown: Milliseconds between spawn attempts
  • spawn_chance: 0-100 probability of spawning when cooldown expires
  • spawn_distance: How far from the spawner to place new enemies

Example combinations:

  • Witch spawning black cats: High health witch that periodically spawns fast black cats
  • Revenant spawning zombies: Tough enemy that creates zombie minions
  • Any enemy type can spawn any other enemy type

Hazards

Skull Storm

{
    "x_range": [40, 60],
    "y": 12,
    "type": "skull_storm",
    "damage": 4,
    "maximum_skulls": 2,
    "frequency": {
        "min": 1,
        "max": 4
    }
}

The maximum_skulls setting controls how many skulls can be falling simultaneously. frequency is the number of seconds that can elapse before the next skull falls.

Skull Storm Sound Overrides:

{
    "x_range": [40, 60],
    "y": 12,
    "type": "skull_storm",
    "damage": 4,
    "maximum_skulls": 2,
    "frequency": {"min": 1, "max": 4},
    "sound_overrides": {
        "skull_storm": "reindeer",
        "falling_skull": "falling_poop",
        "skull_lands": "poop_splat",
        "end_message": "The reindeer fly away.",
        "hit_message": "Hit by reindeer poop!"
    }
}

Override Properties:

  • skull_storm: Sound when entering the skull storm area
  • falling_skull: Sound of skulls falling (system automatically uses numbered variants: falling_poop1, falling_poop2, etc. if they exist)
  • skull_lands: Sound when skulls hit the ground
  • end_message: TTS message when leaving the skull storm area
  • hit_message: TTS message when hit by a falling skull

Catapult

{
    "x": 55,
    "y": 0,
    "type": "catapult",
    "fireInterval": 4000,
    "range": 25
}

Properties:

  • fireInterval: Milliseconds between shots (note: camelCase, not snake_case)
  • range: How far the catapult can shoot

Spider Web

{
    "type": "spider_web",
    "x": 15,
    "y": 3,
    "sound_overrides": {
        "base": "floating_trap",
        "hit_sound": "trap_trigger",
        "spawn_enemy": "elf"
    }
}

Spider Web Mechanics: Spider webs create interactive traps that can slow player movement and attack speed temporarily when triggered. They automatically spawn an enemy at the web location. When triggered, the player bounces back 3 tiles and may receive a 15-second penalty (half movement speed, double attack time) depending on the slowdown setting.

Y-Position Based Behavior:

  • "y": 0 (Ground Level) - Ground trap that triggers when walking/running. Avoid by jumping over it.
  • "y": > 0 (Air Level) - Air trap that triggers when walking or jumping. Avoid by ducking under it.

Sound Override Properties:

  • "base": Override the ambient web sound (e.g., "floating_trap", "bear_trap")
  • "hit_sound": Override the trigger sound (e.g., "trap_trigger", "snap")
  • "spawn_enemy": Override spawned enemy type ("spider", "elf", "witch")
  • "enemy_stats": Override spawned enemy stats (health, damage, speed_multiplier, attack_range)
  • "slowdown": Override slowdown effect (true/false, defaults to true)

Level Design Guidelines:

  • For traditional spider webs, always use "y": > 0 (air placement) unless you're specifically creating a themed ground trap
  • Ground webs ("y": 0) work well for: bear traps, tripwires, pressure plates, snowdrifts, present piles
  • Air webs ("y": > 0) work well for: hanging webs, floating pods, magical traps, dangling ornaments
  • Slowdown considerations: Use "slowdown": false for traps where the slowdown effect doesn't make thematic sense (stepping on a snowdrift shouldn't entangle you like a web would)

Example Themed Variations: note that in true json you cannot use comments like the // lines here for explanations.

// Christmas snowdrift (ground trap - jump to avoid)
{
    "type": "spider_web",
    "x": 50,
    "y": 0,
    "sound_overrides": {
        "base": "snow_drift",
        "hit_sound": "snow_drift_hit",
        "spawn_enemy": "abominable_snowman",
        "enemy_stats": {
            "health": 12,
            "damage": 3,
            "speed_multiplier": 0.8,
            "attack_range": 1
        },
        "slowdown": false
    }
}

// Floating snow cloud (air trap - duck to avoid)
{
    "type": "spider_web",
    "x": 75,
    "y": 4,
    "sound_overrides": {
        "base": "floating_snow_cloud",
        "hit_sound": "cloud_burst",
        "spawn_enemy": "witch",
        "slowdown": true
    }
}

// Traditional spider web (default behavior)
{
    "type": "spider_web",
    "x": 100,
    "y": 2
}

Grasping Hands

{
    "x_range": [40, 60],
    "y": 0,
    "type": "grasping_hands",
    "delay": 1000,
    "crumble_speed": 0.065
}

The ground crumbles beneath the player as undead hands reach up. The delay is in milliseconds before crumbling starts, and crumble_speed controls how fast the crumbling catches up to the player.

Level System Flexibility

The level system supports complex interactions and behaviors:

Dynamic Item Drops

  • Monsters spawning items: Use enemy spawning system to create enemies that drop items when killed
  • Graves with random loot: Each grave can contain different items collected via specific mechanics

Creative Design Techniques

Coffins That Release Enemies

While not directly supported, you can create the illusion of coffins that release enemies when touched:

{
    "type": "spider_web",
    "x": 25,
    "y": 3,
    "sound_overrides": {
        "base": "coffin",
        "hit_sound": "coffin_shatter",
        "spawn_enemy": "elf"
    }
}

Modern Approach (Recommended): Use sound overrides directly in your JSON for cleaner, more maintainable theming. The above creates a "coffin" that shatters and spawns an enemy when touched.

Legacy Approach: You can still replace sounds in your level pack's sound directory:

  • Replace spiderweb.ogg with coffin.ogg (ambient coffin sound)
  • Replace hit_spiderweb.ogg with coffin_shatter.ogg (break sound)
  • Replace spider.ogg with mummy.ogg (spawned enemy sound)
  • Replace spider_dies.ogg with mummy_dies.ogg (death sound)

Result: Players hear a coffin, when they touch it they hear it shatter, get slowed down (representing the enemy emerging), and a "mummy" automatically spawns from the coffin. Since this uses "y": 3 (air level), players must duck to avoid triggering it - creating the "low hanging coffin" effect you described.

Complex Enemy Combinations

  • Spawner + Vulnerability: Create a tough ghost that spawns minions while alternating between vulnerable states
  • Multi-layered encounters: Combine patrol enemies with hunters and spawners for dynamic battles
  • Progressive difficulty: Later waves can spawn stronger enemy types

Environmental Storytelling

  • Themed hazard combinations: Skull storms over graveyards, catapults defending strategic chokepoints
  • Sound design integration: Custom footsteps and ambience per level

Creating New Enemy Types

Want to add a new enemy type? You'll need two sound files in the sounds/ directory:

  • enemy.ogg - The sound the enemy makes while alive
  • enemy_dies.ogg - The death sound

For example, to add a werewolf enemy:

  • Add werewolf.ogg and werewolf_dies.ogg to the sounds directory
  • Use "werewolf" as the enemy_type in your level file

Level Design Tips

Balance Guidelines

  • Add at least 33 bone dust per level (for extra life economy)
  • Space out hazards to give players a chance to react
  • Enemy health recommendations:
    • Regular enemies: 4-6 HP
    • Mini-bosses: 8-15 HP
    • Bosses: 40+ HP
  • Lock boss levels with "locked": true

Advanced Design Patterns

  • Layered challenges: Combine moving enemies with static hazards
  • Risk/reward decisions: Place valuable items near dangerous enemies
  • Tactical positioning: Use terrain and enemy placement to create strategic choices
  • Escalating difficulty: Gradually introduce new mechanics and combinations

Custom Level Pack Structure

You can keep your levels and sounds separate from the main game. Create a directory structure like this for a pack called "Samhain Showdown":

Directory Structure

levels/Samhain Showdown/
├── 1.json
├── 2.json
├── 3.json
└── end.ogg

sounds/Samhain Showdown/
├── custom_footstep.ogg
├── werewolf.ogg
└── werewolf_dies.ogg

sounds/Samhain Showdown/ambience
├── werewolf_hunting.ogg
├── howling_winds.ogg

Advanced Sound Override System

Beyond simple file replacement, Wicked Quest now supports granular sound overrides directly in your level JSON files. This allows thematic consistency where a catapult becomes a "snowball launcher" or grasping hands become an "avalanche" - same mechanics, different sounds and feel.

Weapon Sound Overrides

Override weapon sounds and names globally for an entire level:

{
    "level_id": 1,
    "name": "Winter Wonderland",
    "weapon_sound_overrides": {
        "rusty_shovel": {
            "name": "rusty snow shovel",
            "attack_sound": "player_snow_shovel_attack",
            "hit_sound": "player_snow_shovel_hit"
        },
        "nunchucks": {
            "name": "ice sickles",
            "attack_sound": "player_ice_sickles_attack",
            "hit_sound": "player_ice_sickles_hit"
        },
        "witch_broom": {
            "name": "snow broom",
            "attack_sound": "player_snow_broom_attack",
            "hit_sound": "player_snow_broom_hit"
        }
    }
}

Weapon Override Properties:

  • name: Display name for the weapon (e.g., "ice sickles" instead of "nunchucks")
  • attack_sound: Sound played when attacking
  • hit_sound: Sound played when hitting an enemy

Weapon Override Persistence: Weapon overrides set in level 1 automatically persist throughout the entire level pack! You only need to define weapon_sound_overrides in your first level (1.json) and all subsequent levels will inherit these themed weapon names.

// In levels/Wicked Christmas/1.json - Sets theme for entire pack
{
    "level_id": 1,
    "weapon_sound_overrides": {
        "rusty_shovel": { "name": "rusty snow shovel" },
        "witch_broom": { "name": "snow broom" },
        "nunchucks": { "name": "ice sickles" }
    }
}

// In levels/Wicked Christmas/2.json - No overrides needed!
{
    "level_id": 2,
    // Weapons automatically use themed names from level 1
}

How it works:

  • Level 1 overrides persist across all levels in the same play session
  • Switching to a different level pack resets weapons to their original names
  • Later levels can still override weapons if you want to change themes mid-pack
  • The system stores the original weapon names internally for proper lookups

Object Sound Overrides

Override sounds for individual objects in your level:

{
    "x": 25,
    "y": 0,
    "type": "catapult",
    "fire_interval": 3000,
    "range": 30,
    "sound_overrides": {
        "base": "snowball_launcher",
        "launch": "snowball_launcher_launch"
    }
}
{
    "x_range": [40, 60],
    "y": 0,
    "type": "grasping_hands",
    "delay": 1000,
    "sound_overrides": {
        "base": "avalanche"
    }
}
{
    "x": 35,
    "y": 0,
    "type": "grave",
    "item": "shin_bone",
    "sound_overrides": {
        "base": "snow_mound",
        "item": "candy_cane"
    }
}

Object Sound Override Properties:

  • base: Override the main ambient sound (e.g., "catapult" → "snowball_launcher")
  • launch: Override launch sound for catapults (e.g., "catapult_launch" → "snowball_launcher_launch")
  • item: Override pickup sound for grave items (e.g., "get_shin_bone.ogg" → "get_candy_cane.ogg")
  • warning_message: Override warning message for grasping hands (e.g., "The ground crumbles as snow begins to avalanche!")
  • death_message: Override death message for grasping hands (e.g., "You vanish under tons of snow!")

Themed Item Equivalents

The sound override system includes intelligent item mapping for crafting consistency. Certain themed items automatically behave like their original counterparts:

Christmas Theme:

  • "candy_cane" → Functions as "shin_bone" (increments shin bone count)
  • "reindeer_guts" → Functions as "guts" (enables nunchucks crafting)

Result: Collecting 2 candy canes + reindeer guts = nunchucks (can be renamed to "ice sickles")

This system allows complete thematic consistency where players collect "2 Candy Canes + Reindeer Guts = Ice Sickles" while preserving all original game mechanics. The mapping works automatically across any level pack - simply use themed item names and they'll function correctly.

Adding New Themed Equivalents: To add your own themed items, modify the themed_mappings in src/powerup.py:

themed_mappings = {
    "your_bone_item": "shin_bone",
    "your_guts_item": "guts",
}

Complete Thematic Example

Here's how to transform a Halloween level into a Christmas level using sound overrides:

{
    "level_id": 1,
    "name": "Winter Siege",
    "description": "Santa's workshop is under attack by snow witches!",
    "weapon_sound_overrides": {
        "rusty_shovel": {
            "name": "snow shovel",
            "attack_sound": "player_snow_shovel_attack",
            "hit_sound": "player_snow_shovel_hit"
        }
    },
    "objects": [
        {
            "x": 25,
            "y": 0,
            "type": "catapult",
            "sound_overrides": {
                "base": "snowball_launcher",
                "launch": "snowball_launcher_launch"
            }
        },
        {
            "x_range": [40, 60],
            "y": 12,
            "type": "skull_storm",
            "sound_overrides": {
                "base": "snowball_storm"
            }
        },
        {
            "x": 75,
            "y": 0,
            "type": "grave",
            "item": "shin_bone",
            "sound_overrides": {
                    "item": "candy_cane"
            }
        },
        {
            "x_range": [90, 110],
            "y": 0,
            "type": "grasping_hands",
            "sound_overrides": {
                "base": "avalanche",
                "warning_message": "The ground crumbles as snow begins to avalanche!",
                "death_message": "You vanish under tons of snow!"
            }
        }
    ]
}

Result:

  • Weapons sound winter-themed when attacking
  • "Catapult" becomes "Snowball Launcher" with appropriate launch sounds
  • "Skull Storm" becomes "Snowball Storm"
  • "Graves" containing "Candy Canes" instead of "Shin Bones" (sound override only - base grave sound unchanged)
  • "Grasping Hands" becomes "Avalanche" with snow-themed death messages
  • All mechanics remain identical - only audio and messaging changes

Legacy Sound Override System

  • Custom ambience: Place in sounds/[Pack Name]/ambience/
  • Custom enemy sounds: Place in sounds/[Pack Name]/
  • Custom footsteps: Reference in level JSON as "footstep_sound"
  • Ending scene: Add end.ogg in the level pack directory

This legacy system allows complete audio customization through file replacement. For example, skull storms could become firestorms just by replacing the skull storm sounds in your pack's sound directory.

Complete Example Level

Here's a comprehensive example showing multiple advanced features:

{
    "level_id": 5,
    "name": "The Witch's Domain",
    "dialog": {
        "allow_skip": true,
        "entries": [
            {
                "speaker": "Ancient Spirit",
                "text": "Mortal skeleton, you dare enter the witch's sacred domain?",
                "sound": "ancient_spirit"
            },
            {
                "speaker": "Billy Bones",
                "text": "I'm looking for trouble, and I think I found it."
            },
            {
                "text": "The air grows thick with dark magic as ancient runes begin to glow.",
                "narrative": true,
                "sound": "magic_ambience"
            },
            {
                "speaker": "Ancient Spirit",
                "text": "Then face the consequences of your boldness. The witch's minions will not show mercy.",
                "sound": "evil_laughter"
            },
            {
                "speaker": "Billy Bones",
                "text": "Good thing I don't need any."
            }
        ]
    },
    "locked": true,
    "player_start": {"x": 0, "y": 0},
    "boundaries": {"left": 0, "right": 300},
    "ambience": "witch_theme.ogg",
    "footstep_sound": "footstep_mud",
    "objects": [
        {
            "x_range": [5, 15],
            "y": 3,
            "sound": "bone_dust",
            "collectible": true,
            "static": true
        },
        {
            "x": 25,
            "y": 3,
            "type": "coffin",
            "item": "hand_of_glory"
        },
        {
            "x": 40,
            "y": 0,
            "type": "grave",
            "zombie_spawn_chance": 50,
            "item": "guts"
        },
        {
            "x_range": [60, 80],
            "y": 0,
            "type": "grasping_hands",
            "delay": 500,
            "crumble_speed": 0.08
        },
        {
            "x": 100,
            "y": 0,
            "type": "catapult",
            "fireInterval": 3000,
            "range": 30
        },
        {
            "x_range": [120, 140],
            "y": 12,
            "type": "skull_storm",
            "damage": 3,
            "maximum_skulls": 3,
            "frequency": {"min": 2, "max": 5}
        },
        {
            "x_range": [200, 250],
            "y": 0,
            "enemy_type": "ghost",
            "health": 40,
            "damage": 2,
            "attack_range": 1.5,
            "has_vulnerability": true,
            "vulnerability_duration": 2000,
            "invulnerability_duration": 4000,
            "can_spawn": true,
            "spawn_type": "zombie",
            "spawn_cooldown": 3000,
            "spawn_chance": 60,
            "spawn_distance": 4,
            "attack_pattern": {"type": "hunter", "turn_threshold": 3}
        },
        {
            "x_range": [260, 290],
            "y": 0,
            "enemy_type": "witch",
            "health": 60,
            "damage": 3,
            "attack_range": 2,
            "can_spawn": true,
            "spawn_type": "black_cat",
            "spawn_cooldown": 4000,
            "spawn_chance": 80,
            "spawn_distance": 6,
            "attack_pattern": {"type": "patrol"}
        }
    ]
}

This example demonstrates:

  • Environmental hazards (grasping hands, skull storm, catapult)
  • Interactive elements (coffin with invincibility, grave with health)
  • Advanced enemies (vulnerable zombie-spawning ghost, cat-spawning witch)
  • Custom audio (themed ambience and footsteps)
  • Strategic design (safe zones, risk/reward placement)

Custom Weapons

Level packs can define custom weapons that players can craft and use alongside the standard weapons (1=shovel, 2=broom, 3=nunchucks). Custom weapons are bound to keys 4-0, giving you 7 additional weapon slots.

Basic Structure

Add a custom_weapons array to your level JSON (typically level 1.json):

{
    "custom_weapons": [
        {
            "key": 4,
            "name": "weapon_internal_name",
            "display_name": "Player Visible Name",
            "damage": 6,
            "range": 3,
            "attack_sound": "sound_name",
            "hit_sound": "sound_name"
        }
    ]
}

Required Fields

  • key - Key binding (4-9 or 0 for key 10)
  • name - Internal weapon name (for game logic)
  • damage - Weapon damage (integer)
  • range - Attack range in tiles (integer)
  • attack_sound - Sound when attacking
  • hit_sound - Sound when hitting enemies

Optional Fields

  • display_name - Name shown to player (defaults to name)
  • weapon_type - "melee" or "projectile" (defaults to "melee")
  • cooldown - Milliseconds between attacks (defaults to 500)
  • attack_duration - Milliseconds attack is active (defaults to 200)
  • speed_bonus - Movement speed multiplier (defaults to 1.0)
  • jump_bonus - Jump duration multiplier (defaults to 1.0)
  • requires - Crafting requirements (defaults to none)
  • craft_sound - Sound when weapon is crafted
  • ammo_type - Ammo type for projectile weapons
  • ammo_cost - Ammo consumed per shot (defaults to 1)
  • projectile_speed - Speed of projectiles (defaults to 0.2)

Melee Weapon Example

{
    "custom_weapons": [
        {
            "key": 4,
            "name": "bone_hatchet",
            "display_name": "blood-stained hatchet",
            "damage": 6,
            "range": 2,
            "attack_sound": "player_hatchet_chop",
            "hit_sound": "player_hatchet_hit",
            "cooldown": 400,
            "speed_bonus": 1.1,
            "requires": {
                "shin_bone": 3,
                "hand_of_glory": 1
            },
            "craft_sound": "get_hatchet"
        }
    ]
}

Projectile Weapon Example

{
    "custom_weapons": [
        {
            "key": 6,
            "name": "bone_crossbow",
            "display_name": "cursed crossbow",
            "weapon_type": "projectile",
            "damage": 12,
            "range": 8,
            "attack_sound": "crossbow_fire",
            "hit_sound": "crossbow_impact",
            "cooldown": 1500,
            "attack_duration": 100,
            "ammo_type": "shin_bone",
            "ammo_cost": 3,
            "projectile_speed": 0.3,
            "requires": {
                "shin_bone": 5,
                "guts": 2
            },
            "craft_sound": "get_crossbow"
        }
    ]
}

Crafting System

Weapons with requires are automatically crafted when the player has the necessary materials:

Supported Ammo/Material Types:

  • shin_bone - Shin bones collected
  • bone_dust - Bone dust for extra lives
  • guts - Health/crafting items
  • hand_of_glory - Collectible items
  • jack_o_lantern - Throwable projectiles
  • Any other item type in collectedItems

Crafting Behavior:

  • Materials are NOT consumed (items keep their original functions)
  • Weapons auto-craft when requirements are met
  • Each weapon can only be crafted once per playthrough
  • Crafting plays the craft_sound if specified

Projectile Weapons

Projectile weapons (weapon_type: "projectile") fire projectiles instead of melee attacks:

  • Ammo Consumption - Each shot consumes ammo_cost of ammo_type
  • Out of Ammo - Shows themed message: "Not enough candy canes"
  • Inventory Display - Press 'c' to see current ammo counts
  • High Damage - Usually more powerful than melee weapons
  • Strategic Cost - Must balance ammo usage vs. other needs

Weapon Override Integration

Custom weapons work with the weapon override system. You can theme custom weapons just like standard ones:

{
    "weapon_sound_overrides": {
        "bone_hatchet": {
            "name": "ice hatchet",
            "attack_sound": "player_ice_hatchet_chop",
            "hit_sound": "player_ice_hatchet_hit"
        }
    }
}

Key Binding Reference

  • 1-3: Reserved for standard weapons (shovel, broom, nunchucks)
  • 4-9: Custom weapon slots (6 weapons)
  • 0: Custom weapon slot (key 10, for 7th weapon)

Design Tips

Balanced Progression:

  • Early weapons: Low requirements, moderate power
  • Mid weapons: Medium requirements, good utility
  • Late weapons: High requirements, devastating power

Ammo Economics:

  • Cheap ammo: bone_dust (common)
  • Expensive ammo: shin_bone (valuable for lives)
  • Special ammo: guts, hand_of_glory (limited)

Check out the existing Wicked Quest levels for more examples and inspiration!