LiveCode Text Adventure

Posted by Scott McDonald

Time for a break from games with graphics. Here is a simple text adventure. Calling it an adventure is a little generous because there isn't an in-game story, and the only puzzle is finding your way through the rooms to escape. But as a hack and slash text adventure it still fits in the broad category.

The original version of this game is from 1985, before mouse driven interfaces were standard, and so commands were entered by pressing a single key to indicate a command. For example, press N to go North and C to eat. Pressing C to eat shows one problem of such a simple interface, because the letters N, S, E, W were used for the four basic directions, E could not be used for eating. Instead you Consume food, obvious, right?

In this version, this problem is avoided by using a mouse driven interface, with a heap of dedicated buttons. Perhaps this is no more elegant than the original interface, but it is easy to code and allows the entire game to be played with only clicks, and hence, potentially on a touch driven device without a virtual keyboard.

In this game, you are in a castle full of treasure and dangerous creatures. Your goal is to leave the castle, alive. The original game is called "Werewolves and Wanderer" and has a back story about a mysterious faded letter found in a trunk telling a history of royalty, thunderstorms, a witch and a curse. The tired old story doesn't matter here, because this blog is about game programming.

In this game you will see:

  • A two dimensional array used as a room, treasure and monster map
  • A variable used for inventory with boolean operations
  • A single mouseUp handler for all the button presses
  • An interface that does not allow invalid actions
  • The random function used to add an element of unpredictability

Below is the StartGame handler. This handler is called from the openCard handler and when the Play Again button is clicked and calls commands to initialise the rooms, treasure, monsters and the hero (you!). Then ShowStatus displays the description of the room and other important information.

command StartGame
  put false into sGameOver
  ShowStatus true
end StartGame

InitializeRooms puts information about the castle rooms into a list and then scans the list to set up a two dimensional array that is the map of the game. This two step approach is used because the list makes it easy to edit the rooms during development and planning, while the array results in simpler code to control the game.

Each line of the roomData has 7 comma delimited items. Each room is represented by a number. The first line is for room number 1, and the first 4 items are numbers for the rooms that are connected in the directions of North, South, East or West. If the item is 0 that means you cannot go in that direction. For example, in room 1 (the first line of roomData) there is an exit to the south that goes to room 2.

In the castle of this game there is more than one level, so the fifth and sixth items of each line is for the directions Up and Down. In room 1 these items are both 0 because there are no stairs in that room. The last item of the line is the contents of the room. Every room has this value equal to 0 because the rooms are initially empty before they are randomly filled by InitializeTreasure and InitializeMonsters.

Now that you understand the structure of the roomData variable, a pair of repeat loops read the list and convert it to a 2 dimensional array. The first index of the array is the room number, and the second index is a property of the room, i.e. the direction or the contents.

command InitializeRooms
  local roomData,roomNumber,roomProperty
  -- N,S,E,W,U,D
  put 0,2,0,0,0,0,0 & cr & \ -- room 1
  1,3,3,0,0,0,0 & cr & \ -- room 2
  2,0,5,2,0,0,0 & cr & \ -- room 3
  0,5,0,0,0,0,0 & cr & \ -- room 4
  4,0,0,3,15,13,0 & cr & \ -- room 5
  0,0,1,0,0,0,0 & cr & \ -- room 6
  0,8,0,0,0,0,0 & cr & \ -- room 7
  7,10,0,0,0,0,0 & cr & \ -- room 8
  0,19,0,8,0,8,0 & cr & \ -- room 9
  8,0,11,0,19,0,0 & cr & \ -- room 10
  0,0,0,0,0,0,0 & cr & \ -- room 11
  0,0,0,13,0,0,0 & cr & \ -- room 12
  0,0,12,0,5,0,0 & cr & \ -- room 13
  0,15,17,0,0,0,0 & cr & \ -- room 14
  14,0,0,0,0,5,0 & cr & \ -- room 15
  17,0,19,0,0,0,0 & cr & \ -- room 16
  18,16,0,14,0,0,0 & cr & \ --room 17
  0,17,0,0,0,0,0 & cr & \ -- room 18
  0,0,0,16,0,10,0 & cr into roomData --19
  put 1 into roomNumber
  repeat for each line loopRoom in roomData
    put kRoomNorth into roomProperty
    repeat for each item loopData in loopRoom
      put loopData into sRoomArray[roomNumber][roomProperty]
      add 1 to roomProperty
    end repeat
    add 1 to roomNumber
  end repeat
