The Last Room Visited (scripts, function, & command)

Last Room Visited (updated 8/10/17)

Start script

game.last_room = NewObjectList()

Before entering a room

if ((ListCount(game.last_room)) > 1) {
  lr = ListItem(game.last_room, 1)
  // msg (lr)
  list remove (game.last_room, ListItem(game.last_room, 1))
  // msg ("REMOVED 1")
  list remove (game.last_room, ListItem(game.last_room, 0))
  // msg ("REMOVED 0")
  // msg (game.last_room)
  list add (game.last_room, lr)
  list add (game.last_room, game.pov.parent)
  // msg (game.last_room)
  LastRoom
}
else if ((ListCount(game.last_room)) = 1) {
  list add (game.last_room, game.pov.parent)
  // msg (lr)
  // msg (game.last_room)
  LastRoom
}
else {
  list add (game.last_room, game.pov.parent)
}

Function: LastRoom

if (ListCount(game.last_room) > 0) {
  msg ("Last room:")
  msg (ListItem(game.last_room, 0))
  }
else {
  msg ("You've only been in this room at this point.")
}

There is a variable oldroom. I cannot remember where it is available but i would guess the enter script.


Why make this a List Object instead of a simple variable?
Unless you want to create a list of rooms visited.
Hmmm, maybe as a way to tell the player that they have visited all the rooms and that the region is completed...
For that, a list of room names then delete each room as it is entered...
And when the list length=0, then all rooms visited.
A boolean list, then change the current room to true, but may need the rooms numbered.


Aha!

Thank you!

