Home > notes > Mirror Puzzles

Using the Mirror Puzzle Manager

If you want to re-use GPG's work in DS2 for the rotating mirror puzzles then you need to know how they operate. Not everything is documented in the files, so some things have to be deduced from the examples in the game.

Each rotating statue already has a piece of skrit attached via the template, and there are a number of parameters that need some explanation that you won't find in there. Here is an example of a placed statue from the interactive.gas file in one of my regions.

[t:statue_puzzle_mirror_02,n:0xdad0000a]
{
	[aspect]
	{
	  f scale_multiplier = 1.5;
	}
	[light_beam_puzzle_obj]
	{
	  x light_enable = 0xDAD0003D;
	  x puzzle_manager = 0xDAD0002C;
	  i puzzle_obj_index = 3;
	  x reflecting_point_1 = 0xDAD00009;
	  x reflecting_point_2 = 0xDAD0000C;
	  x reflecting_point_3 = 0xDAD00013;
		state_table1 = "1,p:2,p:2,b:0,r:3";
	}
	[placement]
	{
	  q orientation = 0,-0.382683,0,-0.923879;
	  p position = 2.95455,0,1.06218,0x96556020;
	}
}

"light_beam_puzzle_obj" is the name of the skrit that manages an individual statue. You need to provide that skrit a number of parameters as shown in the associated block. I'll run through them in the order shown

light_enable
This is the SCID of a light_enable gizmo that will flash a light when the reflection starts. It's not the beam itself, just an effect for the event of making another connection.
puzzle_manager
This is the SCID of the single puzzle_manager gizmo that all the statues are linked to. It has its own skrit that sends messages back to the various statues to tell them when to show a beam.
puzzle_obj_index
This number must run from 1 to (max)17 and represents this statue's index in the manager's array of statues.
reflecting_point_n
These are the SCIDs of the statues (or lightweight_pos objects) that a beam may come from, or go to. You can define up to six of these. Note that the statue referenced may be passing the beam, not reflecting it.
state_table1
There can be up to four instances of this and each defines what the statue does to a beam coming from one of the other statues. See the explanation below for the pieces.

Before explaining the state table, let's take a look at the possible beams past a statue. The image below shows a statue and the eight possible beams that can pass it, coming from directions a to h. Since the skrit for a statue only allows for 6 reflecting_point SCIDs, thay can't all exist. Furthermore, at least two of those would have to be outbound only because a state table entry deals with an incoming beam, and you only have room for four of those

In the diagram, the statue is reflecting any beam from a to go to h, or vice versa, blocking beams from c or f and passing all the others through to the opposite side. If the statue is rotated, then all that changes.

State Tables

A state_table entry describes what happens to a beam from one specific direction. The first entry is the number of the "reflecting_point" that the beam arrives from. I.e. code "1" if it comes from the SCID entered as "reflecting_point_1". That statue may have simply passed the beam from a statue further away - the far statue does not appear in your list of reflecting points. Then the next four parts define what happens to the beam.

state_table1 = "1,p:2,p:2,b:0,r:3"

The example shown says that a beam from direction 1 is passed to 2, meaning it goes towards the relecting_point_2 SCID, if the statue is in its original position (p:2). The same if rotated once (counter-clockwise). A second rotation blocks the beam, so it goes nowhere (b:0). and yet another causes a reflection to 3 (r:3). Each state_table line will have one block, one reflect and two passes, because it deals with a beam from just one direction.

The important things to note are that you can't have the full eight beams for any statue, and that of the six directions a beam may go, you only are allowed four which can send you a beam, the others must be objects other than statues, preferably "lightweight_pos". The beam actions in the state_table are in counter-clockwise order, starting at the initial position of the statue, which means that you must check its start position before filling in the values.

The Ends of the puzzle

A statue at the beginning or end of the correct path gets some extra entries, two of which need a bit of explanation. The final statue may receive a beam before the puzzle is solved, so the direction the beam comes in, and what the statue does to that beam, actually decide if the puzzle is solved. So there is a parameter for the SCID of the statue that sends the penultimate beam, and another true/false one to say if it's a pass or reflect at the final statue (obviously it can't be a block!)

More than one statue can be "final" if there are intermediate steps in the puzzle. Each "final" statue will send a message to another object to provide the reward, or advance the quest, and the SCID of that object is also set as a parameter. Usually this will be a trigger, to allow multiple results to chain off the event.

Initial Statue

The mirror-less statues provided and their replacements are different from the others in that they hold the mirror at a different angle to reflect a beam arriving from above. This also shows in the first statue state_table which has a value of "0,p:0,r:1,p:0,p:0" or similar, to show that it only reflects a beam onward in one position and passes all others down. The beam comes from nowhere, so 0 is used as the number. In fact, you must supply an emitter for the downward beam, but it is not referenced by anything in the statue or manager links, and the puzzle works without it, even though setting it up that way wouldn't make sense.

Puzzle Manager

The light_beam_puzzle_manager object (a "special") has parameters "puzzle_mirror_1" up to "puzzle_mirror_17" so you can use only 17 statues in your puzzle (or rewrite the template, all the skrit etc.) You need to copy the SCID for the statue which has puzzle_obj_index set to 1 as "puzzle_mirror_1" and so on. The entries must be consecutive, and the numbers must match, but the order is not important. The statue with the first_statue entry set to true, does not have to be index 1.

The purpose of the manager is to handle the chaining of the beams. Each statue only knows what to do when a beam arrives, (pass, block or reflect) but not the overall state of the puzzle. So as each statue is rotated, the manager must determine which statues need to be notified of the new path of the light, and tell them that the incoming beam has turned on or off.

Multiple paths

I avoided this when I made my puzzle, but the code makes provision for more than one beam (two is the max!) to pass between the same two statues. The state_table string can specify an additional parameter at the end to number the outgoing beam as 1 or 2, and the incoming beam can also be specified as 4:2 for example, to indicate beam 2 from direction 4. The statue then has to have some other booleans set to indicate that it handles conditional beams in, and/or out. Since you can only handle four incoming beams in total, this is not something to do very often.

You can also handle multiple beams from different directions just by setting that flag, but that's nothing like as complex.

Missing Mirrors

Each of the puzzles in the DS2 world starts with you providing a missing mirror to the first statue. This is achieved by placing two statues in the same spot, making one (with a mirror) initially invisible, and having the other be a trigger, used with a quest item - the mirror, to swap the two. In my puzzles, I made the mirror-less ones intermediates, which required a new mesh, but everything else stays the same.

Troubleshooting

There's a lot that can go wrong with setting up the state tables, but the HUD can help you a lot. Once you've added the refecting points, you will see labelled arrows connecting each statue to its sources and targets, so the first check to make is that they really are the adjacent ones, and you didn't skip a statue that passes the beam. The arrows should also run approximately along the rectangular grid, any diagonals are probably errors.

If you run the region in DSMOD and you get the error that the string tool can't find a delimited string, it means you have a typo in a state table. My most frequent mistake was swapping the commas and colons, but I also managed a few semi-colons and numbers for which there were no targets. You will also have at least one state table where you figured the rotations backward, or started at the wrong position. Unfortunately, the only way you find these errors is to try rotating each statue, and see where the beam goes.

When the skrit can't find a valid path for the beam, it will often just turn it off, and give you no indication of an error. The problem can be with the current statue, but more likely it will be the one that should have got the beam next doesn't have a path for it, or needs the flag set to handle multiple beams.

Lara 3