## How to create infinite maze?

Basically I make a 5x4 rooms.
Each of the exits from one to another room is referred as walls, so they have 50% chance of appearing.
This gives us a random maze of a 5x4 rooms size.

Each 5x4 rooms size have a X-coordinate and Y-coordinate named as game.x and game.y.
So there is an enter door at the bottom of the 5x4 dungeon, and an exit door at the top of the 5x4 dungeon.
When the players moves to the exit door, game.y = game.y+1, then move the player to the enter door at the
bottom of the 5x4 dungeon.
So far, everything works great and the game knows that the dungeon are different based on the xy coordinates.

But this is where I encounter a problem, how do I make the game remember that the object chair and walls exist
in this specific room of this specific dungeon of xy coordinates? I could make that the object chair is visible when game.x=0
and game.y=1, but the chair are randomly generated, meaning I clone chair and move to player.parent which is the player's current location, but I cannot access to change the chair's attributes, meaning I cannot make the chair knows that it is in x=0, y=1, if the chair knows, it will be visible, otherwise, invisible.

Another failed solution is that whenever a player enters a room, create a Floor and a Chair, whenever there is a Floor in the
room, the generator will not create anything, this solves my problem of auto-generating, but when tested in real life, the game
does not recognize the Floors, because when you clone an object, it will create Floor1 instead of Floor, because the game cannot handle objects with exactly same names.

OK, there's a lot to unpack here. I'm not sure I understand your post completely, but I'll include as much detail as I think is needed. Sorry if you already have some of this, or it seems irrelevant.

There are two common ways to make an infinite maze, and you seem to have selected a kind of hybrid.

The most common way to do this is to have an inaccessible 'template' room somewhere. Whenever the player goes through an exit that doesn't lead anywhere, the template room is cloned and added to the map at that location. This means you don't need to keep track of what is in each room, because Quest does that for you.
For more variety, you could even have a variety of rooms to choose from, and clone a different one each time.

Another method for a random dungeon is to have a single room, and then modify its attributes and move objects in/out of it to represent the different things that might be found there based on the player's coordinates. So rather than moving the player to a new room, you have an exit which changes the appearance of the current room and then displays the new description. Kind of like in the theatre, changing the backdrop and props to represent travelling.
This is often an efficient method for modelling a large dungeon; but Quest doesn't make it easy. Remembering what was in each room so you can display it again next time can become quite complex. It's doable, but Quest's data structures aren't well-suited to the task.

If I understand you correctly, you are using this second method but with a block of 20 actual rooms. I can see that makes sense, but Quest might make it a little harder to work with compared to other engines.

I clone chair and move to player.parent which is the player's current location, but I cannot access to change the chair's attributes

In this case, you should be able to access the chair's attributes just fine. I would expect you to have something like:

``````thischair = CloneObjectAndMoveHere (Chair)
``````

which creates an object (possibly named `Chair1` or `Chair4` or similar), and stores it in the variable `thischair`. You can then use `thischair` as if it were the object for the remainder of the script. For example, you could do:

``````thischair.x = game.x
thischair.y = game.y
``````

to give the newly created chair a couple of attributes indicating which dungeon it is in.

You could then set it up so that when the player moves to a different x/y, all the objects in their current location are then removed, and if the player is returning to coordinates they've visited before, the objects from those coordinates are restored.

1. Hide the objects that are in the wrong x/y coords.

You would loop over all the objects in the rooms, showing or hiding them depending if their x/y match the current location. For this example I'm assuming there is a room `DungeonContainer` which contains the 20 rooms; as this makes it easier to loop over them:

``````foreach (room, GetDirectChildren (DungeonContainer)) {
foreach (object, GetDirectChildren (room)) {
if (HasInt (object, "x") and HasInt (object, "y") and not Contains (game.pov, object)) {
object.visible = (object.x = game.x and object.y = game.y)
}
}
}
``````

That will show all objects whose x and y match the current `game.x` and `game.y` and hide objects whose x and y are different. In this case it won't do anything with objects that don't have coordinates.

If you want it to work properly if the player picks up an object and drops it elsewhere, you would also need to make sure that objects they are carrying have the correct coordinates. Then the objects will behave correctly when dropped. After changing `game.x` and `game.y` but before showing and hiding objects, you would do something like:

``````foreach (object, ScopeInventory()) {
object.x = game.x
object.y = game.y
}
``````
1. Remove objects when the player changes coordinates; find them and bring them back when the player returns to those coordinates.

This method is a little more complex, as you also need to store which room the objects were in. However, it might be a better option if you already have invisible objects, so that the `visible` flag isn't serving two purposes.

In this case, you'd first want to remove objects from the current rooms, and store their location for future access:

