Can I teleport using lists?

Teleporting using lists.

At the moment, I'm trying to develop a system that uses lists and the ShowMenu function to teleport.

I really want to teleport like they do in the Elder Scrolls and the Fallout games, by only teleporting to locations you've visited.
(Don't be like my dad who says teleporting is bad, and then he teleports in the game...)

This is just what was in the Start script.

rooms = NewStringList()
list add (rooms, The Lab)

And this is what happens when you step into the teleport location.

list add (rooms, Teleport 1)

And this is what the first teleport command looks like.

ShowMenu ("Teleport", rooms, true) {
  switch (result) {
    case ("Teleport 1") {
      MoveObject (player, Teleport 1)
    }
    default {
      msg ("...It didn't work...")
    }
  }
}

Should I be using multiple teleport commands? And... I'd like general advice too...

Game link http://textadventures.co.uk/games/view/5jllte-m4e2e2whw4gf5jq/pokemon-type-harley-johto-and-sinnoh


I'm not sure why it's a string list. Wouldn't an objectlist be better?

Starting with:

game.teleportlocations = NewObjectList()

then add rooms to the list with:

list add (game.teleportlocations, Some Room)

and then your teleport command is:

ShowMenu ("Where to?", game.teleportlocations, true) {
  MoveObject (game.pov, GetObject(result))
}

(I guess it doesn't matter that much if you use a stringlist or objectlist; though it makes it easier to give particular locations a different colour in the menu. But I'm not sure what that switch statement is for)


Not sure. Will try it out.

I'm just really wondering how this will go if I go to new locations...


It looks like you're using the switch because you're planning on having a case for each location you can teleport to.

The string list would work this way, but you'd have to edit the script each time you added a new destination. (This sets you up for extra work when/if you want to add a new destination later on.)

switch (result) {
    case ("Teleport 1") {
      MoveObject (player, Teleport 1)
    }

This sets up a local variable, rooms, as a string list, then tries to add the object The Lab to it.

rooms = NewStringList()
list add (rooms, The Lab)

That throws this error:

Error running script: Unable to cast object of type 'TextAdventures.Quest.Element' to type 'System.String'.

Also, if you alter it so it works (make it an object list or add The Lab.name instead of The Lab), once this script has run, rooms no longer exists. So, it will throw this error when entering Teleport 1:

Error running script: Error compiling expression 'rooms': Unknown object or variable 'rooms'

That's why mrangel went with game.teleportlocations instead of just teleportlocations. (You could just as easily make it game.rooms, or whatever you'd like the list to be named, as long as you set it up as an attribute on an object, like the game object. This makes it a global variable, so it will be accessible throughout the game.)


From here on, I'm using the result from ShowMenu (bypassing the switch script), just as mrangel did. This makes it so you can just add to the list game.room at any time, and you can teleport there without changing anything else. (You could also alter the list, adding or removing destinations, during the game very easily this way.)


So, let's try out mrangel's method, only with your room names and words and with game.rooms as the list name.

NOTE: I added can_teleport to the rooms you can teleport from, so you'll only need one command to handle everything.

    <start type="script">
      game.rooms = NewObjectList()
      list add (game.rooms, The Lab)
      The Lab.can_teleport = true
      Teleport 1.can_teleport = true
    </start>
  <object name="The Lab">
    <inherit name="editor_room" />
  </object>
  <object name="Teleport 1">
    <inherit name="editor_room" />
    <beforefirstenter type="script">
      list add (game.rooms, Teleport 1)
    </beforefirstenter>
  </object>
  <command name="teleport">
    <pattern>teleport;tele;port;t;travel</pattern>
    <script>
      if (game.pov.parent.can_teleport) {
        ShowMenu ("Teleport", game.rooms, true) {
          MoveObject (game.pov, GetObject(result))
        }
      }
      else {
        msg ("You can't do that from here.")
      }
    </script>
  </command>

> teleport
Teleport
1: The Lab
2: Teleport 1

[...after selecting...]

> teleport

You are in The Lab.


Yay! It works! (I never doubted mrangel. It just seemed fitting to celebrate.)


So, with this setup, any time you want to add a room (in this example, it will be Ballroom), you can to this:

list add (game.rooms, Ballroom)

To remove it, just do this:

list remove (game.rooms, Ballroom)

This would work for any room, but, if you want to be able to teleport FROM that room, do this:

Ballroom.can_teleport = true

Then, to turn it off, you can just:

Ballroom.can_teleport = false

Everything else should fall right into place.

Here's an example game:

CLICK HERE TO VIEW THE CODE
<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Teleporting">
    <gameid>b1109d19-2c86-407b-972b-7ee2da530b2c</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <start type="script">
      game.rooms = NewObjectList()
      list add (game.rooms, The Lab)
      The Lab.can_teleport = true
      Teleport 1.can_teleport = true
    </start>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="into the teleport booth" to="Teleport 1">
      <inherit name="indirection" />
    </exit>
  </object>
  <object name="The Lab">
    <inherit name="editor_room" />
    <usedefaultprefix type="boolean">false</usedefaultprefix>
  </object>
  <object name="Teleport 1">
    <inherit name="editor_room" />
    <beforefirstenter type="script">
      list add (game.rooms, Teleport 1)
    </beforefirstenter>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <exit alias="out" to="room">
      <inherit name="outdirection" />
    </exit>
  </object>
  <command name="teleport">
    <pattern>teleport;tele;port;t;travel</pattern>
    <script>
      if (game.pov.parent.can_teleport) {
        ShowMenu ("Teleport", game.rooms, true) {
          MoveObject (game.pov, GetObject(result))
        }
      }
      else {
        msg ("You can't do that from here.")
      }
    </script>
  </command>
</asl>

Or, if you don't want to keep track of which locations a player has unlocked…

Start script:

game.teleportrooms = NewObjectList()
foreach (room, Split("Some Lab;Some Forest;Room 101;Another Location;Big list of room names",";")) {
  list add (game.teleportrooms, GetObject(room))
}

And the teleport command:

ShowMenu ("Where to?", FilterByAttribute(ListExclude(game.teleportrooms, game.pov.parent), "visited", true), true) {
  MoveObject (game.pov, GetObject(result))
}

(I'd likely ditch the list, and give an attribute to rooms you can teleport to. FilterByAttribute(FilterByAttribute(AllObjects(), "teleport destination", true), "visited", true) or similar)


Oh, that's good stuff right there, mrangel! (That's sort of how Pixie does it, too, I think.)


there's already a built-in 'visited' Boolean Attribute, so you could create a 'changedvisited' special Script Attribute, for example:

(actually... there probably already is a 'changedvisited'... so this might be over-writing its built-in functionalities... which would be bad... to be safe... you'd have to create your own 'my_visited' functionality... or edit the built-in 'changedvisited' script attribute)

<object name="player">
  <inherit name="editor_object" />
  <inherit name="editor_player" />
  <attr name="parent" type="object">room</attr>
  <attr name="visited_objectlist_attribute" type="objectlist">room</attr>
</object>

<object name="room">
  <inherit name="editor_room" />
  <inherit name="room_type" />
</object>

<object name="room_2">
  <inherit name="editor_room" />
  <inherit name="room_type" />
</object>

<type name="room_type">
  <attr name="changedvisited" type="script">
    list add (player.visited_objectlist_attribute, player.parent)
  </attr>
</type>

<command name="teleport_command">
  <pattern>teleport</pattern>
  <script>
    show menu ("Destination?", player.visited_objectlist_attribute, false) {
      if (player.parent = result) {
        // do (teleport_command, "script") // not sure if this will work to re-call/re-do/loop this Command or not, otherwise this can be made as a Function or an Object's Script Attribute, in order to be able to loop it
        msg ("You just tried to teleport to where you already are at, silly")
      } else {
        player.parent = result
        msg ("You teleport to " + result.name)
      }
    }
  </script>
</command>

just for an extra resource (though you guys already got it covered), here's my old code of moving without Exits (warping/teleporting), back when I was first learning how to do this type of stuff:

http://textadventures.co.uk/forum/samples/topic/5138/explore-and-travel-code-sample-by-hk

you 'explore' (only done for the 'homeland' location, being just an example) and can get random events of discovering a new location (new location gets added to the 'travel' list), which you can then 'travel (as a Command's input)' (warp/teleport) to, as a destination.


Thanks. I'll try it out.


Okay....

So what happens it is now prints The Lab when the player is already there.

But it does send the player to the second place, Teleport 1, if I've been there before.

This is what's in the start script now.

game.rooms = NewObjectList()
list add (game.rooms, The Lab)

This is the command now.

if (HasAttribute(game, "rooms")) {
  ShowMenu ("Teleport", game.rooms, true) {
    MoveObject (player, GetObject(result))
  }
}
else {
  msg ("...It didn't work...")
}

you don't have to have the 'if (HasAttribute (game, "room"s)) { /* scripting */ }', as its extra UN-needed operations, but it's a good practice in general to have such a check.

Also, since you're using an Object List Attribute, you don't need the 'GetObject()', as the list items are already Objects. If you were using a String List Attribute instead, then you'd need to use the 'GetObject()'

if you want to prevent from moving to the same place (not really too big of a deal if you do... pros/cons of it in terms of various programming operations/issues), you can put in a check, like so:

<game name="example_game">
  <attr name="rooms" type="objectlist">room</attr>
  <attr name="start" type="script">
    list add (this.rooms, lab_1_object)
  </attr>
</game>

<object name="room">
  <inherit name="editor_room" />
</object>

<object name="lab_1_object">
  <inherit name="editor_room" />
  <alias>The Lab</alias>
</object>

<object name="player">
  <inherit name="editor_object" />
  <inherit name="editor_player" />
  <attr name="parent" type="object">room</attr>
</object>

<command name="teleport_command">
  <pattern>teleport</pattern>
  <script>

    list remove (game.rooms, player.parent) // removing the room you're currently in/at from the list, so you can't select it as a teleport location

    ShowMenu ("Teleport", game.rooms, true) {

      list add (game.rooms, player.parent) // restoring/re-adding the room you're currently in/at into/to the list. This MUST be done before (above) the 'MoveObject()', as otherwise, you're moved into a new current room, and thus the previous current room is still missing from the list (as the new current location is what now gets added to the list, as you're no longer at the previous location)

      MoveObject (player, result)
      msg ("You teleport to " + result.alias + ".")
    }
  </script>
</command>

Or use a funny response like:
"You arrive at you destination, but discover nothing has changed... You recheck destination command... and get ready to try again."


since you're using an Object List Attribute, you don't need the GetObject()

I thought that, too, but testing proved otherwise.

    <start type="script">
      game.rooms = NewObjectList()
      list add (game.rooms, The Lab)
      The Lab.can_teleport = true
      Teleport 1.can_teleport = true
    </start>


    <script>
      if (game.pov.parent.can_teleport) {
        ShowMenu ("Teleport", game.rooms, true) {
          MoveObject (game.pov, result)
        }
      }
      else {
        msg ("You can't do that from here.")
      }

Error running script: Error evaluating expression '(not GetBoolean(game.pov.parent, "visited")) and HasScript(game.pov.parent, "beforefirstenter")': GetBoolean function expected object parameter but was passed 'The Lab'
Error running script: Error evaluating expression 'GetBoolean(game.pov.parent, "dark")': GetBoolean function expected object parameter but was passed 'The Lab'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'The Lab'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'The Lab'
Error running script: Error evaluating expression 'GetBoolean(room, "transparent")': GetBoolean function expected object parameter but was passed 'The Lab'
Error running script: Error evaluating expression 'GetAllChildObjects(newParent)': GetAllChildObjects function expected object parameter but was passed 'null'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'The Lab'
Error running script: Error evaluating expression 'GetAllChildObjects(room)': GetAllChildObjects function expected object parameter but was passed 'The Lab'
Error running script: Error evaluating expression 'GetBoolean(room, "transparent")': GetBoolean function expected object parameter but was passed 'The Lab'
Error running script: Error evaluating expression 'GetAllChildObjects(newParent)': GetAllChildObjects function expected object parameter but was passed 'null'


  <command name="teleport">
    <pattern>teleport;tele;port;t;travel</pattern>
    <script>
      if (game.pov.parent.can_teleport) {
        ShowMenu ("Teleport", game.rooms, true) {
          MoveObject (game.pov, GetObject(result))
        }
      }
      else {
        msg ("You can't do that from here.")
      }
    </script>
  </command>

> tele

You are in The Lab.


Here ya' go, jmne:

Lose the list in the start script.

Do like mrangel suggested, just add a Boolean attribute named can_teleport to each room you want your teleport command to work in, and set that Boolean to true.

If you don't want the room to show up on the list of destinations (or if you don't want the teleport command to work) at any point during play, just set the can_teleport Boolean on that room to false.


So, all you will need to do is set that attribute up on the rooms you want, and add this command:

  <command name="teleport">
    <pattern>teleport;tele;port;t;travel</pattern>
    <script>
      if (HasAttribute(game.pov.parent, "can_teleport")) {
        if (game.pov.parent.can_teleport) {
          ShowMenu ("Teleport", ListExclude(FilterByAttribute(AllObjects(), "can_teleport", true), game.pov.parent), true) {
            result = GetObject(result)
            msg ("You teleport to: "+GetDisplayName(result)+".")
            MoveObject (game.pov,result)
          }
        }
        else {
          msg ("...It didn't work...")
        }
      }
      else {
        msg ("You can't teleport from here.")
      }
    </script>
  </command>

That ListExclude bit will keep the current room from showing up as on option.


CLICK HERE TO VIEW THE REVISED Example game:
<!--Saved by Quest 5.7.6404.15496-->
<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="Teleporting">
    <gameid>b1109d19-2c86-407b-972b-7ee2da530b2c</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <start type="script">
      The Lab.can_teleport = true
    </start>
  </game>
  <object name="room">
    <inherit name="editor_room" />
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
    </object>
    <exit alias="into the teleport booth" to="Teleport 1">
      <inherit name="indirection" />
    </exit>
  </object>
  <object name="The Lab">
    <inherit name="editor_room" />
    <usedefaultprefix type="boolean">false</usedefaultprefix>
  </object>
  <object name="Teleport 1">
    <inherit name="editor_room" />
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <beforefirstenter type="script">
      Teleport 1.can_teleport = true
    </beforefirstenter>
    <exit alias="out" to="room">
      <inherit name="outdirection" />
    </exit>
  </object>
  <command name="teleport">
    <pattern>teleport;tele;port;t;travel</pattern>
    <script>
      if (HasAttribute(game.pov.parent, "can_teleport")) {
        if (game.pov.parent.can_teleport) {
          ShowMenu ("Teleport", ListExclude(FilterByAttribute(AllObjects(), "can_teleport", true), game.pov.parent), true) {
            result = GetObject(result)
            msg ("You teleport to: "+GetDisplayName(result)+".")
            MoveObject (game.pov,result)
          }
        }
        else {
          msg ("...It didn't work...")
        }
      }
      else {
        msg ("You can't teleport from here.")
      }
    </script>
  </command>
</asl>

EDITED: Added HK's teleport message.


ShowMenu ("Teleport", ListExclude(FilterByAttribute(AllObjects(), "can_teleport", true), game.pov.parent), true) {
  //script goes here
}

The above is pretty much a shortcut for:

myList = NewObjectList()
foreach (o, AllObjects()){
  if (HasAttribute(o, "can_teleport"){
    if (o.can_teleport){
      list add (myList, o)
    }
  }
}
myExcludedList = ListExclude(myList,  game.pov.parent)
ShowMenu ("Teleport", myExcludedList, true) {
  //script goes here
}

I figured it's probably easier to filter twice, check for "can_teleport" and then check for "visited". That way you don't need to worry about adding the room to the list manually.

@HK

Also, since you're using an Object List Attribute, you don't need the 'GetObject()', as the list items are already Objects

Pretty sure that's wrong. If you pass an objectlist to ShowMenu, then result will be a string, the name of the selected object.


HK's sugesstion works (list remove + list add). Thanks!

(I ended up setting a new value, game.firstteleport = false...)


ah, my bad... about the Object List Attribute and show menu, just assumed it'd be an Object due to using an Object List Attribute... whoopsy... sorry about that. Just put back in the 'GetObject (result)', as it is actually needed.


Log in to post a reply.

Support

Forums