Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://xsok-1.02-8.src.rpm:118461/xsok-1.02-src.tar.gz  info  downloads

xsok-1.02/ 40755    144     62           0  6123003304  10747 5ustar  mbimathoptxsok-1.02/Makefile100644    144     62        2175  6122776755  12543 0ustar  mbimathopt# Note: Typing 'make' from this level will rebuild xsok from scratch.
#       Afterwards, type 'make install' or 'make install.fsstnd'
#	(as root) to install the game in default directories.
#	A manual is in the doc subdirectory and can be TeXed by 'make manual'.
#
#       You may change src/Imakefile for different configurations.
#       But then, you're on your own...

all:
	(cd src && xmkmf && $(MAKE) && strip xsok)
	(cd lib && $(MAKE))
	(cd src && $(MAKE) testname)

manual:
	(cd doc && $(MAKE) xsok.dvi)

# different install targets: imake default, local, Linux FSSTND
install:
	(cd src && $(MAKE) install)

install.local:
	(cd src && $(MAKE) install.local)

install.fsstnd:
	(cd src && $(MAKE) install.fsstnd)

clean:
	(cd lib && $(MAKE) clean)
	(cd src && xmkmf && $(MAKE) clean)
	(cd doc && $(MAKE) clean)
	(cd solver && $(MAKE) clean)
	rm -f src/Makefile
	find . -name "*~" -exec rm \{\} \;

distrib:
	$(MAKE) clean
	(cd ..; tar cvfz $(HOME)/xsok-1.02-src.tar.gz xsok-1.02)

bindistrib:
	(cd /; tar cvfz $(HOME)/xsok-1.02-bin.tar.gz var/games/xsok/*.score \
	 usr/games/bin/xsok usr/man/man6/xsok.6x usr/games/lib/xsok \
	usr/doc/xsok)
xsok-1.02/src/ 40755    144     62           0  6151124576  11556 5ustar  mbimathoptxsok-1.02/src/xsok.h100644    144     62       22162  6122601264  13023 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module xsok.h				     */
/*									     */
/*	This file is included by all sources of xsok.			     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>

/* defaults for user configurable directories */
#ifndef XSOKDIR		/* directory where to get the game data files */
#define XSOKDIR		"/usr/games/lib/xsok"
#endif
#ifndef XSOKSAVE	/* directory where to save moves of solved levels */
#define XSOKSAVE	"/var/games/xsok"
#endif

#define MAXSAVEFILELEN	200	/* pathname length including trailing zero */
#define MAXXSOKDIRLEN	 99	/* pathname length of the xsok directory */
#define MAXFILENAMELEN	 30	/* filename length of keyboard and message file */

/* maximum board dimensions, inclusive outer borders (tunable) */
#define MAXCOL          32	/* max x dim. */
#define MAXROW          22	/* max y dim. */
/* other maximum settings (tunable) */
#define MAXWALLS	32	/* max. different floor types */
#define MAXOBJECTS	32	/* max. different object types */
#define MAXINSTANCES	256	/* max. number of objects */

/* global string variables */
extern char username[256];   /* which user to blame for success					*/
extern const char *savedir;  /* in which directory should saved games be stored (XSOKSAVE)	*/
extern const char *xsokdir;  /* from which directory to read the level files (default: XSOKDIR) */
extern const char *langdir;		/* a string (empty?) defining the language */
extern const char *rulepool[16];
extern int highscore[300];
extern int pushcost;
extern int movecost;
extern void (*lastcmd)(void);
extern int numeric_arg;

#ifndef EXIT_FAILURE	/* poor old SUN's */
#define EXIT_FAILURE (-1)
#endif

#ifndef max
#define max(a, b)     ((a) > (b) ? (a) : (b))
#define min(a, b)     ((a) < (b) ? (a) : (b))
#endif

typedef int boolean;            /* just one bit of information           */
struct key_action {
    char *string;
    void (*action)(void);
    struct key_action *next;
};

#define True		1
#define False		0

#if 0
/* obsolete */
#define XSOK1MAGIC1	0xb5
#define XSOK1MAGIC2	0xa0
#define ARR_UP		0x100
#define ARR_LEFT	0x101
#define ARR_DOWN	0x102
#define ARR_RIGHT	0x103

#endif

#define Disable 0
#define Enable	1
#define EnableAndRedraw 2


struct walls {
    int chr;	/* character for representation		*/
    int pic;	/* picture number			*/
    int enter;
    int leave;
    int mask;
    int effect;
};

/* definitions for the effect field */
/* all effects plus 100: square will turn to normal floor if touched. */
#define E_ONCE		100	/* add this to make one-time effects */
#define E_NOTHING	0
#define E_TURN_CCW	1
#define E_TURN_180	2
#define E_TURN_CW	3
#define E_DEST		4	/* no effect, but required by finished() */
#define E_EXIT		5	/* dito */
#define E_ADDPOWER	6
#define E_SUBPOWER	7
#define E_TELEPORT	8

/* addstrength, teleporters */

struct objects {
    int chr;	/* character for representation		*/
    int pic;	/* picture number			*/
    int movedir;
    int pushdir;
    int weight;
    int power;
    int mask;
    int score;
};

struct game {
    int numrows;	/* game size */
    int numcols;
    int x;		/* player pos */
    int y;
    int n_pushes;	/* counter */
    int n_moves;
    int stored_moves;
    int bookmark;
    int finished;
    int level;
    int score;
    const char *type;
    int macroStart, macroEnd;
    int macro_x, macro_y;
};


extern char levelcomment[100];
extern char levelauthor[100];
extern int gamegraphic;
extern int maxlevel;		/* maximum level number for this type of game */
extern int nwalls, nobjects, ninstances;
extern struct objects objects[MAXOBJECTS];
extern struct walls walls[MAXWALLS];	/* wall types */
extern struct game game;
extern struct walls *map[MAXROW][MAXCOL];
extern struct objects *obj[MAXROW][MAXCOL];
extern struct objects instance[MAXINSTANCES];
extern char *movetab;
extern int numalloc;


/* function prototypes */
/* parse.c */
void ParseDefinitionFile(void);	/* read definitions */
void ParseMapFile(void);	/* read a level */
void OrgLevel(void);		/* restart game */

/* tools.c */
void fatal(const char *, ...);
void *malloc_(size_t);
void *calloc_(size_t, size_t);
void *realloc_(void *, size_t);
void free_(void *);
char *strsav(const char *);

/* main.c */
void change_rules(const char *);
int compute_score(void);
int finished(void);

/* move.c */
#if 0
void savegame(const char *);
int loadgame(const char *);
#endif
void graphics_control(int);
void playermove(int);
#if 0
void restart(void);
int redo_move(void);
int undo_move(void);
#endif

/* username.c */
void buildusername(const char *);

/* messages.c */
void read_message_file(const char *);
void add_keybinding(struct key_action **, const char *, const char *);
void read_keyboard_file(const char *);
void key_pressed(char *);

/* loadsave.c */
void cmd_ReadHighscores(void);
void WriteHighscores(void);
void switch_uid(int);
void setlangdir(void);
void load_game(const char *);
void save_game(const char *);
void link_game(const char *, const char *);

/* commands.c */
void cmd_Up(void);
void cmd_Left(void);
void cmd_Down(void);
void cmd_Right(void);
void cmd_Repeat(void);
void cmd_LevelInfo(void);
void cmd_NextUnsolved(void);
void cmd_NextLevel(void);
void cmd_PrevLevel(void);
void rq_LeaveSok(void);
void rq_RestartGame(void);
void rq_PrevLevel(void);
void rq_NextLevel(void);
void rq_NextUnsolved(void);
void cmd_DropBookmark(void);
void jumpto_movenr(int);
void cmd_RestartGame(void);
void cmd_GotoBookmark(void);
void cmd_SaveGame(void);
void cmd_ShowVersion(void);
void cmd_ShowScore(void);
void cmd_ShowBestScore(void);
void cmd_ShowAuthor(void);
void cmd_ReplayGame(void);
void cmd_LoadGame(void);
void cmd_UndoMove(void);
void cmd_RedoMove(void);

extern const char *xsok_messages[];
#define TXT_QUIT_CONFIRM	(xsok_messages[0])
#define TXT_NEW_CONFIRM		(xsok_messages[1])
#define TXT_RESTART_CONFIRM	(xsok_messages[2])
#define TXT_NEXT_CONFIRM	(xsok_messages[3])
#define TXT_PREV_CONFIRM	(xsok_messages[4])
#define TXT_MOVENOTPOSSIBLE	(xsok_messages[5])
#define TXT_BOOKMARK_SET	(xsok_messages[6])
#define TXT_YOU_WIN		(xsok_messages[7])
#define TXT_OK			(xsok_messages[8])
#define TXT_VERSION		(xsok_messages[9])
#define TXT_SCORE		(xsok_messages[10])
#define TXT_NOUNDO		(xsok_messages[11])
#define TXT_UNDO		(xsok_messages[12])
#define TXT_NOREDO		(xsok_messages[13])
#define TXT_REDO		(xsok_messages[14])
#define TXT_WELCOME		(xsok_messages[15])

#define TXT_SAVE_ERR_BASIC	(xsok_messages[16])
#define TXT_LOAD_ERR_BASIC	(xsok_messages[17])
#define TXT_SAVE_ERR_OPEN	(xsok_messages[18])
#define TXT_LOAD_ERR_OPEN	(xsok_messages[19])
#define TXT_SAVE_ERR_HEADER	(xsok_messages[20])
#define TXT_LOAD_ERR_HEADER	(xsok_messages[21])
#define TXT_SAVE_ERR_MOVES	(xsok_messages[22])
#define TXT_LOAD_ERR_MOVES	(xsok_messages[23])
#define TXT_SAVE_OK		(xsok_messages[24])
#define TXT_LOAD_OK		(xsok_messages[25])
#define TXT_LOAD_ERR_BADMAGIC	(xsok_messages[26])

#define TXT_NOAUTHOR		(xsok_messages[27])
#define TXT_NEWHIGH		(xsok_messages[28])
#define TXT_NOLOAD		(xsok_messages[29])
#define TXT_HELP_KEYS		(xsok_messages[30])
#define TXT_HELP_RULES		(xsok_messages[31])

#define TXT_STARTMACRO		(xsok_messages[32])
#define TXT_ENDMACRO		(xsok_messages[33])
#define TXT_MACRO_BADPOS	(xsok_messages[34])
#define TXT_UNSOLVED_CONFIRM	(xsok_messages[35])
#define TXT_BEST		(xsok_messages[36])
#define TXT_UNSOLVED		(xsok_messages[37])
#define TXT_SAVE_ERR_LINK	(xsok_messages[38])

#define TXT_NOBOX		(xsok_messages[39])
#define TXT_ALREADYBOX		(xsok_messages[40])


/* Xaw-help.c */
/*
void create_help(Widget);
void popup_help(void);
void popdown_help(Widget, XtPointer, XtPointer);
*/

/* Xaw-main.c */
void show_message(const char *str, ...);
void SetTitle(void);
void cmd_LeaveSok(void);
void cmd_Confirm(void);
void cmd_Cancel(void);
void request_confirm(void (*)(void), const char *);
#ifdef SOUND
int checksound(void);
#endif
int main(int argc, char *argv[]);
/* void Force_Resize(XSize_t, XSize_t); */

/* X-widget.c */
/* void AskWidgetForResize(XSize_t, XSize_t); */

/* X-events.c */
void refresh_screen(void);
/* void button_press(XButtonPressedEvent *);
void key_press(XKeyPressedEvent *); */
void cmd_Resize(void);
/* void resize_event(XSize_t, XSize_t); */

/* X-gfx.c */
void sync_and_wait(void);
void NewLevel(int);
void init_layout(void);
void init_gfx(const char *);
/* void dotPaint(int, int, int, int); */
void doPaint(int, int, int, int);
/* void redraw_table(XExposeEvent *); */


#if SOUND
/* X-sound_SUN.c */
int checksound(void);
void play_sound(const char *);
#else
#define play_sound(x)
#endif

/* dummy.c */
void cmd_debug(void);

/* xfopen.c */
FILE *zreadopen(const char *filename);
void zreadclose(FILE *fp);

/* mousemove.c */
void cmd_MouseUndo(void);
void cmd_MouseMove(void);
void cmd_MousePush(void);
void cmd_MouseDrag(void);

extern int mouse_x, mouse_y, mouse_x0, mouse_y0;

void cmd_StartMacro(void);
void cmd_EndMacro(void);
void cmd_PlayMacro(void);
xsok-1.02/src/xfopen.c100644    144     62        4346  5665071060  13323 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module xfopen.c				     */
/*									     */
/*	Possible emulation of the popen() / pclose() functions.		     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif

#ifdef HAVE_POPEN	/* extra prototype (they are not POSIX.1) */

#include "xsok.h"

FILE *popen(const char *, const char *);
int pclose(FILE *);

FILE *zreadopen(const char *filename) {
    char zcmd[MAXXSOKDIRLEN+20+100];	/* assume strlen(GUNZIP_PATH) <= 100 */
    sprintf(zcmd, "%s < %s.gz", GUNZIP_PATH, filename);
    return popen(zcmd, "r");
}
void zreadclose(FILE *fp) {
    pclose(fp);
}

#else

#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>
#include "xsok.h"

#ifndef GUNZIP_PATH
#define GUNZIP_PATH "gunzip"
#endif

FILE *zreadopen(const char *filename) {
    int filedes[2];
    char zname[MAXXSOKDIRLEN+17];
    FILE *fp;

    sprintf(zname, "%s.gz", filename);
    if (access(zname, R_OK))
	return NULL;		/* simpler and more correct */
    if (GUNZIP_PATH[0] == '/')
	if (access(GUNZIP_PATH, X_OK))
	    return NULL;		/* simpler and more correct */
    /* following taken from D. Lewine "POSIX programmers guide, page 104 */
    /* try fork and exec. This requires the path of the gzip binary */
    /* but it is much faster */
    if (pipe(filedes))
	return NULL;	/* cannot create pipe */
    switch (fork()) {
    case -1:		/* cannot fork */
	/* close the pipe and return NULL */
	close(filedes[0]);
	close(filedes[1]);
	return NULL;
    case 0:			/* we are the child. exec the gunzip binary */
	close(STDOUT_FILENO);
	dup(filedes[1]);
	close(filedes[0]);
	close(filedes[1]);
	execlp(GUNZIP_PATH, "gunzip", "-c", zname, NULL);
	exit(1);	/* if exec failed! */
    default:		/* we are the main process */
	fp = fdopen(filedes[0], "r");
	close(filedes[1]);
    }
    return fp;
}

void zreadclose(FILE *fp) {
    int status;
    fclose(fp);
    wait(&status);
}

#endif
xsok-1.02/src/Tableau.h100644    144     62        1550  5665071060  13400 0ustar  mbimathopt#ifndef _Tableau_h
#define _Tableau_h

/* define any special resource names here that are not in <X11/StringDefs.h> */
#define XtNruleset	"rules"
#define XtCRuleset	"Rules"
#define XtNlevel	"level"
#define XtCLevel	"Level"
#define XtNusername	"username"
#define XtCUsername	"Username"
#define XtNxsokdir	"xsokdir"
#define XtCXsokdir	"Xsokdir"
#define XtNxpmdir	"xpmdir"
#define XtCXpmdir	"Xpmdir"
#define XtNsavedir	"xsokdir"
#define XtCSavedir	"Xsokdir"
#define XtNmessageFile	"messageFile"
#define XtCMessageFile	"MessageFile"
#define XtNkeyboardFile	"keyboardFile"
#define XtCKeyboardFile	"KeyboardFile"


/* declare specific TableauWidget class and instance datatypes */

typedef struct _TableauClassRec*	TableauWidgetClass;
typedef struct _TableauRec*		TableauWidget;

/* declare the class constant */

extern WidgetClass tableauWidgetClass;

#endif /* _Tableau_h */
xsok-1.02/src/TableauP.h100644    144     62        1431  5665071060  13516 0ustar  mbimathopt#ifndef _TableauP_h
#define _TableauP_h

#include "Tableau.h"
/* include superclass private header file */
#include <X11/CoreP.h>

/* define unique representation types not found in <X11/StringDefs.h> */

#define XtRTableauResource "TableauResource"

typedef struct {
    int empty;
} TableauClassPart;

typedef struct _TableauClassRec {
    CoreClassPart	core_class;
    TableauClassPart	tableau_class;
} TableauClassRec;

extern TableauClassRec tableauClassRec;

typedef struct {
    /* resources */
    String rules;
    int level;
    String username;
    String xsokdir;
    String xpmdir;
    String savedir;
    String messageFile;
    String keyboardFile;
} TableauPart;

typedef struct _TableauRec {
    CorePart core;
    TableauPart tableau;
} TableauRec;

#endif /* _TableauP_h */
xsok-1.02/src/X-events.c100644    144     62       10453  6122570645  13553 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module X-events.c				     */
/*									     */
/*	Event handler functions for the X window system.		     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#include "X-sok.h"
#include <X11/keysym.h>		/* X11 key code definitions */

void refresh_screen(void) {
    XClearArea(dpy, table, 0, 0, 0, 0, True);
}

/* event entry points are: key_press, button_press, button_release, redraw_table */
int mouse_x = 0, mouse_y = 0, mouse_x0 = 0, mouse_y0 = 0;

void button_press(XButtonPressedEvent *xev) {
    mouse_x0 = xev->x / DX;
    mouse_y0 = xev->y / DY;
}

void button_release(XButtonPressedEvent *xev) {
    mouse_x = xev->x / DX;
    mouse_y = xev->y / DY;
    switch (xev->button) {
    case Button1:            /* quick move */
	key_pressed("Mouse1");
	break;
    case Button2:            /* quick move */
	key_pressed("Mouse2");
	break;
    case Button3:            /* quick move */
	key_pressed("Mouse3");
	break;
    case Button4:            /* quick move */
	key_pressed("Mouse4");
	break;
    case Button5:            /* quick move */
	key_pressed("Mouse5");
	break;
    }
}


void key_press(XKeyPressedEvent *xev) {
    char str[32];
    int num;

#define	get_name_field()	get_selection()

    num = XKeycodeToKeysym(dpy, xev->keycode, 0);

    if (num & 0xff00) {
    	switch (num) {
    	case XK_Up:
	    key_pressed("Up");
	    return;
    	case XK_Left:
	    key_pressed("Left");
	    return;
    	case XK_Down:
	    key_pressed("Down");
	    return;
    	case XK_Right:
	    key_pressed("Right");
	    return;
    	case XK_Return:
    	case XK_Linefeed:
	    key_pressed("\n");
	    return;
    	case XK_BackSpace:
    	case XK_Delete:
	    key_pressed("\b");
	    return;
    	case XK_Escape:
	    key_pressed("\033");
	    return;
	}
        return;
    }

    num = XLookupString(xev, str, 31, NULL, NULL);
    if (num == 0)
	return;
    str[num] = '\0';		/* NULL to terminate it */

    key_pressed(str);
}

/*****************************************************************************/
/*									     */
/*	Functions for resize events and resize requests			     */
/*									     */
/*****************************************************************************/

/* 1) hard resizes (i.e. forcing the outer window to change size) */
/*    I think these are not liked in the Xaw community */

void cmd_Resize(void) {
    XSize_t w, h;
    w = graphic.width;
    h = graphic.height;
    Force_Resize(w, h);
}

/* event handler function. This function is called by the Widget in response
   to a request from us. In Xaw, this is a resize of the logical area, i.e.
   of the virtual size of the tableau. */

void resize_event(XSize_t w, XSize_t h) {
#ifdef LABER
    printf("resize event to (%d,%d) called\n", w, h);
#endif
    if (graphic.height == h && graphic.width == w)
	return;		/* no change of size */

    /* in xlib, we must clear the new area by hand; there may be illegal data
       left in the server. This applies to Xaw as well */
    {   XExposeEvent xev;
	xev.count = -1;
        if (gamegraphic) {
	    if (graphic.height < h) {
		/* window is greater now */
		XClearArea(dpy, table, 0, graphic.height, graphic.width, h - graphic.height, True);
		++xev.count;
	    }
	    if (graphic.width < w) {
		/* window is greater now */
		XClearArea(dpy, table, graphic.width, 0, w - graphic.width, h, True);
		++xev.count;
	    }
	    if (xev.count >= 0) {
		/* generate synthetic expose events for the new area */
		/* this must be done before we possibly change the layout */
		if (graphic.height < h) {
		    /* window is greater now */
		    xev.x = 0;
		    xev.y = graphic.height;
		    xev.width = graphic.width;
		    xev.height = h - graphic.height;
		    redraw_table(&xev);
		    --xev.count;
		}
		if (graphic.width < w) {
		    /* window is greater now */
		    xev.x = graphic.width;
		    xev.y = 0;
		    xev.width = w - graphic.width;
		    xev.height = h;
		    redraw_table(&xev);
		}
	    }
	}
    }
    graphic.height = h;
    graphic.width = w;

    if (!gamegraphic)
	return;
}

xsok-1.02/src/xsok.man100644    144     62       17237  6151124521  13354 0ustar  mbimathopt.TH XSOK 6 "May 1996" "Handmade"
.SH NAME
xsok \- generic Sokoban game for X11, Version 1.02
.SH SYNOPSIS
.B xsok
[
.I options
]
.SH DESCRIPTION
.B xsok
is a single player strategic game, a superset of the well known Sokoban game.
This manpage describes only the user interface of \fBxsok\fP. If you want to
create own levels, you should consult the \fBxsok\fP manual for more information.

The target of \fBSokoban\fP
is to push all the objects into the score area of each level using the
mouse or the arrow keys. For the other level subsets, there are different
kinds of objects, and special effect squares.

\fBxsok\fP can be played using only the mouse, or only the keyboard.  Keyboard
and mouse bindings are defined through a textfile. This manual page describes
the default bindings.

.SH OPTIONS
All standard X toolkit parameters may be given, such as 
\fB\-display\fP \fIdisplay\fP etc.
Additional options are

.TP 4
.B \-rules \fIlevel subset\fP
This option specifies the initial level subset for \fBxsok\fP.
Valid built-in rule names are \fBSokoban\fP, \fBCyberbox\fP, and \fBXsok\fP,
but you may implement new level subsets without recompiling the game.
Level subsets share common characteristics of the board.
In \fBSokoban\fP, for example, all boxes have the same weight.
In \fBXsok\fP, the first level is a demo level, where you can experiment
with the new objects.
.TP 4
.B \-level \fIstartlevel\fP
Set the starting level.
.TP 4
.B \-username \fIusername\fP
In a save-game file, your name, as found in the \fB/etc/passwd\fP file, and the
hostname of your computer, will be stored in the file. The default format is
\fIrealname (username@hostname.domain)\fP, for example
\fBMichael Bischoff (mbi@flawless.ts.rz.tu-bs.de)\fP.
You can override this default string with the argument to the username option and provide a different e-mail address, for example
.br
\fBxsok -username "Michael Bischoff (m.bischoff@tu-bs.de)"\fP.

If you break the scores for one level, your solution will be saved automatically. 

.TP 4
.B \-xsokdir \fIxsokdir\fP
This option sets the root of the \fBxsok\fP data file tree. The default is
\fB/usr/games/lib/xsok\fP.

.TP 4
.B \-xpmdir \fIxpmdir\fP
This gives the directory from where to load the graphic data.

.TP 4
.B \-savedir \fIsavedir\fP
This option sets the directory for save game files and the \fBxsok\fP highscore
files. The default is \fB/var/games/xsok\fP.

.TP 4
.B \-messageFile \fImessagefile\fP
This option sets the name of an alternative message file for \fBxsok\fP.
The pathname is relative to \fIxsokdir\fP. The default is \fBmessages\fP,
and does not exist, which means to use the internal messages.

.TP 4
.B \-keyboardFile \fIkeyboardfile\fP
This option sets the name of the file defining the keyboard bindings.
The pathname is relative to \fIxsokdir\fP. The default is \fBkeys\fP.
The bindings in the default file are described below.

All command line options may be abbreviated, or set by the X11 resource
manager. The resource name for option \fB\-xyz\fP is \fBTableau.xyz\fP and its
class name \fBTableau.Xyz\fP.

.SH KEYBOARD BINDINGS
The arrow keys will move the man. The default binding is similar to the
binding in \fBxsokoban\fP. Some commands accept a numerical prefix (i.e.
typing some digits before the command key), which usually is used as an
operation count.

.TP 8
.B a
Display the author of a level (if known).
.TP 8
.B b
Drops the bookmark.
.TP 8
.B g
Goto bookmark.
.TP 8
.B i
Displays the level comment (if any).
.TP 8
.B s
Saves the current position.
.TP 8
.B L
Reloads a saved game.
.TP 8
.B R
Restart this level. With numerical prefix \fIn\fP, jumps to move number
\fIn\fP.
.TP 8
.B N
Proceed to the next level. With numerical prefix \fIn\fP,
jumps to level \fIn\fP.
.TP 8
.B H
Reread the highscore table.
.TP 8
.B P
Return to the previous level.
.TP 8
.B U
Proceeds to the next unsolved level.
.TP 8
.B q
Quits the game.
.TP 8
.B v
Shows the version of \fBxsok\fP.
.TP 8
.B ?
Shows the current score.
.TP 8
.B b
Shows the best score for this level.
.TP 8
.B c
Drops the bookmark at the current position.
.TP 8
.B u
Undoes the last elementary move. Accepts numerical prefix.
.TP 8
.B r
Redoes last move (undoes an undo). Accepts numerical prefix.
.TP 8
.B (
Starts recording a macro (sequence of moves)
.TP 8
.B )
End a macro.
.TP 8
.B <ENTER>
Replays a macro.

.SH KEYBOARD BINDINGS
With the default button assignment, button 1 is bound to the
function \fBMouseMove\fP. If pressed on a clear square, the man will move to
that location via the optimal path if such a path exists. If pressed on an
object that is adjacent to the player, the object will be pushed.

Button 2 is bound to \fBMouseDrag\fP. This command requires that you press the
mouse button on a location where a box resides, drag the mouse, and release the
button on an empty square. The man will then move the box from the first square
onto the second with the minimal number of pushes, if it is possible at all.
Please note that the man will not move any other object and will only use
squares without effects.

Button 3 is bound to \fBMouseUndo\fP. This function undoes one of the previous
commands, which would possibly require a lot of calls to the atomic undo function.

.SH NATIONAL LANGUAGE SUPPORT
\fBxsok\fP has simple support for different languages. All messages which
appear in the X11 window may be overloaded by files, as well as the key
bindings.  The typical support consists of an application-defaults file, a
message file, and a keyboard file. Possibly translated online-help files are
also there.  To select a different language, call \fBxsok\fP after setting the
environment variable \fBLANG\fP to the desired value.  Currently, no translated
version is available.

.SH FILES
(Directories may differ on your system.)

 \fB/usr/games/bin/xsok\fP
 \fB/var/games/xsok/\fP\fItype\fP\fB.score\fP
 \fB/var/games/xsok/\fP\fItype\fP\fB.\fP\fInn\fP\fB.{sv,bs,mp,mm}\fP
 \fB/usr/doc/xsok/COPYRIGHT.{GNU,xsok,xpm}\fP
 \fB/usr/doc/xsok/xsok.dvi\fP
 \fB/usr/doc/xsok/cyberbox.doc\fP
 \fB/usr/games/lib/xsok/floor.xpm.gz\fP
 \fB/usr/games/lib/xsok/objects.xpm.gz\fP
 \fB/usr/games/lib/xsok/keys\fP
 \fB/usr/games/lib/xsok/keys.help\fP
 \fB/usr/games/lib/xsok/\fP\fItype\fP\fB.def.gz\fP
 \fB/usr/games/lib/xsok/\fP\fItype\fP\fB.help\fP

Where \fItype\fP is one of \fBSokoban\fP, \fBXsok\fP, \fBCyberbox\fP, and
possibly others.

.SH CREDITS
Inspiration for \fBxsok\fP came from \fBxsokoban\fP, a previous implementation
of the \fBSokoban\fP game by Joseph L. Traub. From this game, the wall graphics
were taken, and the mouse button assignment.  \fBxsokoban\fP's level files can
be used without change, but by default, all level files of a level subset are
combined into a single file.  Of course, credits also go to the unknown author
of the curses based game.

The \fBCyberbox\fP levels (and a MSDOS game of the same name) are written by
Doug Beeferman.

.SH BUGS
The undo function is too slow.  Highscore file handling uses no file locking.

\fBCyberbox\fP zappers are implemented as one-way passages, which causes worse
scores and easier levels.

Please mail bug reports to \fBmbi@mo.math.nat.tu-bs.de\fP.  Fixes are
especially welcome.

.SH SEE ALSO
\fBxsokoban(6x)\fP, \fBsokoban(6)\fP

.SH AUTHOR
Michael Bischoff

.SH COPYRIGHT
Copyright (c) 1994 by Michael Bischoff (\fBmbi@mo.math.nat.tu-bs.de\fP)
.sp 1

Permission to use, copy, modify, and distribute this software and its
documentation for any purpose and without fee is hereby granted, provided that
the above copyright notice appear in all copies and that both that copyright
notice and this permission notice appear in supporting documentation.

\fBxsok\fP was developed under Linux, the free UNIX for the IBM-PC and
compatibles. \fBxsok\fP is distributed by terms of the GNU General public
license (GNU Copyleft).
xsok-1.02/src/X-gfx.c100644    144     62       11203  6046457411  13025 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module X-gfx.c				     */
/*									     */
/*	Drawing routines for the X window system.			     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#include "X-sok.h"

/*#include <X11/X.h>*/
#include <xpm.h>

#ifndef DELAY
#define DELAY 50 /* time to sleep (in ms) between auto-moves & replay */
#endif

Display *dpy;
Window table = 0;
struct graphic graphic;
int gamegraphic = 1;

static Pixmap floor, objd, objclip;
static GC gc;
static int resize_pending = 0;

#ifndef HAVE_USLEEP
#include <sys/time.h>
/* usleep emulation code taken from xboing-2.2 by Justin C. Kibell */

static int usleep(unsigned long usec) {
#ifdef SYSV
#ifdef __clipper__
    struct timeval tv;
    tv.tv_sec=((usec)/1000);
    tv.tv_usec=(((usec)%1000)*1000);
    select(1,NULL,NULL,NULL,&tv);
#else
    poll((struct poll *) 0, (size_t) 0, usec / 1000);   /* ms resolution */
#endif
#else
    struct timeval timeout;
    timeout.tv_usec = usec % (unsigned long) 1000000;
    timeout.tv_sec = usec / (unsigned long) 1000000;
    select(0, (void *) 0, (void *) 0, (void *) 0, &timeout);
#endif
    return 0;
}
#endif


void sync_and_wait(void) {
    XSync(dpy, 0);
    usleep(DELAY*1000);
}

void NewLevel(int levelnr) {
    if (levelnr < 1)
	levelnr = 1;
    if (levelnr > maxlevel)
	levelnr = maxlevel;
    game.level = levelnr;
    ParseMapFile();
    SetTitle();
    if (table) {
	init_layout();
	AskWidgetForResize(graphic.width, graphic.height);
	cmd_Resize();
	if (gamegraphic)
	    refresh_screen();
	resize_pending = 1;
    }
}

void init_layout(void) {
    graphic.width = game.numcols * DX;
    graphic.height = game.numrows * DY;
}

void init_gfx(const char *xpmdir) {
    int screen, retcode;
    char s[MAXXSOKDIRLEN+14];
    screen = DefaultScreen(dpy);
    gc = XDefaultGC(dpy, screen);
    sprintf(s, "%s/floor.xpm", xpmdir);
    if ((retcode = XpmReadFileToPixmap(dpy, RootWindow(dpy, screen),
				       s,  &floor, 0, NULL)) == XpmSuccess) {
	sprintf(s, "%s/objects.xpm", xpmdir);
	retcode = XpmReadFileToPixmap(dpy, RootWindow(dpy, screen), s, &objd,
			    &objclip, NULL);
    }
    switch (retcode) {
    case XpmSuccess:
	return;		/* no error */
    case XpmColorFailed:
    case XpmColorError:
	fatal("Not enough colors for %s", s);
    case XpmOpenFailed:
	fatal("Cannot open %s", s);
    case XpmFileInvalid:
	fatal("Invalid File: %s", s);
    case XpmNoMemory:
	fatal("Out of memory reading %s", s);
    default:
	fatal("Unknown error (code %d) reading %s", s);
    }
}

#define ODRAW(c) {   \
    XSetClipOrigin(dpy, gc, x*DX - ((c)&3)*DX, y*DY - ((c)>>2)*DY);\
    XCopyArea(dpy, objd, table, gc, DX*((c)&3), DY*((c)>>2), DX, DY, (x)*DX, (y)*DY); }

