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