chiark / gitweb /
Added a help file, mostly thanks to Jacob.
authorSimon Tatham <anakin@pobox.com>
Mon, 16 Aug 2004 12:23:56 +0000 (12:23 +0000)
committerSimon Tatham <anakin@pobox.com>
Mon, 16 Aug 2004 12:23:56 +0000 (12:23 +0000)
[originally from svn r4460]

13 files changed:
.cvsignore
README
cube.c
fifteen.c
makedist.sh
net.c
netslide.c
nullgame.c
puzzles.but [new file with mode: 0644]
puzzles.h
rect.c
sixteen.c
windows.c

index e47868b11b7b7521955f0661d0e0d672f8c5305f..b892392581687585e2a5bd0f94b3fded16d7b3c7 100644 (file)
@@ -4,3 +4,5 @@ net cube fifteen sixteen rect netslide nullgame
 *.map *.rsp
 *notes
 HACKING
+*.hlp *.cnt
+puzzles.txt
diff --git a/README b/README
index 9009117c26cb6f8995aa1ca32aa09e92f2a670a3..deded6b8559c1c2132c6b5a90fdfc9ab1717f330 100644 (file)
--- a/README
+++ b/README
@@ -1,5 +1,6 @@
 This is the README accompanying the source code to Simon Tatham's
-puzzle collection.
+puzzle collection. The collection's web site is at
+<http://www.chiark.greenend.org.uk/~sgtatham/puzzles/>.
 
 You should find several Makefiles in the source code:
 
@@ -27,3 +28,9 @@ back to the maintainer. The makefiles are generated automatically by
 the Perl script `mkfiles.pl' from the file `Recipe'. If you need to
 change the makefiles as part of a patch, you should change Recipe
 and/or mkfiles.pl.
+
+The manual, provided in Windows Help and text formats, is generated
+from a Halibut source file (puzzles.but), which is the preferred form
+for modification. To generate the manual in other formats, rebuild it,
+or learn about Halibut, visit the Halibut website at
+<http://www.chiark.greenend.org.uk/~sgtatham/halibut/>.
diff --git a/cube.c b/cube.c
index afd2ebd19d1e181f59f35d4ab51e39d0d7022706..72ac527ee5cdc42de4ecb9639bdc7e52f8e41899 100644 (file)
--- a/cube.c
+++ b/cube.c
@@ -12,6 +12,7 @@
 #include "puzzles.h"
 
 const char *const game_name = "Cube";
+const char *const game_winhelp_topic = "games.cube";
 const int game_can_configure = TRUE;
 
 #define MAXVERTICES 20
index 2788604c79012d899940007726a2b14c728b5cb1..147651397f0af70c64e7ce6b9bfb90af9f09e341 100644 (file)
--- a/fifteen.c
+++ b/fifteen.c
@@ -12,6 +12,7 @@
 #include "puzzles.h"
 
 const char *const game_name = "Fifteen";
+const char *const game_winhelp_topic = "games.fifteen";
 const int game_can_configure = TRUE;
 
 #define TILE_SIZE 48
index 16fab3744392395b615a4a3bd5ca72ceb2e81d15..0bd1fdf9c706addd037bef648ce8375f53394b13 100755 (executable)
@@ -5,7 +5,11 @@ perl mkfiles.pl
 mkdir tmp.$$
 mkdir tmp.$$/puzzles
 
-for i in *.c *.h LICENCE README Recipe mkfiles.pl Makefile.*; do
+# Build Windows Help and text versions of the manual for convenience.
+halibut --winhelp=puzzles.hlp --text=puzzles.txt puzzles.but
+
+for i in *.c *.h *.but LICENCE README Recipe mkfiles.pl Makefile.* \
+  puzzles.txt puzzles.hlp puzzles.cnt; do
   ln -s ../../$i tmp.$$/puzzles
 done
 