end InitializeRooms

RandomEmptyRoom, InitializeTreasure and InitializeMonsters are listed together below. RandomEmptyRoom returns a number between 1 and 19 (because there are 19 rooms) but has a loop so if the random number is for a room with something already in it, sRoomArray[roomNumber][kRoomContents] is not zero, the loop repeats and picks another number. The loop also continues if the number is the start or exit room which are kept empty.

RandomEmptyRoom is called by InitializeTreasure to put a random number between 11 and 110 into seven rooms. When the contents of a room is a number larger than 10 it is treasure of that amount. Then InitializeMonsters puts one of each of the six different monsters into a random room. Each monster is represented by a number from 1 to 6, so they cannot be confused with the treasure.

function RandomEmptyRoom
  local roomNumber
  put random(19) into roomNumber
  repeat while sRoomArray[roomNumber][kRoomContents] <> 0 or roomNumber = kRoomStart or roomNumber = kRoomExit
    put random(19) into roomNumber
  end repeat
  return roomNumber
end RandomEmptyRoom

command InitializeTreasure
  repeat 7 times
    put random(100) + kMinimumTreasure into sRoomArray[RandomEmptyRoom()][kRoomContents]
  end repeat
end InitializeTreasure

command InitializeMonsters
  repeat with loopMonster = kRat to kWumpus
    put loopMonster into sRoomArray[RandomEmptyRoom()][kRoomContents]
  end repeat
end InitializeMonsters

InitializeHero fills some variables and puts the player in the starting room.

command InitializeHero
  put 100 into sStrength
  put 75 into sWealth
  put 0 into sFood
  put 0 into sInventory
  put 0 into sTally
  put 0 into sMonsterKilled
  put kRoomStart into sCurrentRoom
end InitializeHero

ShowText and ShowTextDelay append text to the text field and make sure the most recent text is visible with the select line. This is a simple way to scroll to the bottom of a field.

ShowScore does a calculation to work out the score based on the number of monster kills and so on, and is called when the game ends, either because you have escaped the castle, or have died from zero strength.

command ShowText pText
  put pText & cr after field "memoOutput"
  select after last char of field "memoOutput"
end ShowText

command ShowTextDelay pText
  put pText & cr after field "memoOutput"
  select after last char of field "memoOutput"
  wait 1 second
end ShowTextDelay

command ShowScore
  local score
  put 30 * sMonsterKilled + 5 * sStrength + 3 * sTally + 2 * sWealth + sFood into score
  ShowText "Your final score is " & score
end ShowScore

ShowRoomDescription is a switch statement that calls ShowText with the description for the room. In a more polished game, I would put the descriptions in a separate plain text file and then load the descriptions into an array. But for a demo game like this, using a handler with the switch statement is more than adequate, even if it is less elegant.

command ShowRoomDescription pRoom
  local description
  switch pRoom
    case 1
      put "You are in the hallway." & cr & cr & "There is a door to the south. The entrance door to the west is locked. Through windows to the north you can see a secret herb garden." into description
    case 2
      put "This is the audience chamber." & cr & cr & "There is a window to the west, by looking to the right through it you can see the entrance to the castle. Doors leave this room to the north, east and south." into description
    case 3
      put "You are in the great hall." & cr & cr & "An L-shaped room, there are doors to the east and to the north. In the alcove is a door to the west." into description
    case 4
      put "This is the monarch's private meeting room. There is a single exit to the south." into description
    case 5
      put "This inner hallway contains a door to the north, and one to the west, and a circular stairwell passes through the room." & cr & cr & "You can see an ornamental lake through the windows to the south." into description
    case 6
      put "You are at the entrance to a forbidding looking stone castle. You are facing east and feel compelled to enter." into description
    case 7
      put "This is the castle's kitchen." & cr & cr & "Through windows in the north wall you can see a secret herb garden. A door leaves the kitchen to the south." into description
    case 8
      put "You are in the store room, amidst spices, vegetables, and vast stacks of flour and other provisions." & cr & cr & "There is a door to the north and one to the south." into description
    case 9
      -- not used
    case 10
      put "You are in the rear vestibule." & cr & cr & "There are windows to the south from which you can see the ornamental lake. There is an exit to the east and north. Dark stairs head updwards." into description
    case 11
      -- exit, no description
    case 12
      put "You are in the dank, dark dungeon." & cr & cr & "There is a single exit, a small hole in the wall towards the West." into description
    case 13
      put "You are in the prison guard room, in the basement of the castle." & cr & cr & "The stairwell ends in this room. There is one other exit, a small hole in the east wall." into description
    case 14
      put "You are in the master bedroom on the upper level of the castle..." & cr & cr & "Looking down from the window to the west can see the entrance to the castle, while the secret herb garden is visible below the north window. There are doors to the east and to the south." into description
    case 15
      put "This is the L-shaped upper hallway." & cr & cr & "To the north is a door, and there is a stairwell in the hall that goes up and down. You can see the lake through the south windows." into description
    case 16
      put "This room was used as the castle treasury in bygone years..." & cr & cr & "There are no windows, just exits to the north and to the east." into description
    case 17
      put "Ooooh... you are in the chambermaid bedroom." & cr & cr & "There is an exit to the west and a doors to the north and south..." into description
    case 18
      put "This tiny room on the upper level is the dressing chamber." & cr & cr & "There is a window to the north, with a view of the herb garden down below. A door leads to the south." into description
    case 19
      put "This is the small room near dark stairs that head down." & cr & cr & "To the west is a door. You can see the lake through the southern windows." into description
  end switch
  ShowText cr & description