if (IsDefined("oldRoom")) {

OnEnterRoom

  <function name="OnEnterRoom" parameters="oldRoom">
    <![CDATA[
    game.displayroomdescriptiononstart = false
    if (IsDefined("oldRoom")) {
      if (oldRoom <> null) {
        if (game.clearscreenonroomenter) {
          ClearScreen
          if (not game.currentexitmessage = null) {
            msg(game.currentexitmessage)
            game.currentexitmessage = null
          }
        }
        if (HasScript(oldRoom, "onexit")) {
          do (oldRoom, "onexit")
        }
      }
    }
    
    on ready {
      if ((not GetBoolean(game.pov.parent, "visited")) and HasScript(game.pov.parent, "beforefirstenter")) {
        do (game.pov.parent, "beforefirstenter")
      }
  
      on ready {
        if (HasScript(game.pov.parent, "beforeenter")) {
          do (game.pov.parent, "beforeenter")
        }
    
        on ready {
          if (game.gridmap) {
            Grid_CalculateMapCoordinates (game.pov.parent, game.pov)
            Grid_DrawPlayerInRoom (game.pov.parent)
          }
          
          if (IsDefined("oldRoom")) {
            if (oldRoom <> null and game.changeroom_newline and not game.command_newline) {
              msg ("")
            }            
          }
          
          request (UpdateLocation, CapFirst(GetDisplayName(game.pov.parent)))
          roomFrameExists = false
          if (HasString(game.pov.parent, "picture")) {
            if (LengthOf(game.pov.parent.picture) > 0) {
              roomFrameExists = true
              SetFramePicture(game.pov.parent.picture)
            }
          }
          if (game.clearframe and not roomFrameExists) {
            ClearFramePicture
          }
          if (game.showdescriptiononenter) {
            ShowRoomDescription
          }
          
          if (HasScript( game, "roomenter")) {
            do (game, "roomenter")
          }
          on ready {     
            if ((not GetBoolean(game.pov.parent, "visited")) and HasScript(game.pov.parent, "firstenter")) {
              do (game.pov.parent, "firstenter")
            }
            on ready {
              if (HasScript(game.pov.parent, "enter")) {
                do (game.pov.parent, "enter")
              }
            }
            set (game.pov.parent, "visited", true)
          }
        }  
      }
    }
    ]]>
  </function>

UPDATE: oldRoom isn't always working, and I can't find where the parameter is being passed from. It doesn't appear to be an attribute that's tied to anything(?), nor is it a function.

[email protected] MSYS /c/Program Files (x86)/Quest 5
$ grep -r oldRoom *
Core/CoreDescriptions.aslx:  <function name="OnEnterRoom" parameters="oldRoom">
Core/CoreDescriptions.aslx:    if (IsDefined("oldRoom")) {
Core/CoreDescriptions.aslx:      if (oldRoom <> null) {
Core/CoreDescriptions.aslx:        if (HasScript(oldRoom, "onexit")) {
Core/CoreDescriptions.aslx:          do (oldRoom, "onexit")
Core/CoreDescriptions.aslx:          if (IsDefined("oldRoom")) {
Core/CoreDescriptions.aslx:            if (oldRoom <> null and game.changeroom_newline and not game.command_newline) {

an Object Attribute works fine for if you only want to go back to the room you just came from. The trick is that this actually takes 3 VARIABLES to do it: 'player.old_room', 'player.current_room', and 'player.parent', see below for an example:

thee reason is that you got to transfer ("musical chairs") from the old current room to the old room, and from the room you've just moved to, to the current room, when you move to a new room.

player.parent = room_1
player.old_room = room_1
player.current_room = room_1

upon (after) moving:
player.old_room = player.current_room // as can be seen, the old value of the old_room, get's discarded/replaced upon (after) moving
player.current_room = player.parent // then, the current_room's value gets updated to the current room you're in right now (the room you've just moved to).

let's see how it works perfectly:

you move to room_2 from room_1:
// player.old_room = player.current_room = room_1
// player.current_room = player.parent = room_2

you move to room_3 from room_2:
// player.old_room = player.current_room = room_2
// player.current_room = player.parent = room_3

you move to room_4 from room_3:
// player.old_room = player.current_room = room_3
// player.current_room = player.parent = room_4

you move to room_5 from room_4:
// player.old_room = player.current_room = room_4
// player.current_room = player.parent = room_5

you move to room_3 from room_5:
// player.old_room = player.current_room = room_5
// player.current_room = player.parent = room_3

you move to room_1 from room_3:
// player.old_room = player.current_room = room_3
// player.current_room = player.parent = room_1

you move to room_4 from room_1:
// player.old_room = player.current_room = room_1
// player.current_room = player.parent = room_4

you move to room_2 from room_4:
// player.old_room = player.current_room = room_4
// player.current_room = player.parent = room_2


you could do with only 2 VARIABLES:

player.old_room
player.parent

but this just doesn't work as well, because:

// as you'd have to perform/ask-to-do the 'move back' scripting BEFORE you then do this as your very last script upon (after) moving to a new room: player.old_room = parent, and BEFORE you move to another new room


but you need an Object List Attribute for if you want to go back multiple room previous visits and/or in steps (one room at a time)


@ K.V. (and others):

when you add items to a list, they go to the end of the list.

so the "last room", when you already added in, the current room you've just-moved-to, to the list, it is this: ListCount (LIST) - 2 // the second last item in the list. This is more likely to be used, as it works better.

so the "last room", when you have NOT yet added the room you've currently just moved-to, is this: ListCount (LIST) - 1 // the last item in the list. This is less likely to be used, as it doesn't work as well. See the reason give for using an Object Attribute above.

quest has the built-in setup and stuff for doing directly: (2nd) LIFO (second last in, first out/used).

this is just for being able to go back to rooms....

how to handle removing rooms from the list, can be a bit more involved, depending on how it needs to be done.


To get a list of rooms the player has visited:

list = FilterByAttributes(AllObjects(), "visited", true)

The scripts in my first post in this thread worked (but it didn't kick in until after the SECOND room - I just realized this, and the fix is included later on in this post)), but I did try to use Pixie's method, just to have one less extra unnecessary attribute.


I dropped the 's' (changing it to Attribute), and this sort of works, but it seems to list the rooms alphabetically:

list = FilterByAttribute(AllObjects(), "visited", true)
if (ListCount(list) > 0) msg (list)
if (ListCount(list) > 0) msg (GetDisplayName(ListItem(list, ((ListCount(list))) - 1 )))

You are in a room.
You can go north.

north

You are in a room2.
You can go south or north.
List: Object: room;
a room

north

You are in a room3.
You can go south or north.
List: Object: room; Object: room2;
a room2

north

You are in a room4.
You can go north or south.
List: Object: room; Object: room2; Object: room3;
a room3

south

You are in a room3.
You can go south or north.
List: Object: room; Object: room2; Object: room3; Object: room4;
a room4

south

You are in a room2.
You can go south or north.
List: Object: room; Object: room2; Object: room3; Object: room4;
a room4

south

You are in a room.
You can go north.
List: Object: room; Object: room2; Object: room3; Object: room4;
a room4

north

You are in a room2.
You can go south or north.
List: Object: room; Object: room2; Object: room3; Object: room4;
a room4

north

You are in a room3.
You can go south or north.
List: Object: room; Object: room2; Object: room3; Object: room4;
a room4


So:

I went back and altered the before entering room script as well as the function from my first post:
http://textadventures.co.uk/forum/samples/topic/gwlmorbohe6puxrzcfumcg/the-last-room-visited-scripts-function-command#fe64b874-d276-49f8-a375-fe556c2fc0a8

It works perfectly now:


You are in a room.
You can go north.

north

You are in a room2.
You can go south or north.
Last room:
Object: room

north

You are in a room3.
You can go south or north.
Last room:
Object: room2

north

You are in a room4.
You can go north or south.
Last room:
Object: room3

north

You are in a room5.
You can go south.
Last room:
Object: room4

south

You are in a room4.
You can go north or south.
Last room:
Object: room5

south

You are in a room3.
You can go south or north.
Last room:
Object: room4

south

You are in a room2.
You can go south or north.
Last room:
Object: room3

north

You are in a room3.
You can go south or north.
Last room:
Object: room2

south

You are in a room2.
You can go south or north.
Last room:
Object: room3


I didn't even need to be using the list count to find the item in the function's script. (The first way I had written it, I had the list growing longer with each room change. I fixed that, but never thought that I could just use item 0 until I was writing this to explain that part.)


And... back to the point...
Why a list of 1 item and not just the variable player.LastRoom???
Or, game.LastRoom?


Why a list of 1 item and not just the variable player.LastRoom???
Or, game.LastRoom?

Probably because I'm over-complicating it, but I don't know...

I've got this on the before entering a room script for the entire game, not individually tailored for specific rooms so this can be used as a library.

I also want the game to keep track of the last room AFTER it's printed the room description. It seems that this method doesn't quite work that way: (Entrance.Last_Room = "Cave6")

I'm keeping track of the last rooms of the player and all the NPCs with the attribute 'shadowing' (or sometimes whistled,; in the instance you've told the horse to stay and left the room she's in, you can whistle and she will come to your location, room by room, turn by turn.)

This also utilizes PathLib. Any NPC following any animate object will take the shortest route to it's target room. Then, a message prints that informs the player which direction the NPC has just arrived from (but only when the player is in the target room). This comes into play because one member of the player's posse is dirty, back-stabbing son-of-a-buck.

At times, there can be up to 6 followers in the player's posse, and any number of antagonists who have been set up to target the player or any one of the player's posse. You can also tell your NPC buddies to follow bad guys or each other.

Short example:


Valley
You can see Ralph and Sally.
You can go west, east or north.
There is a dried up riverbed underfoot, which leads from east to west.

Your friend, Chainsaw, lives just east of here.

> sally, stay
Sally stops following you.

> n

Top of the Hill
You can see The Harbinger.
You can go south or north.
Ralph arrives from the south.

> n

Town Limits
You can see a badge.
You can go south or north.
Ralph arrives from the south.

> n

Intersection of Alain St. and Farthing St.
You can go south, north or east.
Ralph arrives from the south.

> n

Alain Street
You can go south, north or east.
Ralph arrives from the south.

> n

Intersection of Alain St. and Third St.
You can go east or south.
Ralph arrives from the south.

NOTE: There is a random chance an antagonist will appear and magically move the player to a random room. This next command/cheat emulates that by moving only the player across the map, hence breaking the normal way to have followers follow you:

> cheat move Adventure Street

Adventure Street
You can go south, north, west or in.
Ralph is in Third Street, and headed your way. (for testing)

> whistle
Sally is in Top of the Hill, and headed your way. (for testing)
Ralph is in intersection of Third St. and Adventure St., and headed your way. (for testing)

> z
You wait 1 minute.
Sally is in Town Limits, and headed your way. (for testing)
Ralph arrives from the north.

> z
You wait 1 minute.
Sally is in intersection of Alain St. and Farthing St., and headed your way. (for testing)

> z
You wait 1 minute.
Sally is in Alain Street, and headed your way. (for testing)

> z
You wait 1 minute.
Sally is in Mundane Corral, and headed your way. (for testing)

> z
You wait 1 minute.
Sally arrives from the west.


I'm porting my game from Inform 7 to Quest, you see. So, I'm trying to make the mechanics identical. (It's been fun, but I have the followers script working together with PathLib now, which was the biggest obstacle. I'll be updating that post today, by the way.)

Here's the link to the port in progress. I still have to add in all of the funny bits, most of the bad guys, a few red herrings, responses, etc., but the world model and mechanics are pretty much set up now.

(NOTE: You will see testing messages appear once in a while.)

http://textadventures.co.uk/games/view/rr9vezzxkeaovamsaqgxcw/they-call-ya-mister-quest-prototype-in-progress


If you are using it so that a following NPC can follow you, then the NPC will follow in your footprints, but not move directly towards you.
IE: You move: E, E, N, N, W S, S, S,...
The NPC starts at your location with you.
Then the NPC would follow the same path, 8 steps.
But to get to you, all it takes is 2 steps, E, S.
There are pathing programs out there (I think I have one for BASIC) that would do this easer.
"This also utilizes PathLib"... Oh, you are using one...
Is PathLib from Inform 7? I don't find it in Quest.


It's Quest.

(Digging through files........)

PathLib.asxl


<!--
     PathLib  - v0.9

     === Description ===

     This library implements some simple path determining functions. 
     
     === Functions ===

     - PathLib_GetPath: Pass the start and end rooms, and it will return a list of exits which
     can be used to navigate from start to end.
       * If there is no path from start to end, null is returned
       * If the start and end are the same room, an empty list is returned
       * Otherwise, a list of one or more exits is returned. Given the way the algorithm
         works, this should, in theory, be the shortest path between start and end.
     Note that this function will use all exits existing in the world to determine the path.
     
     - PathLib_GetRestrictedPath: The same as GetPath, except the path is only searched up to a
     maximum length. If the target room is not found within that length, it simply stops
     and returns null. This allows local searches. Passing -1 for maxlength provides the
     same behavior as GetPath.

     - PathLib_GetDistance: Get the distance between two rooms.

     - PathLib_GetPathExt: Full-blown search API. Takes the start room, end room, max path and a list
     of exits to use as its search set. This allows path searches to only use a certain subset
     of exits. Pass -1 for maxlength to perform an unrestricted search.
     Note: the only requirement for an "exit" in the list is that it be an object
     with a "parent" room and a "to" room. There is no requirement that it be an actual
     Quest exit.
     
     === History ===
     v0.7 - 2012-09-24 (Jay Nabonne): Initial revision
     v0.8 - 2012-09-25 (Jay Nabonne): Renamed functions and added GetDistance functions
     v0.9 - 2013-05-08 (Jay Nabonne): Optimizations.
-->

<library>
  <!-- Find a path from start to end using all the exits in the world. -->
  <function name="PathLib_GetPath" parameters="start, end" type="objectlist">
    return (PathLib_GetPathExt(start, end, AllExits(), -1))
  </function>

  <!-- Find a path from start to end using all the exits in the world, to a maximum length. -->
  <function name="PathLib_GetRestrictedPath" parameters="start, end, maxlength" type="objectlist">
    return (PathLib_GetPathExt(start, end, AllExits(), maxlength))
  </function>

  <!-- Compute the distance between two rooms. Returns -1 if no path found. -->
  <function name="PathLib_GetDistance" parameters="start, end" type="int">
    return (PathLib_GetDistanceExt(start, end, AllExits(), -1))
  </function>

  <!-- Compute the distance between two rooms. Returns -1 if no path found. -->
  <function name="PathLib_GetRestrictedDistance" parameters="start, end, maxlength" type="int">
    return (PathLib_GetDistanceExt(start, end, AllExits(), maxlength))
  </function>

  <!-- Compute the distance between two rooms, with restricted search depth. Returns -1 if no path found. -->
  <function name="PathLib_GetDistanceExt" parameters="start, end, exits, maxlength" type="int">
    path = PathLib_GetPathExt(start, end, exits, maxlength)
    if (path = null) {
      distance = -1
    }
    else {
      distance = ListCount(path)
    }
    return (distance)
  </function>

  <!-- Find a path from start to end using a set of exits and maxlength passed. -->
  <function name="PathLib_GetPathExt" parameters="start, end, exits, maxlength" type="objectlist">
    <![CDATA[
    //msg("GetPathExt from " + start + " to " + end)
    // It is more efficient to mark the rooms rather than track them in lists.
    if (not HasInt(game, "pathID")) {
      game.pathID = 0
    }
    // Bump the path ID for this path. This saves us from having to unmark all previously marked rooms.
    game.pathID = game.pathID + 1

    path = null
    current = NewList()
    entry = _PathLib_AddEntry(current, start)
    dictionary add(entry, "path", NewObjectList())
    length = 0
    iterations = 0
  	while (ListCount(current) <> 0 and path = null and (maxlength = -1 or length <= maxlength)) {
      iterations = iterations + 1
  		entry = current[0]
  		list remove(current, entry)
      room = entry["room"]
      room.pathlib_visited = game.pathID
      if (room = end) {
        path = entry["path"]
      } else {
        foreach (exit, exits) {
          toRoom = exit.to
          //msg("toRoom = " + toRoom)
          if (toRoom <> null) {
            if (exit.parent = room and not GetBoolean(exit, "excludeFromPaths")) {
              // This is a room to be investigated.
              if (GetInt(toRoom, "pathlib_current") <> game.pathID and GetInt(toRoom, "pathlib_visited") <> game.pathID) {
                // We have not touched this room yet. Add its exit to the list.
                newEntry = _PathLib_AddEntry(current, toRoom)
                // Assign to an object attribute to force a copy.
                game.PathLib_pathtemp = entry["path"]
                list add(game.PathLib_pathtemp, exit)
                dictionary add(newEntry, "path", game.PathLib_pathtemp)
                game.PathLib_pathtemp = null
              }
            }
          }
        }
      }
      length = ListCount(entry["path"])
  	}
    //msg("iterations = " + iterations + ", path count = " + ListCount(path))
  	return (path)
    ]]>
  </function>

  <!-- Add a room entry to the list. -->
  <function name="_PathLib_AddEntry" parameters="list, room" type="dictionary">
    <!-- msg ("Add entry: " + room.name + "(length:" + ListCount(list) + ")") -->
    entry = NewDictionary()
    dictionary add(entry, "room", room)
    list add(list, entry)
    room.pathlib_current = game.pathID
    return (entry)
  </function>

</library>


I've got NPCs coming at you from numerous directions at any given time, while keeping track of everyone's last room to tell you where they've arrived from (which is sometimes important plot-wise).

If you stay still, they target you. If you're on the move, they target you.

The same goes for if an NPC is following another NPC. (You can command them to do this, but they sometimes do it on their own. I.e., during the big shoot-out, if Handthing is in play, he will follow Murphy around and keep the player from having to chase Murphy around. (NOTE: This is in the Inform version (playable on this site) as I type this, but I haven't written/copied and pasted any of the easy parts into the port yet. I was getting the mechanics down first.)


What made me want to set this up this way?

Well, as I say, I originally made the game in Inform 7, and Emily Short provides an extension* called Simple Followers.

Her extension sets all of this up. I just tried to make the best use of it that I could. (There were only two followers in the beginning: Ralph and the horse. BUT I had this awesome extension, where you could make anyone target anyone from anywhere, so I figured: that's how Western's work, right? When the [expletive deleted] goes down, you and your friends scatter, and the bad guys come at you from all around...)


There are pathing programs out there (I think I have one for BASIC) that would do this easer.

Yes, please! I'd like the one for BASIC! (My old Tandy keyboard has recently been uncovered, and I'll eventually record a text adventure to its cassette 'drive'. (I don't like to call it a cassette deck. It thinks it's a drive.))


K.V. Are you looking to do something in Basic?
I haven't tried to do a parser, but a set of command buttons is easy to do.


Are you looking to do something in Basic?

I will be soon. My mother reported having found the Tandy yesterday, but I haven't picked it up yet.

I think it's a Color Computer II

https://en.wikipedia.org/wiki/TRS-80_Color_Computer#Color_Computer_2_.281983.E2.80.931986.29

I haven't tried to do a parser, but a set of command buttons is easy to do.

Cool!

I was around eight years old the last time I wrote anything in BASIC.

(The only kinds of buttons I knew of in those days were tangible.)

I don't know if I've still got the joystick, but I know I never had a mouse.

The only things I remember doing with it were writing/copying the BASIC programs from the Radio Shack catalogue, and playing Downland.


That is how I learned to program... and to troubleshoot... :D
I still got 3 books of basic games, well, programs, not all were games.

If you got a story, I think I can put a program around it...
I had a Coco back when, still got it, but I'm sure it is dead.
Coco 2, 16k ram, with built in color basic...
The people today do not know the hardships of writing code to fit in such a small space!!!


@ K.V.

if you are not understanding:

Entrance.Last_Room = "Cave6" // the double quotes makes this be a String Value and thus a String Attribute

you need to do this:

Entrance.Last_Room = Cave6 // no double quotes makes this be an Object (reference/pointer) Value and an Object (reference/pointer) Attribute

which can then be used, for example:

player.parent = Entrance.Last_Room
// player.parent = Cave6


another example:

katana.damage = 50
player.right_hand = katana
player.strength = 100
player.damage = player.right_hand.damage + player.right_hand.damage * player.strength / 100
// player.damage = (50) + (50 * 1) = 100

short_sword.damage = 5
player.right_hand = short_sword
player.strength = 100
player.damage = player.right_hand.damage + player.right_hand.damage * player.strength / 100
// player.damage = (5) + (5 * 1) = 10


Got the easy tracker solved...
Unlike the pathing program, this one is much easer AND realistic!
After all, a tracker can not track someone that has not visited a location...
Just add an attribute to each room that determines if the player was here and which direction they went.
Could also add one for each NPC and maybe the tracker (s) if you want an NPC to follow a tracker or another NPC.
Like P_go, which will contain the room name the player went to (picture foot prints)
When a tracker comes across the "tracks" then the tracker can follow the player...
Same for any NPC's, using NPC1_go... (or the NPC's name)
When the player re-enters the room, then leaves again, his "footprints" will lead to a different room...
So, when the player teleports, the footprint trail ends and the tracker can no longer follow the player...


HK,

Those quotation marks definitely did kick my [expletive deleted] for the first week or four, but I finally got it figured out (just after you showed me how to do it, of course). <insert laugh here>

I was really just sharing my code (the first post), though. It works.


Entrance.Last_Room = "Cave6"isn't my code, and, although it does work in DL's Cave, it doesn't work in my game (and it wouldn't, even if it were actually referencing an object/room -- because I'm keeping track of multiple moving objects, their last rooms, and the player's last room). If I don't use the two-object/room list to shift things around, my orchestrated NPCs lose their way, and chaos ensues.

DL's just using it to help the player navigate through his cave, but you would definitely need to change his code to Entrance.Last_Room = player.parent or Entrance.Last_Room = game.pov.parent to be able to use that attribute as room in any scripts.

Entrance.Last_Room = "Cave6"doesn't reference an object/room (like you say), and it wouldn't work even if Cave6 was a room name. (HK is absolutely correct about the quatation marks!) It would need to be Entrance.Last_Room = Cave6(assuming Cave6 was a room name) to be able to use MoveObject(player, Entrance.Last_Room).

The quotation marks save the text as a string. (Right?)


Just to avoid sullying DL's good name: his code does work perfectly in his game, because he's only using to display, 'you climb in/climb up/slip down from wherever.' Which is all he wants to do.


My code (the first post in this thread), though, references the last room for each and every animate object that can move through my map, with no need for entering scripts specific to each and every room.

I'm really only using this to display the direction from which the NPCs are entering the player's location.

Check it out:

http://textadventures.co.uk/games/view/rr9vezzxkeaovamsaqgxcw/they-call-ya-mister-quest-prototype-in-progress


(And I do appreciate (and still occasionally frequently need) the help! Don't take me the wrong way!)


NOTE:

Each code that everyone has posted in this thread keeps track of visited/last rooms in different ways.

Which one you need to use depends upon your purpose for keeping track of the room(s) in the first place.


I am NOT an object programmer, I am a BASIC programmer...
I think in ways that work for me, and if you thought like I do, (heaven forbid!!! :LOL ) then it would work for you too.
For me, yes, "Cave6" is a string and was used to determine which way the player was moving to give the different room descriptions... I could have just used "1", "2", "3"... but when I first wrote the cave, "Cave1" was the room name, I just changed the names later.
Altho, just now thought of it, I could have used "up" or "down" to determine the room descriptions...
(All the more proof that there are several ways to do the same thing...)
To me:
Entrance.Last_Room = Cave6
Is assigning the value of the variable Cave6 to Entrance.Last_Room.
IE: Cave6=9 (The # 9)
then...
Entrance.Last_Room = Cave6
means Entrance.Last_Room = 9
Not that it equals the object Cave6...
That will be tripping be up for some time...

"Don't take me the wrong way!"
I'll take you any way I choose... And I choose "funny"!!! (LOL...)
Life for humans is too short to take you guy too serious...


anything in double quotes is a String Value, including a number: "4" is a String Value, NOT an Integer value

anything not in double quotes and not numerical (integer/double) and not a special/reserved word, is an Object (reference/pointer) Value

a number without double quotes is either: an Integer (example: 4) or a Double (example: 4.56) Value

the 'true/false' Values are special and reserved as Boolean Values

all VARIABLES are special/reserved words technically

the 'this' key-word/key-command is special/reserved

also 'object' is used internally by quest, so it's a special/reserved word


Oh, you can certainly use List/Dictionary Attributes too, just showing you how to use an Object (reference/pointer) Attribute

also... you can do this too:

game.string_attribute = "Cave6"
game.object_attribute = GetObject (game.string_attribute)
player.parent = game.object_attribute


I think in ways that work for me, and if you thought like I do, (heaven forbid!!! :LOL ) then it would work for you too.

This statement encapsulates the beauty of Quest!

There are SO MANY different ways to do things!


Altho, just now thought of it, I could have used "up" or "down" to determine the room descriptions...

If I had a nickel for every time I came up with improvements to my scripts while discussing them on this forum...


"Don't take me the wrong way!"

Ha-ha!
I just meant that I wasn't bashing anyone's suggestions, seeming how they were all correct.

I'll take you any way I choose... And I choose "funny"!!! (LOL...)

Funny? What'dya mean funny?!? You mean the way I talk?

Funny...
You think I'm funny...

Are you saying I'm some kinda clown? Here to amuse you?

(Everyone has seen GOODFELLAS, right?)


IE: Cave6=9 (The # 9)
then...
Entrance.Last_Room = Cave6
means Entrance.Last_Room = 9
Not that it equals the object Cave6...
That will be tripping be up for some time...

It doesn't look like that's tripping you up at all. You got that [expletive deleted] down pat!


It should also be noted that DL has a before entering script, to print the message: 'you just came in from ...', and he has an AFTER entering script, which sets his last room attribute to the current room. (This is true for each room.)

This is exactly what he needs to keep track of the player's movements in his cave system, and it works flawlessly.


I'm too lazy to do all that room by room.

I'll do all the coding in the beginning, setting up an attribute as a constantly updated, two-item object list I can refer to with a function at any point and for any room.

Example:
Adding the starting room to the list as list item 0, then adding the second room as list item 1, then, in every room thereafter, moving list item 1 to list item 0, then deleting list item 1, then adding the current room as list item 1, then referencing list item 0to find the last room was just the easiest way I could find to keep track of the last room without doing any room specific stuff.

Now I can add rooms and not even fool with the extra attribute for each one, and I can save all the scripts I worked up as libraries to use in my upcoming creations.

Does that make sense? Or is this one of those things I'll go back and read over a few weeks from now, wondering what I could have possibly been thinking?


HK,

the 'this' key-word/key-command is special/reserved

Does 'this' only exist once the player has interacted with an object in the game?

(I can't remember how I tried to use it in a script, but I remember being defeated and going a different route...)


the 'this' key-word/key-command GETS the parent Object (of the scripting that it is used within):

<object name="orc_1">
  <attr name="alias" type="string">orc</attr>
  <attr name="look" type="script">
    msg ("The " + this.name + "'s name is " + this.alias + ".")
  </attr>
</object>

<object name="ogre_1">
  <attr name="alias" type="string">ogre</attr>
  <attr name="look" type="script">
    msg ("The " + this.name + "'s name is " + this.alias + ".")
  </attr>
</object>

basically, it's used with an Object's Script Attribute's scripting (it can NOT be used in Functions/Commands/Turnscripts/Timers), but if you need to use other Objects in your scripting, then you can't use 'this', as it is only for GETTING the parent Object, and not other non-parent Objects:

<object name="ogre_1">
  <attr name="alias" type="string">ogre</attr>
  <attr name="look" type="script">
    msg ("The " + this.name + "'s name is " + this.alias + ". And, the " + player.name + "'s name is " + player.alias + ".") // the 'this' only works for the 'ogre_1' Object, not for the other non-parent Object, which in this example is the 'player' Player Object
  </attr>
</object>

<object name="player">
  <attr name="alias" type="string">HK</attr>
</object>

it's really useful for Object Types:

<type name="monster_type">
  <attr name="look" type="script">
    msg ("The " + this.name + "'s name is " + this.alias + ".")
  </attr>
</type>

<object name="orc_1">
  <inherit name="monster_type" />
  <attr name="alias" type="string">orc</attr>
</object>

<object name="ogre_1">
  <inherit name="monster_type" />
  <attr name="alias" type="string">ogre</attr>
</object>

<object name="troll_1">
  <inherit name="monster_type" />
  <attr name="alias" type="string">troll</attr>
</object>

<object name="goblin_1">
  <inherit name="monster_type" />
  <attr name="alias" type="string">goblin</attr>
</object>

@HK

Sweet!

Thank you, kindly, sir!


you can use 'this' as an Argument/Input (withing an Object's Script Attribute) for a Function's Parameter, but you can't use the 'this' within the Function's scripting:

<game name="example_game">
  <attr name="example_string_attribute" type="string">hi</attr>
  <attr name="start" type="script">
    example_function (this.example_string_attribute) // this = game // this.example_string_attribute = game.example_string_attribute = "hi"
    // example_function (this.example_string_attribute) = example_function ("hi")
  </attr>
</game>

<function name="example_function" parameters="string_parameter">
  msg (string_parameter)
</function>

<object name="player">
  <attr name="example_string_attribute" type="string">hi</attr>
  <attr name="example_script_attribute" type="script">
    example_function (this.example_string_attribute) // this = player // this.example_string_attribute = player.example_string_attribute = "hi"
    // example_function (this.example_string_attribute) = example_function ("hi")
  </attr>
</game>

<function name="example_function" parameters="string_parameter">
  msg (string_parameter)
</function>

<object name="ball">
  <attr name="example_string_attribute" type="string">hi</attr>
  <attr name="example_script_attribute" type="script">
    example_function (this.example_string_attribute) // this = ball // this.example_string_attribute = ball.example_string_attribute = "hi"
    // example_function (this.example_string_attribute) = example_function ("hi")
  </attr>
</game>

<function name="example_function" parameters="string_parameter">
  msg (string_parameter)
</function>

you can also use 'this' with 'do' and 'set' too (still though as scripting within an Object's Script Attribute)


EDIT:

Whoops!

Wrong thread!


Only sw this post just now… was this thread before I started using Quest?

But felt I should respond to HK…

but you can't use the 'this' within the Function's scripting

I think you can :-p It just doesn't refer to the object you probably intended it to. Unless I'm getting confused again.


not sure if 'this' can be used or not, but that's indeed what I meant by my comment in my post. Some people new to coding, have a bit of a hard time understanding what 'this' is and how to use it correctly and not incorrectly (where it can and can't be used).


game.lastobjects is what holds 'this' (as far as I can tell).

...and it works when I toy with it.

Let's say the player enters a room, and I print "You can see a WIDGET here!"

I can put this in the room enter script, too:

game.lastobjects = Split("widget", ";")

Now, when the player walks in, the message prints "A WIDGET!", and the command examines the widget.


Not being an object programmer, but a Basic programmer, I see thing a little bit different and sometime more direct...
I made a short program that used a player variable to determine which direction the player was moving and determined the room description based on that.
Like this:

<asl version="550">
  <include ref="English.aslx" />
  <include ref="Core.aslx" />
  <game name="DL_Lost_Cave">
    <gameid>09ea19be-1e27-46e1-b5d4-0fb706b0e100</gameid>
    <version>1.0</version>
    <firstpublished>2017</firstpublished>
    <showpanes type="boolean">false</showpanes>
    <borderlesscursor />
    <showcommandbar />
    <commandcursor><![CDATA[>]]></commandcursor>
    <echohyperlinks type="boolean">false</echohyperlinks>
    <autodisplayverbs type="boolean">false</autodisplayverbs>
    <attr name="autodescription_youarein_useprefix" type="boolean">false</attr>
    <attr name="autodescription_youcango" type="int">0</attr>
    <attr name="autodescription_youcansee" type="int">0</attr>
    <attr name="autodescription_description" type="int">2</attr>
    <attr name="autodescription_youarein" type="int">1</attr>
    <turnoffsavebutton />
    <autodescription />
    <showtitle type="boolean">false</showtitle>
    <start type="script">
      player.Last_Room = "Outside"
    </start>
    <defaultfont>'Lucida Console', Monaco, monospace</defaultfont>
  </game>
  <object name="DL_Cave1">
    <inherit name="editor_room" />
    <objectslistprefix type="string"></objectslistprefix>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <alias>Cave entrance</alias>
    <description type="script">
      if (player.Last_Room="Outside") {
        msg ("You crawl through the hole and into the cool of the cave and look around. Other than the cave entrance behind you, there is only the downward sloping passage to the east. The cave seems to be a natral cavern that has been widened by the use of tools.")
      }
      else {
        msg ("You make your way back to the entrance.")
      }
    </description>
    <enter type="script">
      player.Last_Room = "Cave1"
    </enter>
    <beforeenter type="script">
    </beforeenter>
    <exit alias="east" to="DL_Cave2">
      <inherit name="eastdirection" />
    </exit>
    <exit alias="west" to="DL_Entrance">
      <inherit name="westdirection" />
    </exit>
    <exit alias="out" to="DL_Entrance">
      <inherit name="outdirection" />
    </exit>
  </object>
  <object name="DL_Cave2">
    <inherit name="editor_room" />
    <objectslistprefix type="string"></objectslistprefix>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <alias>Decending Passage</alias>
    <description type="script"><![CDATA[
      if (player.Last_Room="Cave1") {
        msg ("The passage continues down to the east and rises sharply to the west. There are more signs of tool marks on the cavern walls. This is a sure sign that someone worked this passage. You know that worked passages leads to treasure. You start to get more excited with every step.<br/>")
      }
      else {
        msg ("You climb back up from the decending passage.")
      }
    ]]></description>
    <enter type="script">
      player.Last_Room = "Cave2"
    </enter>
    <exit alias="west" to="DL_Cave1">
      <inherit name="westdirection" />
    </exit>
    <exit alias="east" to="DL_Cave3">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="DL_Cave3">
    <inherit name="editor_room" />
    <objectslistprefix type="string"></objectslistprefix>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <alias>Cavern</alias>
    <description type="script">
      if (player.Last_Room="Cave2") {
        msg ("The passages flatens out somewhat here, but still continues down to the east and up in the west. This section is mostly worked walls with little sign of where the original cave was. Someone put in a lot of work to make this passage for it to go nowhere.")
      }
      else {
        msg ("You are relieved to reach this point. The climb back up will be much easer now.")
      }
    </description>
    <enter type="script">
      player.Last_Room = "Cave3"
    </enter>
    <exit alias="west" to="DL_Cave2">
      <inherit name="westdirection" />
    </exit>
    <exit alias="east" to="DL_Cave4">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="DL_Cave4">
    <inherit name="editor_room" />
    <objectslistprefix type="string"></objectslistprefix>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <alias>Steep sandy passage</alias>
    <description type="script">
      if (player.Last_Room="Cave3") {
        msg ("You slip on some loose sand here and almost fall down. The passage sloops much more now and it looks like it gets steeper a little further to the east. If this is a trap, then this is your first sign. The loose sand is making every step just a little bit more hazardus.")
      }
      else if (player.Last_Room="Cave5") {
        msg ("You manage to climb higher out of the sloppery passage.")
      }
    </description>
    <enter type="script">
      player.Last_Room = "Cave4"
    </enter>
    <exit alias="west" to="DL_Cave3">
      <inherit name="westdirection" />
    </exit>
    <exit alias="east" to="DL_Cave5">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="DL_Cave5">
    <inherit name="editor_room" />
    <objectslistprefix type="string"></objectslistprefix>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <alias>Steep sandy passage</alias>
    <description type="script">
      if (player.Last_Room="Cave4") {
        msg ("You continue down the slope. The sides have been worked smooth just like the floor which it covered in more sand. Every step you make is more slipery than the last. If you continue this way, you may not be able to climb back out. But, if there is a treasure at the bottom of this, it could be worth the risk.")
      }
      else if (player.Last_Room="Cave6") {
        msg ("You managed to climb back up from the trap.")
      }
    </description>
    <enter type="script">
      player.Last_Room = "Cave5"
    </enter>
    <exit alias="west" to="DL_Cave4">
      <inherit name="westdirection" />
      <runscript />
      <script type="script">
        R = GetRandomInt(1,6)
        if (R=1 or R=2 or R=3 or R=4) {
          msg ("You try to climb the sloop but it is too slippery and you slide back down.")
          // MoveObject (player, DL_Cave5)
        }
        if (R=5 or R=6) {
          msg ("You manage to climb the slope, but after many failed attempts.")
          MoveObject (player, DL_Cave4)
        }
      </script>
    </exit>
    <exit alias="east" to="DL_Cave6">
      <inherit name="eastdirection" />
    </exit>
  </object>
  <object name="DL_Cave6">
    <inherit name="editor_room" />
    <objectslistprefix type="string"></objectslistprefix>
    <description><![CDATA[The last few steps were more of a slide than steps. But, you made it to the bottom. You look around at the blank walls. There is no indication of any treasure, just a bunch of bones scatteres around the floor. Some human, some animal, and some neither. <br/>Well, if there was a treasure, someone else got it out, and from the looks of the scatered bones, several did not make it out. Looking around, you are begining to wonder if your bones will be added to the piles.<br/>]]></description>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <alias>Bottom of passage</alias>
    <enter type="script">
      player.Last_Room = "Cave6"
    </enter>
    <exit alias="west" to="DL_Cave5">
      <inherit name="westdirection" />
      <runscript />
      <script type="script">
        R = GetRandomInt(1,6)
        if (R=1 or R=2 or R=3 or R=4) {
          msg ("You try to climb the sloop but it is too slippery and you slide back down.")
          // MoveObject (player, DL_Cave6)
        }
        if (R=5 or R=6) {
          msg ("You manage to climb the slope, but after many failed attempts.")
          MoveObject (player, DL_Cave5)
        }
      </script>
    </exit>
  </object>
  <object name="DL_Entrance">
    <inherit name="editor_room" />
    <alias>A cave entrance</alias>
    <usedefaultprefix type="boolean">false</usedefaultprefix>
    <description type="script">
      if (player.Last_Room="Outside") {
        msg ("You are following the mountain trail when you notice a small opening in the rock to the east. It is not much more than 3 foot round, and mostly hidden by the brush. It looks like it could be an animal den, but you know that looks could be deceiving.")
      }
      else {
        msg ("You leave the cave and continue your travels.")
      }
    </description>
    <beforeenter type="script">
    </beforeenter>
    <enter type="script">
      player.Last_Room = "Outside"
    </enter>
    <object name="player">
      <inherit name="editor_object" />
      <inherit name="editor_player" />
      <statusattributes type="stringdictionary" />
    </object>
    <exit alias="in" to="DL_Cave1">
      <inherit name="indirection" />
    </exit>
    <exit alias="east" to="DL_Cave1">
      <inherit name="eastdirection" />
    </exit>
  </object>
</asl>

I guess I could have tweaked the descriptions based on it the player had visited the room before or not...


I have played DL's game, and it does work flawlessly. (It's pretty cool, too!)


Another comment, vaguely relevant to the OP in case anyone is looking for an alternate method of tracking where a player came from.

If the player used the "go" command to get here, then DictionaryItem(game.pov.currentcommandresolvedelements, "exit") looks like it will give you the exit they walked through (if used in an onenter script, you would probably want to check that the specified exit's to actually leads here, to make sure they haven't been redirected by some script, or teleported by a turnscript after moving).


Log in to post a reply.

Support

Forums