Elevator action

jaynabonne
For those times when walking just won't do...

Attached is some code I've been working on. It implements (in a hopefully extensible, customizable way) an elevator object.

Basically, an elevator is a room that moves among a set of other rooms in an orderly way. To create an elevator, you set up a parameters object with a list of "floor parameter" objects (each of which specifies the target exit room and the room designation), and then you invoke Elevator_Create. It probably sounds more complicated than it actually is. Check out the sample to see how it works.

The core elevator code is in "Elevator.aslx" and the elevator sample code is in "ElevatorSample.aslx". The sample includes a stairwell as well, so you can look at the elevator from different floors.

There are built-in components you can use if you just want to slam an elevator into your building. But there are provisions in place for customizing it all to your own design. If you have any trouble customizing it, let me know.

The elevator leverages some other code that was developed explicitly for it, but which has lots of other uses: a "goals" engine. This engine implements a "goals object" which is an object you wish to be "goal-driven." You then add goals to it and update it periodically to let it follows its goals. The goals engines is in "GoalsObject.aslx"

The elevator needs to be updated regularly to operate properly. It is an autonomous object, but it needs a kick to keep it going. This can be any way you like, but the two straightforward ways are via a turn script and via a timer. The former appies if your game design (or philosophy) is for things to happen only when a user makes a turn. The latter is for those games that are comfortable with events happening in real time. I have exercised this code in both modes. In the turn-based mode, you will often need to type "wait" or perform some other actions (like looking around) to make the world state advance. In the real-time mode, the elevator just goes on as it does, but it won't wait for you! I have left the code in the real-time mode, since it's a bit more fun. :) (The turn script is in the sample if you want to use it. Just disable the timer and enable the turn script.)

Note that you must include both "GoalsObject.aslx" and "Elevator.aslx" to incorporate this into your project.

I think this code could easily be adapted to other uses - anything that has a door and travels (for example, a Star Trek style turbolift, an auto taxi sort of thing, etc.

As the elevator code is goal based (with two goals currently - "close door" and "seek floor"), its behavior can easily be adapted as well by adding your own goals. For example, if you wanted to have a haunted house where the elevator breaks down, you could implement a goal that moves the car between floors and then stops.

I learned a lot writing this code. If anyone has any constructive criticism, especially about better ways to do anything, I'd love to hear! I'm looking to develop good techniques for writing modules.

jaynabonne
Almost forgot: the purpose of all the complexity is to allow *multiple* elevators if so desired. You could put one in each building; you could have mutiple ones in the same building, all going to different floors (e.g. the primary public one, a service one, the express to the penthouse, etc).

Pertex
Perfect work! But I fear it is far to complicated for most users to understand your code and create an elevator with your lib. I still don't understand your goalobject so I would code an elevator by myself.

jaynabonne
Thanks for checking it out and for your thoughts. :)

As far as complicated goes, it's ok for things to be complicated if it's all "beneath the covers." My goal with this library was to have some complex code wrapped up in a nice, easy-to-use package, with "easy" depending on how deep you wanted to go with customizations.

As far as just whipping out a stock elevator, I (had) thought the approach I took (the one in the elevator sample) was quite straightforward - a "parameters" object that you fill in. Did you find that part too complicated as well? I had assumed that, since everyone is familiar with objects as things you hang attributes on, that constructing parameters that way would be in line with existing experience. However, if the concept of objects as programming constructs as opposed to just "things you see in your game" is too much of a leap, then perhaps other approaches can be taken. (Keep in mind that this isn't just about this elevator class - I'm keeping an eye toward making more modules in the future, and I want them to be usable.)

If the complexity is in customization, then there may be ways to make that easier. I had originally figured that if someone wanted a custom elevator, they would simply create their own prototypes in line with what's included in the library and pass them in instead with the params. I had even just now thought that perhaps the user could "Show Library Elements" and then copy the prototypes out of the library and into their code, where they can then be mucked with. I tried that just now, and Quest died with an error when I changed the filer ("given key not present in the dictionary"... knowing which key would be mighty helpful, in the error message!), so it looks like I have something to fix in the lib to make that work properly. But assuming you could copy the prototypes out of the library and then customize them at will... I don't know. I am a programmer after all, and these concepts flow freely for me. But if the typical Quest game creator has a different conceptual model of things, then I would need to understand that in order to make useful modules.