end ShowRoomDescription

ShowMonsterDescription is similar to ShowRoomDescription, but also sets the sDanger variable according to how difficult the monster is to defeat. ShowTextDelay is used to add a little suspence when showing the text.

command ShowMonsterDescription pMonster
  put empty into sCreature
  put 0 into sDanger
  switch pMonster
    case kRat
      put "hungry rat" into sCreature
      put 5 into sDanger
    case kBat
      put "vampire bat" into sCreature
      put 10 into sDanger
    case kWerewolf
      put "ferocious werewolf" into sCreature
      put 15 into sDanger
    case kZombie
      put "brain eating zombie" into sCreature
      put 20 into sDanger
    case kSpider
      put "giant spider" into sCreature
      put 25 into sDanger
    case kWumpus
      put "weird Wumpus" into sCreature
      put 30 into sDanger
  end switch
  if sCreature is not empty then
    ShowTextDelay "Danger there is a creature here..."
    ShowTextDelay "It is a " & sCreature & ", the danger level is " & sDanger
  end if
end ShowMonsterDescription

ShowIntroduction tells a story to set the scene.

command ShowIntroduction
  put empty into field "memoOutput"
  ShowText "During a storm your car has broken down near a spooky castle. Stories say this castle was abandoned centuries ago after a curse was placed on the inhabitants by a witch who had been turned out by the king of the castle. "
  ShowText "The king's wife was ailing, and he (wrongly as it turned out) blamed the wise woman for his wife's illness. He thought by throwing the witch out, her malignant influence on his wife would cease. This did not happen, and his wife became more and more ill and finally died."
  ShowText "Her last days were not peaceful. The woman cursed the castle and many odd creatures and ghosts took up residence within it. When the king and his court could stand it no more, they fled from their former home never to be heard of again. The creatures stayed on, living there still. You are about to enter their realm. Can you escape?"
  ShowText empty
end ShowIntroduction

ShowStatus does a few comparisons to see if you are dead or weak, and then shows your inventory followed by the room and monster descriptions. From a programming point of view the most interesting part is the boolean operators used to check what items you have in sInventory and then construct a grammatically acceptable sentence about those items.

command ShowStatus pKeep
  local buffer
  if pKeep <> true then put empty into field "memoOutput"
  if sCurrentRoom = kRoomExit then
    ShowTextDelay "You have found the exit from the castle."
    ShowTextDelay "You succeeded and managed to get out of the castle!"
    put true into sGameOver
    if sStrength < 1 then
      ShowText "You have died of hunger or weakness..."
      put true into sGameOver
      if sStrength < 10 then ShowText "Your strength is running low!"
      ShowText "Your strength is " & sStrength
      ShowText "You have $" & sWealth
      if sFood > 0 then
        if sFood = 1 then
          ShowText "Your provisions sack holds " & sFood & " piece of food"
          ShowText "Your provisions sack holds " & sFood & " pieces of food"
        end if
      end if
      if (sInventory bitAND kArmour) <> 0 then ShowText "You are wearing armour"
      put empty into buffer
      if (sInventory bitAND (kAxe + kSword + kAmulet)) <> 0 then
        if (sInventory bitAND kAxe) <> 0 then put "an axe" after buffer
        if (sInventory bitAND kSword) <> 0 then
          if buffer is not empty then put " and " after buffer
          put "a sword" after buffer
        end if
        if (sInventory bitAND kAmulet) <> 0 then
          if buffer is not empty then put " and " after buffer
          put "the magic amulet" after buffer
        end if
        ShowText "You are carrying " & buffer
      end if
      if (sInventory bitAND kLamp) <> 0 or sCurrentRoom = kRoomStart then
        ShowRoomDescription sCurrentRoom
        ShowText "It is too dark to see clearly!"
      end if
      put sRoomArray[sCurrentRoom][kRoomContents] into sRoomContents
      if sRoomContents > kMinimumTreasure then
        ShowText empty
        ShowText "There is treasure here worth $" & sRoomContents
        ShowText empty
        ShowMonsterDescription sRoomContents
      end if
      ShowText empty
      ShowText "What do you want to do?"
    end if
  end if
