How do i simplify this text-based game?

What is this game?

This is a really simple text-based story game.

This game makes use of the output/console of your executor as your game UI, and your only input is literally editing a line in the script.

What i’m trying to achieve

I am trying to simplify my game, by making each function modular, and somehow make everything more compact.

I also somehow wan’t an easier way to build linked paths from each option you pick, such a tree like-table.

This game is basically a single lua script game that can be ran on any Lua based executor, such as this website, or even Roblox Studio!

--------------------------------------------------------------------------------
--==| ▀▀█▀▀ █░░█ █▀▀   █▀▀█ █▀▀▄ ▀█░█▀ █▀▀ █▀▀▄ ▀▀█▀▀ █░░█ █▀▀█ █▀▀ █▀▀    |==--
--==| ░░█░░ █▀▀█ █▀▀   █▄▄█ █░░█ ░█▄█░ █▀▀ █░░█ ░░█░░ █░░█ █▄▄▀ █▀▀ ▀▀█    |==--
--==| ░░▀░░ ▀░░▀ ▀▀▀   ▀░░▀ ▀▀▀░ ░░▀░░ ▀▀▀ ▀░░▀ ░░▀░░ ░▀▀▀ ▀░▀▀ ▀▀▀ ▀▀▀    |==--
--==| █▀▀█ █▀▀   ▀▀█▀▀ █░░█ █▀▀   █░░ █▀▀█ █▀▀ ▀▀█▀▀   █▀▀▄ █▀▀█ █▀▀█ █▀▀▄ |==--
--==| █░░█ █▀▀   ░░█░░ █▀▀█ █▀▀   █░░ █░░█ ▀▀█ ░░█░░   █░░█ █░░█ █░░█ █▀▀▄ |==--
--==| ▀▀▀▀ ▀░░   ░░▀░░ ▀░░▀ ▀▀▀   ▀▀▀ ▀▀▀▀ ▀▀▀ ░░▀░░   ▀░░▀ ▀▀▀▀ ▀▀▀▀ ▀▀▀░ |==--
--==|                                                                      |==--
--==| By Ethanthegrand14                                                   |==--
--------------------------------------------------------------------------------

----------==========[ PLAY ]==========----------

Action = "Blank" 

-------------------------------------------------

-- Execute this code to play the game















----------==========[ SOURCE CODE ]==========----------

GameVersion = 0.1
ValidAction = false

print("--==[ The Adventures of The Lost Noob v" .. GameVersion .." by Ethanthegrand14 ]==--")
print(" ")

-- Default menu --

if Action == "Blank" or Input == "Restart" then
	ValidAction = true
	print("----------==========[ HOW TO PLAY ]==========----------")
	print(" ")
	print("This game is a text based adventure game and is very simple to play!")
	print("To play, you will need to run this game/code, then if you look in your 'output or console' you will see some actions under the 'ACTIONS:' text.")
	print("To use your actions, go to < Action =" .. ' "Blank" ' .. "> and change it to an action you wish to use.")
	print("For example, i have four actions and one of them is 'GoNorth1' and i'd wan't to use it, i'd just simply change < Action ==" .. ' "Blank" ' .. "> to < Action ==" .. ' "GoNorth1" ' .. "> and then i'll run the script again to progress through the game.")
	print("To start the adventure, please pick an action in the 'ACTIONS:' list.")
	print("Enjoy!")
	print(" ")
	print("-------------------------------------------------------")
	print(" ")
	print("ACTIONS:")
	print(" ")
	print("- Play")
end

-- Game --

if Action == "Play" or Input == "GoBack1" then
	ValidAction = true
	print("You are in the middle of a forest you have never seen before.")
	print("You have nothing but a an old compass that will hopefully guide you through your jounrey.")
	print(" ")
	print("Towards 'north' there is nothing but forest")
	print("Towards 'east' there is even more forest")
	print("Towards 'south' there is a small old shack")
	print("Towards 'west' there is a tree with a note on it")
	print(" ")
	print("ACTIONS:")
	print(" ")
	print("- GoNorth1")
	print("- GoEast1")
	print("- GoSouth1")
	print("- GoWest1")
end

-- Middle of the forest --

if Action == "GoNorth1" then
	ValidAction = true
	print("You walk towards more forest, the forest gets darker and thicker the more you travel through it.")
	print("However, there is a small opening in the forest with what seems to looks like a path")
	print(" ")
	print("ACTIONS:")
	print(" ")
	print("- Continue1")
	print("- GoBack1")
end

if Action == "GoEast1" then
	ValidAction = true
	print("This part of the forest is too thick to travel through. You no choice but to go back")
	print(" ")
	print("ACTIONS:")
	print(" ")
	print("- GoBack1")
end

if Action == "GoSouth1" then
	ValidAction = true
	print("You go towards the shack, it is surrounded by very thick forest.")
	print("You walk up the the shack.")
	print("The front door won't open")
	print(" ")
	print("You can either walk around the shack to see if there are any other ways to get in it, or you can 'go back'")
	print(" ")
	print("ACTIONS:")
	print(" ")
	print("- GoEast2")
	print("- GoWest2")
	print("- GoBack1")
