491 lines
15 KiB
Nim
491 lines
15 KiB
Nim
# Lost in the Jungle: a silly little survival game.
|
|
# 2021-03-25 Felix Pleşoianu <https://felix.plesoianu.ro/>
|
|
# Based on the Lua edition. Use as you like, and enjoy!
|
|
|
|
import random, strutils
|
|
|
|
randomize()
|
|
|
|
var fatigue = 0.0
|
|
var health = 5.0
|
|
var bullets = 6
|
|
|
|
var skill = 0.15
|
|
var distance = 50.0
|
|
var hours = 0
|
|
|
|
var chances = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
|
|
|
proc startGame() =
|
|
fatigue = 0.0
|
|
health = 5.0
|
|
bullets = 6
|
|
|
|
skill = 0.15
|
|
distance = float(44 + rand(1..10))
|
|
hours = 0
|
|
|
|
chances = [0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0]
|
|
|
|
func tiredness(fatigue, health: float): string =
|
|
let energy = health - fatigue
|
|
if energy <= 1:
|
|
return "drained"
|
|
elif energy <= 3:
|
|
return "tired"
|
|
else:
|
|
return "fresh"
|
|
|
|
func healthLevel(health: float): string =
|
|
if health < 2:
|
|
return "bad"
|
|
elif health < 4:
|
|
return "decent"
|
|
else:
|
|
return "good"
|
|
|
|
proc status(): (string, string) =
|
|
var status1 =
|
|
"In " & health_level(health) & " health; " &
|
|
tiredness(fatigue, health) &
|
|
". Bullets: " & $bullets &
|
|
". Time: " & $hours & "h."
|
|
var status2 = ""
|
|
if distance >= 35:
|
|
status2 = "Can't see the sky for the forest canopy."
|
|
elif distance >= 15:
|
|
status2 = "Shafts of sunlight mark the path ahead."
|
|
else:
|
|
status2 = "The trees are growing farther apart now."
|
|
return (status1, status2)
|
|
|
|
proc menu(options: varargs[string]): Natural =
|
|
for i, j in options:
|
|
echo i + 1, ") ", j
|
|
while result < 1 or result > len(options):
|
|
stdout.write "\n> "
|
|
try:
|
|
result = abs(parseInt(stdin.readLine))
|
|
except ValueError:
|
|
echo "Please enter a number."
|
|
except EOFError:
|
|
quit 0
|
|
|
|
proc doWalk()
|
|
proc doRest()
|
|
|
|
proc noEncounter() =
|
|
echo "Around you, the jungle looms."
|
|
case menu("March on", "Get some rest")
|
|
of 1: doWalk()
|
|
of 2: doRest()
|
|
else: raiseAssert("Logic error")
|
|
|
|
proc doWalk() =
|
|
if fatigue >= health:
|
|
echo "You can't take another step."
|
|
doRest()
|
|
else:
|
|
let walked = health - fatigue
|
|
distance -= walked
|
|
fatigue += 1
|
|
hours += 1
|
|
if walked <= 1:
|
|
echo "You crawl along tiredly."
|
|
elif walked <= 3:
|
|
echo "You march on, making steady progress."
|
|
else:
|
|
echo "You advance quickly for now..."
|
|
|
|
proc itsVenomous()
|
|
proc fightMonkeys()
|
|
|
|
proc doRest() =
|
|
hours += 1
|
|
|
|
if health < 5:
|
|
health += 0.5
|
|
if health > 5:
|
|
health = 5
|
|
if fatigue >= health:
|
|
fatigue -= 1
|
|
else:
|
|
fatigue -= 0.5
|
|
if fatigue < 0:
|
|
fatigue = 0
|
|
echo "You rest and heal a little."
|
|
else:
|
|
if fatigue >= health:
|
|
fatigue -= 2
|
|
else:
|
|
fatigue -= 1
|
|
if fatigue < 0:
|
|
fatigue = 0
|
|
echo "You get some good rest."
|
|
|
|
let chance = rand(1.0)
|
|
if chance < 0.15:
|
|
echo "But while you were sleeping...\n"
|
|
fightMonkeys()
|
|
elif chance < 0.3:
|
|
echo "But while you were sleeping...\n"
|
|
itsVenomous()
|
|
|
|
proc drinkWater()
|
|
proc noDrinking()
|
|
|
|
proc findWater() =
|
|
echo "You find a pool of water."
|
|
case menu("Drink some", "Leave it")
|
|
of 1: drinkWater()
|
|
of 2: noDrinking()
|
|
else: raiseAssert("Logic error.")
|
|
|
|
proc drinkWater() =
|
|
fatigue -= 2
|
|
if fatigue < 0:
|
|
fatigue = 0
|
|
echo "The water is cool. You feel refreshed."
|
|
if rand(1.0) >= skill:
|
|
echo "But drinking from the pool soon makes you ill."
|
|
echo "At least you learn the signs better."
|
|
health -= 1
|
|
skill += 0.05
|
|
|
|
proc noDrinking() =
|
|
echo "Better not chance taking a drink at this time."
|
|
|
|
proc eatFruit()
|
|
proc noEating()
|
|
|
|
proc findFruit() =
|
|
echo "You find strange fruit."
|
|
case menu("Eat some", "Leave it")
|
|
of 1: eatFruit()
|
|
of 2: noEating()
|
|
else: raiseAssert("Logic error.")
|
|
|
|
proc eatFruit() =
|
|
health += 1
|
|
if health > 5:
|
|
health = 5
|
|
echo "The fruit is tasty. You recover some strength."
|
|
if rand(1.0) >= skill:
|
|
echo "But soon after eating it you feel drowsy."
|
|
echo "At least you learn the signs better."
|
|
fatigue += 2
|
|
skill += 0.05
|
|
|
|
proc noEating() =
|
|
echo "Better not chance taking a bite at this time."
|
|
|
|
const critter = ["A small herbivore", "Some large rodent", "A flightless bird"]
|
|
const action = [" hears your steps and bolts.", " stumbles out of the bushes."]
|
|
|
|
proc shootGame()
|
|
proc chaseGame()
|
|
proc ignoreGame()
|
|
|
|
proc huntGame() =
|
|
echo critter.sample, action.sample
|
|
case menu("Shoot it", "Run after it", "Just move on")
|
|
of 1: shootGame()
|
|
of 2: chaseGame()
|
|
of 3: ignoreGame()
|
|
else: raiseAssert("Logic error.")
|
|
|
|
proc eatGame()
|
|
|
|
proc shootGame() =
|
|
if bullets < 1:
|
|
echo "Click! Click! No more bullets..."
|
|
echo "The lucky creature soon vanishes."
|
|
else:
|
|
bullets -= 1
|
|
echo "You carefully take aim and... BANG!"
|
|
eatGame()
|
|
|
|
proc chaseGame() =
|
|
if fatigue >= health:
|
|
echo "You're too tired to give chase."
|
|
elif rand(1.0) < skill:
|
|
fatigue += 1
|
|
echo "You hunt it down and catch it."
|
|
eatGame()
|
|
else:
|
|
fatigue += 1
|
|
skill += 0.05
|
|
echo "You chase after it, but it's too fast."
|
|
echo "At least you learn new tricks."
|
|
|
|
proc eatGame() =
|
|
hours += 1
|
|
health += 2
|
|
if health > 5:
|
|
health = 5
|
|
echo "Poor critter is tasty roasted on a tiny fire."
|
|
echo "You recover much of your strength."
|
|
|
|
proc ignore_game() =
|
|
echo "You decide against playing hunter right now."
|
|
|
|
proc shootMonkeys()
|
|
proc scareMonkeys()
|
|
proc runAway()
|
|
|
|
proc fightMonkeys() =
|
|
echo "Screaming monkeys come out of nowhere to harass you!"
|
|
case menu("Shoot at them", "Look scary", "Run away")
|
|
of 1: shootMonkeys()
|
|
of 2: scareMonkeys()
|
|
of 3: runAway()
|
|
else: raiseAssert("Logic error.")
|
|
|
|
proc getMauled()
|
|
|
|
proc shootMonkeys() =
|
|
if bullets < 1:
|
|
echo "Click! Click! No more bullets..."
|
|
getMauled()
|
|
else:
|
|
bullets -= 1
|
|
echo "BANG! Your bullet goes crashing through the foliage."
|
|
echo "The monkeys scatter, shrieking even more loudly."
|
|
|
|
proc scareMonkeys() =
|
|
echo "You shout and wave a branch, trying to look bigger."
|
|
if rand(1.0) < skill:
|
|
echo "The monkeys laugh mockingly at you as they scatter."
|
|
else:
|
|
skill += 0.05
|
|
echo "It doesn't seem to be working very well at all."
|
|
getMauled()
|
|
|
|
proc getMauled() =
|
|
health -= 2
|
|
echo "A rain of kicks and bites descends upon you!"
|
|
echo "At long last, the monkeys scatter, shrieking."
|
|
|
|
proc runAway() =
|
|
hours += 1
|
|
fatigue += 1 # Should be less bad than what we're risking.
|
|
echo "You run away blindly, until your lungs burn."
|
|
echo "The chorus of shrieks slowly remains behind."
|
|
|
|
const crawlie = ["giant centipede", "big hairy spider", "colorful snake"]
|
|
|
|
proc removeCrawlie()
|
|
proc waitOutCrawlie()
|
|
|
|
proc itsVenomous() =
|
|
echo "A ", crawlie.sample, " falls on you from above!"
|
|
case menu("Remove it carefully", "Stand still")
|
|
of 1: removeCrawlie()
|
|
of 2: waitOutCrawlie()
|
|
else: raiseAssert("Logic error.")
|
|
|
|
proc removeCrawlie() =
|
|
if rand(1.0) < skill:
|
|
echo "The crawlie wriggles wetly in your grasp. Yuck!"
|
|
else:
|
|
skill += 0.05
|
|
health -= 1.5
|
|
echo "You carefully try to pick up the crawlie, but... OW!"
|
|
echo "It bites! You're poisoned. Burns pretty badly, too."
|
|
echo "At least it's gone now. Hopefully."
|
|
|
|
proc waitOutCrawlie() =
|
|
hours += 1
|
|
fatigue += 1 # Should be less bad than what we're risking.
|
|
echo "You wait tensely for what seems like hours."
|
|
echo "In the end, it's gone, and you're sweating."
|
|
|
|
proc restAtRuins()
|
|
proc searchRuins()
|
|
proc leaveRuins()
|
|
|
|
proc findRuins() =
|
|
echo "You discover ancient ruins..."
|
|
case menu("Rest here", "Search the place", "Just move on")
|
|
of 1: restAtRuins()
|
|
of 2: searchRuins()
|
|
of 3: leaveRuins()
|
|
else: raiseAssert("Logic error.")
|
|
|
|
proc restAtRuins() =
|
|
fatigue -= 1
|
|
if fatigue < 0:
|
|
fatigue = 0
|
|
health += 1
|
|
if health > 5:
|
|
health = 5
|
|
hours += 2
|
|
echo "You sleep undisturbed for once, before moving on."
|
|
|
|
proc searchRuins() =
|
|
hours += 1
|
|
let chance = rand(1.0)
|
|
if chance < 0.3:
|
|
skill += 0.05
|
|
echo "You find old inscriptions teaching about the jungle."
|
|
elif chance < 0.6:
|
|
echo "You find gold and diamonds. Not much use right now."
|
|
else:
|
|
echo "You find nothing of interest this time around."
|
|
|
|
proc leaveRuins() =
|
|
hours += 1
|
|
fatigue += 1
|
|
distance -= 3 # Not too much, because it's for free.
|
|
echo "You march on, emboldened, covering a good distance."
|
|
|
|
proc crossSwamp()
|
|
proc avoidSwamp()
|
|
|
|
proc reachSwamp() =
|
|
echo "A vast swamp bars your way."
|
|
case menu("Risk a crossing", "Go around it")
|
|
of 1: crossSwamp()
|
|
of 2: avoidSwamp()
|
|
else: raiseAssert("Logic error.")
|
|
|
|
proc crossSwamp() =
|
|
if rand(1.0) < skill:
|
|
echo "Somehow you navigate the maze more or less safely."
|
|
else:
|
|
# Probably too harsh since you get tired either way.
|
|
# fatigue++;
|
|
health -= 1
|
|
skill += 0.05
|
|
echo "Mud pulls at your feet, and you nearly drown once."
|
|
echo "Mosquitos besiege you; their bites make you ill."
|
|
hours += 1
|
|
fatigue += 1
|
|
distance -= 5
|
|
echo "It's a scary shortcut to take, but it saves a lot of travel."
|
|
|
|
proc avoidSwamp() =
|
|
fatigue += 1.5 # Should be bad, but not too bad.
|
|
hours += 2
|
|
echo "A long, tiresome detour. Safe, but no closer to your goal."
|
|
|
|
proc shootPlant()
|
|
proc wrestlePlant()
|
|
proc cutPlant()
|
|
|
|
proc triggerPlant() =
|
|
echo "Creeping vines entangle your limbs and drag you down."
|
|
echo "Oh no! It's a man-eating mandragore, and it's hungry!"
|
|
case menu("Shoot it", "Wrestle free", "Cut the vines")
|
|
of 1: shootPlant()
|
|
of 2: wrestlePlant()
|
|
of 3: cutPlant()
|
|
else: raiseAssert("Logic error.")
|
|
|
|
proc getChewedOn()
|
|
|
|
proc shootPlant() =
|
|
if bullets < 1:
|
|
echo "Click! Click! No more bullets..."
|
|
getChewedOn()
|
|
else:
|
|
bullets -= 1
|
|
echo "BANG! You hit the plant's smelly flower dead center."
|
|
echo "It wilts away with a horrible squelching sound."
|
|
|
|
proc wrestlePlant() =
|
|
let energy = (health - fatigue) * 2 / 10
|
|
if rand(1.0) < energy:
|
|
echo "You vigorously pull at the vines, breaking a few."
|
|
echo "The plant soon decides to wait for easier prey."
|
|
else:
|
|
echo "You pull tiredly at the vines. It's not enough."
|
|
getChewedOn()
|
|
fatigue += 1
|
|
|
|
proc cutPlant() =
|
|
fatigue += 1
|
|
if rand(1.0) < skill:
|
|
echo "You expertly hack at the vines with your knife."
|
|
echo "The plant soon decides to wait for easier prey."
|
|
else:
|
|
skill += 0.05
|
|
echo "You clumsily hack at the vines with your knife."
|
|
getChewedOn()
|
|
|
|
proc getChewedOn() =
|
|
health = health - 1
|
|
echo "The plants chews on you with its toothless maw,",
|
|
" burning you with digestive juices before you escape."
|
|
|
|
const encounters = [
|
|
find_water, find_fruit, hunt_game, fight_monkeys,
|
|
its_venomous, find_ruins, reach_swamp, trigger_plant]
|
|
|
|
proc pickEncounter(): proc() =
|
|
for i, ch in chances:
|
|
if rand(1.0) < chances[i]:
|
|
chances[i] /= 5
|
|
return encounters[i]
|
|
else:
|
|
chances[i] += 0.05
|
|
return noEncounter
|
|
|
|
proc playGame() =
|
|
while health > 0 and distance > 0:
|
|
let (status1, status2) = status()
|
|
echo "---\n", status1, "\n", status2, "\n---\n"
|
|
let encounter = pickEncounter()
|
|
encounter()
|
|
|
|
if health <= 0:
|
|
echo "You died in the jungle, after ",
|
|
hours, " hours of struggle."
|
|
echo "No more than ", distance, "km away from safety."
|
|
if bullets == 6:
|
|
echo "Without as much as firing a single bullet."
|
|
echo "Oh well, better luck next time."
|
|
elif distance <= 0:
|
|
echo "At last, the trees open up. You see a village. Saved!"
|
|
echo "Unless it's a hostile tribe? Just kidding. You win!"
|
|
echo "(In ", hours, " hours, with ",
|
|
bullets, " bullets left.)"
|
|
else:
|
|
echo "Game ended abnormally."
|
|
|
|
const intro = """
|
|
You survived the plane crash.
|
|
|
|
With all your gear intact, too:
|
|
|
|
Gun, knife, compass, lighter.
|
|
|
|
But you have no food or water.
|
|
|
|
And a big bad jungle to cross.
|
|
"""
|
|
|
|
const help = """
|
|
The point of the game is to cross the 50Km or so separating you from safety.
|
|
The exact distance varies every time you play.
|
|
|
|
You advance towards the goal by marching on whenever you get the chance.
|
|
But you have to balance your health and fatigue.
|
|
|
|
The worse your health is, the more easily you get tired. It's not possible
|
|
to die from exhaustion though.
|
|
|
|
Being tired all the time will hold you up, allowing more dangers to catch up
|
|
with you and sap your health.
|
|
|
|
Hope this helps. Enjoy!
|
|
"""
|
|
|
|
echo intro
|
|
|
|
case menu("Play", "Help", "Quit")
|
|
of 1: startGame(); playGame()
|
|
of 2: echo "\n", help
|
|
of 3: echo "\nSee you around!"
|
|
else: raiseAssert "Logic error."
|