end ShowStatus

Then you are asked "What do you want to do?" and UpdateButtons is called. UpdateButtons disables the buttons that do not make sense, or cannot be used at this point in the game. I do not like programs (games and otherwise) that allow you to attempt an action, but then complain that you cannot do that! So while UpdateButtons may look complicated and verbose, it actually makes the rest of the game a lot simpler to code because there is no need to do any error checking, anywhere. The pRun parameter is used by the TryToRun handler mentioned later.

command UpdateButtons pRun
  local monsterInRoom,runaway,canSee
  put pRun = true into runaway
  put (sInventory bitAND kLamp) <> 0 or sCurrentRoom = kRoomStart into canSee
  put sRoomContents > 0 and sRoomContents < kMinimumTreasure into monsterInRoom
  set the enabled of button "butnUp" to (sRoomArray[sCurrentRoom][kRoomUp] <> 0) and (runaway or not monsterInRoom) and canSee and not sGameOver
  set the enabled of button "butnDown" to (sRoomArray[sCurrentRoom][kRoomDown] <> 0) and (runaway or not monsterInRoom) and canSee and not sGameOver
  set the enabled of button "butnNorth" to (sRoomArray[sCurrentRoom][kRoomNorth] <> 0) and (runaway or not monsterInRoom) and canSee and not sGameOver
  set the enabled of button "butnSouth" to (sRoomArray[sCurrentRoom][kRoomSouth] <> 0) and (runaway or not monsterInRoom) and canSee and not sGameOver
  set the enabled of button "butnEast" to (sRoomArray[sCurrentRoom][kRoomEast] <> 0) and (runaway or not monsterInRoom) and canSee and not sGameOver
  set the enabled of button "butnWest" to (sRoomArray[sCurrentRoom][kRoomWest] <> 0) and (runaway or not monsterInRoom) and canSee and not sGameOver
  set the enabled of button "butnFight" to monsterInRoom and not runaway and not sGameOver
  set the enabled of button "butnRun" to monsterInRoom and not runaway and not sGameOver
  set the enabled of button "butnAxe" to false
  set the enabled of button "butnSword" to false
  set the enabled of button "butnPickup" to (sRoomContents >= kMinimumTreasure) and not sGameOver
  set the enabled of button "butnMagic" to ((sInventory bitAND kAmulet) <> 0) and not runaway and not sGameOver
  set the enabled of button "butnEat" to (sFood > 0) and not monsterInRoom and not runaway and not sGameOver
  set the enabled of button "butnBuyFood" to (sWealth >= 2) and not monsterInRoom and not runaway and not sGameOver
  set the enabled of button "butnBuyAxe" to (sWealth >= 10) and ((sInventory bitAND kAxe) = 0) and not monsterInRoom and not runaway and not sGameOver
  set the enabled of button "butnBuyLamp" to (sWealth >= 15) and ((sInventory bitAND kLamp) = 0) and not monsterInRoom and not runaway and not sGameOver
  set the enabled of button "butnBuySword" to (sWealth >= 20) and ((sInventory bitAND kSword) = 0) and not monsterInRoom and not runaway and not sGameOver
  set the enabled of button "butnBuyAmulet" to (sWealth >= 30) and ((sInventory bitAND kAmulet) = 0) and not monsterInRoom and not runaway and not sGameOver
  set the enabled of button "butnBuyArmour" to (sWealth >= 50) and ((sInventory bitAND kArmour) = 0) and not monsterInRoom and not runaway and not sGameOver
end UpdateButtons

