X-Git-Url: https://git.distorted.org.uk/~mdw/sgt/puzzles/blobdiff_plain/f487468f67fa996caab7de5b08a5da2c25ebd551..055b9cd27af52f30534c77af067a98e5ca9c4461:/devel.but diff --git a/devel.but b/devel.but index d310d2c..3695bcd 100644 --- a/devel.but +++ b/devel.but @@ -170,8 +170,8 @@ other miscellaneous functions. All of these are documented in There are a number of function call interfaces within Puzzles, and this guide will discuss each one in a chapter of its own. After -that, there will be a section about how to design new games, with -some general design thoughts and tips. +that, (\k{writing}) discusses how to design new games, with some +general design thoughts and tips. \C{backend} Interface to the back end @@ -193,7 +193,9 @@ end module builds a different puzzle. \b On platforms such as MacOS X and PalmOS, which build all the puzzles into a single monolithic binary, the game structure in each back end must have a different name, and there's a helper module -\c{list.c} which contains a complete list of those game structures. +\c{list.c} (constructed automatically by the same Perl script that +builds the \cw{Makefile}s) which contains a complete list of those +game structures. On the latter type of platform, source files may assume that the preprocessor symbol \c{COMBINED} has been defined. Thus, the usual @@ -443,7 +445,7 @@ difficulty, since to describe a puzzle once generated it's sufficient to give the grid dimensions and the location and contents of the clue squares. (Indeed, one might very easily type in a puzzle out of a newspaper without \e{knowing} what its difficulty level is -in Solo's terminology.) Therefore. Solo's \cw{encode_params()} only +in Solo's terminology.) Therefore, Solo's \cw{encode_params()} only encodes the difficulty level if \c{full} is set. \S{backend-decode-params} \cw{decode_params()} @@ -791,7 +793,7 @@ important enough to save. The location of the keyboard-controlled cursor, for example, can be reset to a default position on reloading the game without impacting the user experience. If the user should somehow manage to save a game while a mouse drag was in progress, -then discarding that mouse drag would be an outright \e{feature}, +then discarding that mouse drag would be an outright \e{feature}. A typical thing that \e{would} be worth encoding in this function is the Mines death counter: it's in the \c{game_ui} rather than the @@ -1097,9 +1099,14 @@ allocating a blitter (see \k{drawing-blitter}). The parameter \c{dr} is a drawing object (see \k{drawing}), which is required if a blitter needs to be allocated. +Back ends may assume (and may enforce by assertion) that this +function will be called at most once for any \c{game_drawstate}. If +a puzzle needs to be redrawn at a different size, the mid-end will +create a fresh drawstate. + \S{backend-colours} \cw{colours()} -\c float *(*colours)(frontend *fe, game_state *state, int *ncolours); +\c float *(*colours)(frontend *fe, int *ncolours); This function is responsible for telling the front end what colours the puzzle will need to draw itself. @@ -1110,15 +1117,7 @@ array of three times that many \c{float}s, containing the red, green and blue components of each colour respectively as numbers in the range [0,1]. -It is passed a sample \c{game_state} in case it needs one, although -currently no puzzle does need this. (In fact, colours are not -reallocated when the game parameters change or a new game is -started, so you can't reliably use this \c{game_state} to allocate a -different number of colours depending on the game. It is probably -actually a mistake to rely on this parameter at all. I ought to -either remove it or fix it; probably the former.) - -The final parameter passed to this function is a front end handle. +The second parameter passed to this function is a front end handle. The only things it is permitted to do with this handle are to call the front-end function called \cw{frontend_default_colour()} (see \k{frontend-default-colour}) or the utility function called @@ -1161,8 +1160,7 @@ State changes as a result of a Restart operation are never animated; the mid-end will handle them internally and never consult this function at all. State changes as a result of Solve operations are also not animated by default, although you can change this for a -particular game by setting a flag in \c{mouse_priorities} -(\k{backend-mouse-priorities}). +particular game by setting a flag in \c{flags} (\k{backend-flags}). The function is also passed a pointer to the local \c{game_ui}. It may refer to information in here to help with its decision (see @@ -1402,16 +1400,12 @@ whether that should come with a newline or not.) \S{backend-wants-statusbar} \cw{wants_statusbar()} -\c int (*wants_statusbar)(void); +\c int wants_statusbar; -This function returns \cw{TRUE} if the puzzle has a use for a +This boolean field is set to \cw{TRUE} if the puzzle has a use for a textual status line (to display score, completion status, currently active tiles, etc). -(This should probably be a static boolean field rather than a -function. I don't remember why I did it this way. I probably ought -to change it.) - \S{backend-is-timed} \c{is_timed} \c int is_timed; @@ -1436,17 +1430,17 @@ the game was first completed (by setting a flag in freeze the timer thereafter so that the user can undo back through their solution process without altering their time. -\S{backend-mouse-priorities} \c{mouse_priorities} +\S{backend-flags} \c{flags} -\c int mouse_priorities; +\c int flags; -This field is badly named. It is in fact a generic flags word. It -consists of the bitwise OR of the following flags: +This field contains miscellaneous per-backend flags. It consists of +the bitwise OR of some combination of the following: \dt \cw{BUTTON_BEATS(x,y)} -\dd Given any \cw{x} and \cw{y} from the set (\cw{LEFT_BUTTON}, -\cw{MIDDLE_BUTTON}, \cw{RIGHT_BUTTON}), this macro evaluates to a +\dd Given any \cw{x} and \cw{y} from the set \{\cw{LEFT_BUTTON}, +\cw{MIDDLE_BUTTON}, \cw{RIGHT_BUTTON}\}, this macro evaluates to a bit flag which indicates that when buttons \cw{x} and \cw{y} are both pressed simultaneously, the mid-end should consider \cw{x} to have priority. (In the absence of any such flags, the mid-end will @@ -1473,11 +1467,11 @@ otherwise be obvious. If a back end needs random numbers at some point during normal play, it can create a fresh \c{random_state} by first calling \c{get_random_seed} (\k{frontend-get-random-seed}) and then passing -the returned seed data to \cw{random_init()}. +the returned seed data to \cw{random_new()}. This is likely not to be what you want. If a puzzle needs randomness in the middle of play, it's likely to be more sensible to store some -sort of random state within the \e{game_state}, so that the random +sort of random state within the \c{game_state}, so that the random numbers are tied to the particular game state and hence the player can't simply keep undoing their move until they get numbers they like better. @@ -1551,14 +1545,13 @@ functions. This enables a single front end to switch between multiple implementations of the drawing API if necessary. For example, the Windows API supplies a printing mechanism integrated into the same GDI which deals with drawing in windows, and therefore -it is likely (although as yet unimplemented in Puzzles) that the -same API implementation can handle both drawing and printing; but on -Unix, the most common way for applications to print is by producing -PostScript output directly, and although it would be \e{possible} to -write a single (say) \cw{draw_rect()} function which checked a -global flag to decide whether to do GTK drawing operations or output -PostScript to a file, it's much nicer to have two separate functions -and switch between them as appropriate. +the same API implementation can handle both drawing and printing; +but on Unix, the most common way for applications to print is by +producing PostScript output directly, and although it would be +\e{possible} to write a single (say) \cw{draw_rect()} function which +checked a global flag to decide whether to do GTK drawing operations +or output PostScript to a file, it's much nicer to have two separate +functions and switch between them as appropriate. When drawing, the puzzle window is indexed by pixel coordinates, with the top left pixel defined as \cw{(0,0)} and the bottom right @@ -1580,10 +1573,10 @@ manipulation. \e{Puzzles' redraw functions may assume that the surface they draw on is persistent}. It is the responsibility of every front end to preserve the puzzle's window contents in the face of GUI window -expose issues and similar. It is not permissible to request the back -end redraw any part of a window that it has already drawn, unless -something has actually changed as a result of making moves in the -puzzle. +expose issues and similar. It is not permissible to request that the +back end redraw any part of a window that it has already drawn, +unless something has actually changed as a result of making moves in +the puzzle. Most front ends accomplish this by having the drawing routines draw on a stored bitmap rather than directly on the window, and copying @@ -1872,6 +1865,11 @@ with the drawing API the property that it may only be called from within the back end redraw function, so this is as good a place as any to document it.) +The supplied text is filtered through the mid-end for optional +rewriting before being passed on to the front end; the mid-end will +prepend the current game time if the game is timed (and may in +future perform other rewriting if it seems like a good idea). + This function is for drawing only; it must never be called during printing. @@ -2077,7 +2075,7 @@ structure called \c{drawing_api}. Each of the functions takes a a more useful type. Thus, a drawing \e{object} (\c{drawing *)} suitable for passing to the back end redraw or printing functions is constructed by passing a \c{drawing_api} and a \cq{void *} to the -function \cw{drawing_init()} (see \k{drawing-init}). +function \cw{drawing_new()} (see \k{drawing-new}). \S{drawingapi-draw-text} \cw{draw_text()} @@ -2123,7 +2121,7 @@ function; see \k{drawing-draw-circle}. \c void (*draw_update)(void *handle, int x, int y, int w, int h); -This function behaves exactly like the back end \cw{draw_text()} +This function behaves exactly like the back end \cw{draw_update()} function; see \k{drawing-draw-text}. An implementation of this API which only supports printing is @@ -2176,19 +2174,9 @@ called unless drawing is attempted. This function behaves exactly like the back end \cw{status_bar()} function; see \k{drawing-status-bar}. -Front ends implementing this function should not use the provided -text directly; they should call \cw{midend_rewrite_statusbar()} -(\k{midend-rewrite-statusbar}) to process it first. - -In a game which has a timer, this function is likely to be called -every time the timer goes off, i.e. many times a second. It is -therefore likely to be common that this function is called with -precisely the same text as the last time it was called. Front ends -may well wish to detect this common case and avoid bothering to do -anything. If they do, however, they \e{must} perform this check on -the value \e{returned} from \cw{midend_rewrite_statusbar()}, rather -than the value passed in to it (because the mid-end will frequently -update the status-bar timer without the back end's intervention). +Front ends implementing this function need not worry about it being +called repeatedly with the same text; the middleware code in +\cw{status_bar()} will take care of this. Implementations of this API which do not provide drawing services may define this function pointer to be \cw{NULL}; it will never be @@ -2279,7 +2267,7 @@ of the puzzle. Similarly, \c{ym} and \c{yc} specify the vertical position of the puzzle as a function of the page height: the page height times -\c{xm}, plus \c{xc} millimetres, equals the desired distance from +\c{ym}, plus \c{yc} millimetres, equals the desired distance from the top of the page to the top of the puzzle. (This unwieldy mechanism is required because not all printing @@ -2360,15 +2348,23 @@ There are a small number of functions provided in \cw{drawing.c} which the front end needs to \e{call}, rather than helping to implement. They are described in this section. -\S{drawing-init} \cw{drawing_init()} +\S{drawing-new} \cw{drawing_new()} -\c drawing *drawing_init(const drawing_api *api, void *handle); +\c drawing *drawing_new(const drawing_api *api, midend *me, +\c void *handle); This function creates a drawing object. It is passed a \c{drawing_api}, which is a structure containing nothing but function pointers; and also a \cq{void *} handle. The handle is passed back to each function pointer when it is called. +The \c{midend} parameter is used for rewriting the status bar +contents: \cw{status_bar()} (see \k{drawing-status-bar}) has to call +a function in the mid-end which might rewrite the status bar text. +If the drawing object is to be used only for printing, or if the +game is known not to call \cw{status_bar()}, this parameter may be +\cw{NULL}. + \S{drawing-free} \cw{drawing_free()} \c void drawing_free(drawing *dr); @@ -2421,7 +2417,7 @@ calling back to functions such as \cw{activate_timer()} function \cw{colours()} (\k{backend-colours}). The parameters \c{drapi} and \c{drhandle} are passed to -\cw{drawing_init()} (\k{drawing-init}) to construct a drawing object +\cw{drawing_new()} (\k{drawing-new}) to construct a drawing object which will be passed to the back end function \cw{redraw()} (\k{backend-redraw}). Hence, all drawing-related function pointers defined in \c{drapi} can expect to be called with \c{drhandle} as @@ -2455,6 +2451,16 @@ previously got it from \cw{midend_fetch_preset()} (\k{midend-fetch-preset}). Thus, this function is usually called in response to the user making a selection from the presets menu. +\H{midend-get-params} \cw{midend_get_params()} + +\c game_params *midend_get_params(midend *me); + +Returns the current game parameters stored in this mid-end. + +The returned value is dynamically allocated, and should be freed +when finished with by passing it to the game's own +\cw{free_params()} function (see \k{backend-free-params}). + \H{midend-size} \cw{midend_size()} \c void midend_size(midend *me, int *x, int *y, int expand); @@ -2797,32 +2803,6 @@ The front end can expect its drawing API and/or \cw{activate_timer()} to be called from within a call to this function. -\H{midend-rewrite-statusbar} \cw{midend_rewrite_statusbar()} - -\c char *midend_rewrite_statusbar(midend *me, char *text); - -The front end should call this function from within -\cw{status_bar()} (\k{drawing-status-bar}). It should be passed the -string that was passed by the back end to \cw{status_bar()}; it will -return a dynamically allocated string adjusted by the mid-end. -(Specifically, adjusted to include the timer if the game is a timed -one.) The returned value should be placed in the actual status bar -in place of the input value. - -(This is a nasty piece of architecture; I apologise for it. It would -seem a lot more pleasant to have the back end pass its status bar -text to the mid-end, which in turn would rewrite it and pass it on -to the front end, so that each front end needed to do nothing -strange. The main reason why I haven't done this is because it means -the back end redraw function would need to be passed a mid-end -pointer \e{as well} as a front end pointer, which seemed like an -excessive proliferation of opaque handles. The only way to avoid -that proliferation would be to have all the drawing API functions -also gatewayed through the mid-end, and that seemed like an -excessive proliferation of wrapper functions. The current setup -isn't nice, but it has minimal impact and I'm unconvinced that any -of the other options are an improvement.) - \H{midend-serialise} \cw{midend_serialise()} \c void midend_serialise(midend *me, @@ -2938,9 +2918,10 @@ base), then there will be two global variables defined: \c extern const int gamecount; \c{gamelist} will be an array of \c{gamecount} game structures, -declared in the source module \c{list.c}. The application should -search that array for the game it wants, probably by reaching into -each game structure and looking at its \c{name} field. +declared in the automatically constructed source module \c{list.c}. +The application should search that array for the game it wants, +probably by reaching into each game structure and looking at its +\c{name} field. } @@ -3030,9 +3011,9 @@ generator has an \e{explicit} state object called a \c{random_state}. One of these is managed by each mid-end, for example, and passed to the back end to generate a game with. -\S{utils-random-init} \cw{random_init()} +\S{utils-random-init} \cw{random_new()} -\c random_state *random_init(char *seed, int len); +\c random_state *random_new(char *seed, int len); Allocates, initialises and returns a new \c{random_state}. The input data is used as the seed for the random number stream (i.e. using @@ -3519,10 +3500,10 @@ sensibly fit anywhere else. \S{utils-truefalse} \cw{TRUE} and \cw{FALSE} The main Puzzles header file defines the macros \cw{TRUE} and -\cw{FALSE}, which are used throughout the code in place of 0 and 1 -to indicate that the values are in a boolean context. For code base -consistency, I'd prefer it if submissions of new code followed this -convention as well. +\cw{FALSE}, which are used throughout the code in place of 1 and 0 +(respectively) to indicate that the values are in a boolean context. +For code base consistency, I'd prefer it if submissions of new code +followed this convention as well. \S{utils-maxmin} \cw{max()} and \cw{min()} @@ -3733,6 +3714,11 @@ compile it conveniently. \e{Do not edit the Makefiles}: they are created automatically by the script \c{mkfiles.pl}, from the file called \c{Recipe}. Edit \c{Recipe}, and then re-run \c{mkfiles.pl}. +Also, don't forget to add your puzzle to \c{list.c}: if you don't, +then it will still run fine on platforms which build each puzzle +separately, but Mac OS X and other monolithic platforms will not +include your new puzzle in their single binary. + Once your source file is building, you can move on to the fun bit. \S{writing-generation} Puzzle generation @@ -4041,7 +4027,7 @@ Then the main redraw loop will look something like this \c if (x == ui->cursor_x && y == ui->cursor_y) \c value |= CURSOR; \c if (ds->symbol_at_position[y][x] != value) { -\c symbol_drawing_subroutine(fe, ds, x, y, value); +\c symbol_drawing_subroutine(dr, ds, x, y, value); \c ds->symbol_at_position[y][x] = value; \c } \c } @@ -4106,9 +4092,7 @@ piece of saved background needs to be. \b In the game's \cw{set_size()} function, once you know the size of the object you'll be dragging around the display and hence the -required size of the blitter, actually allocate the blitter (making -sure to free a previous one if present \dash it's possible that -\cw{set_size()} might be called twice on the same draw state). +required size of the blitter, actually allocate the blitter. \b In \cw{free_drawstate()}, free the blitter if it's not \cw{NULL}.