linux-text-games/jungle.lua

514 lines
13 KiB
Lua

-- Lost in the Jungle: a silly little survival game.
-- 2024-03-28 No Time To Play <https://notimetoplay.org/>
-- Port of a Sinclair Basic game. Use as you like, and enjoy!
-- This is an update of the original 2017 port with some fixes.
math.randomseed(os.time())
local fatigue = 0.0
local health = 5.0
local skill = 0.15
local distance = 50.0
local bullets = 6
local hours = 0
local chances = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}
local function start_game()
fatigue = 0.0
health = 5.0
skill = 0.15
bullets = 6
distance = 44 + math.random(11)
hours = 0
chances = {0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0}
end
local function status()
local function tiredness(fatigue, health)
local energy = health - fatigue
if energy <= 1 then
return "drained"
elseif energy <= 3 then
return "tired"
else
return "fresh"
end
end
local function health_level(health)
if health < 2 then
return "bad"
elseif health < 4 then
return "decent"
else
return "good"
end
end
local status1 = (
"In " .. health_level(health) .. " health; "
.. tiredness(fatigue, health)
.. ". Bullets: " .. bullets
.. ". Time: " .. hours .. "h.")
local status2
if distance >= 35 then
status2 = "Can't see the sky for the forest canopy."
elseif distance >= 15 then
status2 = "Shafts of sunlight mark the path ahead."
else
status2 = "The trees are growing farther apart now."
end
return status1, status2
end
local function menu(options)
local choice
repeat
for i, j in ipairs(options) do
print(i .. ") " .. j)
end
io.write("> ")
choice = math.floor(io.read("*n"))
until 1 <= choice and choice <= #options
return choice
end
local function find_water()
local function drink_water()
fatigue = fatigue - 2
if fatigue < 0 then
fatigue = 0
end
print("The water is cool. You feel refreshed.")
if math.random() >= skill then
print("But drinking from the pool soon makes you ill.")
print("At least you learn the signs better.")
health = health - 1
skill = skill + 0.05
end
end
local function no_drinking()
print("Better not chance taking a drink at this time.")
end
print("You find a pool of water.")
local choice = menu{"Drink some", "Leave it"}
local outcome = select(choice, drink_water, no_drinking)
outcome()
end
local function find_fruit()
local function eat_fruit()
health = health + 1
if health > 5 then
health = 5
end
print("The fruit is tasty. You recover some strength.")
if math.random() >= skill then
print("But soon after eating it you feel drowsy.")
print("At least you learn the signs better.")
fatigue = fatigue + 2
skill = skill + 0.05
end
end
local function no_eating()
print("Better not chance taking a bite at this time.")
end
print("You find strange fruit.")
local choice = menu{"Eat some", "Leave it"}
local outcome = select(choice, eat_fruit, no_eating)
outcome()
end
local critter = {"A small herbivore", "Some large rodent", "A flightless bird"}
local action = {" hears your steps and bolts.", " stumbles out of the bushes."}
local function hunt_game()
local function eat_game()
hours = hours + 1
health = health + 2
if health > 5 then
health = 5
end
print("Poor critter is tasty roasted on a tiny fire.")
print("You recover much of your strength.")
end
local function shoot_game()
if bullets < 1 then
print("Click! Click! No more bullets...")
print("The lucky creature soon vanishes.")
else
bullets = bullets - 1
print("You carefully take aim and... BANG!")
eat_game()
end
end
local function chase_game()
if fatigue >= health then
print("You're too tired to give chase.")
elseif math.random() < skill then
fatigue = fatigue + 1
print("You hunt it down and catch it.")
eat_game()
else
fatigue = fatigue + 1
skill = skill + 0.05
print("You chase after it, but it's too fast.")
print("At least you learn new tricks.")
end
end
local function ignore_game()
print("You decide against playing hunter right now.")
end
print(critter[math.random(3)] .. action[math.random(2)])
local choice = menu{"Shoot it", "Run after it", "Just move on"}
local outcome = select(choice, shoot_game, chase_game, ignore_game)
outcome()
end
local function fight_monkeys()
local function get_mauled()
health = health - 2
print("A rain of kicks and bites descends upon you!")
print("At long last, the monkeys scatter, shrieking.")
end
local function shoot_monkeys()
if bullets < 1 then
print("Click! Click! No more bullets...")
get_mauled()
else
bullets = bullets - 1
print "BANG! Your bullet goes crashing through the foliage."
print "The monkeys scatter, shrieking even more loudly."
end
end
local function scare_monkeys()
print("You shout and wave a branch, trying to look bigger.")
if math.random() < skill then
print "The monkeys laugh mockingly at you and scatter."
else
skill = skill + 0.05
print "It doesn't seem to be working very well at all."
get_mauled()
end
end
local function run_away()
hours = hours + 1
fatigue = fatigue + 1 -- Should be less bad than what we're risking.
print("You run away blindly, until your lungs burn.")
print("The chorus of shrieks slowly remains behind.")
end
print("Screaming monkeys come out of nowhere to harass you!")
local choice = menu{"Shoot at them", "Look scary", "Run away"}
local outcome = select(choice, shoot_monkeys, scare_monkeys, run_away)
outcome()
end
local crawlie = {"giant centipede", "big hairy spider", "colorful snake"}
local function its_venomous()
local function remove_crawlie()
if math.random() < skill then
print "The crawlie wriggles wetly in your grasp. Yuck!"
else
skill = skill + 0.05
health = health - 1.5
print "You carefully try to pick up the crawlie, but... OW!"
print "It bites! You're poisoned. Burns pretty badly, too."
end
print "At least it's gone now. Hopefully."
end
local function wait_out_crawlie()
hours = hours + 1
fatigue = fatigue + 1 -- Should be less bad than what we're risking.
print "You wait tensely for what seems like hours."
print "In the end, it's gone, and you're sweating."
end
print("A " .. crawlie[math.random(3)] .. " falls on you from above!")
local choice = menu{"Remove it carefully", "Stand still"}
local outcome = select(choice, remove_crawlie, wait_out_crawlie)
outcome()
end
local function find_ruins()
local function rest_at_ruins()
fatigue = fatigue - 1
if fatigue < 0 then
fatigue = 0
end
health = health + 1
if health > 5 then
health = 5
end
hours = hours + 2
print "You sleep undisturbed for once, before moving on."
end
local function search_ruins()
hours = hours + 1
local chance = math.random()
if chance < 0.3 then
skill = skill + 0.05
print "You find old inscriptions teaching about the jungle."
elseif chance < 0.6 then
print "You find gold and diamonds. Not much use right now."
else
print "You find nothing of interest this time around."
end
end
local function leave_ruins()
hours = hours + 1
fatigue = fatigue + 1
distance = distance - 3 -- Not too much, because it's for free.
print "You march on, emboldened, covering a good distance."
end
print "You discover ancient ruins..."
local choice = menu{"Rest here", "Search the place", "Just move on"}
local outcome = select(choice, rest_at_ruins, search_ruins, leave_ruins)
outcome()
end
local function reach_swamp()
local function cross_swamp()
if math.random() < skill then
print "Somehow you navigate the maze more or less safely."
else
-- Probably too harsh since you get tired either way.
-- fatigue++;
health = health - 1
skill = skill + 0.05
print "Mud pulls at your feet. You nearly drown once."
print "Mosquitos besiege you; their bites make you ill."
end
hours = hours + 1
fatigue = fatigue + 1
distance = distance - 5
print "A scary shortcut to take, but it saves a lot of travel."
end
local function avoid_swamp()
fatigue = fatigue + 1.5 -- Should be bad, but not too bad.
hours = hours + 2
print "A long, tiresome detour. Safe, but no closer to your goal."
end
print "A vast swamp bars your way."
local choice = menu{"Risk a crossing", "Go around it"}
local outcome = select(choice, cross_swamp, avoid_swamp)
outcome()
end
local function trigger_plant()
local function get_chewed_on()
health = health - 1
print "The plants chews on you with its toothless maw,"
print "burning you with digestive juices before you escape."
end
local function shoot_plant()
if bullets < 1 then
print "Click! Click! No more bullets..."
get_chewed_on()
else
bullets = bullets - 1
print "BANG! You hit the plant's smelly flower dead center."
print "It wilts away with a horrible squelching sound."
end
end
local function wrestle_plant()
local energy = (health - fatigue) * 2 / 10
if math.random() < energy then
print "You vigorously pull at the vines, breaking a few."
print "The plant soon decides to wait for easier prey."
else
print "You pull tiredly at the vines. It's not enough."
get_chewed_on()
end
fatigue = fatigue + 1
end
local function cut_plant()
fatigue = fatigue + 1
if math.random() < skill then
print "You expertly hack at the vines with your knife."
print "The plant soon decides to wait for easier prey."
else
skill = skill + 0.05
print "You clumsily hack at the vines with your knife."
get_chewed_on()
end
end
print("Creeping vines entangle your limbs and drag you down.")
print("Oh no! It's a man-eating mandragore, and it's hungry!")
local choice = menu{"Shoot it", "Wrestle free", "Cut the vines"}
local outcome = select(choice, shoot_plant, wrestle_plant, cut_plant)
outcome()
end
local function no_encounter()
local function do_rest()
hours = hours + 1
if health < 5 then
health = health + 0.5
if health > 5 then
health = 5
end
if fatigue >= health then
fatigue = fatigue - 1
else
fatigue = fatigue - 0.5
end
if fatigue < 0 then
fatigue = 0
end
print("You rest and heal a little.")
else
if fatigue >= health then
fatigue = fatigue - 2
else
fatigue = fatigue - 1
end
if fatigue < 0 then
fatigue = 0
end
print("You get some good rest.")
end
if math.random() < chances[4] then
print("But while you were sleeping...\n")
fight_monkeys()
chances[4] = chances[4] / 5
elseif math.random() < chances[5] then
print("But while you were sleeping...\n")
its_venomous()
chances[5] = chances[5] / 5
else
chances[4] = chances[4] + 0.05
chances[5] = chances[5] + 0.05
end
end
local function do_walk()
if fatigue >= health then
print("You can't take another step.")
do_rest()
else
local walked = health - fatigue
distance = distance - walked
fatigue = fatigue + 1
hours = hours + 1
if walked <= 1 then
print("You crawl along tiredly.")
elseif walked <= 3 then
print("You march on, making steady progress.")
else
print("You advance quickly for now...")
end
end
end
print("Around you, the jungle looms.");
local choice = menu{"March on", "Get some rest"}
local outcome = select(choice, do_walk, do_rest)
outcome()
end
local encounters = {
find_water, find_fruit, hunt_game, fight_monkeys,
its_venomous, find_ruins, reach_swamp, trigger_plant}
local function pick_encounter()
for i = 1, #chances do
if math.random() < chances[i] then
chances[i] = chances[i] / 5
return encounters[i]
else
chances[i] = chances[i] + 0.05
end
end
return no_encounter
end
local 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.
]]
local 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!
]]
if arg[1] == "--help" or arg[1] == "-h" then
print(help)
else
print(intro)
start_game()
repeat
status1, status2 = status()
print("---\n" .. status1 .. "\n" .. status2 .. "\n---\n")
local encounter = pick_encounter()
encounter()
until health <= 0 or distance <= 0
if health <= 0 then
print("You died in the jungle, after "
.. hours .. " hours of struggle.")
print("No more than " .. distance .. "km away from safety.")
if bullets == 6 then
print("Without as much as firing a single bullet.")
end
print("Oh well, better luck next time.")
elseif distance <= 0 then
print("At last, the trees open up. You see a village. Saved!")
print("Unless it's a hostile tribe? Just kidding. You win!")
print("(In " .. hours .. " hours, with "
.. bullets .. " bullets left.)")
else
print("Game ended abnormally.")
end
end