With the buttons now ready for clicking on, where should the code be put that responds to each click? One place is in the mouseUp handler of each button. The LiveCode IDE makes this an obvious place. The contextual menu for each button has the Edit Script command that opens the Script Editor and enters a skeleton mouseUp handler. Since the button is the first control to receive that message, it should contain the code, right?

Not necessarily. When developing a small game like this one, I prefer to have all the code in the one place. One pane in the Script Editor with less than a 1000 lines is easy to navigate, and not putting handlers in the buttons means I can change and delete the buttons during development without the worrying about accidentally deleting code. Putting all code in the Card Script, is easier and fits the way I develop. (There are also reasons related to the benefit of separating logic and user interface of a program, but that discussion is not for here.)

Each button receives a mouseUp message when it is clicked, and if there isn't a mouseUp handler in the script of the button, the message continues along the message path where is comes to the mouseUp handler below. The short name of the target is the name of the clicked button and the switch statement executes the required code for each action. Except for the logic required for fighting a monster, the code for each action has not been put in a separate handler. The professional coder in me knows this is not good practice, but with only a few lines in a case statement I am content to leave it like this.

on mouseUp
  local needToUpdateStatus
  put true into needToUpdateStatus
  switch the short name of the target
    case "butnUp"
      put sRoomArray[sCurrentRoom][kRoomUp] into sCurrentRoom
      subtract 5 from sStrength
    case "butnDown"
      put sRoomArray[sCurrentRoom][kRoomDown] into sCurrentRoom
      subtract 5 from sStrength
    case "butnNorth"
      put sRoomArray[sCurrentRoom][kRoomNorth] into sCurrentRoom
      subtract 5 from sStrength
    case "butnSouth"
      put sRoomArray[sCurrentRoom][kRoomSouth] into sCurrentRoom
      subtract 5 from sStrength
    case "butnEast"
      put sRoomArray[sCurrentRoom][kRoomEast] into sCurrentRoom
      subtract 5 from sStrength
    case "butnWest"
      put sRoomArray[sCurrentRoom][kRoomWest] into sCurrentRoom
      subtract 5 from sStrength
    case "butnFight"
      put false into needToUpdateStatus
    case "butnAxe"
      put round(sDanger * 0.8) into sDanger
      set the enabled of button "butnAxe" to false
      set the enabled of button "butnSword" to false
      put false into needToUpdateStatus
    case "butnSword"
      put round(sDanger * 0.75) into sDanger
      set the enabled of button "butnAxe" to false
      set the enabled of button "butnSword" to false
      put false into needToUpdateStatus
    case "butnRun"
      put false into needToUpdateStatus
    case "butnMagic"
      ShowTextDelay "You use the magic amulet to transport you to a random room in the castle..."
      wait 5 seconds
      put random(19) into sCurrentRoom
      repeat while sCurrentRoom = kRoomStart or sCurrentRoom = kRoomExit
        put random(19) into sCurrentRoom
      end repeat
    case "butnPickup"
      add sRoomContents to sWealth
      put 0 into sRoomArray[sCurrentRoom][kRoomContents]
    case "butnEat"
      ShowTextDelay "You eat a piece of food."
      subtract 1 from sFood
      add 5 to sStrength
    case "butnBuyFood"
      subtract 2 from sWealth
      add 1 to sFood
    case "butnBuyAxe"
      subtract 10 from sWealth
      put sInventory bitOR kAxe into sInventory
    case "butnBuyLamp"
      subtract 15 from sWealth
      put sInventory bitOR kLamp into sInventory
    case "butnBuySword"
      subtract 20 from sWealth
      put sInventory bitOR kSword into sInventory
    case "butnBuyAmulet"
      subtract 30 from sWealth
      put sInventory bitOR kAmulet into sInventory
    case "butnBuyArmour"
      subtract 50 from sWealth
      put sInventory bitOR kArmour into sInventory
      put false into needToUpdateStatus
  end switch
  if needToUpdateStatus then ShowStatus
end mouseUp

When a monster is in a room you have a choice of fighting or running away. To make it interesting, you cannot run away every time. I want to allow the player to run away 70% of the time. To do this the random function generates a number between 1 and 100 and then check if the number is less than or equal to 70. If thinking in percentages suits you, this sort of statement is easy to code and understand. On average 70 times out of 100 the comparison will be true, and the other 30 times it is false. Since it is random you cannot be sure what will happen each time, but in general 30% of the time you will be forced to fight.

The true parameter of UpdateButtons means only the relevant direction buttons are enabled. This is to stop you from deciding to add an item to your inventory, such as a sword, just when you need it. When there is a monster in the room you can fight or flee, but you don't have time to eat and do a bit of shopping.

command TryToRun
  if random(100) <= 70 then
    put 0 into sRoomContents
    ShowTextDelay "Which way do you want to flee?"
    UpdateButtons true
    ShowTextDelay "No, you must stand and fight."
  end if
end TryToRun

If you choose, or are forced, to fight PrepareFight is called. This adjusts the level of danger depending on what is in the inventory. Multiplying the danger by a number less than zero for each useful item improves your chances of beating the monster. If you have an axe and sword the Axe and Sword buttons are enabled to allow you choose the weapon to fight with.

command PrepareFight
  if (sInventory bitAND kArmour) <> 0 then
    ShowTextDelay "Your armour increases your chance of success."
    put round(sDanger * 0.75) into sDanger
  end if
  if (sInventory bitAND (kAxe + kSword)) = 0 then
    ShowTextDelay "You have no weapons you must fight with your bare hands."
    put round(sDanger * 1.2) into sDanger
    if (sInventory bitAND (kAxe + kSword)) = kAxe + kSword then
      ShowTextDelay "Which weapon do you want to fight with?"
      set the enabled of button "butnFight" to false
      set the enabled of button "butnRun" to false
      set the enabled of button "butnMagic" to false
      set the enabled of button "butnAxe" to true
      set the enabled of button "butnSword" to true
      if (sInventory bitAND kAxe) <> 0 then
        ShowTextDelay "You have only an axe to fight with."
        put round(sDanger * 0.8) into sDanger
      end if
      if (sInventory bitAND kSword) <> 0 then
        ShowTextDelay "You have only a sword to fight with."
        put round(sDanger * 0.75) into sDanger
      end if
    end if
  end if
end PrepareFight

After sDanger has been calculated the fight begins with ShowFight. If you haven't played this style of game before it may be surprising, but once the fight begins you have no control. Other than choosing your weapon, if you have one, the fight plays out without intervention from the player. Instead a loop is entered and your initial strength, how dangerous the monster is and random numbers determine your fate.

Each time through the loop, there is a 50% chance for these events: the monster wounds you, or you wound it. There is then a 65% chance that the fight continues. When the fight ends there is another random comparison based on how much damage you inflicted on the monster to decide if it is dead. Even if it is, you may still lose if your strength is too low. If the monster defeats you, your strength is halved, and provided it is not too low, you live to continue your adventure.

command ShowFight
  local fighting
  put true into fighting
  repeat while fighting
    if random(100) > 50 then
      ShowTextDelay "The " & sCreature & " attacks."
      ShowTextDelay "You attack."
    end if
    if random(100) > 50 then
      ShowTextDelay "You manage to wound it."
      put round(sDanger * 0.83) into sDanger
    end if
    if random(100) > 50 then
      ShowTextDelay "The monster wounds you."
      subtract 5 from sStrength
    end if
    put random(100) <= 65 into fighting
  end repeat
  if random(16) > sDanger then
    ShowTextDelay "You managed to kill the " & sCreature & "!"
    add 1 to sMonsterKilled
    put 0 into sRoomArray[sCurrentRoom][kRoomContents]
    if sStrength < 6 then
      ShowTextDelay "But..."
    end if
    ShowTextDelay "The " & sCreature & " defeated you and disappeared."
    put 0 into sRoomArray[sCurrentRoom][kRoomContents]
    put sStrength div 2 into sStrength
  end if
  ShowStatus true
end ShowFight

That's it, a small, but complete hack and slash text adventure in just under 500 lines of code. Can you escape the castle, or will a werewolf get the better of you?

Download the complete LiveCode Text Adventure stack made in LiveCode 6.1.2 from here: LiveCode Text Adventure.livecode.

Happy LiveCoding.

Credit: Based on the game "Werewolves and Wanderer" written in Basic from Amstrad Users Omnibus by Martin Fairbanks. 1985.

Tagged: adventure beginner retro text only turn based

Monday, January 20, 2014

0 Responses

Be the first to make a comment.



Legal Stuff

All blog posts are copyright and cannot be re-used without permission. But all the code and scripts are dedicated to the public domain. Use such code and scripts in any way you want, but I am not responsible if they don't work for you.


Further comments or feedback? You can contact me by email at: