| 1 | \cfg{text-indent}{0} |
| 2 | \cfg{text-width}{72} |
| 3 | \cfg{text-title-align}{left} |
| 4 | \cfg{text-chapter-align}{left} |
| 5 | \cfg{text-chapter-numeric}{true} |
| 6 | \cfg{text-chapter-suffix}{. } |
| 7 | \cfg{text-chapter-underline}{-} |
| 8 | \cfg{text-section-align}{0}{left} |
| 9 | \cfg{text-section-numeric}{0}{true} |
| 10 | \cfg{text-section-suffix}{0}{. } |
| 11 | \cfg{text-section-underline}{0}{-} |
| 12 | \cfg{text-section-align}{1}{left} |
| 13 | \cfg{text-section-numeric}{1}{true} |
| 14 | \cfg{text-section-suffix}{1}{. } |
| 15 | \cfg{text-section-underline}{1}{-} |
| 16 | \cfg{text-versionid}{0} |
| 17 | |
| 18 | \title Hacking guide for Simon Tatham's puzzle collection |
| 19 | |
| 20 | \C{newpuz} Guide to writing a new puzzle |
| 21 | |
| 22 | Start by copying \cw{nullgame.c}. This contains all the function |
| 23 | definitions and stubs that should be necessary to at least compile. |
| 24 | Some things are fine as they are unless you do something that |
| 25 | requires a change (for example, \cw{dup_params()} can usually be |
| 26 | left as it is since game parameters often don't have any |
| 27 | variable-size elements that need to be dynamically allocated); other |
| 28 | things are sure to need changing (for example, the params structure |
| 29 | is likely to need to contain at least one actual variable). Anything |
| 30 | marked \q{FIXME} really needs changing before you have a working |
| 31 | game. |
| 32 | |
| 33 | \e{DO NOT EDIT THE MAKEFILES.} Edit \c{Recipe} instead, and then |
| 34 | re-run \cw{mkfiles.pl}. The individual makefiles are automatically |
| 35 | generated by this mechanism, so editing them directly will not |
| 36 | produce a usable patch. |
| 37 | |
| 38 | \H{newpuz-arch} General architecture tips |
| 39 | |
| 40 | Think carefully about which data structures need to contain which |
| 41 | parts of the game information. |
| 42 | |
| 43 | \b \c{game_state} should contain everything that holds the current |
| 44 | state of play in a specific game. The mid-end maintains one of these |
| 45 | for every move the player has made, and moves back and forwards |
| 46 | along the list when you use Undo and Redo. So anything you would |
| 47 | expect to have restored when you undo needs to go in this state. |
| 48 | |
| 49 | \b \c{game_params} should contain parameters the user can set before |
| 50 | generating a new game. For example, if the game is played on a grid |
| 51 | of variable size, \cw{game_params} contains the grid size. |
| 52 | (\cw{game_state} will \e{also} need to contain the grid size. You |
| 53 | might even wish to have \cw{game_state} contain a \cw{game_params} |
| 54 | member.) |
| 55 | |
| 56 | \b \c{game_ui} contains aspects of the game's user interface which |
| 57 | are not expected to be restored in an undo operation. For example, |
| 58 | if you have a basically mouse-clicky sort of game (such as Net) but |
| 59 | you want to provide a cursor which can be moved with the arrow keys, |
| 60 | then putting the location of the cursor in \c{game_ui} is |
| 61 | reasonable. Or if the game allows you to drag things around the |
| 62 | display, then the current state of dragging is something that can go |
| 63 | in \c{game_ui}. Simple games don't need a \cw{game_ui} structure at |
| 64 | all. |
| 65 | |
| 66 | \b \c{game_drawstate} contains things you know about the current |
| 67 | state of the game's display. For example, if your display is made up |
| 68 | of tiles and you want to redraw as few as possible, you might want |
| 69 | to have \c{game_drawstate} contain a description of the last tile |
| 70 | you drew at every position, so that you can compare it to the new |
| 71 | tile and avoid redrawing tiles that haven't changed. |
| 72 | |
| 73 | \H{newpuz-seed} Designing a game seed |
| 74 | |
| 75 | The game seed is the part of the game ID (what you type in when you |
| 76 | select \q{Game -> Specific}) which comes \e{after} the colon. It |
| 77 | should uniquely specify the starting state of a game, given a set of |
| 78 | game parameters (which are encoded separately, before the colon). |
| 79 | |
| 80 | Try to imagine all the things a user might want to use the game seed |
| 81 | for, and build as much capability into it as possible. |
| 82 | |
| 83 | For a start, if it's feasible for the game seed to \e{directly} |
| 84 | encode the starting position, it should simply do so. This is a |
| 85 | better approach than encoding a random number seed which is used to |
| 86 | randomly generate the game in \cw{new_game()}, because it allows the |
| 87 | user to make up their own game seeds. This property is particularly |
| 88 | useful if the puzzle is an implementation of a well-known game, in |
| 89 | which case existing instances of the puzzle might be available which |
| 90 | a user might want to transcribe into game seeds in order to play |
| 91 | them conveniently. I recommend this technique wherever you can |
| 92 | sensibly use it: \cw{new_game_seed()} should do all the real |
| 93 | thinking about creating a game seed, and \cw{new_game()} should |
| 94 | restrict itself to simply parsing the text description it returns. |
| 95 | |
| 96 | However, sometimes this is genuinely not feasible; Net, for example, |
| 97 | uses the random-number seed approach, because I decided the full |
| 98 | state of even a moderately large Net game is just too big to be |
| 99 | sensibly cut-and-pasted by users. However, even the Net seeds have a |
| 100 | useful property. The order of grid generation in Net is: |
| 101 | |
| 102 | \b First the game sets up a valid completed Net grid. |
| 103 | |
| 104 | \b Then it makes a list of every edge with no connection across it. |
| 105 | These edges are eligible to become barriers. |
| 106 | |
| 107 | \b Then the grid is shuffled by randomly rotating every tile. |
| 108 | |
| 109 | \b Then the game multiplies the number of barrier-candidate edges by |
| 110 | the barrier probability in order to decide how many barriers to |
| 111 | create. |
| 112 | |
| 113 | \b Finally, it picks that many edges out of the barrier candidate |
| 114 | list, removing each edge from the list as it selects it. |
| 115 | |
| 116 | The effect of this is that the actual barrier locations are chosen |
| 117 | \e{last}, which means that if you change the barrier rate and then |
| 118 | enter the same random number seed, \e{only} the barriers change. |
| 119 | Furthermore, if you do this, the barrier sets will be nested (i.e. |
| 120 | the version with more barriers will contain every barrier from the |
| 121 | one with fewer), so that selecting 10 barriers and then 20 barriers |
| 122 | will not give a user 30 pieces of information, only 20. |
| 123 | |
| 124 | \H{newpuz-redraw} Designing a drawing routine |
| 125 | |
| 126 | Front end implementations are required to remember all data drawn by |
| 127 | the game. That is, a game redraw routine MUST never be called simply |
| 128 | because part of the game window was briefly obscured; the front end |
| 129 | is required to remember what the game last drew in that area of the |
| 130 | window, and redraw it itself without bothering the game module. |
| 131 | |
| 132 | Many games will need some form of animation when transferring |
| 133 | between one \cw{game_state} and the next. This is achieved by having |
| 134 | \cw{game_anim_length()} analyse two adjacent game states, decide how |
| 135 | long the linking animation between them should last, and return this |
| 136 | duration in seconds. Then \cw{game_redraw()} will be passed the two |
| 137 | game states plus an indication of how far through the animation it |
| 138 | is, and can do its drawing appropriately. |
| 139 | |
| 140 | \e{Be aware that you will be required to animate on undo}. If you |
| 141 | are at game state A and the user makes a move creating game state B, |
| 142 | then your redraw function will be passed both states A and B, in |
| 143 | that order, and will be expected to animate between them if your |
| 144 | game needs animation. However, if the user then hits Undo, your |
| 145 | redraw function will be passed states B and A, in \e{that} order, |
| 146 | and will be expected to perform the reverse animation. |
| 147 | |
| 148 | This is easy enough for some games. In Fifteen, for example, it's |
| 149 | simply a matter of examining the two game states to work out what |
| 150 | has changed between them, and drawing each tile some proportion of |
| 151 | the way between its starting and finishing positions. |
| 152 | |
| 153 | In Sixteen, things are more difficult. You could examine the grid to |
| 154 | work out which tiles had been moved and decide which way they had |
| 155 | been moved, but this would be disconcerting to the user in some |
| 156 | cases. In a 2xN game of Sixteen, rotating a two-tile row left or |
| 157 | right has the same end result but should look different during the |
| 158 | enimation; so the Sixteen \cw{game_state} in fact stores an extra |
| 159 | piece of information giving the direction of the last move. So when |
| 160 | making a normal move, \cw{game_redraw()} can know which way round it |
| 161 | is expected to animate a two-tile rotation. |
| 162 | |
| 163 | However, even this doesn't fix the undo case. When |
| 164 | \cw{game_redraw()} is passed a pair of game states in the right |
| 165 | chronological order, the second one contains the direction field |
| 166 | which corresponds to the actual difference between the states. |
| 167 | However, when it is passed a pair of states in the opposite order |
| 168 | due to an undo, it should be looking in the \e{first} one to find |
| 169 | the direction field. |
| 170 | |
| 171 | For this reason, in the redraw functions you are provided with an |
| 172 | extra argument \c{dir} which tells you which state was chronologically |
| 173 | first; \c{dir} is +1 for a normal move and -1 for an undo. |