As far as the goals object goes, well... (continued)

jaynabonne
The goals object is in line with my desire to have autonomous NPCs. (Or in the case of an elevator, NPEs (non-player entities)? NPTS (non-player things)?) These would not just be stock objects that sit in a room and wait for the player to interact with them, but would be entities that "have a mind of their own." They might be in line with the goals of the game, or they could be used just to add color and variety.

My first piece of code along these lines was an ActiveObjects module (for lack of a better name), which was just an object that managed a list of objects and a turn script, and on each turn it called an "update" method on each of the objects in its list. In looking around, I know that at least one other game-creation system (no names dropped) has a built in notion of this, though they called the method invoked something to do with "idle", which isn't quite the name I'd choose, but it was the right idea. My own elevator code uses it to drive the elevator, and I anticipate having further "active objects" in my game as well. I didn't include it in the sample since *that* was definitely needless complication. :)

So... the goals object. My vision is that there could be entities in a game that have their own agenda. Despite what we all may believe, the (game) world does not necessarily revolve around us! :lol: An example:

Perhaps you're making a (name deleted) game with a boy at a wizarding academy, and you wish to drop in friendly ghosts who wander the halls and cause mischief (one of whom may or may not look like John Cleese). Rather then having such "color" being room-based (where when the player enters the room, the code decides, say, whether there is such an entity in there and what it's doing), you can turn it around and create an independent, autonomous entity which wanders from room to room and interacts with things, whether the player is actually there or not.

The primary goal for such an entity would be "Wander". There could also be other goals depending on what room its in, what objects are in the room, whether the player is present, etc. Things like this can make the game world more unpredicatable and diverse.

Let's take a look at the "Wander" goal.

The "update" method for a goal updates the goal's internal state. Can the goal be tried? How high a priority is the goal? Has the goal been achieved? A goal like "Wander" would be low-priority and probably not actually achievable (in that it is base behavior and should never stop happening as a default). Whether the wander goal can be tried or not depends on the state of other goals. If there is another goal to have a conversation with the player, then perhaps while that is going on, the "Wander" goal is disabled (though that could also be handled via priorities - the goal to converse with the user takes higher priority).

The "try" method attempts to achieve the goal. In this case, it just makes the entity wander from room to room. That's how it "tries" to wander. :)

The "achieve" method would not be used, as the goal should never be fully achieved - it is ongoing behavior, never ending. The important thing to keep in mind about the "achieve" method is that, once a goal sets "canAchieve" to true, the goal will be removed from the list after the "achieve" method is invoked. It's the "last gasp" method. Or perhaps when night falls, then wandering would be achieved, and the "achieve" method would create a new goal - "sleep".

Let's say there is also a "greet" goal. When the player is in the room where the entity is, it will greet the user. "The ghostly specter nods in your direction." or "The shimmering annoyance says, 'Top of the morning!'" Something like that.

The "update" method would look to see if the player was in the room with it. If not, then it can't even be tried. Or perhaps there is additional logic to see if it has already greeted the player in that room or in the past 20 turns or something like that (so that it doesn't keep saying "Hi" over and over).

The "try" method would actually cause the greeting to be displayed.

Whether the "achieve" method makes sense or not is determined by whether "greeting" ever stops. Perhaps after a couple of random greetings, the goal is done - has been achieved. At that time, it will be removed from the goals list.

As a final example, let's say the entity has important information to convey to the player - but only in a certain room or under certain conditions. Once it has done so, then it never will ever again. For a goal like this, the "update" method will see if the player is with it in the room and if they are both in the special room. If so, then the goal's "canAchieve" will be set to true. And when the goal is achieved, the entity will impart the information before the goal is removed and it becomes silent thereafter. There are lot of ways you could do this.