``````foreach (room, GetDirectChildren (DungeonContainer)) {
foreach (object, GetDirectChildren (room)) {
if (not (object = game.pov or Contains (game.pov, object))) {
object.x = game.x
object.y = game.y
object.room = room
RemoveObject (object)
}
}
}
``````

note that this doesn't delete the objects; it just removes them by moving them into non-player space. In this case I'm specifically testing for the player and their objects, so that they don't get whisked away.

Once we've removed those objects, you increase `game.y`, and then check if there are any objects waiting to be moved back. In this case we end up looping over all objects to find the ones we want. we might be able to make the code easier to read using `FilterByAttribute`, but we would be creating multiple temporary objectlists, which is slower and uses more memory.

``````foreach (object, AllObjects()) {
if (object.parent = null) {
if (Equal (object.x, game.x) and Equal (object.y, game.y)) {
object.parent = object.room
}
}
}
``````

and once all that is done, you can move the player to their new room, so the description will be displayed using the recently moved objects.

1. Actually destroying unnecessary objects

In theory you could destroy any objects that are floating around; store the random numbers used to generate each room in some set of attributes, and use those numbers to clone the objects again when they're needed. But this is already a complex thing to do, and if your objects have any attributes it will become even harder.

whenever there is a Floor in the room, the generator will not create anything, this solves my problem of auto-generating, but when tested in real life, the game does not recognize the Floors, because when you clone an object, it will create Floor1 instead of Floor

Rather than testing if the object named `Floor` is here, you want to test if there is a clone of `Floor` here. The clone functions (`CloneObject`, `CloneObjectAndMove`, `CloneObjectAndMoveHere`, and `CloneObjectAndInitialise`) will all give an object a `prototype` attribute which can be used to find its clones.

For example, the expression `FilterByAttribute (AllObjects(), "prototype", Floor)` will give you an objectlist of all clones of `Floor`.

In this case, a more useful expression would be`FilterByAttribute (GetDirectChildren (game.pov.parent), "prototype", Floor)` which examines all objects in the current room to see if any of them are clones of `Floor`.

You could use this like:

``````floorlist = FilterByAttribute (GetDirectChildren (game.pov.parent), "prototype", Floor)
if (ListCount (floorlist) = 0) {
// do whatever you wanted to do if there *isn't* a floor here
}
else {
thisfloor = PickOneObject (floorlist)
// if you want to do anything when there is a floor here, you can do it here
// you can use the variable `floorlist` to access the floor object in this room
// or just remove the else clause if you don't need to do anything
}
``````

I think that should be everything you need in order to make this work.
Is there anything I've missed?

mrangel have the correct solution for infinite maze, if his solution helps you, you can help him by checking out his books.

You didn't missed anything, you even added more solutions for problems I have not predicted yet.
I like to make easy games or apps to slowly learn about quest textadventure and coding, but it looks like I have stumbled upon a beast.
It would take me some time to code the above then I can reply you whether I am able to do it.

Thanks a lot!

Update: Your first common way is to clone room, I cannot find such an option in quest, it might be done in code view programming, and I googled out https://textadventures.co.uk/forum/quest/topic/muyzncmskuamclqqeiqw9w/cloning-a-room-contents
which is too much for me to do, and I do not even know how to begin with programming "Whenever the player goes through an exit that doesn't lead anywhere", so I shall skip this method.

You second common method is to use single room, this is probably the easiest method for me to deal with, you pointed out a flaw with this method but this flaw does not applies to me, I am basically making rpg games, like randomly generating monsters with stats that are at a lower ratio to player's stats and then sceneries that does not do anything, but I get what you mean, if I decide to expand the game, It will be hard to memorize the map even if I draw a map in real life, because every room will have multiple objects for me to record down.

Your formula below shockingly works and I do not know why :) (Do not bother to re-explain me, I am slow.)

``````thischair = CloneObjectAndMoveHere (Chair)
thischair.x = game.x
thischair.y = game.y
foreach (room, GetDirectChildren (DungeonContainer)) {
foreach (object, GetDirectChildren (room)) {
if (HasInt (object, "x") and HasInt (object, "y") and not Contains (game.pov, object)) {
object.visible = (object.x = game.x and object.y = game.y)}}}
``````
1. To explain why I made a 5x4 dungeon instead of a 1x1 dungeon, it is because I am making an infinite maze, within a 5x4 dungeon, I can predetermined open paths from the north, south, east and west doors to each other, usually in a + crossroads.
For a 1x1 dungeon, each north, south, east and west have 20% of becoming closed paths, it is unlikely to have fully closed paths and players gets stuck, but if the players do encounter such heavy unluckiness, the maze is not infinite anymore.