end

if Action == "GoWest1" then
	ValidAction = true
	print("You walk to the tree with the note on it.")
	print(" ")
	print("You can either walk around the shack to see if there are any other ways to get in it, or you can 'go back'")
	print(" ")
	print("ACTIONS:")
	print(" ")
	print("- GoEast2")
	print("- GoWest2")
	print("- GoBack1")
end

if not ValidAction then
	print("--<< ERROR: '" .. Input .. "' is not a valid action. Please choose an action lited below the 'ACTIONS:' text! >>--")
	print(" ")
	print("ACTIONS:")
	print(" ")
	print("- Play")
	print("- Restart")
end

-- Middle of the forest --

print(" ")
print("-------------------------------------------------------------------")
3 Likes

There could be many ways to simplify this, but here are some things that popped into my head looking at the code.

You should use condition

elseif

rather than having so many if statements.

Also, rather than skipping a line like that, you can do

local str = "Skip to \na new line and \nanother new line!"
print(string.format(str, "%q"))

and it will skip lines for you. Expected Output:

  1. Skip to
  2. a new line and
  3. another new line!
2 Likes


???

Doesn’t seem to work properly :confused:


Multiline strings

For something like this:

print("You are in the middle of a forest you have never seen before.")
print("You have nothing but a an old compass that will hopefully guide you through your jounrey.")
print(" ")
print("Towards 'north' there is nothing but forest")
print("Towards 'east' there is even more forest")

you could instead do

print([[You are in the middle of a forest you have never seen before.
You have nothing but a an old compass that will hopefully guide you through your jounrey.

Towards 'north' there is nothing but forest
Towards 'east' there is even more forest]])

Locations as objects

The way you’ve structured your code, any action that is valid for one location will be valid for all locations. This is because your game just has a list of valid actions and no concept of “where the player is”, or a “current location”.

rant

To fix this, you’ll need to think about what “makes an action valid”. For example, it’s only valid to go to a location if that location is accessible from the current location. Because of that, it’s sensible to represent each location as some kind of object that keeps track of what other locations are accessible from it. It only make sense to “drink the potion” if the player has an inventory and has the potion in their inventory. So it makes sense to represent the player as some kind of object, and their inventory as some kind of object.

That doesn’t mean you need to use OOP, you can keep it super simple but still much more powerful than your current approach by representing things with tables.

A location represented by a table might look like this:
loc_forest_1 = {
	name = "the forest",

	description = [[
	You are in the middle of a forest you have never seen before.
	You have nothing but a an old compass that will hopefully guide you through your jounrey.
	]],

	exits = {
		{direction = "north", description = "nothing but forest", destination = "loc_forest_2"},
		{direction = "east", description = "even more forest", destination = "loc_forest_3"},
		{direction = "south", description = "a small old shack", destination = "loc_outside_shack"},
		{direction = "west", description = "a tree with a note on it", destination = "loc_note_tree"},
	}
}

If you’re new to tables, this might be throwing you into the deep end :sweat_smile:. Tables within tables within tables. The outermost represents the location itself. Each location has a name, a description and a table of exits. Each exit is itself a table of information, like what direction should be typed to use that exit, a description of the exit, and the name of the location that exit leads to.

Notice how there’s no print statements. That’s because describing a location and what can be done there is the same for every location, we just print some of the data in a specific way. So a single function can describe every location. Each location doesn’t describe how to do anything, it’s just data.

A simple “location description function” might look like this:

function describeLocation( location )
	local messages = {string.format("You enter %s.\n%s", location.name, location.description)}

	for _, exit in pairs(location.exits) do
		table.insert(messages, string.format("To the %s you see %s.", exit.direction, exit.description))
	end

	print(table.concat(messages, "\n"))
end

Which we can call like this: describeLocation(lloc_forest_1).

Which generates this output:

You enter the forest.
You are in the middle of a forest you have never seen before.
You have nothing but a an old compass that will hopefully guide you through your jounrey.
		
To the north you see nothing but forest.
To the east you see even more forest.
To the south you see a small old shack.
To the west you see a tree with a note on it.

Reusing logic

It’s now simple to keep track of which location the player is in:

local currentLocation = loc_forest_1

That makes it possible to only allow the player to use exits in the current location:

function enterLocation( location )
	currentLocation = location
	describeLocation(currentLocation)
end

function useExit(exit_direction)
	local success = false
	for _, exit in pairs(currentLocation.exits) do
		if exit.direction == exit_direction then
			success = true
			enterLocation(locations[exit.destination]) --this assumes all the locations are in a dictionary called "locations"
			break
		end
	end

	if not success then
		print("You can't go that direction.")
	end
end

function parseCommand( cmd )
    --If the command starts with "go ", then the rest of the command should be a direction.
	if string.sub(1, 3) == "go " then
		local direction = string.sub(3, string.len(cmd))
		useExit(direction)
	end
end

Notice how these functions work for all the locations, because we have a structured way of representing each location as a table.

4 Likes

wow, this has taught me a lot! Thank you.

Also i don’t know what is wrong with that website that you were using, but it seems to work fine for me.

1 Like