So in the beginning, you would create your entity and give it three goals: "Wander", "Greet", and "ImpartSecretInfo". Then set it loose in the world and let it do with it's going to do. It will wander around, greet the player when in the same room, and impart special knowledge when with player in a certain room. All done with priorities and world-examining and -modifying logic.

That's the idea anyway. It greatly simplified the control logic in the elevator. I was quite excited when the "goals" approach came to me on a walk, as not only did it make the elevator logic almost trivial (just two goals - "close door" and "seek floor"), it was also in line with what I outlined above.

If anyone would like to discuss this more, let me know. It may not be a typical "go from room to room and look for items to unlock other items and everything is centered on the player and reactive to what the player does" type of game... but then, who wants to write a "typical" game? :)

jaynabonne
Updated code. This fixes the "can't show library elements" problems. (Yes, I had included objects in a type again...)

I also restructured the built-in prototypes a bit, since now it seems people might actually want to manipulate them. And you can indeed "Copy" them to current project and modify them. (There are some *really* nice features in the Quest editor!) So that does provide a straightforward path for initial customizations...

To customize the main elevator car or any of its children, copy and modify ElevatorCar_Prototype.
To customize the elevator facade or any of its children (what you see in the room with the elevator), copy and modify ElevatorFacade_Prototype.
To customize the elevator internal buttons, copy and modify ElevatorIntButton_Prototype.

Note that you can remove what you don't want (e.g. the indicators) or add your own objects. The types in the elevator library are components you can pick and choose (besides the three mentioned above - car, facade and inteior buttons - which are required).

Pertex
Hi jaynabonne, thanx for the detailed explanation. "Goals" sounds good so I will have a closer look at it.
Could you think of a way to integrate your code in Quest so that you can create elevators from within the gui? I think, 90% of Quest user don't have knowledge in coding or scripting and can't use your code

jaynabonne
I can look into that. I haven't experimented with the editor UI pieces before, but I just found an "advanced" piece on just that thing on the Wiki last night, so I'll explore it. :)

Jsimmons
This is so interesting! I've created a star trek stype turbo lift before, but had trouble when I tried to add buttons instead of voice command.

Basically for the turbolift I'd have a list of exits, one for each floor and would say "Go to bridge" or "Go to deck 8" as if giving the voice command like they do on Star trek, but I'd love to have access to an "ordinary elevator" for those non-sci-fi things.

rcorra
I am new to this, but I downloaded the files. But I get an error when I am trying to open the sample to see the code and/or game.

Failed to load game.
The following errors occurred:
Error: Cannot find a file called 'Elevator.aslx' in current path or application/resource path


Thank you,

Pertex
The elevator.aslx is in the ZIP in the first post. Extract it and copy it into the directory of the other files

rcorra
hmmm. I had unzipped it. I tried it (ElevatorSample and GoalsObject) in the area where the game downloads games and I tried it in the main Quest file itself.

I want to see the code for the elevator and move object, as I am making a taxi service that works on the same principle. You enter, select where you want to go, and then get out at your destination.... a few dollars poorer, of course.

Thanks for the quick attention

rcorra
While I would still like to see your code, I think I got a work around.

The player enters the taxi (a room in front of their house). I then give them options from Non-directional exits to go to various locations. They are then moved to another taxi (room) but think it is the same one and get a message they are in front of their destination. They can then get out, or go elsewhere.


If there is a better way, I would love to hear, as I am new to this. But I think I can copy the code for the exits and paste in each Taxi instance.

jaynabonne
The elevator code is in a library file. You can't load libraries into Quest the way you do games. You need to edit them with an external text editor. It's all a handy XML format, so it should be straightforward to peruse, if you're so inclined.

george
A little OT, but I'm curious jaynabonne do you have a special editor or language file you use to edit aslx files? Typing all that xml sounds like a lot of work.

HegemonKhan
notepad++ is really nice:

http://notepad-plus-plus.org/