2. But there is a better way to create an infinite maze with 1x1 dungeon, basically the start of xy coordinates = 1 to 5, rooms of 25 have open paths from the very start of maze, after that, further paths will have 20% of becoming closed paths. I do not know the maths, but perhaps there is 400% chance of open path on NSEW, the next path will have 320%, the next path will have 256%, actually we will probably have to write out such a dungeon to see whether it works.

3. The last way to create an infinite maze with 1x1 dungeon is to spawn 3x3 closed rooms, however this type of map does not gives me the feeling of a narrow hedge maze, which is the feeling I am trying to replicate.

The "single room and put stuff in there" is how the original text adventures did it. (And the way I did it in Basic before finding Quest. Still find the idea of objects strange. And clones even stranger!)
The nice thing about programming is that 10 people can give to 20 ways to solve a problem, and in the end, you come up with number 21, that no one else even thought about.

Apparently the forum do not like me editing my old post for new updates.

Me rephrasing MrAngel's solution to try to understand it:
thischair is confusing because it sounds like this(object) or chair(object), but it is just random word for a variable, meaning I can put x1 to replace thischair instead, which I tested and it still works.
If thischair is an object, it would not works, as it can only gains 1 set of x and y, however it is actually a variable, a variable is just a temporary value which disappears after the script has ended. MrAngel used a variable to link up CloneObjectAndMoveHere (Chair).xy = game.xy, because if you directly write my formula, the game do not accepts such equation.
So another way to simplify this is:

``````x1 = CloneObjectAndMoveHere (Chair)
x1.x = game.x
x1.y = game.y
``````

Now for the next program: foreach

``````foreach (room, GetDirectChildren (DungeonContainer)) {
foreach (object, GetDirectChildren (room)) {
if (HasInt (object, "x") and HasInt (object, "y") and not Contains (game.pov, object)) {
object.visible = (object.x = game.x and object.y = game.y)}}}
``````

foreach means to run this same script multiple times.
(room,) means to keep the result of the script to this variable.
(, GetDirectChildren(DungeonContainer)) means to get all the room folders inside the parent folder (DungeonContainer).

The next line of code

``````foreach (object, GetDirectChildren (room))
``````

is similar, run same script multiple times, to get all childrens of room folder which gives us all the objects, and the result is kept in the variable called object.

Third line of code

``````if (HasInt (object, "x") and HasInt (object, "y") and not Contains (game.pov, object))
``````

We retrieve the variable object from previous 2 lines of codes, and test whether they have attributes x or y, and whether they do not have point of view (game.pov), after much googling, game.pov seems to refer to all objects inside player's folder which is basically the player's inventory.
`not Contains (game.pov, object)` means excluding all the objects in the player's inventory, meaning the player's inventory is excluded from the above if code. I am thinking this `not Contains (game.pov, object)` is not important, because generally player's inventory are usually and already visible. The whole 4 lines of code is to make objects visible, but the code is excluding player's inventory when making objects visible, but like I said, player's inventory are usually visible.

Lastly

``````object.visible = (object.x = game.x and object.y = game.y)}}}
``````

object.visible means to make all the objects in this variable "object" visible, the right hand side means make it visible only if the variable object have an x coordinate = to the current game x coordinate.

The code can be rewritten as below for easier understanding.

``````foreach (x2, GetDirectChildren (DungeonContainer)) {
foreach (x3, GetDirectChildren (x2)) {
if (HasInt (x3, "x") and HasInt (x3, "y") and not Contains (game.pov, x3)) {
x3.visible = (x3.x = game.x and x3.y = game.y)}}}
``````

Our next code is fairly simple

``````foreach (object, ScopeInventory()) {
object.x = game.x
object.y = game.y}
``````

ScopeInventory code returns an objectlist containing all the visible objects which the player has in their inventory.
So foreach code again, for each object in player's inventory, change the object xy coordinates to the new xy coordinates.
This code is used when player entering a map of different xy coordinates, so that when the player decides to drop an inventory, it will have the correct xy coordinates.

For MrAngel's solution 2, it is recommended to start on a new quest file, it would be useful to keep the old file for future referencing.

``````foreach (room, GetDirectChildren (DungeonContainer)) {
foreach (object, GetDirectChildren (room)) {
if (not (object = game.pov or Contains (game.pov, object))) {
object.x = game.x
object.y = game.y
object.room = room
RemoveObject (object) }}}
``````

So we input this code, we find out that our doors(object) disappeared, whenever our autogenerator creates new object like a Chair(object), the Chairs disappears too. So if you look at the code similar to MrAngel's first solution, it digs out all objects in the game except for the player and the player's inventory.
`object = game.pov` refers to the player.
`Contains (game.pov, object)` refers to the player's inventory.
`RemoveObject (object)` like MrAngel said, it moves the object away instead of destroying, I am guessing this code moves the object out of parents/rooms.
`object.room = room` refers to adding new attributes to all objects, the attribute is named room, this code is strange as it records the current room name, this is probably useless in 1x1 dungeon infinite maze, this might be for 4x5 dungeon infinite maze, but, in short, its utility is strange.

