From 90f14b842e4855f27161da5564931d270d8baab8 Mon Sep 17 00:00:00 2001 From: Storm Dragon Date: Mon, 15 Sep 2025 17:22:47 -0400 Subject: [PATCH] Fixed jumping while ducking bug. Updated level creation documentation. --- levels/README.md | 504 +++++++++++++++++++++++++++++++++-------------- wicked_quest.py | 2 +- 2 files changed, 362 insertions(+), 144 deletions(-) diff --git a/levels/README.md b/levels/README.md index bfca680..ca21bd5 100644 --- a/levels/README.md +++ b/levels/README.md @@ -1,41 +1,44 @@ # Creating Custom Levels for Wicked Quest -Want to add your own levels? It's pretty simple! Every level is a JSON file, and you can create as many as you want. +Want to add your own levels? It's simple! Every level is a JSON file, and you can create as many as you want. ## Getting Started -1. Make a directory under levels/ with your level pack name: - levels/My Cool Levels/ +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. +2. Start with `1.json` in your new directory. Each level after that is numbered in order: `2.json`, `3.json`, etc. ## Basic Level Structure -Every level needs these things: +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 may not leave the level until all enemies have been defeated. Drop custom ambience files, e.g. music or creepy sound track in sounds/ambience. Add custom footstep sounds into the sounds directory. +```json +{ + "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. ## Adding Objects -All objects go in an "objects" list. Here are some examples of what you can add: +All objects go in an `"objects"` list. Here are examples of what you can add: ### Object Positioning @@ -48,81 +51,104 @@ The `y` coordinate determines the vertical layer: - `y: 3` - Elevated level (bone dust, coffins) - `y: 12` - High level (skull storms) -### Bone Dust +### Collectibles - { - "x_range": [5, 8], - "y": 3, - "sound": "bone_dust", - "collectible": true, - "static": true - } +#### Bone Dust +```json +{ + "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. -### Coffins +### Interactive Objects - { - "x": 15, - "y": 3, - "sound": "coffin", - "type": "coffin", - "item": "extra_life" - } +#### Coffins +```json +{ + "x": 15, + "y": 3, + "sound": "coffin", + "type": "coffin", + "item": "extra_life" +} +``` - Items are optional, can be extra_life, hand_of_glory, jack_o_lantern, or anything from graves. +**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 +- `"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 +#### Graves +```json +{ + "x": 35, + "y": 0, + "type": "grave", + "sound": "grave", + "static": true, + "zombie_spawn_chance": 20, + "item": "shin_bone" +} +``` - { - "x": 35, - "y": 0, - "type": "grave", - "sound": "grave", - "static": true, - "zombie_spawn_chance": 20, - "item": "shin_bone" - } - -Zombie spawn chance is 0-100, higher means more zombies. Item is also optional, can be shin_bone, guts, or any item from coffin. +**Grave items available:** +- `"shin_bone"` - Currency for extra lives (100 needed) +- `"guts"` - Health upgrade/restoration +- 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], // patrol or hunting range - "y": 0, - "enemy_type": "goblin", - "health": 4, - "damage": 2, - "attack_range": 1.5, - "attack_pattern": { - "type": "hunter", - "turn_threshold": 5 - } +```json +{ + "x_range": [20, 35], + "y": 0, + "enemy_type": "goblin", + "health": 4, + "damage": 2, + "attack_range": 1.5, + "attack_pattern": { + "type": "hunter", + "turn_threshold": 5 } +} +``` -Attacks can be "hunter" or "patrol". The "patrol" option does not use the "turn_threshold" option. The "turn_threshold" option is how quickly the hunting enemy will turn around to attack the player. Hunters will leave their area to pursue the player once he has entered the enemy's range. +**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 -#### Special Enemy Behaviors - -Enemies can have special behaviors regardless of their type. Here are some examples: - -##### incorporeal Goblin - -``` json +##### Vulnerability System (Ghost-like Enemies) +```json { "x_range": [400, 415], "y": 0, - "enemy_type": "goblin", - "health": 30, + "enemy_type": "ghost", + "health": 60, "damage": 2, "attack_range": 1, "has_vulnerability": true, "is_vulnerable": false, - "vulnerability_duration": 1000, + "vulnerability_duration": 3000, "invulnerability_duration": 5000, "speed_multiplier": 0.8, "attack_cooldown": 1200, @@ -133,99 +159,291 @@ Enemies can have special behaviors regardless of their type. Here are some examp } ``` -##### Spawning Other Enemies (like revenants) +**Vulnerability system:** Enemy alternates between vulnerable and invulnerable states. They can only be damaged when vulnerable (plays `enemy_is_vulnerable.ogg` sound). -You can mix and match these behaviors. For an example of a witch who spawns black cats, see "Wicked Quest/13.json" +##### Enemy Spawning System +```json +{ + "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 -## Sound Requirements for Special Behaviors - -When adding special behaviors to enemies, you'll need corresponding sound files: - -For vulnerability system: -- enemy_is_vulnerable.ogg - Sound when enemy becomes vulnerable - -For spawning behavior: -- enemy_spawn.ogg (optional) - Sound when spawning new enemies - -## Tips for Custom Enemies - -- Balance special behaviors carefully -- Test enemy combinations thoroughly -- Consider providing audio cues for special behaviors -- Remember faster enemies should generally do less damage -- Vulnerability systems work best with higher health values -- Spawning enemies should have lower health to compensate - +**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 - } +```json +{ + "x_range": [40, 60], + "y": 12, + "type": "skull_storm", + "damage": 4, + "maximum_skulls": 2, + "frequency": { + "min": 1, + "max": 4 } +} +``` -The maximum setting is how many skulls can be falling at once. Frequence is the number of seconds that can expire before the next skull falls. - +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. #### Catapult +```json +{ + "x": 55, + "y": 0, + "type": "catapult", + "fire_interval": 4000, + "range": 25 +} +``` - { - "x": 55, - "y": 0, - "type": "catapult", - "fire_interval": 4000, // milliseconds between shots - "range": 25 - } +**Properties:** +- `fire_interval`: Milliseconds between shots +- `range`: How far the catapult can shoot #### Spider Web +```json +{ + "type": "spider_web", + "x": 15, + "y": 0 +} +``` - { - "type": "spider_web", - "x": 15, - "y": 0 - } +Slows player movement and attack speed temporarily when walked over. Automatically spawns a spider enemy at the web location. #### Grasping Hands - - { - "x_range": [40, 60], - "y": 0, - "type": "grasping_hands", - "delay": 1000, - "crumble_speed": 0.065 - } +```json +{ + "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. -## Creating New Enemies +## Level System Flexibility -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 +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: + +```json +{ + "type": "spider_web", + "x": 25, + "y": 3 +} +``` + +**Setup 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. The enemy is internally still a spider but sounds and feels like a mummy emerging from a sarcophagus. The slow down for the player can be because the skeleton is tangled in the mummy wrappings, or perhapse he's tangled in the shattered wood. It also does not float, so players would quickly learn to be war, maybe this coffin is one to just be passed under (low hanging). + +### 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 +- Add `werewolf.ogg` and `werewolf_dies.ogg` to the sounds directory +- Use `"werewolf"` as the `enemy_type` in your level file -## Tips +## Level Design Tips -- Add at least 33 bone dust per level -- Space out hazards to give players a chance -- Enemy health: +### 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 HP + - Mini-bosses: 8-15 HP - Bosses: 40+ HP -- Lock boss levels with "locked": true -- Test your levels thoroughly! +- **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 +``` + +### 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 system allows complete audio customization. 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: + +```json +{ + "level_id": 5, + "name": "The Witch's Domain", + "description": "Dark magic fills the air as you approach the witch's lair. Beware her minions and the cursed ground beneath your feet.", + "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", + "fire_interval": 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) + +Check out the existing Wicked Quest levels for more examples and inspiration! -Check out the Wicked Quest levels for more examples. diff --git a/wicked_quest.py b/wicked_quest.py index faa12f6..a42f64a 100755 --- a/wicked_quest.py +++ b/wicked_quest.py @@ -263,7 +263,7 @@ class WickedQuest: play_sound(self.get_sounds()[player.currentWeapon.attackSound]) # Handle jumping - if (keys[pygame.K_w] or keys[pygame.K_UP]) and not player.isJumping: + if (keys[pygame.K_w] or keys[pygame.K_UP]) and not player.isJumping and not player.isDucking: player.isJumping = True player.jumpStartTime = currentTime play_sound(self.get_sounds()['jump'])