just open your ".aslx" file with notepad++, then click from the top bar "language", and then choose "XML"

enjoy :D

george
Does NP ++ have autocompletion or something like that for all the aslx? Or do you have to type it all out?

HegemonKhan
I'm not sure what autocompletion is (I'm still a noob with coding), maybe it has it, but I don't know. I just like it, as it color-codes your code, making it easy to spot mistakes in it (and it supports a good many code languages and seems to be made and updated really well, though the extra coding languages doesn't help me much at the moment, as I am only just learning to write still in quest's code language, lol).

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

HK Edit:

yes it does, as I just looked at it's "features" site page, lol:

•Auto-completion: Word completion, Function completion and Function parameters hint

http://notepad-plus-plus.org/features/

•Syntax Highlighting and Syntax Folding
•User Defined Syntax Highlighting and Folding: screenshot 1, screenshot 2, screenshot 3 and screenshot 4
•PCRE (Perl Compatible Regular Expression) Search/Replace
•GUI entirely customizable: minimalist, tab with close button, multi-line tab, vertical tab and vertical document list
•Document Map
•Auto-completion: Word completion, Function completion and Function parameters hint
•Multi-Document (Tab interface)
•Multi-View
•WYSIWYG (Printing)
•Zoom in and zoom out
•Multi-Language environment supported
•Bookmark
•Macro recording and playback
•Launch with different arguments

it seems to be a really code~programming professionally written and updated software program for code writing. I think many coders use notepad++, it's probably one of the best. They do document every version release, letting you know what's been changed, fixed, and~or added to it.

jaynabonne
I use Visual Studio (Express), as I've been using the full VS version for work for years. It has some nice auto-complete type things for XML (e.g. you type the opening tag, and it adds the closing one; you type an attribute and '=' and it puts the quotes in for you; it flags elements that don't match; etc.)

Buddy Bishop
Is there any recent updates to Elevator.aslx?
The most recent one I can find is v0.65.

I'm wanting to use your code for adding elevators to my game.
I'm using Quest 5.6.2 and I'm not able to run your sample, It does load - but won't play.

Error messages on Play:
*********************************************************
Error running script: Unrecognised element 'span'

Error running script: Unrecognised element 'span'
Error running script: Unrecognised element 'div'
Error running script: Error compiling expression 'ListExclude(ScopeVisibleNotHeldNotScenery(), game.pov)': FunctionCallElement: Could find not function 'ListExclude(QuestList`1, Object)'
Sorry, an error occurred.
Object reference not set to an instance of an object. at TextAdventures.Quest.WorldModel.UpdateObjectsList(String scope, ListType listType) at TextAdventures.Quest.WorldModel.UpdateObjectsList() at TextAdventures.Quest.WorldModel.UpdateLists() at TextAdventures.Quest.WorldModel.b__100_0()
*********************************************************

When I attempt to follow the Elevator implementation directions, my game will play, but there is an error message displayed in the game:
*********************************************************
Error running script: Error evaluating expression 'RunDelegateFunction(params, "createCar")': Object 'ElevatorParams' has no delegate implementation 'createCar'
*********************************************************

I also currently have the timer disabled as it too shows an error:
*********************************************************
Error running script: Error compiling expression 'game.elevator': RootExpressionElement: Cannot convert type 'Object' to expression result of 'Element'
*********************************************************

Any suggestions or reference to updated code or forum articles would be greatly appreciated.

Buddy Bishop
I solved these two issues by:
1. First error: Regenerating the GUID - it worked for some reason.
2. Second error: With a text editor, I added the line <inherit name="ElevatorParamsType" /> immediately under the <object name="ElevatorParams"> section.

jaynabonne
For 1, it's quite possible that just the act of saving the game (which causes it to be converted - not at load time as you might expect) may have been the reason why.

So for anyone else trying this (or any other older sample), when you load the sample, immediately save it. If you try to run it before saving, it will fail, but once you save, you can run it.

This topic is now closed. Topics are closed after 180 days of inactivity.

Support

Forums