787cfc96 |
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 | |
713e4dde |
73 | \H{newpuz-params} Notes on parameters |
74 | |
75 | You need to define a textual format for the game parameters (the part |
76 | before the \q{:} or \q{#} in descriptive and random IDs respectively). |
77 | |
78 | The per-game parameter encoding function \cw{encode_params()} is |
79 | passed an argument \c{full}. This serves two purposes: |
80 | |
81 | \b You can suppress inclusion of parameters that only affect game |
82 | generation, and thus would have no effect in a descriptive ID, in the |
83 | ID displayed by \q{Game -> Specific} if \c{full} is \cw{FALSE}. |
84 | |
85 | \b You can ensure that a particular parameter entered as part of a |
86 | game ID does not persist when a new puzzle is generated, for instance |
87 | if you think that a player would not want it to persist beyond a |
88 | single game. An example is the \q{expansion factor} in Rectangles. |
89 | |
90 | When generating a new puzzle instance, give some thought to the order |
91 | in which parameters are processed. For example, the order of grid |
92 | generation in Net is: |
787cfc96 |
93 | |
94 | \b First the game sets up a valid completed Net grid. |
95 | |
96 | \b Then it makes a list of every edge with no connection across it. |
97 | These edges are eligible to become barriers. |
98 | |
99 | \b Then the grid is shuffled by randomly rotating every tile. |
100 | |
101 | \b Then the game multiplies the number of barrier-candidate edges by |
102 | the barrier probability in order to decide how many barriers to |
103 | create. |
104 | |
105 | \b Finally, it picks that many edges out of the barrier candidate |
106 | list, removing each edge from the list as it selects it. |
107 | |
108 | The effect of this is that the actual barrier locations are chosen |
109 | \e{last}, which means that if you change the barrier rate and then |
110 | enter the same random number seed, \e{only} the barriers change. |
111 | Furthermore, if you do this, the barrier sets will be nested (i.e. |
112 | the version with more barriers will contain every barrier from the |
113 | one with fewer), so that selecting 10 barriers and then 20 barriers |
114 | will not give a user 30 pieces of information, only 20. |
115 | |
713e4dde |
116 | \H{newpuz-descid} Notes on descriptive IDs |
117 | |
118 | The descriptive game ID is the part that comes after the colon in the |
119 | ID accessed through \q{Game -> Specific}. It does not need to be |
120 | especially concise, but it should be designed to remain compatible |
121 | with new versions of the puzzle. |
122 | |
123 | Try to imagine all the things a user might want to use the descriptive |
124 | ID for, and build as much capability into it as possible. At a minimum, |
125 | you need to be able to generate one of these given a random number |
126 | source; however, if auto-generation capability is limited, give some |
127 | thought to the possibility of a user making up their own descriptive |
128 | IDs. This property is particularly useful if the puzzle is an |
129 | implementation of a well-known game, in which case existing instances |
130 | of the puzzle might be available which a user might want to transcribe |
131 | into game seeds in order to play them conveniently. |
132 | |
787cfc96 |
133 | \H{newpuz-redraw} Designing a drawing routine |
134 | |
135 | Front end implementations are required to remember all data drawn by |
136 | the game. That is, a game redraw routine MUST never be called simply |
137 | because part of the game window was briefly obscured; the front end |
138 | is required to remember what the game last drew in that area of the |
139 | window, and redraw it itself without bothering the game module. |
140 | |
141 | Many games will need some form of animation when transferring |
142 | between one \cw{game_state} and the next. This is achieved by having |
143 | \cw{game_anim_length()} analyse two adjacent game states, decide how |
144 | long the linking animation between them should last, and return this |
145 | duration in seconds. Then \cw{game_redraw()} will be passed the two |
146 | game states plus an indication of how far through the animation it |
147 | is, and can do its drawing appropriately. |
148 | |
149 | \e{Be aware that you will be required to animate on undo}. If you |
150 | are at game state A and the user makes a move creating game state B, |
151 | then your redraw function will be passed both states A and B, in |
152 | that order, and will be expected to animate between them if your |
153 | game needs animation. However, if the user then hits Undo, your |
154 | redraw function will be passed states B and A, in \e{that} order, |
155 | and will be expected to perform the reverse animation. |
156 | |
157 | This is easy enough for some games. In Fifteen, for example, it's |
158 | simply a matter of examining the two game states to work out what |
159 | has changed between them, and drawing each tile some proportion of |
160 | the way between its starting and finishing positions. |
161 | |
162 | In Sixteen, things are more difficult. You could examine the grid to |
163 | work out which tiles had been moved and decide which way they had |
164 | been moved, but this would be disconcerting to the user in some |
165 | cases. In a 2xN game of Sixteen, rotating a two-tile row left or |
166 | right has the same end result but should look different during the |
167 | enimation; so the Sixteen \cw{game_state} in fact stores an extra |
168 | piece of information giving the direction of the last move. So when |
169 | making a normal move, \cw{game_redraw()} can know which way round it |
170 | is expected to animate a two-tile rotation. |
171 | |
172 | However, even this doesn't fix the undo case. When |
173 | \cw{game_redraw()} is passed a pair of game states in the right |
174 | chronological order, the second one contains the direction field |
175 | which corresponds to the actual difference between the states. |
176 | However, when it is passed a pair of states in the opposite order |
177 | due to an undo, it should be looking in the \e{first} one to find |
c822de4a |
178 | the direction field. |
179 | |
180 | For this reason, in the redraw functions you are provided with an |
181 | extra argument \c{dir} which tells you which state was chronologically |
182 | first; \c{dir} is +1 for a normal move and -1 for an undo. |