DEV Community

Cover image for JavaScript Text Adventure Game
Petrina Ropra
Petrina Ropra

Posted on

JavaScript Text Adventure Game

Intro: This is a small text adventure game created with JavaScript, HTML5, and CSS.

Demo link: https://youtube.com/shorts/F167r8qaQok?feature=share

Note: This could have been done with fewer lines of code. Anyway you take it and do as you please

<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0"> 
    <title>the Old Forest</title>
    <link rel="stylesheet" href="a_new_world.css">
</head>
<body>
    <div id="stage">
        <h1>the Old Forest</h1>
        <img src="" width="400" height="367">
        <p id="output"></p>
        <input id="input" type="text" placeholder="Enter your action...">
        <button>enter</button>
    </div>
    <script src="a_new_world.js"></script>
<body>
</html>
Enter fullscreen mode Exit fullscreen mode
*
{
  font-family: Merriweather;
  font-size: 15px;
  color: #000;  
  padding: 0px;
  margin: 0px;
}

@font-face 
{
  font-family: Merriweather;
  src: url("C:/Users/petix/AppData/Local/Microsoft/Windows/Fonts/Merriweather-Regular.ttf");
}

@font-face 
{
  font-family: Merriweather-Bold;
  src: url("C:/Users/petix/AppData/Local/Microsoft/Windows/Fonts//Merriweather-Bold.ttf");
}

@font-face 
{
  font-family: Ginga;
  src: url("C:/Users/petix/AppData/Local/Microsoft/Windows/Fonts//Ginga.ttf");
}

h1
{
  text-align: center;
  font-family: Ginga;
  font-size: 80px;
  padding-bottom: 10px;
  padding-top: 20px;
  font-weight: normal;
}
em
{
  font-size: 14px;
}
p
{
  width: 300px;
  margin: 0px auto;
}

img
{
  margin: 0px auto;
  display: block;
  margin-bottom: 20px;
}

input
{
  position: absolute;
  bottom: 30px;
  left: 135px;
  width: 160px;
  padding: 2px 2px 2px 5px;
  border: 1px solid black;
  background-color: rgba(255,255,255,0.3);
  -webkit-box-shadow: 5px 5px 3px rgba(0,0,0,0.5);
    -moz-box-shadow: 5px 5px 3px rgba(0,0,0,0.5);
    box-shadow: 3px 3px 5px rgba(0,0,0,0.4);
  margin-top: 20px;
  display: block;
  margin-left: auto;
  margin-right: auto;
}

button
{
  position: absolute;
  bottom: 30px;
  left: 310px;
  height: 25px;
  width: 50px;

  font-family: Merriweather;
    font-size: 14px;
    color: #000;
    border: 1px solid #000;

    -webkit-border-radius: 10px;
    -moz-border-radius: 10px;
    border-radius: 10px;    

    background:-webkit-linear-gradient(top, rgba(255,255,255,0.6), rgba(0,0,0,0.2));
    background:-moz-linear-gradient(top, #a3a3a3, rgba(0,0,0,0.2));
    background: linear-gradient(top, #a3a3a3, rgba(0,0,0,0.2));

    -webkit-box-shadow: 5px 5px 3px rgba(0,0,0,0.5);
    -moz-box-shadow: 5px 5px 3px rgba(0,0,0,0.5);
    box-shadow: 3px 3px 5px rgba(0,0,0,0.4);

    -webkit-user-select: none;
  -moz-user-select: none;
  user-select: none;
  display: block;
  margin: 10px auto 0 auto;
}

body{
    display: flex;
    justify-content: center;
    align-items: center;
    height: 100vh;
    margin: 0;
}


#stage
{
  width: 500px;
  height: 700px;
  background-color: gray;
  position: relative;
  background-image: url("C:/Users/petix/Downloads/page1.png");
  text-align: center;
  padding-bottom: 50px;
}
Enter fullscreen mode Exit fullscreen mode
// Create the map
var map = [];
map[0] = "An old stone keep.";
map[1] = "A deep well.";
map[2] = "A sunny glade.";
map[3] = "A sleeping dragon.";
map[4] = "A narrow pathway.";
map[5] = "A bridge.";
map[6] = "An ancient gate.";
map[7] = "The edge of a river.";
map[8] = "A lonely wooden bench.";
map[9] = "An isolated cottage. Faint music comes from inside.";

// Set the player's start location
var mapLocation = 4;

// Set the images
var images = [];
images[0] = "keep.jpg";
images[1] = "well.jpg";
images[2] = "glade.jpg";
images[3] = "dragon.jpeg";
images[4] = "path.jpg";
images[5] = "bridge.jpg";
images[6] = "gate.jpg";
images[7] = "river.jpg";
images[8] = "bench.jpg";
images[9] = "cottage.jpg";

// Set the new images for when riddles are solved
var solvedImages = [];
solvedImages[0] = "solved_bridge.png"; // Image after solving the first riddle
solvedImages[1] = "solved_river.png";  // Image after solving the second riddle
solvedImages[2] = "solved_dragon.jpeg"; // Image after solving the third riddle

// Set the blocked-path messages
var blockedPathMessages = [];
blockedPathMessages[0] = "The path is blocked by thick brambles.";
blockedPathMessages[1] = "A steep cliff prevents you from going east.";
blockedPathMessages[2] = "The path is flooded and impassable.";
blockedPathMessages[3] = "A large boulder blocks your way.";
blockedPathMessages[4] = "A landslide blocks the path.";
blockedPathMessages[5] = "The way is blocked by a raging fire.";
blockedPathMessages[6] = "The path is covered in ice.";
blockedPathMessages[7] = "A magical barrier blocks your way.";
blockedPathMessages[8] = "A fallen tree blocks the path.";

var riddleSolved = [false, false, false]; // Track which riddles have been solved
var riddleAttempts = [3, 3, 3]; // Track remaining attempts for each riddle

//sets the text that is displayed when the user is at the riddle location
var riddleLocationMessages = [];
riddleLocationMessages[0] = "A huge troll stands in the middle of the bridge blocking your way to the other side. He asks you a riddle.";
riddleLocationMessages[1] = "An eerie looking water nymph stands in the river and prevents you from moving with her magical powers.<br>She asks you a riddle.";
riddleLocationMessages[2] = "You are now in an old castle standing before a dragon sleeping on treasure. A sinister dwarf appears before you and asks you a riddle.";

// Set the positive fate Messages
var positiveFateMessages = [];
positiveFateMessages[0] = "<br>" + "The troll disappears. Now you can walk safely over the bridge.";
positiveFateMessages[1] = "<br>" + "The river nymph disappears.";
positiveFateMessages[2] = "You are suddenly transported back home safely standing in your backyard.";

//set the negative fate messages
var negativeFateMessages = [];
negativeFateMessages[0] = "The troll stomps on the bridge and the bridge broke sending you into the fast-flowing river.";
negativeFateMessages[1] = "The river nymph calls for her other friends and they drown you in the river.";
negativeFateMessages[2] = "The dwarf steals a golden goblet from the dragon and disappears. The dragon wakes up, sees you, and burns you to a crisp.";

// Create the riddles and set their locations
var riddles = [];
riddles[0] = "<em><br>Riddle: Walk right through me, never feel me. Always lurking, never seen. What am I?</em>";
riddles[1] = "<em>Riddle: What always runs but never walks,<br>has a bed but never sleeps?</em>";
riddles[2] = "<em>Riddle: I am always hungry, I must always be fed,<br>The finger I touch will soon turn red.</em>";
var riddleLocations = [5, 7, 3];


var gameLost = false;
var answeredRight = false;

// Create an array of correct answers for the riddles
var riddleAnswers = ["air", "river", "fire"];

// Initialize the player's input
var playersInput = "";

// Initialize the gameMessage
var gameMessage = "";

// Create an array of actions the game understands
// and a variable to store the current action
var actionsIKnow = ["north", "east", "south", "west"];
var action = "";

// An array of items the game understands
// and a variable to store the current item
var answer = "";

// The img element
var image = document.querySelector("img");

// The input and output fields
var output = document.querySelector("#output");
var input = document.querySelector("#input");

// The button
var button = document.querySelector("button");
button.style.cursor = "pointer";
button.addEventListener("click", clickHandler, false);

// Display the player's location
render();

//when the button is pressed this fucntion is called
function clickHandler() {
    playGame();
}

//create a function called playGame
function playGame() {
    // Get the player's input and convert it to lowercase
    playersInput = input.value.toLowerCase();

    // Reset these variables from the previous turn
    gameMessage = "";
    action = "";
    answer = "";

    // Figure out the player's action
    for (var i = 0; i < actionsIKnow.length; i++) {
        if (playersInput.indexOf(actionsIKnow[i]) !== -1) {
            action = actionsIKnow[i];
            break;
        }
    }

    // Figure if the player answered the riddle correctly
    for (var i = 0; i < riddleAnswers.length; i++) {
        if (playersInput.indexOf(riddleAnswers[i]) !== -1) {
            //if the user answers the riddle correctly then
            //the answer variable gets one of the riddle answers 
            answer = riddleAnswers[i];
        }
    }

    // if the player arrives at a riddle location and if it's not solved
    if (riddleLocations.includes(mapLocation) && !riddleSolved[riddleLocations.indexOf(mapLocation)]) {
        //get the index of the riddle location
        var riddleIndex = riddleLocations.indexOf(mapLocation);
        //if the player answered the riddle correctly
        if (answer === riddleAnswers[riddleIndex]) {
            //display a positive fate message
            gameMessage = positiveFateMessages[riddleIndex];
            //mark the riddle as solved
            riddleSolved[riddleIndex] = true;
            riddles[riddleIndex] = ""; // Remove the riddle
            riddleLocationMessages[riddleIndex] = ""; // Remove the riddle location message
            images[mapLocation] = solvedImages[riddleIndex]; // Change the image
            if (riddleIndex === 2) { // Check if the final riddle is solved
                //answeredRight gets true as its value
                answeredRight = true;
            }
        } else {
            //if the player gives a wrong answer attempt will be decreased by one
            riddleAttempts[riddleIndex]--;
            //if the player uses all their attempts
            if (riddleAttempts[riddleIndex] <= 0) {
                //if the riddle location is 5
                if (mapLocation === 5) {
                    //display a negative message
                    gameMessage = negativeFateMessages[0] + "<br>" + " Game over!!";
                    //set gameLost to true
                    gameLost = true;
                //if the riddle location is 7
                } else if (mapLocation === 7) {
                    //display a negative message
                    gameMessage = negativeFateMessages[1] + "<br>" + " Game over!!";
                    //set gameLost to true
                    gameLost = true;
                //if the riddle location is 3 
                } else if (mapLocation === 3) {
                    //display a negative message 
                    gameMessage = negativeFateMessages[2] + "<br>" + " Game over!!";
                    //set gameLost to true
                    gameLost = true;
                }
            } else {
                gameMessage = "Incorrect answer. You have " + riddleAttempts[riddleIndex] + " attempts left.";
            }
        }
    } else {
        // Determine the target location based on the action
        var targetLocation = mapLocation;
        //set the value of blockedPathMessage to an empty string
        var blockedPathMessage = "";

        //display block messages if the user wants to go outside the map area
        switch (action) {
            case "north":
                //move the player up 
                if (mapLocation >= 3) {
                    //
                    targetLocation -= 3;
                } else {
                    blockedPathMessage = blockedPathMessages[0];
                }
                break;
            case "east":
                //move the player right
                if (mapLocation % 3 != 2) {
                    targetLocation += 1;
                } else {
                    blockedPathMessage = blockedPathMessages[1];
                }
                break;
            case "south":
                //move the player down
                if (mapLocation < 6) {
                    targetLocation += 3;
                } else {
                    blockedPathMessage = blockedPathMessages[2];
                }
                break;
            case "west":
                //move the player left
                if (mapLocation % 3 != 0) {
                    targetLocation -= 1;
                } else {
                    blockedPathMessage = blockedPathMessages[3];
                }
                break;
        }

        //if the 
        if (targetLocation === mapLocation) {
            gameMessage = blockedPathMessage;
            // Ensure that the player can only access riddle locations sequentially
        } else if (targetLocation === riddleLocations[1] && !riddleSolved[0]) {
            gameMessage = "You must solve the first riddle before you can proceed.";
        } else if (targetLocation === riddleLocations[2] && !riddleSolved[1]) {
            gameMessage = "You must solve the second riddle before you can proceed.";
        } else {
            mapLocation = targetLocation; // Update the player's location
        }
    }

    // Reset the player's input field to an empty string
    input.value = "";

    // Disable input and button if game is lost or final riddle is solved
    if (gameLost || answeredRight) {
        output.innerHTML = "<br><em>" + gameMessage + "</em>";
        input.disabled = true;
        button.disabled = true;
    }

    // Render the game
    render();
}

function render() {
    // Render the location
    output.innerHTML = " Try any of these words: " + "<br>" + "north, east, south, west";
    image.src = "C:/Users/petix/OneDrive/Desktop/" + images[mapLocation];

    // Display an item if there's one in this location
    var riddleIndex = riddleLocations.indexOf(mapLocation);
    if (riddleIndex !== -1 && riddles[riddleIndex] !== "") {
        output.innerHTML = riddleLocationMessages[riddleIndex] + '<br>' + riddles[riddleIndex];
    }

    // Display the game message
    if (gameLost) {
        output.innerHTML = "<br><em>" + gameMessage + "</em>";
    }
    //if the gameMessage is still empty then display this
    else if(gameMessage) {
        output.innerHTML += "<br><em>" + gameMessage + "</em>";
    }
}

Enter fullscreen mode Exit fullscreen mode

Top comments (1)

Collapse
 
popimet profile image
popimet

Nice work on the text adventure game! It’s always fun to see what can be achieved with JavaScript, HTML5, and CSS. Check out more cool projects and puzzles at riddlemastery.com/!