diff --git a/net.c b/net.c
index 3c3f971e7ce03942e225eaedd01b654f31ef9ea6..43c711bd016bb0fdc53f587f2dda4bc5264450ed 100644 (file)
--- a/net.c
+++ b/net.c
@@ -13,6 +13,7 @@
 #include "tree234.h"
 
 const char *const game_name = "Net";
+const char *const game_winhelp_topic = "games.net";
 const int game_can_configure = TRUE;
 
 #define PI 3.141592653589793238462643383279502884197169399
index 6bbd8135a652c45149e49d0e6817084b76c1aea9..c4f8ae64dcd29f726fa885c270005b2c93a8e78d 100644 (file)
@@ -14,6 +14,7 @@
 #include "tree234.h"
 
 const char *const game_name = "Netslide";
+const char *const game_winhelp_topic = "games.netslide";
 const int game_can_configure = TRUE;
 
 #define PI 3.141592653589793238462643383279502884197169399
index 67982b9119b4a7ed8f4d070426f4d48ab5875b15..a318131f986e7cffcda7c242353e4608cbfb1738 100644 (file)
@@ -21,6 +21,7 @@
 #include "puzzles.h"
 
 const char *const game_name = "Null Game";
+const char *const game_winhelp_topic = NULL;
 const int game_can_configure = FALSE;
 
 enum {
diff --git a/puzzles.but b/puzzles.but
new file mode 100644 (file)
index 0000000..2d10605
--- /dev/null
@@ -0,0 +1,474 @@
+\title Simon Tatham's Portable Puzzle Collection
+
+\cfg{winhelp-filename}{puzzles.hlp}
+\cfg{winhelp-contents-titlepage}{Contents}
+
+\cfg{text-filename}{puzzles.txt}
+
+\cfg{xhtml-contents-filename}{index.html}
+\cfg{xhtml-leaf-level}{1}
+\cfg{xhtml-contents-depth-0}{1}
+\cfg{xhtml-contents-depth-1}{2}
+\cfg{xhtml-leaf-contains-contents}{true}
+
+\cfg{info-filename}{puzzles.info}
+
+\cfg{ps-filename}{puzzles.ps}
+\cfg{pdf-filename}{puzzles.pdf}
+
+This is a collection of small one-player puzzle games.
+
+\copyright This manual is copyright 2004 Simon Tatham. All rights
+reserved. You may distribute this documentation under the MIT licence.
+See \k{licence} for the licence text in full.
+
+\versionid $Id: puzzles.but,v 1.1 2004/08/16 12:23:56 simon Exp $
+
+
+\C{intro} Introduction
+
+I wrote this collection because I thought there should be more small
+desktop toys available: little games you can pop up in a window and
+play for two or three minutes while you take a break from whatever
+else you were doing. And I was also annoyed that every time I found a
+good game on (say) \i{Unix}, it wasn't available the next time I was
+sitting at a \i{Windows} machine, or vice versa; so I arranged that
+everything in my personal puzzle collection will happily run on both.
+When I find (or perhaps invent) further puzzle games that I like,
+they'll be added to this collection and will immediately be available
+on both platforms. And if anyone feels like writing any other front
+ends - Mac OS, PocketPC, or whatever it might be - then all the games
+in this framework will immediately become available on another
+platform as well.
+
+The actual games in this collection were mostly not my invention; I
+saw them elsewhere, and rewrote them in a form that was more
+convenient for me. I do not claim credit, in general, for inventing
+the rules of any of these puzzles; all I claim is authorship of the
+code (or at least those parts of the code that weren't contributed
+by other people!).
+
+This collection is distributed under the \i{MIT licence} (see
+\k{licence}). This means that you can do pretty much anything you like
+with the game binaries or the code, except pretending you wrote them
+yourself, or suing me if anything goes wrong. 
+
+The most recent versions, and \i{source code}, can be found at
+\I{website}\W{http://www.chiark.greenend.org.uk/~sgtatham/puzzles/}\cw{http://www.chiark.greenend.org.uk/~sgtatham/puzzles/}.
+
+Please report \I{feedback}\i{bugs} to
+\W{mailto:anakin@pobox.com}\cw{anakin@pobox.com}.
+You might find it helpful to read this article before reporting a bug:
+
+\W{http://www.chiark.greenend.org.uk/~sgtatham/bugs.html}\cw{http://www.chiark.greenend.org.uk/~sgtatham/bugs.html}
+
+\ii{Patches} are welcome. Especially if they provide a new front end
+(to make all these games run on another platform), or a new game.
+
+
+\C{common} \ii{Common features}
+
+This chapter describes features that are common to all the games.
+
+\H{common-actions} \I{controls}Common actions
+
+These actions are all available from the \I{Game menu}\q{Game} menu
+and via \I{keys}keyboard shortcuts, in addition to any game-specific
+actions.
+
+\dt \ii\e{New game} (\q{N}, Ctrl+\q{N})
+
+\dd Starts a new game, with a random initial state.
+
+\dt \ii\e{Restart game} (\q{R})
+
+\dd Resets the current game to its initial state. Undo is lost.
+
+\dt \ii\e{Undo} (\q{U}, Ctrl+\q{Z}, Ctrl+\q{_})
+
+\dd Undoes a single move. (You can undo moves back to the start of the
+game.)
+
+\dt \ii\e{Redo} (Ctrl+\q{R})
+
+\dd Redoes a previous undone move.
+
+\dt \I{exit}\ii\e{Quit} (\q{Q}, Ctrl+\q{Q})
+
+\dd Closes the application entirely.
+
+\H{common-id} Recreating games with the \ii{game ID}
+
+The \q{\i{Specific...}} option from the \I{Game menu}\q{Game} menu
+lets you see a short string (the \q{game ID}) that captures the
+initial state of the current game.
+
+The precise \I{ID format}format of the ID is specific to each game.
+It consists of two parts delimited by a colon (e.g., \c{c4x4:4F01,0});
+the first part encodes \i\e{parameters} (such as grid size), while the
+second part encodes a \i\e{seed}, which determines the \i{initial
+state} of the game within those parameters.
+
+You can specify a new ID (or just a seed) here. Pressing \q{OK} starts
+a new game with the specified ID (whether you changed it or not).
+Pressing \q{Cancel} returns to the current game.
+
+You can also use the game ID (or just the encoded parameters) as a
+\i{command line} argument; see \k{common-cmdline} for more detail.
+
+Game IDs are portable across platforms; you can use a game ID
+generated by the Windows version of a game on the Unix version, etc.
+
+\H{common-type} The \q{Type} menu
+
+The \I{Type menu}\q{Type} menu, if present, may contain a list of
+\i{preset} game settings. Selecting one of these will start a new
+random game with the parameters specified.
+
+The \q{Type} menu may also contain a \q{\i{Custom...}} option which
+allows you to fine-tune game \i{parameters}. The parameters available
+are specific to each game and are described in the following sections.
+
+\H{common-cmdline} Specifying game parameters on the \i{command line}
+
+The games in this collection deliberately do not ever save
+information on to the computer they run on: they have no high score
+tables and no saved preferences. (This is because I expect at least
+some people to play them at work, and those people will probably
+appreciate leaving as little evidence as possible!)
+
+However, if you do want to arrange for one of these games to default
+to a particular set of parameters, you can specify them on the
+command line.
+
+The easiest way to do this is to set up the parameters you want
+using the \q{Type} menu (see \k{common-type}), and then to select
+\q{Specific} from the \q{Game} menu (see \k{common-id}). The text in
+the \q{Game ID} box will be composed of two parts, separated by a
+colon. The first of these parts represents the game parameters (the
+size of the playing area, for example, and anything else you set
+using the \q{Type} menu).
+
+If you run the game with just that parameter text on the command
+line, it will start up with the settings you specified.
+
+For example: if you run Cube (see \k{cube}), select \q{Octahedron}
+from the \q{Type} menu, and then go to the game ID selection, you
+will see a string of the form \cq{o2x2:911A81,10}. Take only the
+part before the colon (\cq{o2x2}), and start Cube with that text on
+the command line: \cq{cube o2x2}.
+
+If you copy the \e{entire} game ID on to the command line, the game
+will start up in the specific game that was described. This is
+occasionally a more convenient way to start a particular game ID
+than by pasting it into the game ID selection box.
+
+\C{net} \i{Net}
+
+\cfg{winhelp-topic}{games.net}
+
+(\e{Note:} the \i{Windows} version of this game is called
+\i\cw{NETGAME.EXE} to avoid clashing with Windows's own \cw{NET.EXE}.)
+
+I originally saw this in the form of a Flash game called \i{FreeNet}
+\k{FreeNet}, written by Pavils Jurjans. The computer prepares a
+network by connecting up the centres of squares in a grid, and then
+shuffles the network by rotating every tile randomly. Your job is to
+rotate it all back into place. The successful solution will be an
+entirely connected network, with no closed loops. \#{Is it also true
+that a correct solution will not contain any cycles?} As a visual aid,
+all tiles which are connected to the one in the middle are
+highlighted. 
+
+\B{FreeNet} \W{http://www.jurjans.lv/stuff/net/FreeNet.htm}\cw{http://www.jurjans.lv/stuff/net/FreeNet.htm}
+
+\H{net-controls} \i{Net controls}
+
+\IM{Net controls} controls, for Net
+\IM{Net controls} keys, for Net
+\IM{Net controls} shortcuts (keyboard), for Net
+
+This game can be played with either the keyboard or the mouse. The
+controls are:
+
+\dt \e{Select tile}: mouse pointer, arrow keys
+
+\dt \e{Rotate tile anticlockwise}: left mouse button, \q{A} key
+
+\dt \e{Rotate tile clockwise}: right mouse button, \q{D} key
+
+\dt \e{Lock (or unlock) tile}: middle mouse button, shift-click, \q{S} key
+
+\dd You can lock a tile once you're sure of its orientation. You can
+also unlock it again, but while it's locked you can't accidentally
+turn it.
+
+(All the actions described in \k{common-actions} are also available.)
+
+\H{net-params} \I{parameters, for Net}Net parameters
+
+These parameters are available from the \q{Custom...} option on the
+\q{Type} menu.
+
+\dt \e{Width}, \e{Height}
+
+\dd Size of grid in tiles.
+
+\dt \e{Walls wrap around}
+
+\dd If checked, flow can pass from the left edge to the right edge,
+and from top to bottom, and vice versa.
+
+\dt \e{Barrier probability}
+
+\dd A number between 0.0 and 1.0 controlling whether an immovable
+barrier is placed between two tiles to prevent flow between them (a
+higher number gives more barriers). Since barriers are immovable, they
+act as constraints on the solution (i.e., hints).
+
+\lcont{
+
+The grid generation in Net has been carefully arranged so that the
+barriers are independent of the rest of the grid. This means that if
+you change the \e{Barrier probability} parameter, and then re-enter
+the same game ID you were playing before (see \k{common-id}), you
+should see exactly the same starting grid, with the only change
+being the number of barriers. So if you're stuck on a particular
+grid and need a hint, you could start up another instance of Net,
+set up the same parameters but a higher barrier probability, and
+enter the game seed from the original Net window.
+
+}
+
+\C{cube} \i{Cube}
+
+\cfg{winhelp-topic}{games.cube}
+
+This is another one I originally saw as a web game. This one was a
+Java game \k{cube-java-game}, by Paul Scott. You have a grid of 16
+squares, six of which are blue; on one square rests a cube. Your move
+is to use the arrow keys to roll the cube through 90 degrees so that
+it moves to an adjacent square. If you roll the cube on to a blue
+square, the blue square is picked up on one face of the cube; if you
+roll a blue face of the cube on to a non-blue square, the blueness is
+put down again. (In general, whenever you roll the cube, the two faces
+that come into contact swap colours.) Your job is to get all six blue
+squares on to the six faces of the cube at the same time. Count your
+moves and try to do it in as few as possible. 
+
+Unlike the original Java game, my version has an additional feature:
+once you've mastered the game with a cube rolling on a square grid,
+you can change to a triangular grid and roll any of a tetrahedron, an
+octahedron or an icosahedron. 
+
+\B{cube-java-game} \W{http://www3.sympatico.ca/paulscott/cube/cube.htm}\cw{http://www3.sympatico.ca/paulscott/cube/cube.htm}
+
+\H{cube-controls} \i{Cube controls}
+
+\IM{Cube controls} controls, for Cube
+\IM{Cube controls} keys, for Cube
+\IM{Cube controls} shortcuts (keyboard), for Cube
+
+This game is played with the keyboard. The arrow keys are used to roll the
+cube (or other solid).
+
+On the triangular grids, the mapping of arrow keys to directions is
+more approximate. Vertical movement is disallowed where it doesn't
+make sense. The four keys surrounding the arrow keys on the numeric
+keypad (\q{7}, \q{9}, \q{1}, \q{3}) can be used for diagonal movement.
+
+(All the actions described in \k{common-actions} are also available.)
+
+\H{cube-params} \I{parameters, for Cube}Cube parameters
+
+These parameters are available from the \q{Custom...} option on the
+\q{Type} menu.
+
+\dt \e{Type of solid}
+
+\dd Selects the solid to roll (and hence the shape of the grid):
+tetrahedron, cube, octahedron, or icosahedron.
+
+\dt \e{Width / top}, \e{Height / bottom}
+
+\dd On a square grid, horizontal and vertical dimensions. On a
+triangular grid, the number of triangles on the top and bottom rows
+respectively.
+
+
+\C{fifteen} \i{Fifteen}
+
+\cfg{winhelp-topic}{games.fifteen}
+
+The old ones are the best: this is the good old \q{\i{15-puzzle}} with
+sliding tiles. You have a 4x4 square grid; 15 squares contain numbered
+tiles, and the sixteenth is empty. Your move is to choose a tile next
+to the empty space, and slide it into the space. The aim is to end up
+with the tiles in numerical order, with the space in the bottom right
+(so that the top row reads 1,2,3,4 and the bottom row reads
+13,14,15,\e{space}).
+
+\H{fifteen-controls} \i{Fifteen controls}
+
+\IM{Fifteen controls} controls, for Fifteen
+\IM{Fifteen controls} keys, for Fifteen
+\IM{Fifteen controls} shortcuts (keyboard), for Fifteen
+
+This game can be controlled with the mouse or the keyboard.
+
+A left-click with the mouse in the row or column containing the empty
+space will move as many tiles as necessary to move the space to the
+mouse pointer.
+
+The arrow keys will move a tile adjacent to the space in the direction
+indicated (moving the space in the \e{opposite} direction).
+
+(All the actions described in \k{common-actions} are also available.)
+
+\H{fifteen-params} \I{parameters, for Fifteen}Fifteen parameters
+
+The only options available from the \q{Custom...} option on the \q{Type}
+menu are \e{Width} and \e{Height}, which are self-explanatory. (Once
+you've changed these, it's not a \q{15-puzzle} any more, of course!)
+
+
+\C{sixteen} \i{Sixteen}
+
+\cfg{winhelp-topic}{games.sixteen}
+
+Another sliding tile puzzle, visually similar to Fifteen (see
+\k{fifteen}) but with a different type of move. This time, there is no
+hole: all 16 squares on the grid contain numbered squares. Your move
+is to shift an entire row left or right, or shift an entire column up
+or down; every time you do that, the tile you shift off the grid
+re-appears at the other end of the same row, in the space you just
+vacated. To win, arrange the tiles into numerical order (1,2,3,4 on
+the top row, 13,14,15,16 on the bottom). When you've done that, try
+playing on different sizes of grid. 
+
+I \e{might} have invented this game myself, though only by accident if
+so (and I'm sure other people have independently invented it). I
+thought I was imitating a screensaver I'd seen, but I have a feeling
+that the screensaver might actually have been a Fifteen-type puzzle
+rather than this slightly different kind. So this might be the one
+thing in my puzzle collection which represents creativity on my part
+rather than just engineering.
+
+\H{sixteen-controls} \I{controls, for Sixteen}Sixteen controls
+
+This game is played with the mouse. Left-clicking on an arrow will
+move the appropriate row or column in the direction indicated.
+Right-clicking will move it in the opposite direction.
+
+(All the actions described in \k{common-actions} are also available.)
+
+\H{sixteen-params} \I{parameters, for Sixteen}Sixteen parameters
+
+The only parameters available from the \q{Custom...} option on the
+\q{Type} menu are \e{Width} and \e{Height}, which are
+self-explanatory.
+
+
+\C{rectangles} \i{Rectangles}
+
+\cfg{winhelp-topic}{games.rectangles}
+
+You have a grid of squares, with numbers written in some (but not all)
+of the squares. Your task is to subdivide the grid into rectangles of
+various sizes, such that (a) every rectangle contains exactly one
+numbered square, and (b) the area of each rectangle is equal to the
+number written in its numbered square.
+
+Credit for this game goes to the Japanese puzzle magazine \i{Nikoli}
+\k{nikoli}; I've also seen a Palm implementation at \i{Puzzle Palace}
+\k{puzzle-palace}. Unlike Puzzle Palace's implementation, my version
+automatically generates random grids of any size you like. The quality
+of puzzle design is therefore not quite as good as hand-crafted
+puzzles would be (in particular, a unique solution cannot be
+guaranteed), but on the plus side you get an inexhaustible supply of
+puzzles tailored to your own specification.
+
+\B{nikoli} \W{http://www.nikoli.co.jp/puzzles/7/index_text-e.htm}\cw{http://www.nikoli.co.jp/puzzles/7/index_text-e.htm}
+
+\B{puzzle-palace} \W{http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en}\cw{http://www.puzzle.gr.jp/puzzle/sikaku/palm/index.html.en}
+
+\H{rectangles-controls} \I{controls, for Rectangles}Rectangles controls
+
+This game is played with the mouse.
+
+Left-click any edge to toggle it on or off, or click and drag to draw
+an entire rectangle (or line) on the grid in one go (removing any
+existing edges within that rectangle).
+
+When a rectangle of the correct size is completed, it will be shaded.
+
+(All the actions described in \k{common-actions} are also available.)
+
+\H{rectangles-params} \I{parameters, for Rectangles}Rectangles parameters
+
+The only parameters available from the \q{Custom...} option on the
+\q{Type} menu are \e{Width} and \e{Height}, which are
+self-explanatory.
+
+
+\C{netslide} \i{Netslide}
+
+\cfg{winhelp-topic}{games.netslide}
+
+This game was submitted by Richard Boulton. It combines the grid
+generation of Net (see \k{net}) with the movement of Sixteen (see
+\k{sixteen}): you have a Net grid, but instead of rotating tiles back
+into place you have to slide them into place by moving a whole row at
+a time. 
+
+
+As in Sixteen, \I{controls, for Netslide}control is with the mouse.
+See \k{sixteen-controls}.
+
+\I{parameters, for Netslide}Game parameters are the same as for Net
+(see \k{net-params}).
+
+
+\A{licence} \I{MIT licence}\ii{Licence}
+
+This software is \i{copyright} 2004 Simon Tatham.
+
+Portions copyright Richard Boulton.
+
+Permission is hereby granted, free of charge, to any person
+obtaining a copy of this software and associated documentation files
+(the "Software"), to deal in the Software without restriction,
+including without limitation the rights to use, copy, modify, merge,
+publish, distribute, sublicense, and/or sell copies of the Software,
+and to permit persons to whom the Software is furnished to do so,
+subject to the following conditions:
+
+The above copyright notice and this permission notice shall be
+included in all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
+
+\IM{specific...} Specific..., menu option
+\IM{custom...} Custom..., menu option
+
+\IM{game ID} game ID
+\IM{game ID} ID, game
+\IM{ID format} ID format
+\IM{ID format} format, ID
+\IM{ID format} game ID, format
+
+\IM{keys} keys
+\IM{keys} shortcuts (keyboard)
+
+\IM{initial state} initial state
+\IM{initial state} state, initial
+
+\IM{MIT licence} MIT licence
+\IM{MIT licence} licence, MIT
index 37636f4fa489e626b9e2e60510715286f83c5383..b04ec971943a99a264b1a10590bc377a340bca97 100644 (file)
--- a/puzzles.h
+++ b/puzzles.h
@@ -160,6 +160,7 @@ void random_free(random_state *state);
  * Game-specific routines
  */
 extern const char *const game_name;
+extern const char *const game_winhelp_topic;
 const int game_can_configure;
 game_params *default_params(void);
 int game_fetch_preset(int i, char **name, game_params **params);
diff --git a/rect.c b/rect.c
index 7fff9af24ca3c76f845de4e2b0f7c6ba99e078ae..f270d91f6592cd8f8e283712d5dca808889c001a 100644 (file)
--- a/rect.c
+++ b/rect.c
@@ -40,6 +40,7 @@
 #include "puzzles.h"
 
 const char *const game_name = "Rectangles";
+const char *const game_winhelp_topic = "games.rectangles";
 const int game_can_configure = TRUE;
 
 enum {
index 5b7b98e258f4c789daffb3f1f8d68374d5807d6e..1e865c2e167deacf4356307b813a212d8f2bfd8a 100644 (file)
--- a/sixteen.c
+++ b/sixteen.c
@@ -14,6 +14,7 @@
 #include "puzzles.h"
 
 const char *const game_name = "Sixteen";
+const char *const game_winhelp_topic = "games.sixteen";
 const int game_can_configure = TRUE;
 
 #define TILE_SIZE 48
@@ -397,7 +398,7 @@ game_state *make_move(game_state *from, game_ui *ui, int x, int y, int button)
     int dx, dy, tx, ty, n;
     game_state *ret;
 
-    if (button != LEFT_BUTTON)
+    if (button != LEFT_BUTTON && button != RIGHT_BUTTON)
         return NULL;
 
     cx = FROMCOORD(x);
@@ -413,6 +414,13 @@ game_state *make_move(game_state *from, game_ui *ui, int x, int y, int button)
     else
         return NULL;                   /* invalid click location */
 
+    /* reverse direction if right hand button is pressed */
+    if (button == RIGHT_BUTTON)
+    {
+        dx = -dx; if (dx) cx = from->w - 1 - cx;
+        dy = -dy; if (dy) cy = from->h - 1 - cy;
+    }
+
     ret = dup_game(from);
 
     do {
index 80a929da74e4fa034947daf7d9d4b41f70e4a9b6..9fa6c95784f8810f6a67e39c6ef126289e98e9a1 100644 (file)
--- a/windows.c
+++ b/windows.c
 #define IDM_QUIT      0x0050
 #define IDM_CONFIG    0x0060
 #define IDM_SEED      0x0070
+#define IDM_HELPC     0x0080
+#define IDM_GAMEHELP  0x0090
 #define IDM_PRESETS   0x0100
 
+#define HELP_FILE_NAME  "puzzles.hlp"
+#define HELP_CNT_NAME   "puzzles.cnt"
+
 #ifdef DEBUG
 static FILE *debug_fp = NULL;
 static HANDLE debug_hdl = INVALID_HANDLE_VALUE;
@@ -98,6 +103,8 @@ struct frontend {
     struct cfg_aux *cfgaux;
     int cfg_which, cfg_done;
     HFONT cfgfont;
+    char *help_path;
+    int help_has_contents;
 };
 
 void fatal(char *fmt, ...)
@@ -310,6 +317,35 @@ void activate_timer(frontend *fe)
     }
 }
 
+/*
+ * See if we can find a help file.
+ */
+static void find_help_file(frontend *fe)
+{
+    char b[2048], *p, *q, *r;
+    FILE *fp;
+    if (!fe->help_path) {
+        GetModuleFileName(NULL, b, sizeof(b) - 1);
+        r = b;
+        p = strrchr(b, '\\');
+        if (p && p >= r) r = p+1;
+        q = strrchr(b, ':');
+        if (q && q >= r) r = q+1;
+        strcpy(r, HELP_FILE_NAME);
+        if ( (fp = fopen(b, "r")) != NULL) {
+            fe->help_path = dupstr(b);
+            fclose(fp);
+        } else
+            fe->help_path = NULL;
+        strcpy(r, HELP_CNT_NAME);
+        if ( (fp = fopen(b, "r")) != NULL) {
+            fe->help_has_contents = TRUE;
+            fclose(fp);
+        } else
+            fe->help_has_contents = FALSE;
+    }
+}
+
 static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
 {
     frontend *fe;
@@ -332,6 +368,9 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
         }
     }
 
+    fe->help_path = NULL;
+    find_help_file(fe);
+
     fe->inst = inst;
     midend_new_game(fe->me);
     midend_size(fe->me, &x, &y);
@@ -415,6 +454,19 @@ static frontend *new_window(HINSTANCE inst, char *game_id, char **error)
        AppendMenu(menu, MF_ENABLED, IDM_REDO, "Redo");
        AppendMenu(menu, MF_SEPARATOR, 0, 0);
        AppendMenu(menu, MF_ENABLED, IDM_QUIT, "Exit");
+        if (fe->help_path) {
+            HMENU hmenu = CreateMenu();
+            AppendMenu(bar, MF_ENABLED|MF_POPUP, (UINT)hmenu, "Help");
+            AppendMenu(hmenu, MF_ENABLED, IDM_HELPC, "Contents");
+            if (game_winhelp_topic) {
+                char *item;
+                assert(game_name);
+                item = snewn(9+strlen(game_name), char); /*ick*/
+                sprintf(item, "Help on %s", game_name);
+                AppendMenu(hmenu, MF_ENABLED, IDM_GAMEHELP, item);
+                sfree(item);
+            }
+        }
        SetMenu(fe->hwnd, bar);
     }
 
@@ -846,6 +898,21 @@ static LRESULT CALLBACK WndProc(HWND hwnd, UINT message,
            if (get_config(fe, CFG_SEED))
                new_game_type(fe);
            break;
+          case IDM_HELPC:
+            assert(fe->help_path);
+            WinHelp(hwnd, fe->help_path,
+                    fe->help_has_contents ? HELP_FINDER : HELP_CONTENTS, 0);
+            break;
+          case IDM_GAMEHELP:
+            assert(fe->help_path);
+            assert(game_winhelp_topic);
+            {
+                char *cmd = snewn(10+strlen(game_winhelp_topic), char); /*ick*/
+                sprintf(cmd, "JI(`',`%s')", game_winhelp_topic);
+                WinHelp(hwnd, fe->help_path, HELP_COMMAND, (DWORD)cmd);
+                sfree(cmd);
+            }
+            break;
          default:
            {
                int p = ((wParam &~ 0xF) - IDM_PRESETS) / 0x10;