I am skipping `FilterByAttribute`

This next code do not seems to works.

``````foreach (object, AllObjects()) {
if (object.parent = null) {
if (Equal (object.x, game.x) and Equal (object.y, game.y)) {
object.parent = object.room}}}
``````

It basically takes out all objects and store them in variable object,
Find all the objects have no parents/room, then amongst them,
find objects with same xy coordinates as the current map xy coordinates,
Finally, change this object's parent into a room.

Why it does not works is because the doors appears but the autogenerated old Chairs reappear whenever the player
enters a new map of different xy.
While we do not have an answer for that, after rereading, we know that solution 2 is better than solution 1 because it does not
relies on visibility, but rather on rooms instead, therefore we could still introduce invisible objects in our game.
Because that is the main difference, our coding error lies in that area too, we are missing some lines of coding about rooms.

For MrAngel's solution 3, start a new quest file and keep the old file for future referencing.

``````floorlist = FilterByAttribute (GetDirectChildren (game.pov.parent), "prototype", Floor)
if (ListCount (floorlist) = 0) {
// do whatever you wanted to do if there *isn't* a floor here
}
else {
thisfloor = PickOneObject (floorlist)
// if you want to do anything when there is a floor here, you can do it here
// you can use the variable `floorlist` to access the floor object in this room
// or just remove the else clause if you don't need to do anything}
``````

For this code, it is called FilterByAttribute, FilterByAttribute returns a new object list containing only the objects in the given list for which the named attribute has the given value.

``````floorlist = FilterByAttribute (GetDirectChildren (game.pov.parent), "prototype", Floor)
``````

floorlist is most likely a variable, FilterByAttribute gives us something,
(GetDirectChildren (game.pov.parent) are the parents of the players which is the room player is at right now.
"prototype" is an attribute, Floor is used here so we can find out about it.
In short, variable = Find(player's room, "prototype" attribute, value=Floor)
So to rephrase it again, Find prototype Floor in the player's room and gives us that value inside a variable, so like MrAngel said, the prototype means that this Floor is a clone, therefore this line of code is extremely important to all our future games and coding, because I am going to streamline my coding to autogeneration as autogeneration codes uses one set of code to play 100 to unlimited rooms, as compared to making 100 codes for 100 rooms, which I have tried in my previous games, I will give up and surrender!

Creating clones baffle me too...
So, why use them?
The player is only in 1 room at a time.
why not place the "one and only" chair in the current room (if one is needed), when the player enters the room?
You could even randomize the chair's description each time. But, I see where the chair would keep changing colors if the player jumps back and forth between 2 rooms with the chair in it. In that case, add an attribute to the chair based on the room number (.X and .Y not needed.)
4x5 rooms numbered this way:
01, 02, 03, 04, 05
06, 07, 08, 09, 10
11, 12, 13, 15, 15
16, 17, 18, 19, 20
exit=room 03
start room=18
I should be very easy to randomize the room contents like this:
// random floors
(pseudo code because I think in BASIC and must translate to Quest)
for a=0 t0 20
x=rnd(6) ' 6 different floors
floor(a)=x ' make room#A.floor= random floor# X
next a '
Now you have the room floor descriptions set.
Floor="5,2,4,1,3,2,5,5,2,3,4,2,1,3,6,6,1,3,2,3"
And do the same for the chair
0=no chair, >0 = a chair of the random color
Now, when the player enters the room, just read the floor(room#) to get the floor,
and chair(room#) to place the chair, and the same for every other item you want to add.
If the player picks up the chair, change chair(room#)=0 (no chair)
Altho, this would limit each room to only having 1 chair.
This isn't object programming, but it does work the same way, altho, if the chair IS an object, then would it count?

For DarkLizerd, creating clones might be required as I generally make rpg games, I have to create multiple enemies like AxeDwarf1 and AxeDwarf2, players have the option to retreat after battling halfway, meaning there is one dwarf with half hp, and the other with full hp. (If it matters, I am using autogeneration monsters, objects, everything, so cloning seems relevant even if I am no master of it.)
I am going to take some time to read the rest of your code.

Guys stop giving me additional code for Infinite Maze, LOL, I only know if else programming, anymore is stressing me out for now.
I cannot even comprehend MrAngel's solution and I do not know BASIC code or any other programming language.

Give me a few days and I can slap an example together. Right now, I'm getting my Dark Halloween re-working, and expanded.

Quest
Squiffy
ActiveLit

Documentation
Blog
GitHub

Forums