514 lines
13 KiB
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
|