static void do_redraw(int x, int y) {
    if (x >= game.numcols || y >= game.numrows || map[y][x]->pic == 16)
	return; /* x = y = 0; */
#ifndef SIMPLE_WALLS
    if (!map[y][x]->pic) {
	int b;
	b = 0;
	if (!map[y][x-1]->pic)
	    b += 1;
	if (!map[y+1][x]->pic)
	    b += 2;
	if (!map[y][x+1]->pic)
	    b += 4;
	if (!map[y-1][x]->pic)
	    b += 8;
	XCopyArea(dpy, floor, table, gc,
		  DX * (b & 7), DY * (b / 8), DX, DY, (x)*DX, (y)*DY);
    } else
#endif
    XCopyArea(dpy, floor, table, gc, DX * (map[y][x]->pic&7),
	      DY * (map[y][x]->pic >> 3), DX, DY, (x)*DX, (y)*DY);
    if (obj[y][x]) {
	int c;
	XSetClipMask(dpy, gc, objclip);
	c = obj[y][x]->pic;
	ODRAW(c);
	XSetClipMask(dpy, gc, None);
    }
}

static void dotPaint(int minx, int miny, int maxx, int maxy) {
    int x, y;
    if (minx > maxx || miny > maxy) {
	int h;
	h = minx; minx = maxx; maxx = h;
	h = miny; miny = maxy; maxy = h;
    }
    x = minx-1;
    do {
	++x;
	for (y = miny; y <= maxy; ++y) {
	    do_redraw(x, y);
	}
    } while (x != maxx);
}

/* doPaint: just request it */
void doPaint(int minx, int miny, int maxx, int maxy) {
#if 0
    XClearArea(dpy, table, minx*DX, miny*DY, (maxx+1)*DX-1, (maxy+1)*DY-1, True);
#else
    dotPaint(minx, miny, maxx, maxy);
#endif
}

void redraw_table(XExposeEvent *xev) {
    int minx, miny, maxx, maxy;
    if (resize_pending) {
	if (xev->count)
	    return;
	/* after a resize, do a complete redraw */
	XClearArea(dpy, table, 0, 0, 0, 0, False);
	dotPaint(1, 1, game.numcols-2, game.numrows-2);
	resize_pending = 0;
    } else {
	minx = xev->x / DX;
	miny = xev->y / DY;
	maxx = (xev->x + xev->width - 1) / DX;
	maxy = (xev->y + xev->height - 1) / DY;
	dotPaint(minx, miny, maxx, maxy);
    }
}
xsok-1.02/src/score.c100644    144     62        3065  5665071060  13134 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module score.c				     */
/*									     */
/*	Score computation and checking for finished levels.		     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include "xsok.h"

void change_rules(const char *type) {
    game.type = type;
    game.level = 0;
    ParseDefinitionFile();
}

int compute_score(void) {
    int x, y;
    int retval = 1;
    game.score = 0;
    for (x = 1; x < game.numcols; ++x)
	for (y = 1; y < game.numrows; ++y) {
	    int c;
	    c = map[y][x]->effect;
	    if (c == E_EXIT) {
		if (game.x != x || game.y != y)
		    retval = 0;	/* EXIT field with no player on it */
		else
		    game.score += obj[y][x]->score;
	    }
	    if (c == E_DEST)
		if (!obj[y][x] || !(obj[y][x]->mask & ~1))
		    retval = 0;	/* player doesn't score! */
		else
		    game.score += obj[y][x]->score;
	}
    if (retval && !objects->score)
	game.score += 10000;	/* finished-score if no special EXIT square */
    game.score -= movecost * game.n_moves + pushcost * game.n_pushes;
    if (game.score < 0)
	game.score = 0;
    return retval;
}

int finished(void) {
    if (!compute_score())
	return game.finished = 0;
    cmd_ShowScore();
    return game.finished = 1;
}
xsok-1.02/src/tools.c100644    144     62        2743  5665071060  13163 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module tools.c				     */
/*									     */
/*	Miscellaneous utility functions.				     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include "xsok.h"

void fatal(const char *msg, ...) {
    va_list args;

    va_start(args, msg);
    vfprintf(stderr, msg, args);
    fprintf (stderr, "\n");
    exit (1);
}

void *malloc_(size_t n) {
    void *p;
    if (!n)
	return NULL;	/* since malloc(0) may return NULL */
    p = malloc(n);
    if (!p)
	fatal("out of memory");
    return p;
}

void *calloc_(size_t n, size_t s) {
    void *p;
    if (!n)
	return NULL;	/* WATCOM C says "out of memory" in the case n = 0 */
    if (!(p = calloc(n, s)))
        fatal("out of memory");
    return p;
}

void *realloc_(void *p, size_t n) {
    if (p == NULL)	/* no old block of size > 0 exists */
	return malloc_(n);
    if (!n) {
	free_(p);
	return NULL;
    }
    if (!(p = realloc(p, n)))
        fatal("out of memory\n");
    return p;
}

void free_(void *p) {
    if (p)
	free(p);
}

char *strsav(const char *txt) {
    char *p = malloc_(1 + strlen(txt));
    strcpy(p, txt);
    return p;
}
xsok-1.02/src/commands.c100644    144     62       14274  5665071060  13646 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module commands.c				     */
/*									     */
/*	Most of the entries for commands assignable to keys		     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include <sys/types.h>
#include <unistd.h>
#include "xsok.h"
#include "version.h"

void cmd_Up(void) {
    playermove(0);
}
void cmd_Left(void) {
    playermove(1);
}
void cmd_Down(void) {
    playermove(2);
}
void cmd_Right(void) {
    playermove(3);
}

void cmd_Repeat(void) {
    if (game.n_moves)
	playermove(movetab[game.n_moves-1]);
}

void cmd_ShowAuthor(void) {
    if (*levelauthor)
	show_message("%s", levelauthor);
    else
	show_message("%s", TXT_NOAUTHOR);
}

void cmd_LevelInfo(void) {
    if (*levelcomment) {
	if (highscore[game.level])
	    show_message("%s (Best Score: %d)", levelcomment, highscore[game.level]);
	else
	    show_message("%s (Unsolved level)", levelcomment);
    } else
	cmd_ShowBestScore();
}

void cmd_NextUnsolved(void) {
    while (game.level < maxlevel) {
	if (!highscore[++game.level]) {
	    NewLevel(game.level);
	    cmd_LevelInfo();
	    return;
	}
    }
}

void cmd_NextLevel(void) {
    if (numeric_arg)
	if (numeric_arg <= maxlevel)
	    game.level = numeric_arg - 1;	/* & fall through */
    if (game.level < maxlevel) {
	if (game.stored_moves && !game.finished) {
	    play_sound("giveup");
	}
	NewLevel(game.level+1);
	cmd_LevelInfo();
    }
}

void cmd_PrevLevel(void) {
    if (game.level > 1) {
	if (game.stored_moves && !game.finished) {
	    play_sound("giveup");
	}
	NewLevel(game.level-1);
	cmd_LevelInfo();
    }
}

void rq_LeaveSok(void) {
    request_confirm(cmd_LeaveSok, TXT_QUIT_CONFIRM);
}

/* unused, since this can be undone */
void rq_RestartGame(void) {
    request_confirm(cmd_RestartGame, TXT_RESTART_CONFIRM);
}

void rq_PrevLevel(void) {
    request_confirm(cmd_PrevLevel, TXT_PREV_CONFIRM);
}
void rq_NextLevel(void) {
    request_confirm(cmd_NextLevel, TXT_NEXT_CONFIRM);
}
void rq_NextUnsolved(void) {
    request_confirm(cmd_NextUnsolved, TXT_UNSOLVED_CONFIRM);
}


void cmd_DropBookmark(void) {
    game.bookmark = game.n_moves;	/* easy, isn't it? */
    show_message(TXT_BOOKMARK_SET);
}

void jumpto_movenr(int move_ptr) {
    int remgraphic = gamegraphic;
    if (move_ptr == game.n_moves)
	return;
    /* assert(move_ptr <= game.stored_moves); */
    if (remgraphic)		/* graphic was on */
	graphics_control(Disable);

    if (move_ptr < game.n_moves)	/* must reset first */
	OrgLevel();
    while (move_ptr > game.n_moves) {
	/* printf("doing move %d of %d (%d)\n", game.n_moves, move_ptr, movetab[game.n_moves]); */
	int xx;
	xx = game.n_moves;
	playermove(movetab[game.n_moves]);
	if (xx == game.n_moves)
	    fatal("Shit, same old bug again!\n");
    }
    if (remgraphic)
	graphics_control(EnableAndRedraw);
}

void cmd_RestartGame(void) {
    if (numeric_arg <= game.stored_moves)
	jumpto_movenr(numeric_arg);
    else 
	jumpto_movenr(game.stored_moves);
    cmd_LevelInfo();
}

void cmd_GotoBookmark(void) {
    jumpto_movenr(game.bookmark);
    cmd_ShowScore();
}

void cmd_SaveGame(void) {
    game.finished = compute_score();
    save_game("sv");
}
void cmd_ShowVersion(void) {
    show_message(TXT_VERSION, VERSION);
}


void cmd_ShowScore(void) {
    compute_score();
    show_message(TXT_SCORE, game.n_moves, game.n_pushes, game.score,
		 obj[game.y][game.x]->power - obj[game.y][game.x]->weight);
}
void cmd_ShowBestScore(void) {
    if (highscore[game.level])
	show_message(TXT_BEST, highscore[game.level+100],
		     highscore[game.level+200], highscore[game.level]);
    else
	show_message(TXT_UNSOLVED);
}
void cmd_ReplayGame(void) {
    if (game.n_moves) {
	int rem = game.n_moves;
	cmd_RestartGame();
	sync_and_wait();
	sync_and_wait();
	do {
	    cmd_RedoMove();
	    sync_and_wait();
	    sync_and_wait();
	} while (game.n_moves < rem);
	cmd_ShowScore();
    }
}

void cmd_LoadGame(void) {
    char filename[MAXSAVEFILELEN];
    static const char **p, *extensions[] = { "sv", "bs", "mp", "mm", "sav", "sol", NULL };
    for (p = extensions; *p; ++p) {
	sprintf(filename, "%s/%s.%02d.%s", savedir, game.type, game.level, *p);
	if (!access(filename, R_OK)) {
	    load_game(filename);
	    return;
	}
    }
    show_message(TXT_NOLOAD);
}
void cmd_StartMacro(void) {
    game.macroStart = game.n_moves;
    game.macroEnd = game.n_moves;
    game.macro_x = game.x;
    game.macro_y = game.y;
    show_message(TXT_STARTMACRO);
}
void cmd_EndMacro(void) {
    if (game.macroStart >= 0) {
	game.macroEnd = game.n_moves;
	show_message(TXT_ENDMACRO, game.n_moves-game.macroStart);
    }
}
void cmd_PlayMacro(void) {
    /* show_message("Stard %d, End %d, at (%d,%d)", game.macroStart, game.macroEnd,
       game.macro_x, game.macro_y); */
    if (game.macroStart >= 0) {
	mouse_x = game.macro_x;
	mouse_y = game.macro_y;
	cmd_MouseMove();	/* sets the before_move variable */
	if (game.x == game.macro_x && game.y == game.macro_y) {
	    int i, base;
	    base = game.n_moves;
	    for (i = game.macroStart; i < game.macroEnd;) {
		playermove(movetab[i++]);
		if (game.n_moves != base + i - game.macroStart)
		    break;	/* invalid move */
	    }
	} else
	    show_message(TXT_MACRO_BADPOS);
    }
}

void cmd_UndoMove(void) {
    if (game.n_moves) {
	int num = numeric_arg;
	if (!num)
	    num = 1;
	if (game.n_moves >= num)
	    jumpto_movenr(game.n_moves-num);
	else
	    jumpto_movenr(0);
	show_message(TXT_UNDO);
	if (game.n_moves < game.macroStart || game.n_moves < game.macroEnd)
	    game.macroStart = -1;
    } else if (game.stored_moves) {
	jumpto_movenr(game.stored_moves);
	show_message(TXT_UNDO);
    } else
	show_message(TXT_NOUNDO);
}
void cmd_RedoMove(void) {
    if (game.n_moves < game.stored_moves) {
	int num = numeric_arg;
	if (!num)
	    num = 1;
	if (game.n_moves + num <= game.stored_moves)
	    jumpto_movenr(game.n_moves+num);
	else
	    jumpto_movenr(game.stored_moves);
	show_message(TXT_REDO);
    } else
	show_message(TXT_NOREDO);
}
xsok-1.02/src/X-sok.h100644    144     62        5254  6122571522  13026 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module X-sok.h				     */
/*									     */
/*	This file is included by all sources for the X interface.	     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#include "xsok.h"
#include <X11/Xlib.h>
#include <X11/Xutil.h>
#include <X11/Xos.h>
#include <X11/Intrinsic.h>

#include <X11/StringDefs.h>
#include <X11/Shell.h>
#include <X11/Xaw/Cardinals.h>
#include <X11/Xaw/Paned.h>
#include <X11/Xaw/Box.h>	
#include <X11/Xaw/Label.h>	
#include <X11/Xaw/Viewport.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/Dialog.h>
#include <X11/Xaw/Sme.h>
#include <X11/Xaw/SmeBSB.h>
#include <X11/Xaw/Toggle.h>

/* in X11R3, XSize_t was int, since R4 we seem to have a mixture of int  */
/* and unsigned int! (complain!)					 */
typedef unsigned int XSize_t;   /* type used by X for width and height   */
                                /* this is not consistent used by X11R5  */

extern struct graphic {
    boolean autolayout;         /* automatic new layout at resize events */
    XSize_t width;              /* the width of the table window         */
    XSize_t height;             /* the height of the table window        */
} graphic;

extern Display *dpy;
extern Window table;
extern Widget toplevel;

#define DX	32	/* size of one square. we could even read this from the xpm file */
#define DY	32



/* prototypes. some of them may be in xsok.h already */
/* Xaw-help.c */
#ifdef ONLINE_HELP
void create_help(void);
void popup_help(void);
void popdown_help(Widget, XtPointer, XtPointer);
#endif

/* Xaw-main.c */
void show_message(const char *str, ...);
void SetTitle(void);
void cmd_LeaveSok(void);
void cmd_Confirm(void);
void cmd_Cancel(void);
void request_confirm(void (*)(void), const char *);
#ifdef SOUND
int checksound(void);
#endif
int main(int argc, char *argv[]);
void Force_Resize(XSize_t, XSize_t);

/* X-widget.c */
void AskWidgetForResize(XSize_t, XSize_t);

/* X-events.c */
void refresh_screen(void);
void button_press(XButtonPressedEvent *);
void button_release(XButtonPressedEvent *);
void key_press(XKeyPressedEvent *);
void cmd_Resize(void);
void resize_event(XSize_t, XSize_t);

/* X-gfx.c */
void NewLevel(int);
void init_layout(void);
void init_gfx(const char *);
/* void dotPaint(int, int, int, int); */
void doPaint(int, int, int, int);
void redraw_table(XExposeEvent *);
xsok-1.02/src/move.c100644    144     62       27271  5665071060  13014 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module move.c				     */
/*									     */
/*	Detection of valid moves, and effect handling functions.	     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include "xsok.h"

#define SAVE_STATE	/* variant which should flicker less */
#define SELECTOR_HACK	/* ugly hack to allow Cyberbox selectors */

static int dxtab[4] = { 0, -1, 0, 1 };
static int dytab[4] = { -1, 0, 1, 0 };

char *movetab = NULL;
int numalloc = 0;

/* declare the unmovable blocker which prevents race conditions */
static struct objects blocked = { 1, 0, 0, 0, 0, 0, 0, 0 };

static void storemove(int res, int dir) {   
    if (res > 1)
	++game.n_pushes;
    if (game.n_moves == numalloc)
	movetab = realloc_(movetab, numalloc += 256);
    if (game.stored_moves > game.n_moves && movetab[game.n_moves] == dir) {
	/* This is a redo, but the user retyped it. Be nice. */
	++game.n_moves;
    } else {
	/* this is a new move: reset number of stored moves (no redo beyond this one) */
	if (game.bookmark > game.n_moves)
	    game.bookmark = game.n_moves;
	movetab[game.n_moves++] = dir;
	game.stored_moves = game.n_moves;	/* reset the redo limit */
    }
}


#define DOPAINT(x1,y1,x2,y2)	if (gamegraphic) doPaint(x1,y1,x2,y2);

#ifdef SAVE_STATE
static struct walls *savemap[MAXROW][MAXCOL];
static struct objects *saveobj[MAXROW][MAXCOL];
static struct objects saveinstance[MAXINSTANCES];

static void save_state(void) {
    int x, y;
    gamegraphic = 0;
    memcpy(savemap, map, sizeof(map));	/* dereferenced objects are readonly */
    memcpy(saveinstance, instance, sizeof(instance));
    memcpy(saveobj, obj, sizeof(obj));
    for (y = 2; y < game.numrows-2; ++y)
	for (x = 2; x < game.numcols-2; ++x)
	    if (obj[y][x]) {
		int i;
		i = obj[y][x] - instance;
		saveobj[y][x] = saveinstance + i;
	    }
}

static void update_state(void) {
    int x, y;
    gamegraphic = 1;
    for (y = 2; y < game.numrows-2; ++y)
	for (x = 2; x < game.numcols-2; ++x) {
	    int pica, picb;
	    pica = obj[y][x] ? obj[y][x]->pic : -1;
	    picb = saveobj[y][x] ? saveobj[y][x]->pic : -1;
	    if (pica != picb || map[y][x] != savemap[y][x])
		doPaint(x,y, x,y);
#if 0
	    if (pica != picb) {
		printf("At (%2d,%2d): pics %d and %d differ\n", x, y, pica, picb);
	    }
#endif
	}
}
#define SAVE	save_state();
#define UPDATE	update_state();
#else
#define SAVE	gamegraphic = 0;
#define UPDATE  { gamegraphic = 1; doPaint(2,2, game.numcols-3,game.numrows-3); }
#endif

void graphics_control(int on) {
    switch (on) {
    case Disable:
	SAVE;
	break;
    case Enable:
	gamegraphic = 1;
	break;
    case EnableAndRedraw:
	UPDATE;
	break;
    }
}


/* Check if object on square (x,y) has enough power to move in direction dir */
/* If it has, do the move and return 1 or 2 (1 if object moved alone)        */

static int do_move(int x, int y, int dir) {
    struct objects *ip;
    struct walls *wp;
    int dx, dy, tx, ty;
    int dirbits, power;
#ifdef SELECTOR_HACK
    static struct objects *sel_ip = NULL;
    struct objects *new_sel_ip;
    int forbidden = 0;
    int sel_enter = 0, sel_leave = 0;

    if (obj[y][x]->pic == 7)
	sel_leave = 1;
#endif

    dx = dxtab[dir];
    dy = dytab[dir];
    dirbits = 1 << dir;
    
    tx = x;
    ty = y;

    
    wp = map[ty][tx];
    ip = obj[ty][tx];	/* what moves? */
    power = 0;
    do {
	if (ip->chr)			/* involves object already moved? */
	    return 0;
	if (!(ip->movedir & dirbits))	/* object isn't allowed to go this way */
	    return 0;
	if (ip->pushdir & dirbits)	/* does this one help pushing? */
	    power += ip->power;
	power -= ip->weight;
	if (power < 0)			/* does our power suffice? */
	    return 0;			/* it's not enough to check this at the end of the loop */
	/* may we leave from here? */
	if (!(wp->leave & dirbits))
	    return 0;	/* nope */
#ifdef SELECTOR_HACK
	if (ip->mask & forbidden) {	/* may not be pushed by THIS object */
	    switch (obj[ty-dy][tx-dx]->pic) {
	    case 0:	/* man: */
	    case 7:	/* man in selector */
		if (ip->mask == 0x30010) {	/* walkable selector */
		    sel_enter = 1;
		    new_sel_ip = ip;
		    goto move_ok;
		}
	    }
	    return 0;
	}
	forbidden = (ip->mask & 0xffff) << 16;	/* for next object */
#endif
	tx += dx;
	ty += dy;
	wp = map[ty][tx];
	if (!(wp->enter & dirbits))
	    return 0;				/* may not enter from here */
	if (!(wp->mask & ip->mask))
	    return 0;				/* may not enter square anyway */
	ip = obj[ty][tx];			/* next object, if any */
    } while (ip);

move_ok:
    ;
    /* yeah, move is OK, do it! */
    /* do the move, count blocks moved */
    {   int n;
	n = 0;
	do {
	    ++n;
	    (obj[ty][tx] = obj[ty-dy][tx-dx])->chr = 1;	/* mark object 'moved' */
	    tx -= dx;
	    ty -= dy;
	} while (tx != x || ty != y);
#ifdef SELECTOR_HACK
	if (sel_leave) {
	    obj[ty][tx] = sel_ip;
	    obj[ty+dy][tx+dx]->pic = 0;	/* normal man again */
	    sel_ip->chr = 1;
	    sel_ip = NULL;
	} else {
	    obj[ty][tx] = NULL;
	}
	if (sel_enter) {
	    sel_ip = new_sel_ip;
	    obj[ty+n*dy][tx+n*dx]->pic = 7;	/* man in a box */
	}
	DOPAINT(x, y, x+n*dx, y+n*dy);
	if (!sel_leave)
	    obj[ty][tx] = &blocked;

#else
	obj[ty][tx] = NULL;
	DOPAINT(x, y, x+n*dx, y+n*dy);
	obj[ty][tx] = &blocked;
#endif
	return n;
    }
}

static int automoves(void) {
    int x, y, flag = 0;

    for (x = game.numcols-3; x>1; --x)
	for (y = game.numrows-3; y>1; --y) {
	    struct objects *ip;
	    if ((ip = obj[y][x])) {
		if ((ip->pushdir & 1) && do_move(x, y, 0))
		    flag = 1;
		else if ((ip->pushdir & 2) && do_move(x, y, 1))
		    flag = 1;
	    }
	}
    for (x = 2; x < game.numcols-2; ++x)
	for (y = 2; y < game.numrows-2; ++y) {
	    struct objects *ip;
	    if ((ip = obj[y][x])) {
		if ((ip->pushdir & 4) && do_move(x, y, 2))
		    flag = 1;
		else if ((ip->pushdir & 8) && do_move(x, y, 3))
		    flag = 1;
	    }
	}
    return flag;	/* turn if at least one object was moved */
}

#define TURN(object, bits)	((((object) << (bits)) & 0x0f) | ((object) >> (4-(bits))))

static void check_effects(void) {
    /* check moved objects, if they entered effect squares */
    /* if so, apply effect				   */
    /* mark objects unmoved and remove the blockers	   */
    int x, y;
    for (x = 2; x < game.numcols-2; ++x)
	for (y = 2; y < game.numrows-2; ++y)
	    if (obj[y][x] && obj[y][x]->chr) {
		struct objects *ip;
		ip = obj[y][x];
		if (ip == &blocked) {
		    obj[y][x] = NULL;	/* square is free now */
		    if (map[y][x]->effect >= 2*E_ONCE)
			/* square will change now to other type */
			map[y][x] = walls + (map[y][x]->effect / E_ONCE) - 2;
		} else {
		    int effect;
		    ip->chr = '\0';
		    if ((effect = map[y][x]->effect)) {
			if (effect > E_ONCE && effect < 2 * E_ONCE)
			    map[y][x] = walls;	/* one-time effect only */
			effect %= E_ONCE;
			switch (effect) {
			case E_TURN_CCW:
			case E_TURN_180:
			case E_TURN_CW:
			    /* does a rotation affect the object? */
			    if ((ip->movedir != 0 && ip->movedir != 0x0f) ||
				(ip->pushdir != 0 && ip->pushdir != 0x0f)) {
				/* yes, it does. Are there 2 or 4 pictures for this tile? */
				if (TURN(ip->movedir, 2) == ip->movedir &&
				    TURN(ip->pushdir, 2) == ip->pushdir)
				    /* only two pictures */
				    ip->pic ^= (effect & 1);
				else
				    /* four pictures */
				    ip->pic = (ip->pic & ~3) | ((ip->pic + effect) & 3);
				ip->movedir = TURN(ip->movedir, effect);
				ip->pushdir = TURN(ip->pushdir, effect);
				    
				DOPAINT(x, y, x, y);
			    }
			    break;
			case E_ADDPOWER:
			    ++ip->power;
			    break;
			case E_SUBPOWER:
			    if (ip->power)
				--ip->power;
			    break;
			case E_TELEPORT:
			    {   int xx, yy;
				/* find a matching teleporter */
				for (xx = 2; xx < game.numcols-2; ++xx)
				    for (yy = 2; yy < game.numrows-2; ++yy)
					if ((xx != x || yy != y) &&
					    (!obj[yy][xx] || obj[yy][xx] == &blocked) &&
					    map[yy][xx]->effect % E_ONCE == E_TELEPORT) {
					    /* found a matching free teleporter */
					    obj[yy][xx] = ip;
					    if (map[yy][xx]->effect == E_TELEPORT+E_ONCE)
						map[yy][xx] = walls;
					    obj[y][x] = NULL;
					    if (gamegraphic) {
						doPaint(xx,yy,xx,yy);
						doPaint(x,y,x,y);
					    }
					    goto done;
					}
			    }
			    /* fall through if just a single teleporter, */
			    /* or no other teleporter is free: ignore! */
			done:
			    break;
			}
		    }
		} /* moved object */
	    } /* any object at all */
}

void playermove(int dir) {	/* dir is 0..3 */
    int result;
    struct objects *ip;
#if 0
    {
	int x, y;
	for (x = 2; x < game.numcols-2; ++x)
            for (y = 2; y < game.numrows-2; ++y)
		if (obj[y][x] && obj[y][x]->chr) {
		    printf("unclean object at (%d,%d) of chr %x\n", x, y, obj[y][x]->chr);
		    obj[y][x]->chr = '\0';
		}
    }
#endif
    (ip = obj[game.y][game.x])->pushdir = 1 << dir;

#ifdef SELECTOR_HACK
    if (ip->pic == 7) /* no one may push from behind */
	result = do_move(game.x, game.y, dir);
    else
#endif
    {
	int n = 0;
	/* check if there are blocks behind us that help pushing */
	/* stupid compiler, result IS initialized! */
	do
	    ++n;
	while (obj[game.y-n*dytab[dir]][game.x-n*dxtab[dir]]);
	do
	    --n;
	while (!(result = do_move(game.x-n*dxtab[dir], game.y-n*dytab[dir], dir)) && n);
	if (result && result-1 < n)
	    fatal("internal error\n");
    }
    ip->pushdir = 0;	/* this must be reset BEFORE check_effects! */

    if (result) {
	int x, y;
	storemove(result, dir);
	do {
	    if (gamegraphic)
		sync_and_wait();
	    /* add sound here too! */
	    check_effects();
	} while (automoves());
	/* player may get pushed around: search him! */
	game.x = game.y = 0;
	for (x = 2; x < game.numcols-2; ++x)
            for (y = 2; y < game.numrows-2; ++y)
		if (obj[y][x] == ip) {
		    game.y = y;
		    game.x = x;
		    break;
		}
	/* fatal("Ooops, player has vanished!\n"); */
	if (finished()) {
	    int update = 0;
	    cmd_ReadHighscores();	/* read the actual values! TODO: lock the highscore file */
	    if (highscore[game.level] < game.score) {
		highscore[game.level] = game.score;
		update = 1;
	    }
	    if (highscore[game.level+100] > game.n_moves) {
		highscore[game.level+100] = game.n_moves;
		update |= 2;
	    }
	    if (highscore[game.level+200] > game.n_pushes) {
		highscore[game.level+200] = game.n_pushes;
		update |= 4;
	    }
	    if (update) {
		const char *firstfile = NULL;
		WriteHighscores();
#if 0
		if (highscore[game.level] == game.score)
		    save_game("sol");	/* optimum score */
		else if (highscore[game.level+200] == game.n_pushes)
		    save_game("mp");	/* minimal pushes */
		else if (highscore[game.level+100] == game.n_moves)
		    save_game("mm");	/* minimal moves */
		/* TODO: should remove obsolete files and rename others. That's hard! */
#else
		/* possibly save multiple files */
		if (highscore[game.level] == game.score)
		    save_game(firstfile = "bs");	/* best score */
		if (highscore[game.level+200] == game.n_pushes)
		    firstfile ? link_game(firstfile, "mp") :
			save_game(firstfile = "mp");	/* minimal pushes */
		if (highscore[game.level+100] == game.n_moves)
		    firstfile ? link_game(firstfile, "mm") :
			save_game(firstfile = "mm");	/* minimal moves */
#endif
		show_message(TXT_NEWHIGH, game.score);
		return;
	    }
	    /* TODO: release the highscore file lock */
	    show_message(TXT_YOU_WIN, game.score, highscore[game.level]);
	    return;
	} /* if (finished()) */
	cmd_ShowScore();
    } else
	if (!game.finished)	/* hack to avoid complains on excess moves at the end */
	    show_message(TXT_MOVENOTPOSSIBLE);
}
xsok-1.02/src/parse.c100644    144     62       16647  5665071060  13165 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module parse.c				     */
/*									     */
/*	Parsing of the level subset definition files and level files.	     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include "xsok.h"

#define MAXABBREVS 32
static char abbrevs[MAXABBREVS][4];
static int numabbrevs;

int nwalls, nobjects, ninstances;
int pushcost, movecost;
const char *xsokdir;
struct objects objects[MAXOBJECTS];
struct walls walls[MAXWALLS];	/* wall types */
struct game game;
struct walls *map[MAXROW][MAXCOL];
struct objects *obj[MAXROW][MAXCOL];
struct objects instance[MAXINSTANCES];

static struct game init = { 1, 1, -1, -1, 0, 0, 0 };
static struct walls the_void = { '\0', 16, 0,0,0,0 };

static struct walls   *omap[MAXROW][MAXCOL];
static struct objects *oobj[MAXROW][MAXCOL];
static struct objects oinstance[MAXINSTANCES];
static struct game    ogame;

/* restore the game state for initial tableau. No graphics update */
void OrgLevel(void) {
    memcpy(map, omap, sizeof(map));
    memcpy(obj, oobj, sizeof(obj));
    memcpy(instance, oinstance, sizeof(instance));
    ogame.macroStart = game.macroStart;
    ogame.macroEnd   = game.macroEnd;
    ogame.macro_x    = game.macro_x;
    ogame.macro_y    = game.macro_y;
    ogame.bookmark = game.bookmark;
    ogame.stored_moves = game.stored_moves;
    game = ogame;
}

int maxlevel;
char levelcomment[100];
char levelauthor[100];
static int piped;

/* open the level database and read, starting at a given line */
static FILE *def_open(const char *firstline) {
    FILE *fp;
    char s[MAXXSOKDIRLEN+14];
    char shorttype[8];
    strcpy(shorttype, game.type);
    shorttype[7] = '\0';

    sprintf(s, "%s/%s.def", xsokdir, shorttype);
    if (!(fp = fopen(s, "r"))) {
	if (!(fp = zreadopen(s)))	/* uncompress on-the-fly */
	    fatal("Cannot open definition file for %s\n", game.type);
	piped = 1;
    }
    while (fgets(s, sizeof(s), fp))
	if (!strcmp(s, firstline))
	    return fp;
    fatal("No matching line found\n");
    /* this end is not reached */
    return fp;	/* but keep the compiler happy (volatile functions are not ANSI) */
}

void ParseDefinitionFile(void) {
    FILE *fp;
    int mode = 0;
    char s[MAXXSOKDIRLEN+22];

    piped = 0;
    maxlevel = 99;
    pushcost = 10;
    movecost = 1;
    sprintf(s, "%s/%s/definitions", xsokdir, game.type);
    if (!(fp = fopen(s, "r")))
	fp = def_open(";WALLS\n");
    numabbrevs = nwalls = nobjects = 0;
    while (fgets(s, sizeof(s), fp)) {
	int len;
	len = strlen(s);
	if (len && s[len-1] == '\n')
	    s[--len] = '\0';
	if (!strcmp(s, ";WALLS")) {
	    mode = 0;
	} else if (!strcmp(s, ";OBJECTS")) {
	    mode = 1;
	} else if (!strncmp(s, ";MAXLEVEL", 9)) {
	    maxlevel = atoi(s+9);
	    if (maxlevel < 1 || maxlevel > 99)
		maxlevel = 99;
	} else if (!strncmp(s, ";PUSHCOST", 9)) {
	    pushcost = atoi(s+9);
	} else if (!strncmp(s, ";MOVECOST", 9)) {
	    movecost = atoi(s+9);
	} else if (!strncmp(s, ";ATOP ", 6)) {
	    if (numabbrevs == MAXABBREVS)
		fatal("Too many abbrevs!\n");
	    strncpy(abbrevs[numabbrevs++], s+6, 3);
	} else if (!strncmp(s, ";LEVEL", 6))
	    break;
	if (!len || *s == ';')
	    continue;	/* comment or empty line */
	switch (mode) {
	case 0:
	    {   struct walls *wp;
		if (nwalls == MAXWALLS)
		    fatal("Too many wall types\n");
		wp = walls + nwalls++;
		wp->chr = *s;
		if (sscanf(s+1, "%x %x %x %x %d", &wp->pic, &wp->enter,
			   &wp->leave, &wp->mask, &wp->effect) != 5)
		    fatal("Bad line for character '%c':\n%s\n",
			  wp->chr, s);
	    }
	    break;
	case 1:
	    {   struct objects *wp;
		if (nobjects == MAXOBJECTS)
		    fatal("Too many object types\n");
		wp = objects + nobjects++;
		wp->chr = *s;
		if (sscanf(s+1, "%x %x %x %d %d %x %d", &wp->pic, &wp->movedir,
			   &wp->pushdir, &wp->weight, &wp->power, &wp->mask,
			   &wp->score) != 7)
		    fatal("Bad line for character '%c':\n%s\n",
			  wp->chr, s);
	    }
	    break;
	default:
	    ;
	}
    }
    if (piped)
	zreadclose(fp);
    else
	fclose(fp);
    if (!nwalls || !nobjects)
	fatal("Definition file is empty\n");
}


static void dfs(int x, int y) {
    if (x < 0 || y < 0 || x >= game.numcols || y >= game.numrows)
	return;
    if (map[y][x] != walls)
	return;
    map[y][x] = &the_void;
    dfs(x-1, y);
    dfs(x, y-1);
    dfs(x+1, y);
    dfs(x, y+1);
}

/* read current level of current game.type */

void ParseMapFile(void) {
    FILE *fp;
    int x, y;
    struct objects *ip;
    char s[MAXXSOKDIRLEN+20];

    piped = 0;
    sprintf(s, "%s/%s/screen.%02d", xsokdir, game.type, game.level);
    if (!(fp = fopen(s, "r"))) {
	sprintf(s, ";LEVEL %d\n", game.level);
	fp = def_open(s);
    }
    ninstances = 0;
    for (x = 0; x < MAXCOL; ++x)
	for (y = 0; y < MAXROW; ++y) {
	    map[y][x] = walls;
	    obj[y][x] = NULL;
	}
    init.level = game.level;
    init.type = game.type;
    *levelcomment = '\0';
    *levelauthor = '\0';
    game = init;
    ip = instance;
    for (y = 1; fgets(s, sizeof(s), fp); ++y) {
	int c, cc;
	/* parse s to map */
	if (*s == ';') {
	    if (!strncmp(s+1, "LEVEL", 5))
		break;
	    --y;	/* line doesn't count */
	    if (!strncmp(s+1, "COMMENT ", 8)) {
		strncpy(levelcomment, s+9, sizeof(levelcomment)-1);
		levelcomment[sizeof(levelcomment)-1] = '\0';
		if (strchr(levelcomment, '\n'))
		    *strchr(levelcomment, '\n') = '\0';
	    }
	    if (!strncmp(s+1, "AUTHOR ", 7)) {
		strncpy(levelauthor, s+8, sizeof(levelauthor)-1);
		levelauthor[sizeof(levelauthor)-1] = '\0';
		if (strchr(levelauthor, '\n'))
		    *strchr(levelauthor, '\n') = '\0';
	    }
	    continue;	/* skip this line (extra comment) */
	}
	if (y == MAXROW-1)
	    fatal("Level is too big\n");
	for (x = 1; (c=s[x-1]) && c != '\n'; ++x) {
	    struct objects *op;
	    struct walls *wp;
	    int n;
	    if (x == MAXCOL-1)
		fatal("Level is too wide\n");
	    if (x > game.numcols)
		game.numcols = x;
	    /* check, if c is an abbrev */
	    cc = walls[0].chr;	/* make standard floor below (should be space) */
	    for (n = 0; n < numabbrevs; ++n)
		if (abbrevs[n][0] == c) {
		    c = abbrevs[n][1];
		    cc = abbrevs[n][2];
		}
	    for (op = objects, n = nobjects; n; --n, ++op)
		if (op->chr == c) {	/* object found */
		    if (op == objects) {	/* player himself */
			if (game.x >= 0)
			    fatal("Multiple player positions\n");
			game.x = x;
			game.y = y;
		    }
		    if (ninstances++ == MAXINSTANCES)
			fatal("Too many objects\n");
		    *ip = *op;	/* copy object */
		    ip->chr = '\0';	/* mark unmoved object */
		    obj[y][x] = ip++;
		    c = cc;		/* floor type */
		    break;
		}
	    for (wp = walls, n = nwalls; n; --n, ++wp)
		if (wp->chr == c) {	/* wall found */
		    map[y][x] = wp;
		    break;
		}
	    if (!n)
		fatal("No wall type found for character '%c'\n", c);
	}
    }
    if (piped)
	zreadclose(fp);
    else
	fclose(fp);
    game.numrows = y+1;
    game.numcols += 2;
    /* change floor to void */
    dfs(0, 0);

    /* save to orglevel for easy restart */
    memcpy(omap, map, sizeof(map));
    memcpy(oobj, obj, sizeof(obj));
    memcpy(oinstance, instance, sizeof(instance));
    game.macroStart = -1;	/* no macro available */
    ogame = game;
    cmd_ReadHighscores();
    lastcmd = NULL;
}
xsok-1.02/src/X-widget.c100644    144     62       15337  6122571155  13535 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module X-widget.c				     */
/*									     */
/*	The tableau widget for Xsok.					     */
/*	written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#include "X-sok.h"
#include <X11/IntrinsicP.h>
#include <X11/StringDefs.h>
#include "TableauP.h"

static XtResource resources[] = {
#define offset(field) XtOffsetOf(TableauRec, tableau.field)
    /* {name, class, type, size, offset, default_type, default_addr}, */
    {XtNruleset, XtCRuleset, XtRString,    sizeof(String),    offset(rules),    XtRString,    "Sokoban"},
    {XtNlevel,   XtCLevel,   XtRInt,       sizeof(int),       offset(level),    XtRImmediate, (XtPointer)1},
    {XtNusername,XtCUsername,XtRString,    sizeof(String),    offset(username), XtRString,    NULL},
    {XtNxsokdir, XtCXsokdir, XtRString,    sizeof(String),    offset(xsokdir),  XtRString,    XSOKDIR},
    {XtNxpmdir,  XtCXpmdir,  XtRString,    sizeof(String),    offset(xpmdir),   XtRString,    NULL},
    {XtNsavedir, XtCSavedir, XtRString,    sizeof(String),    offset(savedir),  XtRString,    XSOKSAVE },
    {XtNmessageFile,XtCMessageFile,XtRString,sizeof(String),  offset(messageFile), XtRString, "messages"},
    {XtNkeyboardFile,XtCKeyboardFile,XtRString,sizeof(String),offset(keyboardFile),XtRString, "keys"},
#undef offset
};


/* actions on the desktop area */
/*ARGSUSED*/
static void TableauKey(Widget w, XEvent *xev, String *s, Cardinal *num) {
    key_press((XKeyPressedEvent *)xev);
}
/*ARGSUSED*/
static void TableauBtn_down(Widget w, XEvent *xev, String *s, Cardinal *num) {
    button_press((XButtonPressedEvent *)xev);
}
/*ARGSUSED*/
static void TableauBtn_up(Widget w, XEvent *xev, String *s, Cardinal *num) {
    button_release((XButtonPressedEvent *)xev);
}
/*ARGSUSED*/
static void Redisplay(Widget w, XEvent *xev, Region region) {
    redraw_table((XExposeEvent *)xev);
}

static XtActionsRec actions[] = {
    /* {name, procedure}, */
    { "tableau_k",	TableauKey },
    { "tableau_d",	TableauBtn_down },
    { "tableau_u",	TableauBtn_up },
};

static char translations[] = "\
<Key>:		tableau_k()	\n\
<BtnDown>:	tableau_d()	\n\
<BtnUp>:	tableau_u()	\n\
";


static Boolean SetValues(Widget current, Widget request, Widget desired,
			 ArgList args, Cardinal *num_args) {
    return FALSE;
}

static void Initialize(Widget request, Widget xnew, ArgList args, Cardinal *n);
static void Resize(Widget gw);


static void Realize(Widget w, XtValueMask *valuemask, XSetWindowAttributes *winattr) {
    *valuemask |= CWEventMask | CWBackingStore | CWBitGravity;
    winattr->backing_store = WhenMapped;
    winattr->bit_gravity = NorthWestGravity;
    winattr->event_mask = KeyPressMask | ExposureMask | ButtonPressMask |
            ButtonReleaseMask | StructureNotifyMask | Button3MotionMask;
   (*(tableauClassRec.core_class.superclass)->core_class.realize)(w, valuemask, winattr);
}

TableauClassRec tableauClassRec = {
  { /* core fields */
    /* superclass		*/	(WidgetClass) &widgetClassRec,
    /* class_name		*/	"Tableau",
    /* widget_size		*/	sizeof(TableauRec),
    /* class_initialize		*/	NULL,
    /* class_part_initialize	*/	NULL,
    /* class_inited		*/	FALSE,
    /* initialize		*/	Initialize,
    /* initialize_hook		*/	NULL,
    /* realize			*/	Realize,
    /* actions			*/	actions,
    /* num_actions		*/	XtNumber(actions),
    /* resources		*/	resources,
    /* num_resources		*/	XtNumber(resources),
    /* xrm_class		*/	NULLQUARK,
    /* compress_motion		*/	TRUE,
    /* compress_exposure	*/	TRUE,
    /* compress_enterleave	*/	TRUE,
    /* visible_interest		*/	FALSE,
    /* destroy			*/	NULL,
    /* resize			*/	Resize,
    /* expose			*/	Redisplay,
    /* set_values		*/	SetValues,
    /* set_values_hook		*/	NULL,
    /* set_values_almost	*/	XtInheritSetValuesAlmost,
    /* get_values_hook		*/	NULL,
    /* accept_focus		*/	NULL,
    /* version			*/	XtVersion,
    /* callback_private		*/	NULL,
    /* tm_table			*/	translations,
    /* query_geometry		*/	XtInheritQueryGeometry,
    /* display_accelerator	*/	XtInheritDisplayAccelerator,
    /* extension		*/	NULL
  },
  { /* tableau fields */
    /* empty			*/	0
  }
};

WidgetClass tableauWidgetClass = (WidgetClass)&tableauClassRec;

static Widget toplev = NULL;

static void Resize(Widget gw) {
    TableauWidget w = (TableauWidget) gw;
    /* printf("Parent wants me to have size %d,%d\n",
	   w->core.width, w->core.height); */
    resize_event(w->core.width, w->core.height);
    /* (*pileWidgetClass->core_class.superclass->core_class.resize)(gw); */
}

void AskWidgetForResize(XSize_t x, XSize_t y) {
    XtWidgetGeometry Geo;
    XtGeometryResult r;

    Geo.width = x;
    Geo.height = y;
    do {
	Geo.request_mode = CWWidth | CWHeight;
#ifdef LABER
	printf("resize to %d %d yielded ", Geo.width, Geo.height);
#endif
	r = XtMakeGeometryRequest(toplev, &Geo, &Geo);
#ifdef LABER
	switch (r) {
	case XtGeometryYes:	printf("YES!\n");break;
	case XtGeometryNo:	printf("NO!\n"); break;
	case XtGeometryAlmost:printf("Almost!\n"); break;
	case XtGeometryDone:	printf("Done!\n"); break;
	}
#endif
    } while (r == XtGeometryAlmost);
}

const char *keyfilename;

static void Initialize(Widget request, Widget xnew, ArgList args, Cardinal *n) {
    static int is_inited = 0;
    TableauWidget new = (TableauWidget)xnew;
    TableauPart *p = &new->tableau;
    toplev = xnew;
    if (is_inited) {
	fprintf(stderr, "Sorry, currently only one instance of Tableau is allowed\n");
	exit(EXIT_FAILURE);
    }

    xsokdir = p->xsokdir;
    savedir = p->savedir;
    setlangdir();
    if (!p->xpmdir)
	p->xpmdir = p->xsokdir;
    if (strlen(savedir) > MAXSAVEFILELEN-16 ||
	strlen(xsokdir) > MAXXSOKDIRLEN ||
	strlen(p->xpmdir) > MAXXSOKDIRLEN) {
	fprintf(stderr, "directory too long\n");
	exit(1);
    }
    if (strlen(p->keyboardFile) > MAXFILENAMELEN ||
	strlen(p->messageFile) > MAXFILENAMELEN) {
	fprintf(stderr, "filename too long\n");
	exit(1);
    }
    keyfilename = p->keyboardFile;
    read_message_file(p->messageFile);
    read_keyboard_file(p->keyboardFile);

    /* assign global data for old Xlib program */
    dpy    = XtDisplay(new);

    buildusername(p->username);
    /* gamegraphic = 1; */
    change_rules(p->rules);
    NewLevel(p->level);

    init_gfx(p->xpmdir);		/* make GCs, read xpm files */
    init_layout();
#ifdef LABER
    printf("Init widget: res %d grap %d\n", new->core.width, graphic.width);
#endif
    if (new->core.width < graphic.width)
	new->core.width = graphic.width;
    if (new->core.height < graphic.height)
	new->core.height = graphic.height;
}
xsok-1.02/src/Imakefile100644    144     62       13604  6122776563  13517 0ustar  mbimathopt# Imakefile for xsok
#
# ****************************************************************************

# customizing:
#
# 0.) extra warnings for gcc and development
#undef EXTRA_WARNINGS

# 1.) specify, if you want online help
# affected file(s): Xaw-main.c, Xaw-help.c
HELP_OPTION = -DONLINE_HELP

# 2.) specify, if you want sound (then, SOUNDOBJ should be one module of
#	X-sound_*.o, else empty)
#     Note: for X-sound_SUN.o, /dev/audio must have 666 permissions
# affected file(s): (several, you should recompile completely)
# note: sound isn't too great at the moment, we better leave it off.
SOUND_OPTION = # -DSOUND
SOUNDOBJ = # X-sound_SUN.o

# 3.) there is a function popen() in sys-V / X/OPEN which opens a pipe.
# Define -DHAVE_POPEN if you want to use this function for decompressing
# level files. Do not define it if you want to use my emulation, which
# does only require a standard POSIX.1 system and is faster, since it does
# not spawn a shell.
# Attention! In both cases, you need a binary of gunzip in your PATH.
# affected file(s): xfopen.c
PIPE_DEFINE = # -DHAVE_POPEN

# 4.) There is a function gethostbyname() in BSD systems, which will extract
# the domain of your host from the /etc/hosts database. The definition of the
# relevant structure is in the system include file netdb.h.
# This file is availaible on Linux, SUN-OS, HP-UX 9. (But it is not
# part of the POSIX standard.)
# Remove this define, if you do not have this function.
# affected file(s): username.c
NET_DEFINE = -DBSD_NETKIT

# 5.) For the replay option, we need the possibility to sleep for a short
# period of time. This can be done by the usleep() function.
# Remove this, if you need usleep() emulation code.
# affected file(s): X-gfx.c
SLEEP_DEFINE = -DHAVE_USLEEP

# BINDIR and LIBDIR should be predefined by the templates
# BINDIR = /usr/bin/X11
# LIBDIR = /usr/lib/X11
XSOKLIBDIR = /usr/games/lib/xsok
APPDEFSDIR = $(LIBDIR)
XSOKMANDIR = /usr/man/man6
XSOKDOCDIR = /usr/doc/xsok

# This is the name of the save directory, where solved games are stored:
# an alternative path would be $(XSOKLIBDIR)/save
# The directory XSOKSAVEDIR must have permissions rwx for world, else
# xsok must be installed suid, and XSOKDIR must have write permissions for
# the owner of xsok
XSOKSAVEDIR = /var/games/xsok

# paths for installation in user's home-directory.
LXSOKBINDIR = $(HOME)/bin
LXSOKMANDIR = $(HOME)/xsok
LAPPDEFSDIR = $(HOME)

# xsok needs to know where the xpm library resides
XPMLIB 			= -L$(USRLIBDIR) -lXpm
XPMINCLUDE		= -I $(INCDIR)

# *****************************************************************************
# I hope you don't need to change anything below this point
# *****************************************************************************
#if defined(HPArchitecture) || defined(AIXArchitecture)
CC = c89
CCOPTIONS =
#else
CC = gcc
#ifdef EXTRA_WARNINGS
CCOPTIONS = -O2 -pipe -ansi -fno-common -Wall -Wshadow -Wpointer-arith \
	-Wcast-qual -Wcast-align -Waggregate-return \
	-Wstrict-prototypes -Wmissing-prototypes \
	-Wnested-externs -Wwrite-strings
#else
CCOPTIONS = -O2 -pipe -ansi -Wall -fno-common
#endif
#endif

# Xaw interface (the only one currently available)
KIT_LIBS = XawClientLibs
KIT_OBJS = Xaw-main.o Xaw-help.o
DEPLIBS = XawClientDepLibs

LOCAL_LIBRARIES = $(XPMLIB) $(KIT_LIBS)

VER=1.02

XOBJS   = X-events.o X-gfx.o X-widget.o $(SOUNDOBJ)
STDOBJS = messages.o commands.o score.o parse.o tools.o move.o \
	loadsave.o username.o xfopen.o mousemove.o

OBJS = $(STDOBJS) $(XOBJS) $(KIT_OBJS)
MYPROG = xsok
ALLTARGETS = username combine showscore mergescores $(MYPROG)
DEFINES = $(HELP_OPTION) $(SOUND_OPTION) $(XPMINCLUDE) $(NET_DEFINE) \
   $(PIPE_DEFINE) -DXSOKDIR=\"$(XSOKLIBDIR)\" -DXSOKSAVE=\"$(XSOKSAVEDIR)\" \
   $(SLEEP_DEFINE)

# Dependencies:
# *.c  require  version.h xsok.h
# X*.c additionally require X-sok.h and Tableau.h
# X-widget.c additionally requires TableauP.h
LIBCONTS = *.gz *.help keys

all::	$(ALLTARGETS)

clean::
	rm -f $(ALLTARGETS)

testname:
	@echo
	@echo "The name used for highscores you break is"
	@./username
	@echo "If you do not like this, please set the Tableau.username \
resource explicitly."
	@echo

username: username.c
	$(CC) $(NET_DEFINE) -DTESTING -s -o username username.c

combine: combine.c
	$(CC) -s -o combine combine.c

# the install targets require that make has been run in the lib directory
install:: $(MYPROGS)
	(umask 022 && mkdirhier $(XSOKLIBDIR))
	# chmod 755 $(XSOKLIBDIR)
	(umask 022 && mkdirhier $(XSOKSAVEDIR))
	chmod 777 $(XSOKSAVEDIR)
	(cd ../lib; tar cf - $(LIBCONTS) | (cd $(XSOKLIBDIR); tar xf -))
	chown -R root $(XSOKLIBDIR) $(XSOKSAVEDIR)
	chmod -R a+r $(XSOKLIBDIR)
	(cd ../lib && ../src/mergescores $(XSOKSAVEDIR)/Xsok.score \
	   $(XSOKSAVEDIR)/Sokoban.score $(XSOKSAVEDIR)/Cyberbox.score)
	chmod 666 $(XSOKSAVEDIR)/[A-z]*.score
	(umask 022 && mkdirhier $(XSOKDOCDIR))
	if [ -r ../doc/xsok.dvi ]; then cp ../doc/xsok.dvi $(XSOKDOCDIR); fi
	cp ../doc/cyberbox.doc $(XSOKDOCDIR)
	cp ../etc/COPYRIGHT* $(XSOKDOCDIR)
	chmod -R a+r $(XSOKDOCDIR)
	mkdirhier $(XSOKMANDIR)
	cp xsok.man $(XSOKMANDIR)/xsok.6x
	chmod 644 $(XSOKMANDIR)/xsok.6x

ComplexProgramTarget($(MYPROG))
InstallAppDefaults(XSok)

install.fsstnd:
	$(MAKE) install
	mkdirhier /usr/games/bin
	chmod 755 /usr/games/bin
	mv $(BINDIR)/xsok /usr/games/bin

install.local: $(MYPROGS)
	mkdirhier $(LXSOKBINDIR) $(LXSOKMANDIR) $(XSOKLIBDIR) $(XSOKSAVEDIR) \
	   $(LAPPDEFSDIR)/app-defaults
	chmod 755 $(XSOKLIBDIR) $(LXSOKMANDIR) $(LAPPDEFSDIR)/app-defaults
	chmod 777 $(XSOKSAVEDIR)
	cp XSok.ad $(LAPPDEFSDIR)/app-defaults/XSok
	chmod 755 $(LAPPDEFSDIR)/app-defaults/XSok
	(cd ../lib; tar cf - $(LIBCONTS) | (cd $(XSOKLIBDIR); tar xf -))
	chmod -R a+r $(XSOKLIBDIR)
	cp xsok $(LXSOKBINDIR)
	chmod 755 $(LXSOKBINDIR)/xsok
	cp xsok.man $(LXSOKMANDIR)/xsok.6x
	chmod 644 $(LXSOKMANDIR)/xsok.6x
	(cd ../lib && ../src/mergescores $(XSOKSAVEDIR)/Xsok.score \
	   $(XSOKSAVEDIR)/Sokoban.score $(XSOKSAVEDIR)/Cyberbox.score)
	chmod 666 $(XSOKSAVEDIR)/[A-z]*.score
xsok-1.02/src/Xaw-main.c100644    144     62       27717  6037770724  13543 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module Xaw-main.c				     */
/*									     */
/*	main function for the Athena Widget interface.			     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#include "X-sok.h"
#include "Tableau.h"
#include "version.h"

Widget toplevel;

static XtAppContext app_con;
static void (*execfunc)(void) = NULL;
static Widget messagebox, container, desktop;
static Widget dialog, popup, paned;
static Window mainwindow;


void show_message(const char *str, ...) {
    if (gamegraphic) {
	static char last_message[256];
	Arg Args;
	va_list args;
	va_start(args, str);
	
	if (!str) {
	    memset(last_message, ' ', sizeof(last_message)-1);
	    last_message[sizeof(last_message)-1] = '\0';
	} else
	    vsprintf(last_message, str, args);
	
	XtSetArg(Args, XtNlabel, last_message);
	XtSetValues(messagebox, &Args, 1);
    }
}

void SetTitle(void) {
    if (XtWindow(toplevel)) {
	static char windowname[48];
	sprintf(windowname, "%s - Level %d", game.type, game.level);
	/* printf("SetTitle(): toplevel = %p, window = %x\n",
	   toplev, XtWindow(toplevel)); */
	XStoreName(dpy, XtWindow(toplevel), windowname);
    }
}

void cmd_LeaveSok(void) {
    play_sound("goodbye");
    XtDestroyApplicationContext(app_con);
    exit(0);
}

static void perform_command(Widget widget, XtPointer client_data, XtPointer call_data) {
    (*(void (*)(void))client_data)();	/* any questions? */
}

static void popup_confirm(const char *prompt) {
    Arg args[2];
    Position x, y;
    Dimension xx, yy, wx, wy;

    XtSetArg(args[0], XtNlabel, prompt);
    XtSetValues(dialog, args, 1);
    XtVaGetValues(dialog,   XtNwidth, &xx, XtNheight, &yy, NULL);
    XtVaGetValues(toplevel, XtNwidth, &wx, XtNheight, &wy, NULL);
    x = (wx - xx)/2;
    y = (wy - yy)/2;

    XtTranslateCoords(toplevel, x, y, &x, &y);
    XtSetArg(args[0], XtNx, x);
    XtSetArg(args[1], XtNy, y);
    XtSetValues(popup, args, 2);
    XtPopup(popup, XtGrabNone);
}

void cmd_Confirm(void) {
    if (execfunc) {
	void (*execfunc2)(void) = execfunc;	/* erase it first! */
	execfunc = NULL;
	XtPopdown(popup);
	(*execfunc2)();	/* finally execute the desired function */
    }
}
void cmd_Cancel(void) {
    if (execfunc) {
	execfunc = NULL;
	XtPopdown(popup);
    }
}

/* type converter functions: */
static void mXtAP_Cancel (Widget w, XEvent *xev, String *params, Cardinal *num) { cmd_Cancel();  }
static void mXtAP_Confirm(Widget w, XEvent *xev, String *params, Cardinal *num) { cmd_Confirm(); }
static void Cancel(Widget widget, XtPointer client_data, XtPointer call_data)	{ cmd_Cancel();  }
static void Ok(Widget widget, XtPointer client_data, XtPointer call_data)	{ cmd_Confirm(); }

void request_confirm(void (*dofunc)(void), const char *prompt) {
    if (execfunc)
	return;		/* request pending => deny another one */
    if (game.finished || !game.n_moves) {
	(*dofunc)();	/* perform action without confirmation */
	return;
    }
    execfunc = dofunc;
    popup_confirm(prompt);
}

static String fallback_resources[] = { 
    "*beNiceToColormap:			false",
    "*shapeStyle:			Rectangle",
    "*topShadowContrast:		20",
    "*bottomShadowContrast:		40",
    "*Scrollbar*background:		Grey70",
    "*Background:			grey85",
    "*Foreground:			black",
    "*resizeToPreferred:		True",
    "*input:				True",
    "*showGrip:				off",
    "*shadowWidth:                   	2",
    "*messages.justify:			Left",
    "*upperbox.orientation:		XtorientHorizontal",
    "*lowerbox.orientation:		XtorientHorizontal",
    "*Tableau.backingStore:		WhenMapped",
    "*Tableau.keyboardFile:		keys",
    "*Tableau.messageFile:		messages",
    "*Tableau.background:		black",
    "*Tableau.rules:		        Sokoban",
    "*Viewport.allowHoriz:		False",		/* scrollbar disable! */
    "*Viewport.allowVert:		False",		/* code is buggy! */
    "*Viewport.forceBars:		False",
    "*Viewport.useBottom:		True",
    "*Viewport.useRight:		True",
    "*Label.shadowWidth:		0",
    "*Label.BorderWidth:		2",
    "*Dialog*Translations: #override \n<Key>y: Ok()\n<Key>n: Cancel()\n",
    "XSok*title:			XSok",
    "XSok.prompt.allowShellResize:	True",
    "XSok.prompt.saveUnder:		True",
    "*Dialog*resizable:			True",
    "*Hint.Translations: #override\n<BtnDown>:set()\n<BtnUp>:HintNotify()unset()\n",
    "*Sound.state:			True",
    "XSok.help.width:			403",
    "XSok.help.height:			200",
    "XSok.help.title:			XSok Help Window",
    "XSok.help.saveUnder:		True",
    "XSok*Close Help.fromHoriz:		Topic",
    "*helptext*string:			Please choose a topic.",
    "*helptext*displayCaret:		False",
    "*helptext*scrollHorizontal:	whenNeeded",
    "*helptext*scrollVertical:		whenNeeded",
    "*helptext*editType:		read",
    NULL,
};

static XrmOptionDescRec options[] = {
    /* tableau resources */
    { "-rules",		"*Tableau.rules",	XrmoptionSepArg, NULL },
    { "-level",		"*Tableau.level",	XrmoptionSepArg, NULL },
    { "-username",	"*Tableau.username",	XrmoptionSepArg, NULL },
    { "-xsokdir",	"*Tableau.xsokdir",	XrmoptionSepArg, NULL },
    { "-xpmdir",	"*Tableau.xpmdir",	XrmoptionSepArg, NULL },
    { "-savedir",	"*Tableau.savedir",	XrmoptionSepArg, NULL },
    { "-messageFile",	"*Tableau.messageFile",	XrmoptionSepArg, NULL },
    { "-keyboardFile",	"*Tableau.keyboardFile",XrmoptionSepArg, NULL },

    /* non-tableau resources */
#ifdef SOUND
    { "-sound", 	"*Sound.state",      	XrmoptionNoArg, (XtPointer)"True" },
    { "-nosound", 	"*Sound.state",      	XrmoptionNoArg, (XtPointer)"False" },
#endif
};

static XtActionsRec moreActions[] = {
    { "Cancel",		mXtAP_Cancel },
    { "Ok",		mXtAP_Confirm }
};

static void process_extra_args(int argc, char *argv[]) {
    /* check extra args */
    if (argc >= 2) {
	fprintf(stderr, "xsok: invalid argument: %s\n", argv[1]);
	fprintf(stderr, "usage: xsok [options]\n"
		"options are all standard X11 toolkit options and\n"
                "-rules (ruleset)     to initially use specified rules\n"
                "-level (levelnr)     to set the startlevel\n"
                "-username (username) to set individual username for highscores\n"
		"-xsokdir (dir)       to set the game directory\n"
		"-xpmdir (dir)        to set the directory for xpm files\n"
		"-savedir (dir)       to set the directory for saved games\n"
		"-messageFile (file)  to set the message file name\n"
		"-keyboardFile (file) define the keyboard assignment\n"
#ifdef SOUND
		"-sound               sound toggle on\n"
		"-nosound             sound toggle off\n"
#endif
		);
	exit(EXIT_FAILURE);
    }
}

const char *rulepool[16] = { "Xsok", "Sokoban", "Cyberbox", NULL };

static void selectrules(Widget w, XtPointer number, XtPointer garbage) {
    const char *s = XtName(w);
    /* printf("widget %s has been selected\n", s); */
    change_rules(s);
    NewLevel(1);
    cmd_LevelInfo();
}

#ifdef SOUND
static Widget sound;

int checksound(void) {
    Boolean retval;
    Arg args[1];
    XtSetArg(args[0], XtNstate, &retval);
    XtGetValues(sound, args, 1);
    return retval & 0xff;
}
#endif


static void read_gametypes(void) {
    char filename[256], s[80];
    FILE *fp;
    sprintf(filename, "%s/gametypes", xsokdir);
    if ((fp = fopen(filename, "r"))) {
	int i;
	for (i = 3; i < 15; ++i) {
	    if (!fgets(s, sizeof(s), fp))
		break;
	    if (*s == ';') {
		--i;
		continue;
	    }
	    if (strchr(s, '\n'))
		*strchr(s, '\n') = '\0';
	    if (strlen(s) > 8)
		s[8] = '\0';
	    rulepool[i] = strsav(s);
	}
	rulepool[i] = NULL;
	fclose(fp);
    } /* else keep default pool */
}

int main(int argc, char *argv[]) {
    Widget buttonpanel;
    Widget gamebutton, gamemenu, rulesbutton, rulesmenu;
    int i;
    struct button {
	const char *name; void (*func)(void);
    } *bp;
    static struct button buttons[] = {
	{ "Undo",	  	cmd_UndoMove },
	{ "Redo",	  	cmd_RedoMove },
	{ "Next Level",	  	cmd_NextLevel },
	{ "Score",	  	cmd_ShowScore },
#ifdef ONLINE_HELP
	{ "Help",	  	popup_help },
#endif
	{ "Save",	  	cmd_SaveGame },
	{ "Load",		cmd_LoadGame }
    }, mbuttons[] = {
	{ "Drop Bookmark",	cmd_DropBookmark },
	{ "Goto Bookmark",	cmd_GotoBookmark },
	{ "Replay",		cmd_ReplayGame },
	{ "Restart",		cmd_RestartGame },
 	{ "Next Level",		cmd_NextLevel },
 	{ "Previous Level",	cmd_PrevLevel },
	{ "Quit",		rq_LeaveSok }
    };

    /* use the command line arguments concerning the widgets */
    switch_uid(1);
    toplevel = XtAppInitialize(&app_con, "XSok", options, XtNumber(options),
			       &argc, argv, fallback_resources, NULL, 0);
    switch_uid(0);
    process_extra_args(argc, argv);
    XtAppAddActions(app_con, moreActions, XtNumber(moreActions));

    /* basic elements */
    paned       = XtCreateManagedWidget("paned",	panedWidgetClass,    toplevel,	  NULL, 0);
    buttonpanel = XtCreateManagedWidget("buttonpanel",	boxWidgetClass,     paned,	  NULL, 0);
    messagebox = XtCreateManagedWidget("messages", labelWidgetClass, paned, NULL, 0);
    show_message(TXT_WELCOME, VERSION);
    graphics_control(Disable);

    container   = XtCreateManagedWidget("container",	viewportWidgetClass, paned,	  NULL, 0);
    desktop     = XtCreateManagedWidget("desktop",	tableauWidgetClass,  container,	  NULL, 0);
    /* XtAddCallback(container, XtNreportCallback, reportfunc, NULL); */

    /* create the button panel and its menus */
    gamebutton  = XtCreateManagedWidget("Game", menuButtonWidgetClass, buttonpanel, NULL, 0);
    gamemenu    = XtCreatePopupShell("gamemenu", simpleMenuWidgetClass, gamebutton, NULL, 0);
    for (bp = mbuttons, i = 0; i < XtNumber(mbuttons); ++i) {
	Widget w;
	w = XtCreateManagedWidget(bp->name, smeBSBObjectClass, gamemenu, NULL, 0);
	if (bp->func) XtAddCallback(w, XtNcallback, perform_command, bp->func);
	++bp;
    }
    XtVaSetValues(gamebutton, XtNmenuName, "gamemenu", NULL);

    /* create Rules button just right of the Game button */
    rulesbutton = XtCreateManagedWidget("Level Subset", menuButtonWidgetClass, buttonpanel, NULL, 0);
    rulesmenu   = XtCreatePopupShell("rulesmenu", simpleMenuWidgetClass, rulesbutton, NULL, 0);
    XtVaSetValues(rulesbutton, XtNmenuName, "rulesmenu", NULL);

    /* rest of the buttons */
    for (bp = buttons, i = 0; i < XtNumber(buttons); ++i) {
	Widget w;
	w = XtCreateManagedWidget(bp->name, commandWidgetClass, buttonpanel, NULL, 0);
	if (bp->func) XtAddCallback(w, XtNcallback, perform_command, bp->func);
	++bp;
    }
#ifdef SOUND
    sound = XtCreateManagedWidget("Sound", toggleWidgetClass, buttonpanel, NULL, 0);
#endif

    /* OK. Now do the pop-up shells */
    popup = XtCreatePopupShell("prompt", transientShellWidgetClass, toplevel, NULL, 0);
    dialog = XtCreateManagedWidget("dialog", dialogWidgetClass, popup, NULL, 0);
    XawDialogAddButton(dialog, "ok",     Ok,     (XtPointer)dialog);
    XawDialogAddButton(dialog, "cancel", Cancel, (XtPointer)dialog);

#ifdef ONLINE_HELP
    create_help();
#endif
    graphic.width = graphic.height = 0;
    graphic.autolayout = 1;
    XtRealizeWidget(toplevel);
    XSync(dpy, 0);
    mainwindow = XtWindow(toplevel);
    XSetIconName(dpy, mainwindow, "xsok");
    SetTitle();
    table  = XtWindow(desktop);

    read_gametypes();
    {   const char **rp;
	for (rp = rulepool; *rp; ++rp) {
	    Widget w;
	    w = XtCreateManagedWidget(*rp, smeBSBObjectClass, rulesmenu, NULL, 0);
	    XtAddCallback(w, XtNcallback, selectrules, NULL);
	}
    }

    graphics_control(Enable);
    XtRealizeWidget(popup);
    XtAppMainLoop(app_con);	/* does not return */
    return 0;			/* keep compiler happy */
}

void Force_Resize(XSize_t w, XSize_t h) {
    Arg args[1];
    int hh;
    Dimension hhh = 0;
    XtSetArg(args[0], XtNheight, &hhh);
    XtGetValues(paned, args, 1);
    hh = hhh;		/* unsigned short => int */
    XtGetValues(container, args, 1);
    /* printf("rq %d, paned = %d, container = %d\n", h, hh, hhh); */
    h += hh - hhh;	/* difference between overall size and Viewport size */

    XResizeWindow(dpy, mainwindow, w, h);
}
xsok-1.02/src/messages.c100644    144     62       20020  6122601321  13622 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.01 -- module messages.c				     */
/*									     */
/*	Internationalisation and keyboard translation/customisation.	     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include "xsok.h"
#include <ctype.h>

void (*lastcmd)(void);
int numeric_arg = 0;

const char *xsok_messages[] = {
    "Quit game?",
    "Another game?",
    "Restart game?",
    "Next level?",
    "Previous level?",
    "Not possible",
    "Bookmark set",
    "You won! (Score %d, Best score: %d)",
    "OK",
    "XSok version %s",
    "Moves: %d, Pushes: %d, Score: %d. Current strength: %d.",
    "Already at starting position.",
    "Move undone.",
    "Redo not possible.",
    "Move redone.",
    "Welcome to XSok version %s!",

    "Saving of game FAILED.",
    "Loading the game FAILED.",
    "Could not open file.",
    "Could not open file.",
    "Could not write header.",
    "Could not read header.",
    "Could not write moves.",
    "Could not read moves.",
    "Saving the game succeeded.",
    "Loading the game succeeded.",
    "Magic match failed.",
    
    "The author of this level is unknown.",
    "New record for this level!",
    "Cannot find a savegame file.",
    "Help on keys",
    "Help on the %s level subset",

    "Starting macro recording.",
    "Recorded macro has %d moves.",
    "Wrong position for macro replay.",

    "Proceed to the next unsolved level?",
    "Least moves: %d, Least pushes: %d, Best score: %d.",
    "This level is unsolved.",
    "Cannot link savegame files.",

    "There is no box.",
    "There is already a box.",
};

void read_message_file(const char *filename) {
    FILE *fp;
    int i;
    char line[256];
    if (*filename != '/') {
	sprintf(line, "%s/%s/%s", xsokdir, langdir, filename);
	filename = line;
    }
    if (!(fp = fopen(filename, "r")))
	return;		/* Xt philosophy: ignore error */
    for (i = 0; i < sizeof(xsok_messages) / sizeof(const char *); ++i) {
	char *p;
    again:
	if (!fgets(line, sizeof(line), fp))
	    break;	/* EOF */
	if (*line == '#')
	    goto again;
	if ((p = strrchr(line, '\n')))
	    *p = '\0';
	if (*line)	/* empty lines => keep old text */
	    xsok_messages[i] = strsav(line);
    }
    fclose(fp);
}

static void cmd_None(void) {}

static void replace_binding(struct key_action *p, const char *name) {
    int i;
    static struct translator {
	const char *name;
	void (*func)(void);
    } translator[] = {
	{ "None",		cmd_None },
	{ "rq_LeaveSok",	rq_LeaveSok },
	{ "rq_RestartGame",	rq_RestartGame },
	{ "rq_NextLevel",	rq_NextLevel },
	{ "rq_NextUnsolved",	rq_NextUnsolved },
	{ "rq_PrevLevel",	rq_PrevLevel },
	{ "Up",			cmd_Up },
	{ "Left",		cmd_Left },
	{ "Down",		cmd_Down },
	{ "Right",		cmd_Right },
	{ "NextUnsolved",	cmd_NextUnsolved },
	{ "NextLevel",		cmd_NextLevel },
	{ "PrevLevel",		cmd_PrevLevel },
	{ "UndoMove",		cmd_UndoMove },
	{ "RedoMove",		cmd_RedoMove },
	{ "LeaveSok",		cmd_LeaveSok },
	{ "ShowScore",		cmd_ShowScore },
	{ "ShowBestScore",	cmd_ShowBestScore },
	{ "ShowAuthor",		cmd_ShowAuthor },
	{ "RestartGame",	cmd_RestartGame },
	{ "ReplayGame",		cmd_ReplayGame },
	{ "SaveGame",		cmd_SaveGame },
	{ "LoadGame",		cmd_LoadGame },
	{ "ReadScores",		cmd_ReadHighscores },
	{ "ShowVersion",	cmd_ShowVersion },
	{ "ResizeWindow",	cmd_Resize },
	{ "RepeatMove",		cmd_Repeat },
	{ "MouseMove",		cmd_MouseMove },	/* requires x, y */
	{ "MousePush",		cmd_MousePush },	/* requires x, y */
	{ "MouseUndo",		cmd_MouseUndo },
	{ "MouseDrag",		cmd_MouseDrag },
	{ "LevelInfo",		cmd_LevelInfo },
	{ "DropBookmark",	cmd_DropBookmark },
	{ "GotoBookmark",	cmd_GotoBookmark },
	{ "StartMacro",		cmd_StartMacro },
	{ "EndMacro",		cmd_EndMacro },
	{ "PlayMacro",		cmd_PlayMacro },
/*	{ "Debug",		cmd_debug }, */
	{ "Cancel",		cmd_Cancel },
	{ "Confirm",		cmd_Confirm }
    };
    for (i = 0; i < sizeof(translator) / sizeof(translator[0]); ++i)
	if (!strcmp(name, translator[i].name)) {
	    p->action = translator[i].func;
	    return;
	}
    fprintf(stderr, "WARNING: no function corresponds to \"%s\"\n", name);
    p->action = cmd_None;
}

static struct key_action *global_bindings = NULL;
const char *langdir = "";

void add_keybinding(struct key_action **cp, const char *cmd, const char *function) {
    /* a NULL pointer for cmd is a wildcard */
    int done = 0;
    struct key_action *p;

    if (!cp)
	return;		/* bindings for unimplemented rulesets */
    while (*cp) {
	p = *cp;
	if (!cmd || !strcmp(p->string, cmd)) {
	    /* replace this! */
	    replace_binding(p, function);
	    done = 1;
	}
	cp = &(p->next);
    }
    if (!done && cmd) {
	/* didn't find previous command */
	/* add a new entry */
	p = *cp = malloc_(sizeof(struct key_action));
	p->next = NULL;
	p->string = strsav(cmd);
	replace_binding(p, function);
    }
}


void read_keyboard_file(const char *filename) {
    FILE *fp;
    char line[256];
    char buff[32], cmd[2];
    struct key_action **cp = &global_bindings;

    cmd[1] = '\0';	/* 1-char commands currently */
    if (*filename != '/') {
	sprintf(line, "%s/%s/%s", xsokdir, langdir, filename);
	filename = line;
    }
    /* printf("reading keyboard file \"%s\"\n", filename); */
    if (!(fp = fopen(filename, "r"))) {
	/* in xsok, the keyboard file is required, not optional */
	/* therefore, we issue an error */
	fprintf(stderr, "Cannot read keyboard definition file %s\n",
		filename);
	if (*langdir)
	    fprintf(stderr, "Hint: Perhaps unsetting LANG or making a symbolic"
		    " link\nfrom %s/%s to %s helps.\n", xsokdir,
		    langdir, xsokdir);
	exit(1);
    }
    while (fgets(line, sizeof(line), fp)) {
	char *p;
	if ((p = strrchr(line, '\n')))
	    *p = '\0';
	if (!*line)
	    continue;
	if (!strncmp(line, "#c", 2))	/* comment */
	    continue;
	if (!strncmp(line, "#include ", 9)) {	/* include */
	    read_keyboard_file(line+9);
	    continue;
	}
	if (!strncmp(line, "#x", 2) && strlen(line) < 32) { /* hex number */
	    int c;
	    sscanf(line+2, "%x %s", &c, buff);
	    cmd[0] = c;
	    add_keybinding(cp, cmd, buff);
	    continue;
	}
	/* else assume string<space>commandname */
	if (strlen(line) >= 3 && strlen(line) < 32) {
	    p = line+1;
	    while (*p && *p != '\t' && *p != ' ')
		++p;
	    if (*p) {
		*p = '\0';
		while (*++p && (*p == '\t' || *p == ' '))
		    ;
		if (*p) {
		    add_keybinding(cp, line, p);
		    continue;
		}
	    }
	}
	fprintf(stderr, "Warning: cannot parse line in keys file:%s\n", line);
    }
    fclose(fp);
}

void key_pressed(char *str) {
    struct key_action *p;

    /* search for global binding */
    for (p = global_bindings; p; p = p->next)
	if (!strcmp(p->string, str)) {
	    (*p->action)();
	    lastcmd = p->action;
	    numeric_arg = 0;
	    return;
	}

    /* not found. break up the string to smaller pieces */
    if (strlen(str) > 1) {
	char s[2];
	while (*str) {
	    s[0] = *str++;
	    s[1] = '\0';
	    key_pressed(s);
	}
	return;
    }	/* use hardcoded entries. Note: These can be overridden by assigning them "None" before. */
	
    /* process digits */
    if (isdigit(str[0])) {
	if (numeric_arg >= 3267)
	    numeric_arg = 0;
	numeric_arg = 10 * numeric_arg + (str[0] - '0');
	show_message("%d", numeric_arg);
	return;
    }
    switch (str[0]) {
    case '\b':
	if (numeric_arg >= 10) {
	    show_message("%d", numeric_arg /= 10);
	    return;
	}
	/* else fall through */
    case '\033':	/* esc */
	numeric_arg = 0;
	show_message(" ");
	return;
    case '\014':	/* ctrl-L */
    case '\022':	/* ctrl-R */
	refresh_screen();
	return;
    }
    if (str[0]) {
	const char *rulechange = "XCS";
	const char *rulename[] = { "Xsok", "Cyberbox", "Sokoban" };
	const char *s;

	if ((s = strchr(rulechange, str[0]))) {
	    /* printf("found %s\n", rulename[s-rulechange]); */
	    change_rules(rulename[s-rulechange]);
	    NewLevel(1);
	    cmd_LevelInfo();
	    return;
	}
    }
}
xsok-1.02/src/loadsave.c100644    144     62       15453  6046460626  13647 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module loadsave.c				     */
/*									     */
/*	Functions for highscores and loading/saving games.		     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include <limits.h>
#include <unistd.h>
#include <time.h>
#include "xsok.h"
#include "version.h"

/* code to switch between real and effective user id */
/* we must use the real user id when saving files */

void switch_uid(int to_real) {
#ifdef _POSIX_SAVED_IDS
    static int uid_state = -1; /* -1 = unknown, 1 = real, 0 = effective */
    static uid_t real_uid, effective_uid;
    if (uid_state < 0) {
	real_uid = getuid();
	effective_uid = geteuid();
	uid_state = 0;
    }
    if (to_real != uid_state && real_uid != effective_uid) {
	setuid(to_real ? real_uid : effective_uid);
	uid_state = to_real;
    }
#endif
}

void setlangdir(void) {
    const char *s;
    char p[100];
    if ((s = getenv("LANG"))) {
	sprintf(p, "%s/%s", xsokdir, s);
	if (!access(p, F_OK)) {		/* langdir does exist */
	    langdir = s;
	    return;
	}
    }
    langdir = "";
}

const char *savedir = NULL;

#define NARGS	16	/* score, pushes, moves, time */
#define BUFSIZE	256	/* at least length of longest shortname + 1 */

#define MAGIC1	0x741b	/* magic of xsok version 1 */
#define MAGICS	0x741c	/* magic of xsok version 1 simple file */
#define MAGICH	0x741d	/* magic of xsok version 1 highscore file */


static void read_err(const char *msg) {
    if (gamegraphic) {
	show_message("%s %s", TXT_LOAD_ERR_BASIC, msg);
	cmd_LeaveSok();				/* make it better! */
    }
    fprintf(stderr, "%s %s\n", TXT_LOAD_ERR_BASIC, msg);
    exit(EXIT_FAILURE);
}

static void portable_to_internal(long *args, unsigned char *p, int num) {
    do {
	int j;
	*args = 0;
	for (j = 0; j < 4; ++j)
	    *args += (long)p[3-j] << (j << 3);
	++args;
	p += 4;
    } while (--num);
}

static void internal_to_portable(unsigned char *p, long *args, int num) {
    do {
	int j;
	memset(p, (*args < 0 ? -1 : 0), 4);
	for (j = 0; j < 4; ++j)
	    p[3-j] = (unsigned char)(*args >> (j << 3));
	++args;
	p += 4;
    } while (--num);
}

int highscore[300];

void cmd_ReadHighscores(void) {
    FILE *fp;
    char filename[MAXSAVEFILELEN];
    int i;

    memset(highscore, 0, sizeof(highscore));
    for (i = 100; i < 300; ++i)
	    highscore[i] = 0x7fffffff;

    sprintf(filename, "%s/%s.score", savedir, game.type);
    if ((fp = fopen(filename, "rb"))) {
	long p[300];
	unsigned char s[1200];
	fread(s, 4, 300, fp);
	portable_to_internal(p, s, 300);	
	for (i = 0; i < 300; ++i)
	    highscore[i] = p[i];
	fclose(fp);
    }
    highscore[0] = MAGICH;
}

void WriteHighscores(void) {
    FILE *fp;
    char filename[MAXSAVEFILELEN];
    sprintf(filename, "%s/%s.score", savedir, game.type);
    if ((fp = fopen(filename, "wb"))) {
	int i;
	long p[300];
	unsigned char s[1200];
	for (i = 0; i < 300; ++i)
	    p[i] = highscore[i];
	internal_to_portable(s, p, 300);
	fwrite(s, 4, 300, fp);
	fclose(fp);
    }
}

void load_game(const char *filename) {
    FILE *fp;
    long args[NARGS];
    int i, remgraphic = gamegraphic;
    unsigned char p[NARGS * 4];

    if (gamegraphic)	/* interactive loading */
	graphics_control(Disable);
    OrgLevel();
    if (!(fp = fopen(filename, "rb")))
	read_err(TXT_LOAD_ERR_OPEN);

    if (fread(p, 4, 1, fp) != 1)
	read_err(TXT_LOAD_ERR_HEADER);
    portable_to_internal(args, p, 1);
    if (args[0] == MAGICS) {
	fseek(fp, 0L, SEEK_END);
	game.stored_moves = ftell(fp) - 4;
	game.n_moves = game.bookmark = game.stored_moves;
	game.macroStart = -1;
	fseek(fp, 4L, SEEK_SET);
	goto readmoves;
    }

    if (args[0] != MAGIC1)
	read_err(TXT_LOAD_ERR_BADMAGIC);
    if (fread(p, 4, NARGS-1, fp) != NARGS-1)
	read_err(TXT_LOAD_ERR_HEADER);
    portable_to_internal(args+1, p, NARGS-1);

    game.n_moves = args[3];
    if (args[7] == -1) {	/* loading a game from the alpha version */
	fseek(fp, 32, SEEK_SET);
	game.stored_moves = args[3];
	game.bookmark = game.n_moves;
	game.macroStart = -1;
    } else {
	game.stored_moves = args[7];
	game.macroStart = args[8];
	game.macroEnd = args[9];
	game.macro_x = args[10];
	game.macro_y = args[11];
	game.bookmark = args[12];
    }
    /* skip game type and level */
    fseek(fp, 8L, SEEK_CUR);

    /* skip user name */
    i = getc(fp);
    fseek(fp, (long)i, SEEK_CUR);

 readmoves:
    if (game.stored_moves > numalloc) {
	numalloc = 256 + (game.stored_moves & ~255);
	movetab = realloc_(movetab, numalloc);
    }
    if (fread(movetab, 1, game.stored_moves, fp) != game.stored_moves)
	read_err(TXT_LOAD_ERR_MOVES);
    fclose(fp);

    {   int rem;
	rem = game.n_moves;
	game.n_moves = 0;
	jumpto_movenr(rem);
    }

    if (remgraphic)
	graphics_control(EnableAndRedraw);
    cmd_ShowScore();
}


void save_game(const char *ext) {
    FILE *fp;
    char filename[MAXSAVEFILELEN];
    long args[NARGS];
    int i;
    unsigned char p[4 * NARGS];

    compute_score();
    sprintf(filename, "%s/%s.%02d.%s", savedir, game.type, game.level, ext);
    remove(filename);	/* kill any old one first! */
    if (!(fp = fopen(filename, "wb"))) {
	show_message("%s %s", TXT_SAVE_ERR_BASIC, TXT_SAVE_ERR_OPEN);
	goto werr2;
    }
    args[0] = MAGIC1;
    args[1] = game.score;
    args[2] = game.n_pushes;
    args[3] = game.n_moves;
    args[4] = time(NULL);
    args[5] = game.finished;
    args[6] = game.level;
    args[7] = game.stored_moves;
    args[8] = game.macroStart;
    args[9] = game.macroEnd;
    args[10] = game.macro_x;
    args[11] = game.macro_y;
    args[12] = game.bookmark;
    args[13] = args[14] = args[15] = -1;

    internal_to_portable(p, args, NARGS);
    if (fwrite(p, 4, NARGS, fp) != NARGS) {
    werr3:
	show_message("%s %s", TXT_SAVE_ERR_BASIC, TXT_SAVE_ERR_HEADER);
	goto werr;
    }
    strncpy(filename, game.type, 8);
    if (fwrite(filename, 1, 8, fp) != 8)
	goto werr3;

    i = strlen(username);
    putc(i, fp);
    if (fwrite(username, 1, i, fp) != i)
	goto werr3;
    if (fwrite(movetab, 1, game.stored_moves, fp) != game.stored_moves)
	goto werr3;

    fclose(fp);
    show_message(TXT_SAVE_OK);
    play_sound("ok");	/* found no sound file for this. maybe later */
    return;

werr:
    fclose(fp);
werr2:
    play_sound("cannotsave");
}

void link_game(const char *old, const char *ext) {
    char file1[MAXSAVEFILELEN], file2[MAXSAVEFILELEN];

    sprintf(file1, "%s/%s.%02d.%s", savedir, game.type, game.level, old);
    sprintf(file2, "%s/%s.%02d.%s", savedir, game.type, game.level, ext);
    remove(file2);	/* kill any old one first! */
    if (link(file1, file2))
	show_message(TXT_SAVE_ERR_LINK);
}
xsok-1.02/src/username.c100644    144     62        4207  6037671344  13644 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.01 -- module username.c				     */
/*									     */
/*	Tries to compute a nice user- and hostname (e-mail address).	     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	changed October 1995						     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include <unistd.h>
#include <pwd.h>
#include <sys/types.h>
#include <sys/utsname.h>
#include "xsok.h"

#ifdef BSD_NETKIT
#include <netdb.h>
#endif

char username[256];

void buildusername(const char *name) {
    if (name) {
	if (strlen(name) > 255) {
	    strncpy(username, name, 255);
	    username[256] = '\0';
	} else
	    strcpy(username, name);
    } else {
	struct passwd *pp;
	const char *realname, *loginname;
	char fqdn[256];
	struct utsname buf;
#ifdef BSD_NETKIT
	struct hostent *hp;
#endif
	/* getlogin() fails when xsok is called from the fvwm window
	   manager menu (why?) and cuserid() has disappeared in POSIX
	   1990. We use getuid() now. */
	if ((pp = getpwuid(getuid()))) {
	    if (pp->pw_gecos && strchr(pp->pw_gecos, ','))
		*strchr(pp->pw_gecos, ',') = '\0';
	    realname = pp->pw_gecos;
	    loginname = pp->pw_name;
	} else {
	    /* unable to obtain passwd entry */
	    realname = NULL;
	    loginname = "unknown";
	}
	if (uname(&buf))
	    strcpy(buf.nodename, "unknown");
#ifdef BSD_NETKIT
	if ((hp = gethostbyname(buf.nodename)))
	    strcpy(fqdn, hp->h_name);
	else
#endif
	    sprintf(fqdn, "%s.(unknown)", buf.nodename);

	if (realname)
	    sprintf(username, "%s (%s@%s)", realname, loginname, fqdn);
	else
	    sprintf(username, "%s@%s", loginname, fqdn);
    }
}

#ifdef TESTING
int main(int argc, char *argv[]) {
    if (argc == 3 && !strcmp(argv[1], "-u"))
	buildusername(argv[2]);
    else
	buildusername(NULL);
    printf( /* "Automatically generated username is\n" */
	   "\"%s\"\n", username);
    return 0;
}
#endif
xsok-1.02/src/Xaw-help.c100644    144     62        6055  5665071060  13510 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module Xaw-help.c				     */
/*									     */
/*	Online help functions for the Athena Widget interface.		     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifdef ONLINE_HELP
#include "X-sok.h"
#include "Tableau.h"

#include <X11/Shell.h>
#include <X11/Xaw/MenuButton.h>
#include <X11/Xaw/SimpleMenu.h>
#include <X11/Xaw/Command.h>
#include <X11/Xaw/AsciiText.h>
#include <X11/Xaw/Form.h>
#include <X11/Xaw/Sme.h>
#include <X11/Xaw/SmeBSB.h>

static int help_active = 0;
static Widget help, helppaned, helppanel, helptext, helpclose;
extern const char *keyfilename;	/* from X-widget.c */

static void selecttopic(Widget w, XtPointer number, XtPointer garbage) {
    char filename[200];
    const char *s = XtName(w);
    Arg Args[2];
    int i = atoi(s+4);

    sprintf(filename, "%s/%s/%s.help", xsokdir, langdir,
	    i ? rulepool[i-1] : keyfilename);
    XtSetArg(Args[0], XtNstring, filename);
    XtSetArg(Args[1], XtNtype, XawAsciiFile);
    XtSetValues(helptext, Args, 2);
}

void create_help(void) {
    Widget topicsmenu, topicsbutton, w;
    Arg Args[1];
    help         = XtCreatePopupShell("help", transientShellWidgetClass, toplevel, NULL, 0);
    helppaned    = XtCreateManagedWidget("helppaned",	panedWidgetClass,      help,	     NULL, ZERO);
    helppanel 	 = XtCreateManagedWidget("helppanel",	boxWidgetClass,        helppaned,    NULL, ZERO);
    helptext	 = XtCreateManagedWidget("helptext",	asciiTextWidgetClass,  helppaned,    NULL, ZERO);
    XtSetArg(Args[0], XtNmenuName, "topicsmenu");
    topicsbutton = XtCreateManagedWidget("Topic",       menuButtonWidgetClass, helppanel,    Args, 1);
    topicsmenu   = XtCreatePopupShell("topicsmenu",     simpleMenuWidgetClass, topicsbutton, NULL, ZERO);
    helpclose	 = XtCreateManagedWidget("Close Help",	commandWidgetClass,    helppanel,    NULL, ZERO);
    XtAddCallback(helpclose, XtNcallback, popdown_help, NULL);

    XtSetArg(Args[0], XtNlabel, TXT_HELP_KEYS);
    w = XtCreateManagedWidget("Help0", smeBSBObjectClass, topicsmenu, Args, 1);
    XtAddCallback(w, XtNcallback, selecttopic, NULL);
    {   const char **rp;
	for (rp = rulepool; *rp; ++rp) {
	    char n[8], s[40];
	    sprintf(n, "Help%d", rp-rulepool+1);
	    XtSetArg(Args[0], XtNlabel, s);
	    sprintf(s, TXT_HELP_RULES, *rp);
	    w = XtCreateManagedWidget(n, smeBSBObjectClass, topicsmenu, Args, 1);
	    XtAddCallback(w, XtNcallback, selecttopic, NULL);
	}
    }

}

void popup_help(void) {
    if (help_active)
	return;		/* request pending => deny another one */
    help_active = 1;
    XtPopup(help, XtGrabNone);
}

void popdown_help(Widget w, XtPointer a, XtPointer b) {
    if (!help_active)
	return;		/* request pending => deny another one */
    help_active = 0;
    XtPopdown(help);
}

#endif
xsok-1.02/src/mousemove.c100644    144     62       22442  6123001237  14045 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.02 -- module mousemove.c				     */
/*									     */
/*	Computes paths to squares in the distance.			     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November 1994 ... March 1996					     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifndef _POSIX_SOURCE
#define _POSIX_SOURCE
#endif
#include "xsok.h"
#include <assert.h>

static int before_move;

void cmd_MouseUndo(void) {
    if (lastcmd != cmd_MouseMove &&
	lastcmd != cmd_MousePush &&
	lastcmd != cmd_MouseDrag &&
	lastcmd != cmd_PlayMacro) {
	cmd_UndoMove();	/* normal undo */
	return;
    }
    jumpto_movenr(before_move);
    cmd_ShowScore();
}
    
#define RBSIZE	  1024	/* only powers of 2 will work */
#ifndef sgn
#define sgn(x)		((x) < 0 ? -1 : 1)
#endif

static int noeffect(int eff) {
    switch(eff) {
    case E_NOTHING:
    case E_EXIT:
    case E_DEST:
	return 1;
    default:
	return 0;
    }
}

#define STEP(dx,dy,dir) if ( \
  (map[y+(dy)][x+(dx)]->mask & 1) && \
   noeffect(map[y+(dy)][x+(dx)]->effect) && \
   (map[y+(dy)][x+(dx)]->enter & (1 << dir)) && \
   (map[y+(dy)][x+(dx)]->leave & (1 << dir)) && \
   !obj[y+(dy)][x+(dx)] && \
   dist[y+(dy)][x+(dx)] > d) { \
    dist[remy[wr] = y+(dy)][remx[wr]= x+(dx)] = d; \
    if ((wr = (wr + 1) & (RBSIZE-1)) == rd) break; }

/* search from destination to source */
static int backsteps(unsigned dist[MAXROW][MAXCOL],
		 int x1, int y1, int x2, int y2) {
    int rd = 0, wr = 1, remx[RBSIZE], remy[RBSIZE];
    memset(dist, 0xff, sizeof(unsigned)*MAXROW*MAXCOL);
    if (!(map[y1][x1]->mask & 1))
	return -1;
    remx[0] = x1;
    remy[0] = y1;
    dist[y1][x1] = 0;
    while (rd != wr) {
	int x, y, d;
	if (dist[y2][x2] < 30000)
	    return dist[y2][x2];
	x = remx[rd];
	y = remy[rd];
	rd = (rd+1) & (RBSIZE-1);
	d = 1 + dist[y][x];
	STEP(1,0,1);	/* dir is reverse since we do backward search */
	STEP(0,1,0);
	STEP(-1,0,3);
	STEP(0,-1,2);
    }
    /* no path is found */
    return -1;
}

static void subcmd_pushto(int dx, int dy) {
    int i, dir;

    if (dx) {
	i = abs(dx);
	dir = 2 + sgn(dx);
    } else {
	i = abs(dy);
	dir = 1 + sgn(dy);
    }
    while (i--)
	playermove(dir);
}

void cmd_MousePush(void) {
    int dx, dy;

    before_move = game.n_moves;
    dx = mouse_x - game.x;
    dy = mouse_y - game.y;
    if (dx && dy)
	cmd_MouseMove();
    else
	subcmd_pushto(dx, dy);
}

static void subcmd_moveto(int xx, int yy) {
    unsigned dist[MAXROW][MAXCOL];
    struct objects *ip = obj[game.y][game.x];

    /* case 1: a distance 1 click will move or push */
    if (xx == game.x && yy == game.y)
	return;	/* shortcut! */

    if (abs(xx - game.x) + abs(yy - game.y) == 1) {
	if (xx - game.x)
	    if (xx > game.x)
		playermove(3);
	    else
		playermove(1);
	else
	    if (yy > game.y)
		playermove(2);
	    else
		playermove(0);
	return;
    }
    /* for greater distance, only use free space. */
    
    obj[game.y][game.x] = NULL;
    if (backsteps(dist, xx, yy, game.x, game.y) < 0) {
	obj[game.y][game.x] = ip;
	show_message(TXT_MOVENOTPOSSIBLE);
	return;
    }
    obj[game.y][game.x] = ip;
    while (game.y != yy || game.x != xx) {
	unsigned length;
	int omove;
	length = dist[game.y][game.x] - 1;
	omove = game.n_moves;
	     if (dist[game.y-1][game.x] == length) playermove(0);
	else if (dist[game.y][game.x-1] == length) playermove(1);
	else if (dist[game.y+1][game.x] == length) playermove(2);
	else if (dist[game.y][game.x+1] == length) playermove(3);
	if (dist[game.y][game.x] > length)
	    break;	/* else may cause cycling (with teleporters) */
	if (game.n_moves != omove + 1)
	    break;	/* precomputed move not possible any more */
    }
}

void cmd_MouseMove(void) {
    before_move = game.n_moves;
    subcmd_moveto(mouse_x, mouse_y);
}

static int dxtab[4] = { 0, -1, 0, 1 };
static int dytab[4] = { -1, 0, 1, 0 };

void cmd_MouseDrag(void) {
    struct objects *ip = obj[game.y][game.x], *box;
    unsigned dist[MAXROW][MAXCOL];
    int xx, yy, number[MAXROW][MAXCOL], num = 0;

    before_move = game.n_moves;
    if (mouse_x == mouse_x0 && mouse_y == mouse_y0)
	return;	/* this is a no-op */
    if (!(box = obj[mouse_y0][mouse_x0])) {
	show_message(TXT_NOBOX);
	return;
    }
    obj[game.y][game.x] = NULL;	/* remove player */
    if (obj[mouse_y][mouse_x]) {
	show_message(TXT_ALREADYBOX);
	obj[game.y][game.x] = ip;	/* restore player */
	return;
    }
    if (backsteps(dist, mouse_x0, mouse_y0, game.x, game.y) < 0) {
    notposs:
	obj[game.y][game.x] = ip;
	show_message(TXT_MOVENOTPOSSIBLE);
	return;
    }

    /* number the possibilities for the box */
    num = 1;
    for (xx = 0; xx < game.numcols; ++xx)
	for (yy = 0; yy < game.numrows; ++yy)
	    if ((map[yy][xx]->mask & obj[mouse_y0][mouse_x0]->mask)
		&& !obj[yy][xx])
		number[yy][xx] = num++;
	    else
		number[yy][xx] = -1;
    number[mouse_y0][mouse_x0] = 0;
    if (number[mouse_y][mouse_x] < 0)
	goto notposs;

    {	/* allocate array for the possible box states */
	int d;
	struct boxdist {
	    int pushes;
	    int moves;
	    int x, y;	/* box position */
	    int inqueue;
	    int predecessor;
	} *boxdist;
	int *states, rd = 0, wr = 0;
	boxdist = malloc(4 * num * sizeof(struct boxdist));
	states = malloc(4 * num * sizeof(int));
	for (xx = 0; xx < 4 * num; ++xx) {
	    boxdist[xx].pushes = boxdist[xx].moves = 30000;
	    boxdist[xx].inqueue = 0;
	}
	/* initial positions */
	for (xx = 0; xx < 4; ++xx) {
	    d = backsteps(dist,
			  mouse_x0+dxtab[xx], mouse_y0+dytab[xx],
			  game.x, game.y);
	    if (d >= 0) {
		states[wr++] = xx;
		boxdist[xx].moves = d;
		boxdist[xx].pushes = 0;
		boxdist[xx].x = mouse_x0;
		boxdist[xx].y = mouse_y0;
		boxdist[xx].inqueue = 1;
		boxdist[xx].predecessor = -1;
	    }
	}
	/* loop */
	obj[mouse_y0][mouse_x0] = NULL;	/* remove box */
	while (rd < wr) {
	    /* get position */
	    struct boxdist *now;
	    now = boxdist + (yy = states[rd++]);
	    now->inqueue = 2;
#ifdef TESTING
	    printf("Scanning square %d: %d,%d, pushes=%d, moves=%d\n",
		   yy, now->x, now->y, now->pushes, now->moves);
#endif
	    obj[now->y][now->x] = box;
	    /* player is at x+dxtab[yy & 3], y+dytab[yy & 3] */
	    for (xx = 0; xx < 4; ++xx) {
		int newx, newy, newpos;
		newy = now->y-dytab[xx];
		newx = now->x-dxtab[xx];
		newpos = number[newy][newx];
		if (newpos < 0)
		    continue;
		newpos = 4 * newpos + xx;	/* is index */
		if (boxdist[newpos].pushes <= now->pushes)
		    continue;	/* fewer pushes with the old path */
		/* shift into dir 2^xx */
		if (!(map[newy][newx]->mask & box->mask) ||
		    !(map[now->y][now->x]->mask & 1) ||
		    obj[newy][newx] || obj[now->y+dytab[xx]][now->x+dxtab[xx]])
		    continue;
		d = backsteps(dist,
			      now->x+dxtab[xx], now->y+dytab[xx],
			      now->x+dxtab[yy&3], now->y+dytab[yy&3]);
		if (d < 0)
		    continue;
		d += now->moves;
                if (boxdist[newpos].pushes > now->pushes+1 ||
		    (boxdist[newpos].pushes == now->pushes+1 &&
		    boxdist[newpos].moves > d)) {
		    boxdist[newpos].pushes = now->pushes+1;
		    boxdist[newpos].moves = d;
		    boxdist[newpos].x = newx;
		    boxdist[newpos].y = newy;
		    boxdist[newpos].predecessor = yy;
		    if (!boxdist[newpos].inqueue) {
			boxdist[newpos].inqueue = 1;
			states[wr++] = newpos;
			/* printf("  adding state %d\n", newpos);
		    } else {
			printf("  improving state %d\n", newpos); */
		    }
		    assert(boxdist[newpos].inqueue != 2);
		}
	    }
	    obj[now->y][now->x] = NULL;
	}
	obj[mouse_y0][mouse_x0] = box;	/* restore box */
	free(states);

#ifdef TESTING
	printf("box move from %d,%d to %d,%d requested, %d reachable\n",
	       mouse_x0, mouse_y0, mouse_x, mouse_y, num);
	for (xx = 0; xx < 4; ++xx)
	    printf("xx = %d: pushes = %5d, moves = %5d\n",
		   xx,
		   boxdist[4*number[mouse_y][mouse_x]+xx].pushes,
		   boxdist[4*number[mouse_y][mouse_x]+xx].moves);
#endif
	/* find best end place */
	d = yy = 4*number[mouse_y][mouse_x];
	for (xx = 1; xx < 4; ++xx) {
	    if (boxdist[yy+xx].pushes < boxdist[d].pushes ||
		(boxdist[yy+xx].pushes == boxdist[d].pushes &&
		 boxdist[yy+xx].moves < boxdist[d].moves)) {
		d = yy+xx;
	    }
	}
	if (boxdist[d].pushes == 30000) {
	    free(boxdist);
	    goto notposs;	/* not possible */
	}
	obj[game.y][game.x] = ip;	/* restore player */

	/* no the move definitely is possible */
	/* compute path by predecessor entries */
	xx = -1;	/* last */
	yy = d;		/* current */
	do {
	    boxdist[yy].inqueue = xx;	/* next */
	    xx = yy;
	    yy = boxdist[yy].predecessor;
	} while (yy != -1);
	/* have path. xx is first position to achieve */
	/* first move is different (no push, just setup) */
	xx = boxdist[xx].inqueue;
	while (xx != -1) {
#ifdef TESTING
	    mouse_x = boxdist[xx].x + 2*dxtab[xx&3];
	    mouse_y = boxdist[xx].y + 2*dytab[xx&3];
	    printf("at %d,%d, xx=%d, require moveto %d,%d, pushto %d,%d\n",
		   game.x, game.y, xx, mouse_x, mouse_y,
		   boxdist[xx].x, boxdist[xx].y);
#endif
	    subcmd_moveto(boxdist[xx].x + 2*dxtab[xx&3],
			  boxdist[xx].y + 2*dytab[xx&3]);
#if 0
	    mouse_x = boxdist[xx].x + dxtab[xx&3];
	    mouse_y = boxdist[xx].y + dytab[xx&3];
	    cmd_MousePush();
#else
	    subcmd_pushto(-dxtab[xx&3],-dytab[xx&3]);
#endif
	    xx = boxdist[xx].inqueue;	/* next move */
	}
	free(boxdist);
    }
}
xsok-1.02/src/X-sound_SUN.c100644    144     62        2164  5665071060  14102 0ustar  mbimathopt/*****************************************************************************/
/*									     */
/*									     */
/*	Xsok version 1.00 -- module X-sound_SUN.c			     */
/*									     */
/*	SUN audio functions play_sound().				     */
/*	Written by Michael Bischoff (mbi@mo.math.nat.tu-bs.de)		     */
/*	November-1994							     */
/*	see COPYRIGHT.xsok for Copyright details			     */
/*									     */
/*									     */
/*****************************************************************************/
#ifdef SOUND
#include "X-sok.h"

#ifndef AUDIO_DEVICE
#define AUDIO_DEVICE "/dev/audio"
#endif

void play_sound(const char *filename) {
    static int audio = 1;
    if (audio && checksound()) {
	char fullname[200];
	FILE *fp, *fsnd;
	int c;
	if (!(fsnd = fopen(AUDIO_DEVICE, "wb"))) {
	    audio = 0;
	    return;		/* cannot open /dev/audio */
	}
	XSync(dpy, 0);	/* text first! */
	sprintf(fullname, "%s/audio/%s.au", xsokdir, filename);
	if (!(fp = fopen(fullname, "rb"))) {
	    fclose(fsnd);
	    return;
	}
	/* yeah, copy data */
	while ((c = getc(fp)) != EOF)
	    fputc(c, fsnd);
	fclose(fsnd);
	fclose(fp);
    }
}
#endif
xsok-1.02/src/showscore.c100644    144     62        4764  6055646517  14055 0ustar  mbimathopt#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>
#include <time.h>

#define MAGICH	0x741d	/* magic of xsok version 1 highscore file */

static void portable_to_internal(long *args, unsigned char *p, int num) {
    do {
	int j;
	*args = 0;
	for (j = 0; j < 4; ++j)
	    *args += (long)p[3-j] << (j << 3);
	++args;
	p += 4;
    } while (--num);
}
int highscore[300];
static void ReadHighscores(const char *levelfile) {
    FILE *fp;
    char filename[256], base_name[32], *s;
    int i;

    memset(highscore, 0, sizeof(highscore));
    for (i = 100; i < 300; ++i)
	    highscore[i] = 0x7fffffff;

    strcpy(base_name, levelfile);
    if (!(s = strchr(base_name, '.')))
	return;
    strcpy(s+1, "score");
    sprintf(filename, "%s/%s", XSOKSAVE, base_name);
    if ((fp = fopen(filename, "rb"))) {
	long p[300];
	unsigned char ss[1200];
	fread(ss, 4, 300, fp);
	portable_to_internal(p, ss, 300);	
	for (i = 0; i < 300; ++i)
	    highscore[i] = p[i];
	fclose(fp);
    }
    highscore[0] = MAGICH;
}


static int brief = 1;
#define NARGS 16

static void checkfile(const char *filename) {
    FILE *fp;
    long p[NARGS];
    unsigned char s[256];
    char type[10], *z;
    int namelen, level;

    if (!(fp = fopen(filename, "rb")))
	return;
    fread(s, 4, NARGS, fp);
    portable_to_internal(p, s, NARGS);
    if (p[0] != 0x741b)
	return;
    fread(type, 1, 8, fp);
    level = p[6];
    type[8] = '\0';
    namelen = getc(fp);
    fread(s, 1, namelen, fp);
    s[namelen] = '\0';

    if (strrchr(filename, '/'))
	filename = strrchr(filename, '/') + 1;
    ReadHighscores(filename);

    z = ctime(&p[4]);
    if (strchr(z, '\n'))
	*strchr(z, '\n') = '\0';

    if (!brief) {
	printf("%-14s %-7s Level %2d:  Score: %5ld, Pushes: %4ld, Moves: %4ld\n",
	       filename, type, level, p[1], p[2], p[3]);
#if 0
	if (!p[5])	/* unsolved */
	    printf("\n");
	else
#endif
	    printf("saved %s by %s\n", z, s);
    } else {
	int c1, c2, c3;
	c1 = p[5] && highscore[level]     == p[1] ? '*' : ' ';
	c2 = p[5] && highscore[level+200] == p[2] ? '*' : ' ';
	c3 = p[5] && highscore[level+100] == p[3] ? '*' : ' ';
	printf("%2d %5ld%c %4ld%c %4ld%c  %s\n", level, p[1], c1, p[2], c2, p[3], c3, s);
    }
}

int main(int argc, char *argv[]) {
    int i;
    if (argc == 1) {
	fprintf(stderr, "usage: showscore [-b] (savefiles)\n");
	exit(1);
    }
    i = 1;
    if (!strcmp(argv[i], "-b")) {
	brief = 0;
	++i;
    } else
	printf("Lv Score Pushes Moves  Player\n");
    for (; i < argc; ++i)
	checkfile(argv[i]);
    return 0;
}
xsok-1.02/src/combine.c100644    144     62        2026  5665071060  13431 0ustar  mbimathopt#define _POSIX_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

static int stripcomments = 0;

static int copy(FILE *fout, char *s, int i) {
    FILE *fp;
    if (!(fp = fopen(s, "r")))
	return 0;
    if (i)
	fprintf(fout, ";LEVEL %d\n", i);
    while (fgets(s, 100, fp)) {
	if (stripcomments) {
	    if (!strncmp(s, "; ", 2))
		continue;
	    if (!strcmp(s, ";\n"))
		continue;
	}
	fprintf(fout, "%s", s);
    }
    fclose(fp);
    return 1;
}

int main(int argc, char *argv[]) {
    int c, i;
    for (c = 1; c < argc; ++c) {
	FILE *fout;
	char s[100];
	if (!strcmp(argv[c], "-s")) {
	    stripcomments = 1;
	    continue;
	}
	sprintf(s, "%s.def", argv[c]);
	if (!(fout = fopen(s, "w"))) {
	    fprintf(stderr, "Cannot open output file %s\n", s);
	    exit(1);
	}
	sprintf(s, "%s/definitions", argv[c]);
	if (!copy(fout, s, 0)) {
	    fprintf(stderr, "No file %s\n", s);
	    exit(1);
	}
	for (i = 1; i < 100; ++i) {
	    sprintf(s, "%s/screen.%02d", argv[c], i);
	    if (!copy(fout, s, i))
		break;
	}
    }
    return 0;
}
xsok-1.02/src/version.h100644    144     62          30  6122776727  13453 0ustar  mbimathopt#define VERSION  "1.02"
xsok-1.02/src/mergescores.c100644    144     62        4030  6055646577  14347 0ustar  mbimathopt#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdarg.h>

int highscore[300];
int newscore[300];

#define MAGICH	0x741d	/* magic of xsok version 1 highscore file */

static void portable_to_internal(long *args, unsigned char *p, int num) {
    do {
	int j;
	*args = 0;
	for (j = 0; j < 4; ++j)
	    *args += (long)p[3-j] << (j << 3);
	++args;
	p += 4;
    } while (--num);
}
static void internal_to_portable(unsigned char *p, long *args, int num) {
    do {
	int j;
	memset(p, (*args < 0 ? -1 : 0), 4);
	for (j = 0; j < 4; ++j)
	    p[3-j] = (unsigned char)(*args >> (j << 3));
	++args;
	p += 4;
    } while (--num);
}
static void ReadHighscores(const char *filename) {
    FILE *fp;
    int i;
    memset(highscore, 0, sizeof(highscore));
    for (i = 100; i < 300; ++i)
	    highscore[i] = 0x7fffffff;
    if ((fp = fopen(filename, "rb"))) {
	long p[300];
	int num;
	unsigned char s[1200];
	num = fread(s, 4, 300, fp);
	portable_to_internal(p, s, num);	
	for (i = 0; i < num; ++i)
	    highscore[i] = p[i];
	fclose(fp);
    }
    highscore[0] = MAGICH;
}
static void WriteHighscores(const char *filename) {
    FILE *fp;
    if ((fp = fopen(filename, "wb"))) {
	int i;
	long p[300];
	unsigned char s[1200];
	for (i = 0; i < 300; ++i)
	    p[i] = highscore[i];
	internal_to_portable(s, p, 300);
	fwrite(s, 1, 1200, fp);
	fclose(fp);
    }
}

static void mergescores(const char *filename) {
    const char *base_name;
    int i;
    base_name = strrchr(filename, '/');
    if (!base_name) {
	fprintf(stderr, "need directory components for %s\n", filename);
	exit(1);
    }
    ++base_name;
    ReadHighscores(filename);
    memcpy(newscore, highscore, sizeof(highscore));
    ReadHighscores(base_name);
    for (i = 1; i < 100; ++i)
	if (newscore[i] > highscore[i])
	     highscore[i] = newscore[i];
    for (i = 100; i < 300; ++i)
	if (newscore[i] < highscore[i])
	     highscore[i] = newscore[i];
    WriteHighscores(filename);
}


int main(int argc, char *argv[]) {
    int i;
    for (i = 1; i < argc; ++i)
	mergescores(argv[i]);
    return 0;
}
xsok-1.02/src/XSok.ad100644    144     62        2521  5665071060  13043 0ustar  mbimathoptXSok*beNiceToColormap:		false
XSok*shapeStyle:		Rectangle
XSok*topShadowContrast:		20
XSok*bottomShadowContrast:	40
XSok*Scrollbar*background:	Gray70
XSok*Background:		grey85
XSok*Foreground:		black
XSok*resizeToPreferred:		True
XSok*input:			True
XSok*showGrip:			off
XSok*shadowWidth:               2
XSok*messages.justify:		Left
XSok*upperbox.orientation:	XtorientHorizontal
XSok*lowerbox.orientation:	XtorientHorizontal
XSok*Tableau.keyboardFile:	keys
XSok*Tableau.messageFile:	messages
XSok*Tableau.background:	black
XSok*Tableau.rules:		Sokoban
XSok*Viewport.allowHoriz:	False
XSok*Viewport.allowVert:	False
XSok*Viewport.useBottom:	True
XSok*Viewport.useRight:		True
XSok*Label.shadowWidth:		0
XSok*Label.BorderWidth:		2
XSok*Dialog*Translations: #override \n\
<Key>y: Ok()\n\
<Key>n: Cancel()\n

XSok*title:			XSok
XSok.prompt.allowShellResize:	True
XSok.prompt.saveUnder:		True
XSok*Dialog*resizable:		True
XSok*Hint.Translations: #override\n\
<BtnDown>:set()\n\
<BtnUp>:HintNotify()unset()\n

XSok*Sound.state:		True
XSok.help.width:		403
XSok.help.height:		200
XSok.help.title:		XSok Help Window
XSok.help.saveUnder:		True
XSok*Close Help.fromHoriz:	Topic
XSok*helptext*string:		Please choose a topic.
XSok*helptext*displayCaret:	False
XSok*helptext*scrollHorizontal:	whenNeeded
XSok*helptext*scrollVertical:	whenNeeded
XSok*helptext*editType:		read
xsok-1.02/src/convertscore.c100644    144     62        1171  5665071060  14531 0ustar  mbimathopt#include <stdio.h>
#include <stdlib.h>

/* convert a savegame file from the alpha version to the beta version */

int main(void) {
    long len;
    unsigned char p[64];
    unsigned char s[10000];
    memset(p, 0xff, sizeof(p));
    fread(p, 32, 1, stdin);
    
    len = fread(s, 1, 10000, stdin);

    memcpy(p+28, p+12, 4);	/* stored move */
    memset(p+20, 0, 8);
    p[23] = 1;		/* assume it's finished */
    p[27] = s[7];	/* level */
    memcpy(p+48, p+12, 4);	/* bookmark where started */
    if (s[0] == 'C')
	s[7] = 'x';
    else
	s[7] = '\0';
    fwrite(p, 1, 64, stdout);
    fwrite(s, 1, len, stdout);
    return 0;
}
xsok-1.02/README100644    144     62        3372  5665071060  11747 0ustar  mbimathoptHi,
Here is a short checklist of what you need to compile and run xsok-1.00.

- an ANSI C compiler
- a POSIX.1 conforming system (OK, with some patches, you may do without)
- GNU gzip / gunzip binaries somewhere in your PATH (same comment)
- X11 R5 or R6 (older ones possibly work, but are untested)
- the XPM library (libXpm.*), preferably version 3.2g or newer. I used the
  dll version of Mitch DSouza (mitchum.dsouza@mrc-apu.cam.ac.uk) found in
  sunsite.unc.edu:/pub/Linux/libs/X/libXpm-3.4c.tar.gz (28-aug-1994)
- LaTeX if you want to print the manual.

For a standard installation, type 'make', optionally 'make manual', then
(as root) 'make install'. Type 'install.fsstnd' if you want to install the
binary in /usr/games/bin instead of X11's bin directory (I prefer this).
If you want to install xsok locally, i.e. in your home directory, change
XSOKDIR and XSOKSAVE to $(HOME)/xsok in src/Imakefile, then type 'make'
and 'make install.local'. There is a patch for this in the diffs subdirectory.

Apart from Linux, this software has been tested on a HP 9000/720 (HP-UX 9.01),
which required commenting out the HAVE_USLEEP and BSD_NETKIT options in
src/Imakefile. Diffs for this can be found in the diffs subdirectory.

Compiling on a SUN (SUNOS 4.1.3) produced LOTS of warnings due to missing
prototypes in the non-ANSI include files, but the binary worked nevertheless.

If the installation succeeds, but you get the error message
'Cannot read floor.xpm', you perhaps have an older version of libXpm.
Simply gunzip $(XSOKDIR)/*.xpm.gz and be happy again.
(This was the case with both the SUN and the HP machine.)

Please report bugs to mbi@mo.math.nat.tu-bs.de.

Should you create new levels, I would be glad if you could send them to me.

        Have fun
           Michael
xsok-1.02/diffs/ 40755    144     62           0  5665071060  12060 5ustar  mbimathoptxsok-1.02/diffs/diff.local100644    144     62        2256  5665071060  14106 0ustar  mbimathopt*** src/Imakefile	Thu Nov 24 15:19:07 1994
--- src/Imakefile.local	Thu Nov 24 15:50:41 1994
***************
*** 46,52 ****
  # BINDIR and LIBDIR should be predefined by the templates
  # BINDIR = /usr/bin/X11
  # LIBDIR = /usr/lib/X11
! XSOKLIBDIR = /usr/games/lib/xsok
  APPDEFSDIR = $(LIBDIR)
  XSOKMANDIR = /usr/man/man6
  XSOKDOCDIR = /usr/doc
--- 46,52 ----
  # BINDIR and LIBDIR should be predefined by the templates
  # BINDIR = /usr/bin/X11
  # LIBDIR = /usr/lib/X11
! XSOKLIBDIR = $(HOME)/xsok
  APPDEFSDIR = $(LIBDIR)
  XSOKMANDIR = /usr/man/man6
  XSOKDOCDIR = /usr/doc
***************
*** 56,62 ****
  # The directory XSOKSAVEDIR must have permissions rwx for world, else
  # xsok must be installed suid, and XSOKDIR must have write permissions for
  # the owner of xsok
! XSOKSAVEDIR = /var/games/xsok
  
  # paths for installation in user's home-directory.
  LXSOKBINDIR = $(HOME)/bin
--- 56,62 ----
  # The directory XSOKSAVEDIR must have permissions rwx for world, else
  # xsok must be installed suid, and XSOKDIR must have write permissions for
  # the owner of xsok
! XSOKSAVEDIR = $(HOME)/xsok
  
  # paths for installation in user's home-directory.
  LXSOKBINDIR = $(HOME)/bin
xsok-1.02/diffs/diff.hpux100644    144     62        2157  5665071060  14000 0ustar  mbimathopt*** src/Imakefile	Thu Nov 24 15:19:07 1994
--- src/Imakefile.hpux	Thu Nov 24 15:50:51 1994
***************
*** 35,47 ****
  # part of the POSIX standard.)
  # Remove this define, if you do not have this function.
  # affected file(s): username.c
! NET_DEFINE = -DBSD_NETKIT
  
  # 5.) For the replay option, we need the possibility to sleep for a short
  # period of time. This can be done by the usleep() function.
  # Remove this, if you need usleep() emulation code.
  # affected file(s): X-gfx.c
! SLEEP_DEFINE = -DHAVE_USLEEP
  
  # BINDIR and LIBDIR should be predefined by the templates
  # BINDIR = /usr/bin/X11
--- 35,47 ----
  # part of the POSIX standard.)
  # Remove this define, if you do not have this function.
  # affected file(s): username.c
! NET_DEFINE = #-DBSD_NETKIT
  
  # 5.) For the replay option, we need the possibility to sleep for a short
  # period of time. This can be done by the usleep() function.
  # Remove this, if you need usleep() emulation code.
  # affected file(s): X-gfx.c
! SLEEP_DEFINE = #-DHAVE_USLEEP
  
  # BINDIR and LIBDIR should be predefined by the templates
  # BINDIR = /usr/bin/X11
xsok-1.02/etc/ 40755    144     62           0  6151124576  11542 5ustar  mbimathoptxsok-1.02/etc/magic100644    144     62        1057  5665071060  12643 0ustar  mbimathopt# /etc/magic values for xpat and xsok as of 13-nov-1994
# 1) for low-endian machines (i386)
0	long	0x19740000	xpat save game file
0	long	0x1a740000	xpat2 save game file
0	long	0x1b740000	xsok save game file
0	long	0x1c740000	xsok simple save game file (autosolver)
0	long	0x1d740000	xsok highscore file
# 2) for high-endian machines (SUN, HP-RISC)
0	long	0x00007419	xpat save game file
0	long	0x0000741a	xpat2 save game file
0	long	0x0000741b	xsok save game file
0	long	0x0000741c	xsok simple save game file (autosolver)
0	long	0x0000741d	xsok highscore file
xsok-1.02/etc/COPYRIGHT.GNU100644    144     62       35433  5665071060  13610 0ustar  mbimathopt		    GNU GENERAL PUBLIC LICENSE
		       Version 2, June 1991

 Copyright (C) 1989, 1991 Free Software Foundation, Inc.
                          675 Mass Ave, Cambridge, MA 02139, USA
 Everyone is permitted to copy and distribute verbatim copies
 of this license document, but changing it is not allowed.

			    Preamble

  The licenses for most software are designed to take away your
freedom to share and change it.  By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users.  This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it.  (Some other Free Software Foundation software is covered by
the GNU Library General Public License instead.)  You can apply it to
your programs, too.

  When we speak of free software, we are referring to freedom, not
price.  Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.

  To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.

  For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have.  You must make sure that they, too, receive or can get the
source code.  And you must show them these terms so they know their
rights.

  We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.

  Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software.  If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.

  Finally, any free program is threatened constantly by software
patents.  We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary.  To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.

  The precise terms and conditions for copying, distribution and
modification follow.

		    GNU GENERAL PUBLIC LICENSE
   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION

  0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License.  The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language.  (Hereinafter, translation is included without limitation in
the term "modification".)  Each licensee is addressed as "you".

Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope.  The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.

  1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.

You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.

  2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:

    a) You must cause the modified files to carry prominent notices
    stating that you changed the files and the date of any change.

    b) You must cause any work that you distribute or publish, that in
    whole or in part contains or is derived from the Program or any
    part thereof, to be licensed as a whole at no charge to all third
    parties under the terms of this License.

    c) If the modified program normally reads commands interactively
    when run, you must cause it, when started running for such
    interactive use in the most ordinary way, to print or display an
    announcement including an appropriate copyright notice and a
    notice that there is no warranty (or else, saying that you provide
    a warranty) and that users may redistribute the program under
    these conditions, and telling the user how to view a copy of this
    License.  (Exception: if the Program itself is interactive but
    does not normally print such an announcement, your work based on
    the Program is not required to print an announcement.)

These requirements apply to the modified work as a whole.  If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works.  But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.

Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.

In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.

  3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:

    a) Accompany it with the complete corresponding machine-readable
    source code, which must be distributed under the terms of Sections
    1 and 2 above on a medium customarily used for software interchange; or,

    b) Accompany it with a written offer, valid for at least three
    years, to give any third party, for a charge no more than your
    cost of physically performing source distribution, a complete
    machine-readable copy of the corresponding source code, to be
    distributed under the terms of Sections 1 and 2 above on a medium
    customarily used for software interchange; or,

    c) Accompany it with the information you received as to the offer
    to distribute corresponding source code.  (This alternative is
    allowed only for noncommercial distribution and only if you
    received the program in object code or executable form with such
    an offer, in accord with Subsection b above.)

The source code for a work means the preferred form of the work for
making modifications to it.  For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable.  However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.

If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.

  4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License.  Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.

  5. You are not required to accept this License, since you have not
signed it.  However, nothing else grants you permission to modify or
distribute the Program or its derivative works.  These actions are
prohibited by law if you do not accept this License.  Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.

  6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions.  You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.

  7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License.  If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all.  For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.

If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.

It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices.  Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.

This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.

  8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded.  In such case, this License incorporates
the limitation as if written in the body of this License.

  9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time.  Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.

Each version is given a distinguishing version number.  If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation.  If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.

  10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission.  For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this.  Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.

			    NO WARRANTY

  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.

  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.

		     END OF TERMS AND CONDITIONS
xsok-1.02/etc/COPYRIGHT.xsok100644    144     62        1345  5665071060  14116 0ustar  mbimathopt/*
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 2 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details. (The file COPYRIGHT.GNU)

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.		     */
xsok-1.02/etc/xsok.lsm100644    144     62        1055  6151124070  13326 0ustar  mbimathoptBegin3
Title:          xsok
Version:        1.02
Entered-date:   23MAY96
Description:    Strategy game for X11, implementation of Sokoban, Cyberbox.
Keywords:       Sokoban, Cyberbox, puzzle
Author:         mbi@mo.math.nat.tu-bs.de (Michael Bischoff)
Maintained-by:  mbi@mo.math.nat.tu-bs.de (Michael Bischoff)
Primary-site:   sunsite.unc.edu: /pub/Linux/games/x11/strategy
		117kB xsok-1.02-src.tar.gz
		 58kB xsok-1.02-dllbin.tar.gz (X11R5)
		 64kB xsok-1.02-elfbin.tar.gz (X11R6)
Platform:       X11, Athena Widgets, Xpm library
Copying-policy: GPL2
End
xsok-1.02/etc/COPYRIGHT.xpm100644    144     62        3253  5665071060  13736 0ustar  mbimathopt/*
 * Copyright (C) 1989-94 GROUPE BULL
 *
 * 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
 * GROUPE BULL 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.
 *
 * Except as contained in this notice, the name of GROUPE BULL shall not be
 * used in advertising or otherwise to promote the sale, use or other dealings
 * in this Software without prior written authorization from GROUPE BULL.
 */

Arnaud LE HORS      BULL Research FRANCE -- Koala Project 
                    (XPM - X PixMap format version 2 & 3)
    Internet:       lehors@sophia.inria.fr
Surface Mail:       Arnaud LE HORS, INRIA - Sophia Antipolis, 
                    2004, route des Lucioles, 06565 Valbonne Cedex -- FRANCE
 Voice phone:       (33) 93.65.77.71, Fax: (33) 93 65 77 66, Telex: 97 00 50 F
xsok-1.02/etc/Changelog100644    144     62         333  6151123774  13427 0ustar  mbimathoptChanges from version 1.01 to version 1.02:

- the middle mouse button now acts in a more smart fashion:
  With this button, you may move the box on a non-linear
  path with a single click! See the man-page for details.
xsok-1.02/doc/ 40755    144     62           0  6123003304  11514 5ustar  mbimathoptxsok-1.02/doc/Makefile100644    144     62         246  5665071060  13251 0ustar  mbimathoptall: xsok.ps

xsok.ps: xsok.dvi
	dvips -f < xsok.dvi > xsok.ps

xsok.dvi: xsok.tex
	latex xsok
	latex xsok
	latex xsok

clean:
	rm -f *~ *.log *.aux *.toc *.dvi *.ps
xsok-1.02/doc/xsok.tex100644    144     62       45171  6123003063  13351 0ustar  mbimathopt\documentstyle[12pt]{article}
\newcommand{\xsok}{{\tt xsok}}
\title{\xsok\ Version 1.02 Manual}
\author{Michael Bischoff}
\date{16-Mar-1996}
\begin{document}
\maketitle
\tableofcontents

\newpage
\section{Introduction}
\subsection{WARNING}
Be warned. This manual is under construction. It may currently contain a lot of typos,
bad English, bad style, and it's unfinished. The information herein should be correct, however.

\subsection{\xsok\ --- A Generic Sokoban Game for X11}
Similar to Tetris, almost every operating system has an implementation of
the Sokoban game. It baffles by its easy rules, but nevertheless
complex strategies.

For Linux, I found a textmode implementation and an X11-based version, both
written 1992. The X11 version seemed to be based on the textmode version,
and both use the same format for the level definition files.

\xsok\ is a generalization of the standard Sokoban game.
All original Sokoban levels may be played with \xsok\ (again, using the same
format for the level definition files). Some levels of a similar MSDOS game,
Cyberbox, may be played also.

\xsok\ is a one-person game played on a square-tiled board. It has no random
elements, and is a pure strategic game. There are different
floor types and walls, and objects standing on the floor. The objective is
to push certain objects onto marked target squares, and to move onto the EXIT
square, if one exists.
The objects on the floor, which we will refer to as boxes, have certain
attributes,
such as weight, value, possible directions of movement, and own power.
A special kind of object is the player itself. He has a certain power, which
represents the maximal sum of the weights of the boxes he can push in a single
move.
The default power is one hundred, and equals the weight of a standard box.
There are lighter (empty) boxes of weight one, which simply block your way,
especially since some of them may be moved either only horizontally or only
vertically.
Some boxes even show interest in moving themselves into a certain direction,
and may even push standard boxes! (I have no explanation for this phenomenon!)
Luckily, most boxes are marked with arrows and color, so that you may
distinguish them.

As well as the boxes, even the floor squares may have attributes.
In Sokoban, the only floor attribute was the distinction between normal floor
and target spaces.
In \xsok, there may be different target spaces, for different box types.
Some squares may be passed in only one direction, or restrict the box types
which may be moved upon them.
There are floor types which turn boxes, by 90 or 180 degrees.
Some squares may give you power cookies, others let you suffer from weakness.

To manage this zoo, all possible levels are partioned into level sets, which
share a common subset of the possible square types.
A level set definition file assigns the attributes to characters.

The definition table for the floor types must follow a line with
the contents ``{\tt ;WALLS}'' in the level subset definition file.
For a floor type, there are the following attributes.

\begin{center}
  \begin{tabular}{|l|l|p{8cm}|}
    \hline
    field & format & description\\
    \hline
    char   & ascii & character, by which this floor type is identified in the level file\\
    pic    & hex & offset into the graphic data file\\
    enter  & hex & one bit set for every direction from which any object may enter this square\\
    leave  & hex & one bit set for every direction to which any object may leave this square\\
    mask   & hex & one bit set for every object class which is allowed on this square\\
    effect & dec & identifies a special effect (rotation, target, exit)\\
    \hline
  \end{tabular}
\end{center}

The format determines how the entry is interpreted: as ASCII character, as
hexadecimal number, or as decimal number.
You may not use the ';' sign as ASCII representation of an object or a floor
type, since it introduces comments and commands.
Picture id 0 is reserved for the standard walls: There are 16 different
tiles, from which one is selected depending on the 4 neighbour squares.

The effect field has the following meaning.

\begin{center}
  \begin{tabular}{|r|l|}
    \hline
    effect mod 100 & description\\
    \hline
    0 & no effect \\
    1 & rotate counterclockwise by 90 degrees\\
    2 & rotate by 180 degrees\\
    3 & rotate clockwise by 90 degrees\\
    4 & this is a target square for boxes\\
    5 & this is the exit square\\
    6 & increase power by 1\\
    7 & decrease power by 1\\
    8 & teleport\\
    \hline
  \end{tabular}
\end{center}

If the effect field is less than 100, the effect will affect every object once
it enters the square. If the effect is at least 100, but less than 200, the
effect will affect the first object which enters the square, and then the
square
will be substituted by a standard floor square.
The standard floor square is the floor type which occurs first in the table.
If the effect field is at least 200, the square will change to floor type
(effect-200) / 100 once it is free again.

A teleporter will teleport any object on it to the first free teleporter
available,
or do nothing, if all other teleporters are occupied.


The definition table for the object types must follow a line with
the contents ``{\tt ;OBJECTS}'' in the level subset definition file,
and must be behind the floor definition array.
For an object, there are the following attributes.

\begin{center}
  \begin{tabular}{|l|l|p{8cm}|}
    \hline
    field & format & description\\
    \hline
    char    & ascii & character, by which this floor type is identified in the level file\\
    pic     & hex & offset into the graphic data file\\
    movedir & hex & one bit set for every direction in which this object may move\\
    pushdir & hex & one bit set for every direction in which this object
    will move automatically\\
    weight  & dec & the weight of this object\\
    power   & dec & the power which the object has for moving\\
    mask    & hex & defines the object class (multiple classes are possible)\\
    score   & hex & the bonus you receive if this object is on a target square\\
    \hline
  \end{tabular}
\end{center}

The object which represents the man is the first object in the table.
Its {\tt mask} entry must be 1, since this is hardcoded into the program.
The {\tt mask} entry should only use bits 0 to 15. The higher bits are
needed for the {\tt Cyberbox} selectors, their coding is subject to change.

\section{Adding New Level Subsets}
If you want to create new level subsets, create a text file {\tt gametypes}
in the directory {\tt /usr/games/lib/xsok}, where every line of this file
represents the name of a new level subset.
Suppose you want to create the subset {\tt Foo}.
Create a description in the file {\tt /usr/games/lib/xsok/Foo.help}.
Create a subdirectory {\tt /usr/games/lib/xsok/Foo}, and put in a file
{\tt definitions} and the files {\tt screen.??} for the levels.
For examples, see the subdirectories of the {\tt lib} directory in the source
distribution.
Edit the level files until you are satisfied. Then, you may concatenate
all the files in the {\tt /usr/games/lib/xsok/Foo} directory using the {\tt
  combine} program, and create the more compact file {\tt
  /usr/games/lib/xsok/Foo.def.gz}.

The level file simply is an ASCII representation of the floor types and
objects. The floor below an object is by default the first floor type which
occurs in the {\tt definitions} file. If you need another combination
(for example a box already on a target square), you have to dedicate
a new character for this combination, and add an {\tt ATOP} command in
the {\tt definitions} file. In Sokoban, a box is represented by a dollar
sign and a target square by a dot. For a box on a target square,
a star is used. The defining line in the Sokoban definitions file is
``{\tt ;ATOP *\$.}''.
The possible 
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions