1
Fork 0
mirror of https://github.com/RGBCube/nu_scripts synced 2025-08-02 15:17:47 +00:00
nu_scripts/games/humlespring/script.nu
Lennart Kiil 67e74c5657
add games folder and simple game demonstrating nu code concepts (#1100)
I'd like to contribute this game.

The code exemplifies several nu concepts.
2025-04-22 18:10:59 -05:00

182 lines
6.6 KiB
Text
Executable file

#!/usr/bin/env nu
# --- Game Data ---
# Define the locations in the village
let map = {
village_square: {
desc: "You are in the charming village square of Humlespring. Cobblestones pave the ground. Paths lead north, east, and west. Olivia is here, looking worried."
exits: { north: "tavern", east: "market", west: "alexander_house" }
items: ["leaflet"]
npcs: {
olivia: "Olivia paces back and forth. 'Oh, Alexander... have you seen Mittens? My cat is missing! I last saw her near the old oak tree by the market.'"
}
},
tavern: {
desc: "The 'Leaky Mug' tavern. It smells faintly of ale and sawdust. The only exit is south."
exits: { south: "village_square" }
items: ["mug"]
npcs: {}
},
market: {
desc: "The village market area. Stalls are mostly empty now, but an old oak tree stands tall nearby. A faint 'meow' can be heard from the tree. The path leads back west."
exits: { west: "village_square" }
items: [] # Mittens isn't an 'item' to take, but is found here
npcs: {}
special: "You look up the old oak tree and see Mittens stuck on a branch! You carefully coax her down." # Add a trigger for this
},
alexander_house: {
desc: "You are outside a small, tidy cottage. This must be Alexander's house. The only exit is east. Alexander is tending his small garden."
exits: { east: "village_square" }
items: ["watering_can"]
npcs: {
alexander: "'Ah, hello!' Alexander says, wiping his brow. 'Lovely day, isn't it? Though Olivia seems quite upset about her cat, Mittens. Maybe check near the big oak by the market?'"
}
}
}
# --- Game State ---
# Player's current status (mutable)
mut player_state = {
location: "village_square" # Starting location ID
inventory: []
found_cat: false
}
# --- Helper Functions ---
# Describe the current location
def describe_location [state: record, map: record] {
let current_loc_id = $state.location
let loc_data = ($map | get $current_loc_id)
# Description
print $loc_data.desc
# Items
if not ($loc_data.items | is-empty) {
print $"You see here: ($loc_data.items | str join ', ')"
}
# NPCs
let npcs = ($loc_data.npcs | columns)
if not ($npcs | is-empty) {
print $"People here: ($npcs | str join ', ')"
}
# Exits
let exits = ($loc_data.exits | columns | str join ', ')
print $"Exits are: ($exits)"
# Check for winning condition trigger
if $current_loc_id == "market" and not $state.found_cat {
print "\nHint: Maybe you should 'search tree'?"
}
}
# Handle player actions are now inlined in the main loop below
# --- Main Game Loop ---
print "Welcome to Humlespring!"
print "-------------------------"
describe_location $player_state $map
loop {
# Get player input
let user_input = (input "> " | str trim)
# Skip empty input
if $user_input == "" { continue }
# Parse input (simple verb-noun)
let parts = ($user_input | split row " ")
let verb = ($parts | get 0 | str downcase)
# Use `get` and `default` for robust noun handling (handles commands with no noun)
let noun = if ($parts | length) > 1 { $parts | get 1 | default "" | str downcase } else {""}
# grab the current location once
let loc_data = ($map | get $player_state.location)
# Handle the action directly in the loop
match $verb {
"quit" | "exit" => {
print "Goodbye!"
exit
}
"look" | "l" => {
describe_location $player_state $map
}
"go" | "move" => {
if ( $noun not-in ( $loc_data.exits | columns )) {
print "You can't go that way."
} else {
let new_loc = ($loc_data.exits | get $noun)
$player_state.location = $new_loc
print $"You go ($noun)."
print "" # line break
describe_location $player_state $map
}
}
"inventory" | "i" => {
if ($player_state.inventory | is-empty) {
print "Your inventory is empty."
} else {
print $"You are carrying: ($player_state.inventory | str join ', ')"
}
}
"take" | "get" => {
if ($loc_data.items | find -r $noun).0? != null {
# Just add to inventory
$player_state.inventory = ($player_state.inventory | append $noun)
print $"You take the ($noun)."
} else {
print $"There is no '($noun)' here to take."
}
}
"talk" => {
if ( $noun not-in ( $loc_data.npcs | columns )) {
print $"You cannot talk to ($noun) " } else {
if ($loc_data.npcs | get $noun) == null {
print $"There is no one called '($noun)' here to talk to."
} else {
print ($loc_data.npcs | get $noun)
}
}
}
"search" => {
if $noun == "tree" and $player_state.location == "market" {
if $player_state.found_cat {
print "You already found Mittens!"
} else {
print ($loc_data | get special)
$player_state.found_cat = true
print "\nMittens purrs happily in your arms. You should return her to Olivia!"
}
} else {
print "You search around, but find nothing special."
}
}
"give" => {
if $noun == "cat" and $player_state.location == "village_square" and $player_state.found_cat {
if ('olivia' in ($loc_data.npcs | columns)) {
print "\nYou give Mittens back to Olivia. She is overjoyed!"
print "'Oh, thank you, thank you!' she cries, hugging her cat. 'You saved her!'"
print "\n*** Congratulations! You completed the adventure! ***"
exit
} else {
print "Olivia isn't here right now."
}
} else if $player_state.found_cat and $noun == "cat" {
print "You need to be in the village square to give the cat back to Olivia."
} else {
print "You don't have that to give, or you can't give it here/now."
}
}
_ => {
print "I don't understand that command. Try: go, look, take, inventory, talk, search, give, quit."
}
}
print "" # Add a newline for better readability
}