\cfg{text-indent}{0} \cfg{text-width}{72} \cfg{text-title-align}{left} \cfg{text-chapter-align}{left} \cfg{text-chapter-numeric}{true} \cfg{text-chapter-suffix}{. } \cfg{text-chapter-underline}{-} \cfg{text-section-align}{0}{left} \cfg{text-section-numeric}{0}{true} \cfg{text-section-suffix}{0}{. } \cfg{text-section-underline}{0}{-} \cfg{text-section-align}{1}{left} \cfg{text-section-numeric}{1}{true} \cfg{text-section-suffix}{1}{. } \cfg{text-section-underline}{1}{-} \cfg{text-versionid}{0} \title Hacking guide for Simon Tatham's puzzle collection \C{newpuz} Guide to writing a new puzzle Start by copying \cw{nullgame.c}. This contains all the function definitions and stubs that should be necessary to at least compile. Some things are fine as they are unless you do something that requires a change (for example, \cw{dup_params()} can usually be left as it is since game parameters often don't have any variable-size elements that need to be dynamically allocated); other things are sure to need changing (for example, the params structure is likely to need to contain at least one actual variable). Anything marked \q{FIXME} really needs changing before you have a working game. \e{DO NOT EDIT THE MAKEFILES.} Edit \c{Recipe} instead, and then re-run \cw{mkfiles.pl}. The individual makefiles are automatically generated by this mechanism, so editing them directly will not produce a usable patch. \H{newpuz-arch} General architecture tips Think carefully about which data structures need to contain which parts of the game information. \b \c{game_state} should contain everything that holds the current state of play in a specific game. The mid-end maintains one of these for every move the player has made, and moves back and forwards along the list when you use Undo and Redo. So anything you would expect to have restored when you undo needs to go in this state. \b \c{game_params} should contain parameters the user can set before generating a new game. For example, if the game is played on a grid of variable size, \cw{game_params} contains the grid size. (\cw{game_state} will \e{also} need to contain the grid size. You might even wish to have \cw{game_state} contain a \cw{game_params} member.) \b \c{game_ui} contains aspects of the game's user interface which are not expected to be restored in an undo operation. For example, if you have a basically mouse-clicky sort of game (such as Net) but you want to provide a cursor which can be moved with the arrow keys, then putting the location of the cursor in \c{game_ui} is reasonable. Or if the game allows you to drag things around the display, then the current state of dragging is something that can go in \c{game_ui}. Simple games don't need a \cw{game_ui} structure at all. \b \c{game_drawstate} contains things you know about the current state of the game's display. For example, if your display is made up of tiles and you want to redraw as few as possible, you might want to have \c{game_drawstate} contain a description of the last tile you drew at every position, so that you can compare it to the new tile and avoid redrawing tiles that haven't changed. \H{newpuz-params} Notes on parameters You need to define a textual format for the game parameters (the part before the \q{:} or \q{#} in descriptive and random IDs respectively). The per-game parameter encoding function \cw{encode_params()} is passed an argument \c{full}. This serves two purposes: \b You can suppress inclusion of parameters that only affect game generation, and thus would have no effect in a descriptive ID, in the ID displayed by \q{Game -> Specific} if \c{full} is \cw{FALSE}. \b You can ensure that a particular parameter entered as part of a game ID does not persist when a new puzzle is generated, for instance if you think that a player would not want it to persist beyond a single game. An example is the \q{expansion factor} in Rectangles. When generating a new puzzle instance, give some thought to the order in which parameters are processed. For example, the order of grid generation in Net is: \b First the game sets up a valid completed Net grid. \b Then it makes a list of every edge with no connection across it. These edges are eligible to become barriers. \b Then the grid is shuffled by randomly rotating every tile. \b Then the game multiplies the number of barrier-candidate edges by the barrier probability in order to decide how many barriers to create. \b Finally, it picks that many edges out of the barrier candidate list, removing each edge from the list as it selects it. The effect of this is that the actual barrier locations are chosen \e{last}, which means that if you change the barrier rate and then enter the same random number seed, \e{only} the barriers change. Furthermore, if you do this, the barrier sets will be nested (i.e. the version with more barriers will contain every barrier from the one with fewer), so that selecting 10 barriers and then 20 barriers will not give a user 30 pieces of information, only 20. \H{newpuz-descid} Notes on descriptive IDs The descriptive game ID is the part that comes after the colon in the ID accessed through \q{Game -> Specific}. It does not need to be especially concise, but it should be designed to remain compatible with new versions of the puzzle. Try to imagine all the things a user might want to use the descriptive ID for, and build as much capability into it as possible. At a minimum, you need to be able to generate one of these given a random number source; however, if auto-generation capability is limited, give some thought to the possibility of a user making up their own descriptive IDs. This property is particularly useful if the puzzle is an implementation of a well-known game, in which case existing instances of the puzzle might be available which a user might want to transcribe into game seeds in order to play them conveniently. \H{newpuz-redraw} Designing a drawing routine Front end implementations are required to remember all data drawn by the game. That is, a game redraw routine MUST never be called simply because part of the game window was briefly obscured; the front end is required to remember what the game last drew in that area of the window, and redraw it itself without bothering the game module. Many games will need some form of animation when transferring between one \cw{game_state} and the next. This is achieved by having \cw{game_anim_length()} analyse two adjacent game states, decide how long the linking animation between them should last, and return this duration in seconds. Then \cw{game_redraw()} will be passed the two game states plus an indication of how far through the animation it is, and can do its drawing appropriately. \e{Be aware that you will be required to animate on undo}. If you are at game state A and the user makes a move creating game state B, then your redraw function will be passed both states A and B, in that order, and will be expected to animate between them if your game needs animation. However, if the user then hits Undo, your redraw function will be passed states B and A, in \e{that} order, and will be expected to perform the reverse animation. This is easy enough for some games. In Fifteen, for example, it's simply a matter of examining the two game states to work out what has changed between them, and drawing each tile some proportion of the way between its starting and finishing positions. In Sixteen, things are more difficult. You could examine the grid to work out which tiles had been moved and decide which way they had been moved, but this would be disconcerting to the user in some cases. In a 2xN game of Sixteen, rotating a two-tile row left or right has the same end result but should look different during the enimation; so the Sixteen \cw{game_state} in fact stores an extra piece of information giving the direction of the last move. So when making a normal move, \cw{game_redraw()} can know which way round it is expected to animate a two-tile rotation. However, even this doesn't fix the undo case. When \cw{game_redraw()} is passed a pair of game states in the right chronological order, the second one contains the direction field which corresponds to the actual difference between the states. However, when it is passed a pair of states in the opposite order due to an undo, it should be looking in the \e{first} one to find the direction field. For this reason, in the redraw functions you are provided with an extra argument \c{dir} which tells you which state was chronologically first; \c{dir} is +1 for a normal move and -1 for an undo.