#include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #undef setmode #define setmode setmode_ extern const char *__progname; #define ANIMDIV 3 #define SLIME_TICKS 50 #include #include "rnd.h" #include "cmap.h" #include "font.h" #include "board.h" #include "bitmap.h" #include "levelio.h" #include "default-levels.h" #include "bitmap-cg6-extern.h" static const char *fbpath = "/dev/cgsix0"; static const char *kbpath = "/dev/kbd"; static const char *mspath = "/dev/mouse"; #define how_many(x,y) (((x)+(y)-1)/(y)) #define round_up(x,y) (how_many(x,y)*(y)) static int fbfd; static int kbfd; static int msfd; static void *fbmap; static size_t fbmaplen; static volatile struct cg6fbc *fb; static volatile struct brooktree *bt; static volatile unsigned char *vram; static int fbmode; static int fbalu; static int fbfg; static int fbpm; static volatile unsigned long int hardtime; static unsigned long int softtime; static unsigned long int drawtime; static unsigned long int queuetime; #define EVQ_SIZE 64 /* must be a power of two */ static int evq[EVQ_SIZE]; static int evqh; static int evqt; #define EV_TYPE 0x000f0000 #define EVT_NIL 0x00000000 #define EVT_KBD 0x00010000 #define EVK_CODE 0x0000007f /* must be low bits */ #define EVK_UPDN 0x00000080 #define EVK_UP 0x00000080 #define EVK_DN 0x00000000 #define EVT_TICK 0x00020000 #define EVT_DRAW 0x00030000 #define EVT_MOUSE 0x00040000 #define EVM_TYPE 0x0000c000 #define EVM_T_DX 0x00004000 #define EVM_T_DY 0x00008000 #define EVM_T_BUT 0x0000c000 #define EVM_SIGN 0x00002000 #define EVM_S_NEG 0x00002000 #define EVM_S_POS 0x00000000 #define EVM_DELTA 0x00001fff /* must be low bits */ #define EVM_UPDN 0x00000004 #define EVM_UP 0x00000004 #define EVM_DN 0x00000000 #define EVM_BUTID 0x00000003 #define EVM_BUT_L 0x00000000 #define EVM_BUT_M 0x00000001 #define EVM_BUT_R 0x00000002 #define GRIDX B_XSIZE #define GRIDY B_YSIZE #define CELLW B_XCELL #define CELLH B_YCELL #define MAXX ((GRIDX*CELLW)+2) #define MAXY ((GRIDY*CELLH)+2) #define XOFF ((1152-MAXX)/2) #define YOFF ((900-MAXY)/2) #define LEVSELX (XOFF+1) #define LEVSELY (YOFF+1) #define LEVSELW ((GRIDX*CELLW)/4) #define LEVSELH ((GRIDY*CELLH)/4) #define NAMEW (FONT_X*LEVNAME_MAX) #define NAMEH FONT_Y #define NAMEX ((1152-NAMEW)/2) #define NAMEY (YOFF-NAMEH) typedef struct fuse FUSE; typedef struct level LEVEL; typedef struct levelfile LEVELFILE; typedef struct slime SLIME; typedef struct xypair XYPAIR; struct xypair { XYPAIR *link; int x; int y; } ; struct slime { SLIME *flink; SLIME *blink; unsigned char x; unsigned char y; unsigned char hdg; #define SH_U 0 #define SH_L 1 #define SH_D 2 #define SH_R 3 unsigned char done; unsigned long int map[33]; } ; struct levelfile { LEVELFILE *flink; LEVELFILE *blink; int n; int inx; char *fn; int nlevels; int alevels; LEVEL **levels; FILE *f; int dirty; } ; struct level { LCELL cells[B_XSIZE][B_YSIZE]; char *name; LEVELFILE *fromfile; int fileinx; int dirty; BITMAP *small; } ; struct fuse { unsigned long int when; void (*fn)(void *); void *arg; } ; static int fuses_n; static int fuses_a; static FUSE **fuses; static int wantrender; static int wantredo; static int drawbit; static int drawpm; static int mousex; static int mousey; static int mousecx; static int mousecy; static BCELL *mousec; static BCELL *droploc; static int mouselfi; static int carrying; static int carryx; static int carryy; static BCELL carrycell; static BCELL *carryfrom; static int stickycode = -1; static BCELL *stickyclone; static BCELL *stickyloc; static int anim; static int animinc; static int canedit; static int editing; static int ename; static int enamecurs = -1; static int autorepeat; static void *autorepeat_fuse; static int flashrot; static int flashmov; static int flashrgb; static int kbflags; #define KBF_SL 0x00000001 #define KBF_SR 0x00000002 #define KBF_S (KBF_SL|KBF_SR) #define KBF_C 0x00000004 static int nlevelfiles = 0; static LEVELFILE *levelfiles_f = 0; static LEVELFILE *levelfiles_b = 0; static int have_npfile; static LEVEL *curlevel; static LCELL resetboard[B_XSIZE][B_YSIZE]; static BCELL board[B_XSIZE][B_YSIZE]; static char lname[LEVNAME_MAX]; static int levelsel; static int ldirty; static LEVELFILE *curlf; static const char *msgfooter; static void *msgfooter_fuse; static const char *confirming; static void (*confirm_fn)(int, void *); static void *confirm_arg; static LEVEL *lscarry; static int complete; static void (*tntfn)(int, int); static int exploding; static FUSE *slimefuse; static SLIME *slimes_f = 0; static SLIME *slimes_b = 0; static int showkbd = 0; static int debug = 0; static const int slimehdg_to_dir[4] = { [SH_U] DIR_U, [SH_L] DIR_L, [SH_D] DIR_D, [SH_R] DIR_R }; static const int dir_d[DIR__N][2] = { { 1, 0 }, { 1, -1 }, { 0, -1 }, { -1, -1 }, { -1, 0 }, { -1, 1 }, { 0, 1 }, { 1, 1 } }; /* These tables describe the default colors and orientations for new cells. When a cell of type OLD is changed to type NEW, these tables are indexed [OLD][NEW], and COPY indicates to copy the value from the old cell to the new cell. */ /* To keep the tables smaller, equivalent rows and columns are collapsed. Both subscripts to FOO are run through the FOOx lookup table first. */ #define COPY (-1) /* 0: not coloured; 1: coloured */ static int defcolx[BT__N] = { 0,1,0,0,0,0,0,1,0,1,0,0,0,0,0,0,1,1,0,0,0 }; static int defcol[2][2] /* color */ = { { COL_K, COL_W }, { COL_K, COPY } }; /* 0: ignores info; 1: info is direction; 2 and up: info is idiosyncratic */ static int definfox[BT__N] = { 0,1,1,1,1,1,1,0,2,3,4,1,1,1,1,0,1,1,0,1,0 }; static int definfo[5][5] /* info */ = { { 0, 0, 0, 0, 0 }, { 0,COPY, 0, 0, 0 }, { 0, 0,COPY, 0, 0 }, { 0, 0, 0,COPY, 0 }, { 0, 0, 0, 0,COPY } }; /* 0: no rotation; 1: normal rotatable; 2: rotates, not by default */ static int defrotx[BT__N] = { 0,2,1,1,1,1,1,0,0,0,0,1,1,1,1,0,1,1,0,1,0 }; static int defrot[3][3] /* canrot */ = { { 0, 1, 0 }, { 0,COPY, 0 }, { 0, 1,COPY } }; /* 0: no movement; 1: normal moveable; 2: moves, not by default */ static int defmovx[BT__N] = { 0,2,1,1,1,1,1,0,0,0,0,1,1,1,1,0,1,1,1,1,0 }; static int defmov[3][3] /* mobile */ = { { 0, 1, 0 }, { 0,COPY, 0 }, { 0, 1,COPY } }; static const unsigned int color_up_table[8] = { [COL_K] COL_K, [COL_R] COL_G, [COL_G] COL_B, [COL_B] COL_R, [COL_C] COL_M, [COL_M] COL_Y, [COL_Y] COL_C, [COL_W] COL_W }; static const unsigned int color_dn_table[8] = { [COL_K] COL_K, [COL_R] COL_B, [COL_G] COL_R, [COL_B] COL_G, [COL_C] COL_Y, [COL_M] COL_C, [COL_Y] COL_M, [COL_W] COL_W }; /* mouse_bits[movable][rotateable][1(fg)/0(bg)] is row of 16 bitmaps. */ /* mouse_off[movable][rotateable] is X ([0]) and Y ([1]) offsets for that mouse image. */ /* mouse_editor_bits and mouse_editor_off are used instead of mouse_bits[0][0] and mouse_off[0][0], when editing. */ static const unsigned short int mouse_bits[2][2][2][16] = { { { { 0xc000,0xe000,0xf000,0xf800,0xfc00,0xfe00,0xff00,0xff80, /* !m!r */ 0xffc0,0xffc0,0xfe00,0xef00,0xcf00,0x0780,0x0780,0x0300 }, { 0x0000,0x4000,0x6000,0x7000,0x7800,0x7c00,0x7e00,0x7f00, 0x7f80,0x7c00,0x6c00,0x4600,0x0600,0x0300,0x0300,0x0000 } }, { { 0xc7e0,0xeff0,0xfff8,0xfffc,0xfc1c,0xfe0c,0xff00,0xff00, /* !m+r */ 0x00ff,0x00ff,0x307f,0x383f,0x3fff,0x1fff,0x0ff7,0x07e3 }, { 0x0000,0x47e0,0x6ff0,0x7c18,0x4808,0x4c00,0x7e00,0x0000, 0x0000,0x007e,0x0032,0x1012,0x183e,0x0ff6,0x07e2,0x0000 } } }, { { { 0x03c0,0x03c0,0x07e0,0x0ff0,0x17e8,0x3bdc,0xffff,0xffff, /* +m!r */ 0xffff,0xffff,0x3bdc,0x17e8,0x0ff0,0x07e0,0x03c0,0x03c0 }, { 0x0000,0x0180,0x03c0,0x07e0,0x0180,0x1188,0x318c,0x7ffe, 0x7ffe,0x318c,0x1188,0x0180,0x07e0,0x03c0,0x0180,0x0000 } }, { { 0x7f80,0xffc0,0xffe0,0xfff0,0x7ff8,0x1ff8,0x3ff8,0x1ffc, /* +m+r */ 0x3ffe,0x1fff,0x0ffe,0x07fc,0x03f8,0x01f0,0x00e0,0x0040 }, { 0x0000,0x3fc0,0x4020,0x3f10,0x0808,0x0708,0x0808,0x0714, 0x0822,0x0641,0x0182,0x0124,0x0088,0x0050,0x0020,0x0000 } } } }; static const int mouse_off[2][2][2] = { { { 1, 1 }, /* !m!r */ { 8, 8 } }, /* !m+r */ { { 8, 8 }, /* +m!r */ { 2, 2 } } }; /* +m+r */ static const unsigned short int mouse_editor_bits[2][16] = { { 0x1ff8,0x3ffc,0x3ffc,0x3ff8,0x3c00,0x3c00,0x3fc0,0x3fe0, 0x3fe0,0x3fc0,0x3c00,0x3c00,0x3ff8,0x3ffc,0x3ffc,0x1ff8 }, { 0x0000,0x1ff8,0x1ff8,0x1800,0x1800,0x1800,0x1800,0x1fc0, 0x1fc0,0x1800,0x1800,0x1800,0x1800,0x1ff8,0x1ff8,0x0000 } }; static const int mouse_editor_off[2] = { 8, 8 }; #if (B_XCELL != 48) || (B_YCELL != 48) #error Fix beam bitmaps for B_XCELL and B_YCELL #endif #if 1 unsigned long int beam_h[16][8] = { { 0x00000000, 0x00000000, 0x00000000, 0xffffff00, 0xffffff00, 0x00000000, 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000, 0x00000000, 0xffffff00, 0xffffff00, 0x00000000, 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000, 0x00141800, 0xffffff00, 0xffffff00, 0x3e104200, 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000, 0x70281300, 0xffffff00, 0xffffff00, 0x00124000, 0x00000000, 0x00000000 }, { 0x00000000, 0x0c025300, 0xff372f00, 0xffffff00, 0xffffff00, 0xa4d21a00, 0xa0208400, 0x00000000 }, { 0x00000000, 0x83880900, 0xe5744900, 0xffffff00, 0xffffff00, 0x4946c000, 0x4004b100, 0x00000000 }, { 0x00000000, 0x06100100, 0xa5945f00, 0xffffff00, 0xffffff00, 0xc4e8fc00, 0xd111c100, 0x00000000 }, { 0x02001c00, 0x915cbb00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0x2d55eb00, 0x2320c000 }, { 0x04012300, 0x7e62fe00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xa1bd4a00, 0x05040800 }, { 0x0e008400, 0xf0bc6300, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0x6f3ac100, 0x11a9c400 }, { 0x00000000, 0x2120e600, 0xf5587100, 0xffffff00, 0xffffff00, 0x8fab4600, 0x08158800, 0x00000000 }, { 0x00000000, 0x7114a000, 0x2de39500, 0xffffff00, 0xffffff00, 0x2b422400, 0x50194800, 0x00000000 }, { 0x00000000, 0x80830000, 0xf4b11d00, 0xffffff00, 0xffffff00, 0x2bb19600, 0x14218000, 0x00000000 }, { 0x00000000, 0x00000000, 0x10010400, 0xffffff00, 0xffffff00, 0x04003100, 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000, 0x8ca0a000, 0xffffff00, 0xffffff00, 0x48330100, 0x00000000, 0x00000000 }, { 0x00000000, 0x00000000, 0x00000000, 0xffffff00, 0xffffff00, 0x00000000, 0x00000000, 0x00000000 } }; unsigned long int beam_v[16][24] = { { 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000 }, { 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000 }, { 0x00018000, 0x00018000, 0x0001c000, 0x0001c000, 0x0001c000, 0x0001c000, 0x0001c000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x0003c000, 0x00018000, 0x00038000, 0x00018000, 0x00018000, 0x00018000, 0x0001c000, 0x00018000, 0x00038000, 0x00038000, 0x00018000, 0x0001c000, 0x00018000 }, { 0x00018000, 0x00038000, 0x00038000, 0x00038000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00038000, 0x0001c000, 0x00038000, 0x00018000, 0x0001c000, 0x00018000, 0x00018000, 0x0001c000, 0x00018000, 0x00038000, 0x00018000, 0x00018000, 0x00038000, 0x00038000 }, { 0x0003e000, 0x00038000, 0x0003e000, 0x00038000, 0x00078000, 0x0007c000, 0x00038000, 0x00038000, 0x0001c000, 0x0001c000, 0x0003a000, 0x0003c000, 0x00018000, 0x00038000, 0x0007c000, 0x00038000, 0x0001a000, 0x00058000, 0x00038000, 0x0005c000, 0x0003c000, 0x0003a000, 0x0007c000, 0x00078000 }, { 0x00078000, 0x0003e000, 0x00038000, 0x00018000, 0x0001c000, 0x00038000, 0x00058000, 0x0007c000, 0x00058000, 0x0003c000, 0x00038000, 0x00038000, 0x00058000, 0x0003e000, 0x0001c000, 0x00018000, 0x0001e000, 0x0003c000, 0x0001a000, 0x0001a000, 0x00078000, 0x00018000, 0x00018000, 0x0007a000 }, { 0x0003e000, 0x0001e000, 0x00038000, 0x0001a000, 0x00018000, 0x0007c000, 0x00058000, 0x0003a000, 0x0003c000, 0x0001c000, 0x0001c000, 0x0007a000, 0x0001c000, 0x00038000, 0x00018000, 0x0001a000, 0x0001e000, 0x0003e000, 0x0001c000, 0x0003c000, 0x0003c000, 0x0003c000, 0x00038000, 0x0007a000 }, { 0x0007c000, 0x0003c000, 0x0003f000, 0x0007c000, 0x0003e000, 0x0003e000, 0x000bd000, 0x0007f000, 0x0003c000, 0x0007e000, 0x0003d000, 0x0007e000, 0x0007c000, 0x0007e000, 0x0003c000, 0x0003e000, 0x0007f000, 0x0003f000, 0x0007e000, 0x000fc000, 0x000fe000, 0x000bc000, 0x0007e000, 0x0007e000 }, { 0x0003e000, 0x0007c000, 0x0007e000, 0x0007c000, 0x0007c000, 0x000fd000, 0x0007c000, 0x0003f000, 0x0003e000, 0x0007c000, 0x0007e000, 0x0003e000, 0x0003e000, 0x0003f000, 0x0007c000, 0x000be000, 0x0007c000, 0x0007e000, 0x000fc000, 0x0007c000, 0x0007f000, 0x0007c000, 0x000fe000, 0x000bc000 }, { 0x0007c000, 0x0007e000, 0x0007e000, 0x0007d000, 0x000be000, 0x000be000, 0x000be000, 0x0003f000, 0x0007d000, 0x0003c000, 0x0007f000, 0x0007e000, 0x0007f000, 0x0007c000, 0x0003e000, 0x0003d000, 0x000bf000, 0x0007f000, 0x0007c000, 0x0003c000, 0x0003c000, 0x000bd000, 0x0007c000, 0x0007e000 }, { 0x0003c000, 0x00038000, 0x00078000, 0x00038000, 0x0001e000, 0x0003c000, 0x0001c000, 0x0007c000, 0x0001c000, 0x00038000, 0x0005c000, 0x0003a000, 0x0003c000, 0x0001a000, 0x0001c000, 0x0001e000, 0x0005a000, 0x0007c000, 0x00078000, 0x00038000, 0x0001a000, 0x0005c000, 0x0005c000, 0x00038000 }, { 0x00018000, 0x0005a000, 0x0007c000, 0x0005a000, 0x0003c000, 0x00038000, 0x0001c000, 0x0007c000, 0x00038000, 0x0003c000, 0x00038000, 0x0005a000, 0x0001a000, 0x00058000, 0x0003c000, 0x0003a000, 0x00078000, 0x0001a000, 0x0005c000, 0x00038000, 0x0001a000, 0x0003c000, 0x00018000, 0x00038000 }, { 0x00078000, 0x00038000, 0x0003c000, 0x0003a000, 0x0001c000, 0x0003a000, 0x0001c000, 0x0001c000, 0x0007c000, 0x00018000, 0x0003e000, 0x0003c000, 0x00018000, 0x00018000, 0x00058000, 0x0007e000, 0x0001e000, 0x00018000, 0x00018000, 0x0003c000, 0x00038000, 0x0003c000, 0x0001c000, 0x00038000 }, { 0x00018000, 0x00018000, 0x00018000, 0x00038000, 0x00018000, 0x0001c000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00038000, 0x00018000, 0x00018000, 0x0001c000, 0x0001c000, 0x00018000, 0x00038000, 0x00018000, 0x0001c000 }, { 0x00038000, 0x0001c000, 0x00018000, 0x00018000, 0x0003c000, 0x00038000, 0x00018000, 0x00018000, 0x00038000, 0x00018000, 0x0003c000, 0x0001c000, 0x00018000, 0x00018000, 0x0001c000, 0x0001c000, 0x00038000, 0x00018000, 0x00038000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x0001c000 }, { 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000, 0x00018000 } }; unsigned long int beam_ul_dr[16][29] = { { 0x00000000, 0x20000000, 0x70000000, 0x38000000, 0x1c000000, 0x0e000000, 0x07000000, 0x03800000, 0x01c00000, 0x00e00000, 0x00700000, 0x00380000, 0x001c0000, 0x000e0000, 0x00070000, 0x00038000, 0x0001c000, 0x0000e000, 0x00007000, 0x00003800, 0x00001c00, 0x00000e00, 0x00000700, 0x00000380, 0x000001c0, 0x000000e0, 0x00000070, 0x00000020, 0x00000000 }, { 0x00000000, 0x20000000, 0x70000000, 0x38000000, 0x1c000000, 0x0e000000, 0x07000000, 0x03800000, 0x01c00000, 0x00e00000, 0x00700000, 0x00380000, 0x001c0000, 0x000e0000, 0x00070000, 0x00038000, 0x0001c000, 0x0000e000, 0x00007000, 0x00003800, 0x00001c00, 0x00000e00, 0x00000700, 0x00000380, 0x000001c0, 0x000000e0, 0x00000070, 0x00000020, 0x00000000 }, { 0x00000000, 0x30000000, 0x70000000, 0x38000000, 0x1c000000, 0x0f000000, 0x07000000, 0x03800000, 0x01c00000, 0x00e00000, 0x00700000, 0x003c0000, 0x001c0000, 0x000f0000, 0x000f8000, 0x00038000, 0x0001e000, 0x0000e000, 0x00007800, 0x00007800, 0x00001c00, 0x00000f00, 0x00000700, 0x00000380, 0x000001c0, 0x000000e0, 0x00000070, 0x00000020, 0x00000000 }, { 0x00000000, 0x20000000, 0x70000000, 0x38000000, 0x1c000000, 0x0e000000, 0x07000000, 0x03800000, 0x01c00000, 0x01e00000, 0x00700000, 0x007c0000, 0x001e0000, 0x000e0000, 0x000f0000, 0x00038000, 0x0001e000, 0x0000f000, 0x00007000, 0x00007800, 0x00003c00, 0x00001e00, 0x00000780, 0x00000780, 0x000003c0, 0x000000f0, 0x00000070, 0x00000020, 0x00000000 }, { 0x00000000, 0x30000000, 0x78000000, 0x3e000000, 0x3e000000, 0x0f800000, 0x0f000000, 0x03800000, 0x05e00000, 0x01f00000, 0x00780000, 0x003c0000, 0x003d0000, 0x000f0000, 0x00070000, 0x0007c000, 0x0003e000, 0x0003e000, 0x0000fc00, 0x00003a00, 0x00001f00, 0x00001f80, 0x00000700, 0x00000380, 0x000003e0, 0x000001f8, 0x000001f0, 0x000000a0, 0x00000000 }, { 0x00000000, 0x20000000, 0x70000000, 0x38000000, 0x7c000000, 0x0f000000, 0x07000000, 0x07e00000, 0x03e00000, 0x00e00000, 0x01780000, 0x007c0000, 0x005c0000, 0x001e0000, 0x00178000, 0x0003c000, 0x0001f000, 0x0001e000, 0x00017c00, 0x0000fc00, 0x00007c00, 0x00000e00, 0x000017c0, 0x000003a0, 0x000001c0, 0x000000f0, 0x000000f0, 0x00000060, 0x00000000 }, { 0x00000000, 0x38000000, 0x78000000, 0x7e000000, 0x3c000000, 0x2e800000, 0x0f000000, 0x0b800000, 0x01c00000, 0x01e80000, 0x00f40000, 0x007c0000, 0x003e0000, 0x000e0000, 0x00178000, 0x0003e000, 0x0003c000, 0x0001e000, 0x0000f800, 0x00003a00, 0x00001e00, 0x00000f00, 0x00000f40, 0x000003c0, 0x000001e0, 0x000001f8, 0x000001f0, 0x000000a0, 0x00000000 }, { 0x10000000, 0x30000000, 0x7c000000, 0xfc000000, 0x7e000000, 0x3f000000, 0x1f800000, 0x07d00000, 0x0ff00000, 0x01f00000, 0x02f80000, 0x007c0000, 0x003f0000, 0x003f8000, 0x001fe000, 0x000fc000, 0x0003f000, 0x0005f800, 0x0000fe00, 0x00007c00, 0x00007e00, 0x00005f00, 0x00001fe0, 0x000007f0, 0x000007e0, 0x000007f8, 0x000000f0, 0x00000060, 0x000000c0 }, { 0x10000000, 0x3c000000, 0x78000000, 0x7e000000, 0x3f000000, 0x1f000000, 0x0f800000, 0x17d00000, 0x03e80000, 0x03f40000, 0x01f80000, 0x007e0000, 0x007f0000, 0x001f8000, 0x003f8000, 0x0017e000, 0x000fe800, 0x0001f800, 0x0001fe00, 0x0000fe00, 0x00003e80, 0x00001f80, 0x00000fc0, 0x000007d0, 0x000007f8, 0x000005f0, 0x000000f0, 0x000000e0, 0x00000000 }, { 0x10000000, 0x30000000, 0x7c000000, 0x7d000000, 0xbe000000, 0x1f800000, 0x2fc00000, 0x07c00000, 0x07f00000, 0x01f00000, 0x01f80000, 0x007d0000, 0x007f0000, 0x005f8000, 0x000fc000, 0x0007f000, 0x000fe000, 0x0001fc00, 0x0001fc00, 0x00007e00, 0x00003f00, 0x00003fc0, 0x00000fc0, 0x000007e0, 0x00000fe0, 0x000003f8, 0x000003f0, 0x00000060, 0x00000000 }, { 0x10000000, 0x20000000, 0x78000000, 0x3c000000, 0x3d000000, 0x1e000000, 0x0f000000, 0x03c00000, 0x03e00000, 0x02f80000, 0x007c0000, 0x007c0000, 0x005c0000, 0x001f0000, 0x000f8000, 0x0003e000, 0x0003c000, 0x0002f000, 0x00007000, 0x00007800, 0x00007c00, 0x00000f00, 0x00000740, 0x000007c0, 0x000001e0, 0x000003f8, 0x000000f0, 0x00000020, 0x00000000 }, { 0x00000000, 0x20000000, 0x78000000, 0xfc000000, 0x3d000000, 0x2e000000, 0x0f000000, 0x07800000, 0x01f00000, 0x02e80000, 0x00fc0000, 0x007c0000, 0x007e0000, 0x000f0000, 0x00070000, 0x0007c000, 0x0007e000, 0x0001e800, 0x00007800, 0x00007a00, 0x00001d00, 0x00001e00, 0x00000f00, 0x000003a0, 0x000001d0, 0x000003f0, 0x00000170, 0x00000060, 0x00000040 }, { 0x00000000, 0x20000000, 0x78000000, 0x38000000, 0x3d000000, 0x0f000000, 0x0f800000, 0x07c00000, 0x07c00000, 0x00f80000, 0x00f00000, 0x00780000, 0x001d0000, 0x000f0000, 0x000f4000, 0x000fa000, 0x0003e000, 0x0001e800, 0x00007c00, 0x00003c00, 0x00001c00, 0x00001e00, 0x00000f80, 0x000003c0, 0x000001e0, 0x000000e0, 0x00000070, 0x00000060, 0x00000000 }, { 0x00000000, 0x20000000, 0x70000000, 0x38000000, 0x3e000000, 0x0e000000, 0x07000000, 0x07800000, 0x01c00000, 0x00f00000, 0x00780000, 0x00380000, 0x003c0000, 0x000f0000, 0x00070000, 0x0003c000, 0x0001c000, 0x0000e000, 0x00007000, 0x00003800, 0x00003c00, 0x00000f00, 0x00000700, 0x00000780, 0x000001e0, 0x000000e0, 0x000000f0, 0x00000020, 0x00000000 }, { 0x00000000, 0x20000000, 0x70000000, 0x38000000, 0x1c000000, 0x1e000000, 0x07000000, 0x03800000, 0x01c00000, 0x01e00000, 0x00f00000, 0x00780000, 0x001c0000, 0x001f0000, 0x00070000, 0x00038000, 0x0001e000, 0x0000e000, 0x0000f000, 0x00003800, 0x00001c00, 0x00000f00, 0x00000780, 0x00000380, 0x000001c0, 0x000000e0, 0x000000f0, 0x00000020, 0x00000000 }, { 0x00000000, 0x20000000, 0x70000000, 0x38000000, 0x1c000000, 0x0e000000, 0x07000000, 0x03800000, 0x01c00000, 0x00e00000, 0x00700000, 0x00380000, 0x001c0000, 0x000e0000, 0x00070000, 0x00038000, 0x0001c000, 0x0000e000, 0x00007000, 0x00003800, 0x00001c00, 0x00000e00, 0x00000700, 0x00000380, 0x000001c0, 0x000000e0, 0x00000070, 0x00000020, 0x00000000 } }; unsigned long int beam_ur_dl[16][29] = { { 0x00000000, 0x00000020, 0x00000070, 0x000000e0, 0x000001c0, 0x00000380, 0x00000700, 0x00000e00, 0x00001c00, 0x00003800, 0x00007000, 0x0000e000, 0x0001c000, 0x00038000, 0x00070000, 0x000e0000, 0x001c0000, 0x00380000, 0x00700000, 0x00e00000, 0x01c00000, 0x03800000, 0x07000000, 0x0e000000, 0x1c000000, 0x38000000, 0x70000000, 0x20000000, 0x00000000 }, { 0x00000000, 0x00000020, 0x00000070, 0x000000e0, 0x000001c0, 0x00000380, 0x00000700, 0x00000e00, 0x00001c00, 0x00003800, 0x00007000, 0x0000e000, 0x0001c000, 0x00038000, 0x00070000, 0x000e0000, 0x001c0000, 0x00380000, 0x00700000, 0x00e00000, 0x01c00000, 0x03800000, 0x07000000, 0x0e000000, 0x1c000000, 0x38000000, 0x70000000, 0x20000000, 0x00000000 }, { 0x00000000, 0x00000060, 0x00000070, 0x000000e0, 0x000001c0, 0x00000780, 0x00000700, 0x00000e00, 0x00001c00, 0x00003800, 0x00007000, 0x0001e000, 0x0001c000, 0x00078000, 0x000f8000, 0x000e0000, 0x003c0000, 0x00380000, 0x00f00000, 0x00f00000, 0x01c00000, 0x07800000, 0x07000000, 0x0e000000, 0x1c000000, 0x38000000, 0x70000000, 0x20000000, 0x00000000 }, { 0x00000000, 0x00000020, 0x00000070, 0x000000e0, 0x000001c0, 0x00000380, 0x00000700, 0x00000e00, 0x00001c00, 0x00003c00, 0x00007000, 0x0001f000, 0x0003c000, 0x00038000, 0x00078000, 0x000e0000, 0x003c0000, 0x00780000, 0x00700000, 0x00f00000, 0x01e00000, 0x03c00000, 0x0f000000, 0x0f000000, 0x1e000000, 0x78000000, 0x70000000, 0x20000000, 0x00000000 }, { 0x00000000, 0x00000060, 0x000000f0, 0x000003e0, 0x000003e0, 0x00000f80, 0x00000780, 0x00000e00, 0x00003d00, 0x00007c00, 0x0000f000, 0x0001e000, 0x0005e000, 0x00078000, 0x00070000, 0x001f0000, 0x003e0000, 0x003e0000, 0x01f80000, 0x02e00000, 0x07c00000, 0x0fc00000, 0x07000000, 0x0e000000, 0x3e000000, 0xfc000000, 0x7c000000, 0x28000000, 0x00000000 }, { 0x00000000, 0x00000020, 0x00000070, 0x000000e0, 0x000001f0, 0x00000780, 0x00000700, 0x00003f00, 0x00003e00, 0x00003800, 0x0000f400, 0x0001f000, 0x0001d000, 0x0003c000, 0x000f4000, 0x001e0000, 0x007c0000, 0x003c0000, 0x01f40000, 0x01f80000, 0x01f00000, 0x03800000, 0x1f400000, 0x2e000000, 0x1c000000, 0x78000000, 0x78000000, 0x30000000, 0x00000000 }, { 0x00000000, 0x000000e0, 0x000000f0, 0x000003f0, 0x000001e0, 0x00000ba0, 0x00000780, 0x00000e80, 0x00001c00, 0x0000bc00, 0x00017800, 0x0001f000, 0x0003e000, 0x00038000, 0x000f4000, 0x003e0000, 0x001e0000, 0x003c0000, 0x00f80000, 0x02e00000, 0x03c00000, 0x07800000, 0x17800000, 0x1e000000, 0x3c000000, 0xfc000000, 0x7c000000, 0x28000000, 0x00000000 }, { 0x00000040, 0x00000060, 0x000001f0, 0x000001f8, 0x000003f0, 0x000007e0, 0x00000fc0, 0x00005f00, 0x00007f80, 0x00007c00, 0x0000fa00, 0x0001f000, 0x0007e000, 0x000fe000, 0x003fc000, 0x001f8000, 0x007e0000, 0x00fd0000, 0x03f80000, 0x01f00000, 0x03f00000, 0x07d00000, 0x3fc00000, 0x7f000000, 0x3f000000, 0xff000000, 0x78000000, 0x30000000, 0x18000000 }, { 0x00000040, 0x000001e0, 0x000000f0, 0x000003f0, 0x000007e0, 0x000007c0, 0x00000f80, 0x00005f40, 0x0000be00, 0x00017e00, 0x0000fc00, 0x0003f000, 0x0007f000, 0x000fc000, 0x000fe000, 0x003f4000, 0x00bf8000, 0x00fc0000, 0x03fc0000, 0x03f80000, 0x0be00000, 0x0fc00000, 0x1f800000, 0x5f000000, 0xff000000, 0x7d000000, 0x78000000, 0x38000000, 0x00000000 }, { 0x00000040, 0x00000060, 0x000001f0, 0x000005f0, 0x000003e8, 0x00000fc0, 0x00001fa0, 0x00001f00, 0x00007f00, 0x00007c00, 0x0000fc00, 0x0005f000, 0x0007f000, 0x000fd000, 0x001f8000, 0x007f0000, 0x003f8000, 0x01fc0000, 0x01fc0000, 0x03f00000, 0x07e00000, 0x1fe00000, 0x1f800000, 0x3f000000, 0x3f800000, 0xfe000000, 0x7e000000, 0x30000000, 0x00000000 }, { 0x00000040, 0x00000020, 0x000000f0, 0x000001e0, 0x000005e0, 0x000003c0, 0x00000780, 0x00001e00, 0x00003e00, 0x0000fa00, 0x0001f000, 0x0001f000, 0x0001d000, 0x0007c000, 0x000f8000, 0x003e0000, 0x001e0000, 0x007a0000, 0x00700000, 0x00f00000, 0x01f00000, 0x07800000, 0x17000000, 0x1f000000, 0x3c000000, 0xfe000000, 0x78000000, 0x20000000, 0x00000000 }, { 0x00000000, 0x00000020, 0x000000f0, 0x000001f8, 0x000005e0, 0x000003a0, 0x00000780, 0x00000f00, 0x00007c00, 0x0000ba00, 0x0001f800, 0x0001f000, 0x0003f000, 0x00078000, 0x00070000, 0x001f0000, 0x003f0000, 0x00bc0000, 0x00f00000, 0x02f00000, 0x05c00000, 0x03c00000, 0x07800000, 0x2e000000, 0x5c000000, 0x7e000000, 0x74000000, 0x30000000, 0x10000000 }, { 0x00000000, 0x00000020, 0x000000f0, 0x000000e0, 0x000005e0, 0x00000780, 0x00000f80, 0x00001f00, 0x00001f00, 0x0000f800, 0x00007800, 0x0000f000, 0x0005c000, 0x00078000, 0x00178000, 0x002f8000, 0x003e0000, 0x00bc0000, 0x01f00000, 0x01e00000, 0x01c00000, 0x03c00000, 0x0f800000, 0x1e000000, 0x3c000000, 0x38000000, 0x70000000, 0x30000000, 0x00000000 }, { 0x00000000, 0x00000020, 0x00000070, 0x000000e0, 0x000003e0, 0x00000380, 0x00000700, 0x00000f00, 0x00001c00, 0x00007800, 0x0000f000, 0x0000e000, 0x0001e000, 0x00078000, 0x00070000, 0x001e0000, 0x001c0000, 0x00380000, 0x00700000, 0x00e00000, 0x01e00000, 0x07800000, 0x07000000, 0x0f000000, 0x3c000000, 0x38000000, 0x78000000, 0x20000000, 0x00000000 }, { 0x00000000, 0x00000020, 0x00000070, 0x000000e0, 0x000001c0, 0x000003c0, 0x00000700, 0x00000e00, 0x00001c00, 0x00003c00, 0x00007800, 0x0000f000, 0x0001c000, 0x0007c000, 0x00070000, 0x000e0000, 0x003c0000, 0x00380000, 0x00780000, 0x00e00000, 0x01c00000, 0x07800000, 0x0f000000, 0x0e000000, 0x1c000000, 0x38000000, 0x78000000, 0x20000000, 0x00000000 }, { 0x00000000, 0x00000020, 0x00000070, 0x000000e0, 0x000001c0, 0x00000380, 0x00000700, 0x00000e00, 0x00001c00, 0x00003800, 0x00007000, 0x0000e000, 0x0001c000, 0x00038000, 0x00070000, 0x000e0000, 0x001c0000, 0x00380000, 0x00700000, 0x00e00000, 0x01c00000, 0x03800000, 0x07000000, 0x0e000000, 0x1c000000, 0x38000000, 0x70000000, 0x20000000, 0x00000000 } }; #else unsigned long int beam_h[16][8] = { { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 }, { 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00, 0xffffff00 } }; unsigned long int beam_v[16][24] = { { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 }, { 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000, 0x000ff000 } }; unsigned long int beam_ul_dr[16][29] = { { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 }, { 0x18000000, 0x3c000000, 0x7e000000, 0xff000000, 0xff800000, 0x7fc00000, 0x3fe00000, 0x1ff00000, 0x0ff80000, 0x07fc0000, 0x03fe0000, 0x01ff0000, 0x00ff8000, 0x007fc000, 0x003fe000, 0x001ff000, 0x000ff800, 0x0007fc00, 0x0003fe00, 0x0001ff00, 0x0000ff80, 0x00007fc0, 0x00003fe0, 0x00001ff0, 0x00000ff8, 0x000007f8, 0x000003f0, 0x000001e0, 0x000000c0 } }; unsigned long int beam_ur_dl[16][29] = { { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 }, { 0x000000c0, 0x000001e0, 0x000003f0, 0x000007f8, 0x00000ff8, 0x00001ff0, 0x00003fe0, 0x00007fc0, 0x0000ff80, 0x0001ff00, 0x0003fe00, 0x0007fc00, 0x000ff800, 0x001ff000, 0x003fe000, 0x007fc000, 0x00ff8000, 0x01ff0000, 0x03fe0000, 0x07fc0000, 0x0ff80000, 0x1ff00000, 0x3fe00000, 0x7fc00000, 0xff800000, 0xff000000, 0x7e000000, 0x3c000000, 0x18000000 } }; #endif static int beam_xoff[] = { [DIR_U] 8, [DIR_D] 8, [DIR_L] 0, [DIR_R] 24, [DIR_UR] 47-26, [DIR_DR] 47-26, [DIR_DL] -2, [DIR_UL] -2 }; static int beam_yoff[] = { [DIR_U] 0, [DIR_D] 24, [DIR_L] 20, [DIR_R] 20, [DIR_UR] -2, [DIR_DR] 47-26, [DIR_DL] 47-26, [DIR_UL] -2 }; static int beam_nv[] = { [DIR_U] 24, [DIR_D] 24, [DIR_L] 8, [DIR_R] 8, [DIR_UR] 29, [DIR_DR] 29, [DIR_DL] 29, [DIR_UL] 29 }; static void setcmap(int bit) { int i; int x; bt->addr = 0; for (i=0;i<256;i++) { x = (bit ? (i>>4) : i) & 15; bt->cmap = cmap[x][0] * 0x01000000; bt->cmap = cmap[x][1] * 0x01000000; bt->cmap = cmap[x][2] * 0x01000000; } } static void drain(void) { while (fb->s & 0x10000000) ; } static void draw(void) { while ((fb->draw & 0xa0000000) == 0xa0000000) ; } static void setpm(int pm) { if (pm != fbpm) { fbpm = pm; fb->pm = pm; } } static void setfg(int fg) { fg = (fg & 15) * 0x11; if (fg != fbfg) { fbfg = fg; fb->fg = fg; } } static void setalu(int alu) { alu = (alu & 0x0000ffff) | ALU_NORMAL; if (alu != fbalu) { fbalu = alu; fb->alu = alu; } } static void setmode(int mode) { mode |= MODE_NORMAL; if (mode != fbmode) { fbmode = mode; fb->mode = mode; } } static void fbrrect(int fg, int x1, int y1, int x2, int y2) { setfg(fg); fb->arecty = y1; fb->arectx = x1; fb->rrecty = y2; fb->rrectx = x2; draw(); } static void fbrlines(int fg, int nl, int x0, int y0, ...) { va_list ap; int x; int y; setfg(fg); fb->aliney = y0 + YOFF; fb->alinex = x0 + XOFF; va_start(ap,y0); for (;nl>0;nl--) { x = va_arg(ap,int); y = va_arg(ap,int); fb->rliney = y; fb->rlinex = x; draw(); } va_end(ap); } static void setupfb(void) { struct fbgattr a; fbfd = open(fbpath,O_RDWR,0); if (fbfd < 0) { fprintf(stderr,"%s: %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } if ( (ioctl(fbfd,FBIOGATTR,&a) < 0) || (a.fbtype.fb_type != FBTYPE_SUNFAST_COLOR) || (a.fbtype.fb_width != 1152) || (a.fbtype.fb_height != 900) || (a.fbtype.fb_depth != 8) ) { close(fbfd); fprintf(stderr,"%s: %s: not a cg6\n",__progname,fbpath); exit(1); } fbmaplen = 0x16000 + a.fbtype.fb_size; fbmap = mmap(0,fbmaplen,PROT_READ|PROT_WRITE,MAP_SHARED,fbfd,0x70000000); if (fbmap == MAP_FAILED) { fprintf(stderr,"%s: can't mmap %s: %s\n",__progname,fbpath,strerror(errno)); exit(1); } fb = fbmap; bt = (void *)(0x2000+(unsigned char *)fbmap); vram = 0x16000 + (unsigned char *)fbmap; drawbit = 0; fbfg = -1; fbpm = -1; fbalu = -1; fbmode = -1; fb->bg = 0; fb->pixelm = ~0; fb->s = 0; setmode(MODE_COLOR8); setalu(ALU_FG); fb->clip = 0; fb->offx = 0; fb->offy = 0; fb->incx = 0; fb->incy = 1; fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; drain(); fb->pm = ~0; fbrrect(CMAP_RGBBASE+COL_K,0,0,1151,899); drain(); fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; setpm(15); } static void setupkb(void) { int type; int mode; kbfd = open(kbpath,O_RDWR,0); if (kbfd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,kbpath,strerror(errno)); exit(1); } if ( (ioctl(kbfd,KIOCTYPE,&type) < 0) || (type != KB_SUN3) ) { close(kbfd); fprintf(stderr,"%s: %s isn't a type-3\n",__progname,kbpath); exit(1); } mode = 1; ioctl(kbfd,KIOCSDIRECT,&mode); mode = TR_UNTRANS_EVENT; ioctl(kbfd,KIOCTRANS,&mode); mode = 1; ioctl(kbfd,FIONBIO,&mode); kbflags = 0; } static void cancel_fuse(FUSE *f) { f->fn = 0; f->arg = 0; } static void limit_info(BCELL *c) { switch (c->c.type) { case BT_BLANK: c->c.color = 0; c->c.info = 0; c->c.canrot = 0; c->c.mobile = 0; break; case BT_COIN: case BT_TNT: case BT_LBENDER: case BT_SLIME: case BT_MINE: /* info unused */ break; case BT_LASER: case BT_MIRROR: case BT_PRISM: case BT_SPLITTER: case BT_DIODE: case BT_THREEWAY: case BT_RECOLOR: case BT_SELECTOR: case BT_COMPLEX: c->c.info &= 7; break; case BT_DBLMIR: case BT_REFRACT: case BT_DBLSLIT: case BT_MIR225: c->c.info &= 3; break; case BT_WALL: case BT_BLOCK: /* info used, but all 16 possible values meaningful */ break; case BT_FILTER: if (c->c.info >= 5) c->c.info = 0; break; default: abort(); break; } } static void slimechk(void) { int i; int n; int x; int y; SLIME *s; static void chkcell(BCELL *c) { if (c->c.type == BT_SLIME) n ++; } n = 0; for (x=0;xflink) { i --; if (i < 0) abort(); } if (i) abort(); i = n; for (s=slimes_b;s;s=s->blink) { i --; if (i < 0) abort(); } if (i) abort(); } static void editmousec(void) { limit_info(mousec); resetboard[mousecx][mousecy] = mousec->c; ldirty = 1; } static void anim_abort(BCELL *c) { if (c->c.type != BT_COIN) return; switch (c->animstate) { case ANIM_ENDING: cancel_fuse(c->animfuse); break; } c->animstate = ANIM_NO; } static void typespec_free(BCELL *c) { switch(c->c.type) { case BT_SLIME: { SLIME *s; s = c->typespec; if (s->flink) s->flink->blink = s->blink; else slimes_b = s->blink; if (s->blink) s->blink->flink = s->flink; else slimes_f = s->flink; free(s); c->typespec = 0; } break; } } static void typespec_init(BCELL *c) { c->typespec = 0; switch (c->c.type) { case BT_SLIME: { SLIME *s; s = malloc(sizeof(SLIME)); if (slimes_b == 0) slimes_f = s; else slimes_b->flink = s; s->flink = 0; s->blink = slimes_b; slimes_b = s; s->hdg = 0; bzero(&s->map[0],sizeof(s->map)); c->typespec = s; } break; } } static void typespec_copied(BCELL *c) { switch (c->c.type) { case BT_SLIME: { SLIME *s; s = malloc(sizeof(SLIME)); *s = *(SLIME *)c->typespec; c->typespec = s; } break; } } static void typespec_moved(BCELL *c) { switch (c->c.type) { case BT_SLIME: break; } } static void copybcell(BCELL *from, BCELL *to) { anim_abort(from); anim_abort(to); typespec_free(to); *to = *from; typespec_copied(to); } static void setblank(LCELL *c) { c->type = BT_BLANK; c->color = COL_K; c->info = 0; c->canrot = 0; c->mobile = 0; } static void movebcell(BCELL *from, BCELL *to) { anim_abort(from); anim_abort(to); typespec_free(to); *to = *from; typespec_moved(to); setblank(&from->c); } static void swapbcell(BCELL *a, BCELL *b) { BCELL t; anim_abort(a); anim_abort(b); t = *a; *a = *b; *b = t; typespec_moved(a); typespec_moved(b); } static int have_nplev(void) { int maxn; if (curlf->inx) return(1); maxn = have_npfile ? 14 : 16; if (editing) maxn --; if (curlf->nlevels > maxn) return(1); return(0); } static int morelevsbelow(void) { int maxn; maxn = have_npfile ? 14 : 16; if (have_nplev()) maxn -= 2; if (editing) maxn --; return(curlf->nlevels > curlf->inx+maxn); } static int inxoffset(void) { return(have_npfile+have_nplev()); } static int levonscreen(void) { return(16-(2*inxoffset())); } static void newmouseloc(void) { if (levelsel) { /* if we could count on division to round towards negative infinity, these next two lines would be (mouse - 1) / LEVSEL. */ mousecx = ((mousex + LEVSELW - 1) / LEVSELW) - 1; mousecy = ((mousey + LEVSELH - 1) / LEVSELH) - 1; mousec = 0; mouselfi = curlf->inx + mousecx + (mousecy * 4) - inxoffset(); if ( (mousecx < 0) || (mousecy < 0) || (mousecx > 3) || (mousecy > 3) || (mouselfi < curlf->inx) || (mouselfi >= curlf->inx+levonscreen()) ) { mouselfi = -1; } } else { mousecx = ((mousex + CELLW - 1) / CELLW) - 1; mousecy = ((mousey + CELLH - 1) / CELLH) - 1; if ( (mousecx < 0) || (mousecy < 0) || (mousecx >= GRIDX) || (mousecy >= GRIDY) ) { mousecx = -1; mousecy = -1; mousec = 0; } else { mousec = &board[mousecx][mousecy]; if (stickyclone && (mousec != stickyloc) && (mousec != stickyclone)) { copybcell(stickyclone,mousec); editmousec(); stickyloc = mousec; wantredo = 1; } } mouselfi = -1; } } static void setupms(void) { int mode; msfd = open(mspath,O_RDWR,0); if (msfd < 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,mspath,strerror(errno)); exit(1); } mode = 1; ioctl(msfd,FIONBIO,&mode); } static void initms(void) { mousex = MAXX / 2; mousey = MAXY / 2; newmouseloc(); } static void handle_sigalrm(int sig __attribute__((__unused__))) { hardtime ++; } static void setuptimer(void) { struct itimerval itv; struct sigaction sa; hardtime = 0; softtime = 0; drawtime = 0; queuetime = 0; sa.sa_handler = handle_sigalrm; sigemptyset(&sa.sa_mask); sa.sa_flags = SA_RESTART; sigaction(SIGALRM,&sa,0); itv.it_value.tv_sec = 0; itv.it_value.tv_usec = 10000; itv.it_interval = itv.it_value; setitimer(ITIMER_REAL,&itv,0); } static void initevq(void) { evqh = 0; evqt = 0; } static void fuse_bubble_up(void) { unsigned int x; unsigned int u; FUSE *fx; FUSE *fu; x = fuses_n - 1; fx = fuses[x]; while (x > 0) { u = (x-1) / 2; fu = fuses[u]; if (fx->when >= fu->when) break; fuses[x] = fu; x = u; } fuses[x] = fx; } static FUSE *add_fuse(int when, void (*fn)(void *), void *arg) { FUSE *f; f = malloc(sizeof(FUSE)); f->when = queuetime + when; f->fn = fn; f->arg = arg; if (fuses_n >= fuses_a) fuses = realloc(fuses,(fuses_a=fuses_n+6)*sizeof(FUSE *)); fuses[fuses_n++] = f; fuse_bubble_up(); return(f); } static void fuse_bubble_down(void) { unsigned int x; unsigned int l; unsigned int r; FUSE *fx; FUSE *fl; FUSE *fr; x = 0; fx = fuses[0]; while (x < fuses_n) { l = x + x + 1; r = l + 1; fl = (l < fuses_n) ? fuses[l] : 0; fr = (r < fuses_n) ? fuses[r] : 0; if (fl && (fl->when < fx->when)) { if (fr && (fr->when < fx->when)) { if (fl->when < fr->when) { fuses[x] = fl; x = l; } else { fuses[x] = fr; x = r; } } else { fuses[x] = fl; x = l; } } else { if (fr && (fr->when < fx->when)) { fuses[x] = fr; x = r; } else { break; } } } fuses[x] = fx; } static void setib(BCELL *c, int bits, BITMAP *cutbits) { int i; if (bits == 0) return; c->ibeams |= bits; for (i=0;i<24;i++) if ((bits >> i) & 1) c->cutbm[i] = cutbits; if (cutbits == 0) c->icut &= ~bits; else c->icut |= bits; } static void trace_beam(int x, int y, int color, int dir) { int o; BCELL *c; int i; int ib; while (1) { if (color == 0) return; o = color << BB_SHIFT(dir); c = &board[x][y]; if ((o & c->obeams) == o) return; c->obeams |= o; x += dir_d[dir][0]; y += dir_d[dir][1]; if ((x < 0) || (y < 0) || (x >= B_XSIZE) || (y >= B_YSIZE)) return; c = &board[x][y]; ib = color << BB_SHIFT(DIR_OTHER(dir)); setib(c,ib,0); i = c->c.info; switch (c->c.type) { default: abort(); break; case BT_BLANK: break; case BT_LASER: if (dir != DIR_OTHER(i)) setib(c,ib,c->c.canrot?&cut_laser_rot:&cut_laser_nrot[i]); return; break; case BT_MIRROR: i = DIR_OTHER(i); if (dir == i) { dir = DIR_OTHER(dir); } else if (dir == DIR_CW(i)) { dir = DIR_OTHER(DIR_CCW(i)); } else if (dir == DIR_CCW(i)) { dir = DIR_OTHER(DIR_CW(i)); } else { setib(c,ib,&cut_mirror[DIR_OTHER(i)]); return; } break; case BT_DBLMIR: if ((dir == i) || (dir == DIR_OTHER(i))) { dir = DIR_OTHER(dir); } else if (dir == DIR_CW(i)) { dir = DIR_OTHER(DIR_CCW(i)); } else if (dir == DIR_CCW(i)) { dir = DIR_OTHER(DIR_CW(i)); } else if (dir == DIR_OTHER(DIR_CW(i))) { dir = DIR_CCW(i); } else if (dir == DIR_OTHER(DIR_CCW(i))) { dir = DIR_CW(i); } else { setib(c,ib,&cut_dblmir[i]); return; } break; case BT_PRISM: if (dir == DIR_OTHER(i)) { trace_beam(x,y,color&COL_R,dir); dir = DIR_CW(dir); trace_beam(x,y,color&COL_G,dir); dir = DIR_CW(dir); color &= COL_B; } else if (dir == i) { setib(c,(color&~COL_R)<c.info]); return; break; case BT_FILTER: if ( (i != BI_FILTER_ALL) && (dir != i) && (dir != DIR_OTHER(i)) ) { setib(c,ib,&cut_filter); return; } if (color & ~c->c.color) { setib(c,(color&~c->c.color)<c.color; break; case BT_BLOCK: setib(c,ib,&cut_block); return; break; case BT_DIODE: if (dir != i) { setib(c,ib,&cut_diode[i]); return; } break; case BT_THREEWAY: if (dir == DIR_OTHER(i)) { trace_beam(x,y,color,DIR_CW(dir)); dir = DIR_CCW(dir); } else if ((dir == DIR_CW(i)) || (dir == DIR_CCW(i))) { dir = i; } else { setib(c,ib,&cut_threeway[i]); return; } break; case BT_RECOLOR: if (dir == i) { color = color_up_table[color]; } else if (dir == DIR_OTHER(i)) { color = color_dn_table[color]; } else { setib(c,ib,&cut_recolor[i]); return; } break; case BT_DBLSLIT: if ((dir == i) || (dir == DIR_OTHER(i))) { dir = DIR_OTHER(dir); } else if (dir == DIR_CW(i)) { dir = DIR_OTHER(DIR_CCW(i)); } else if (dir == DIR_CCW(i)) { dir = DIR_OTHER(DIR_CW(i)); } else if (dir == DIR_OTHER(DIR_CW(i))) { dir = DIR_CCW(i); } else if (dir == DIR_OTHER(DIR_CCW(i))) { dir = DIR_CW(i); } #if 0 else if ((dir == DIR_CW2(i)) || (dir == DIR_CCW2(i))) { /* do nothing */ } else { /* can't happen, all cases covered above! */ return; } #endif break; case BT_TNT: (*tntfn)(x,y); return; break; case BT_SELECTOR: if (dir == DIR_OTHER(i)) { trace_beam(x,y,color&~c->c.color,dir); dir = DIR_CW(dir); color &= c->c.color; } else if (dir != i) { setib(c,ib,&cut_selector[i]); return; } break; case BT_COMPLEX: if (dir == DIR_OTHER(i)) { trace_beam(x,y,color&~c->c.color,dir); dir = DIR_CW(dir); color &= c->c.color; } else if (dir == i) { if (color & c->c.color) setib(c,(color&c->c.color)<c.color; } else if (dir == DIR_CW(i)) { if (color & ~c->c.color) setib(c,(color&~c->c.color)<c.color; dir = i; } else { setib(c,ib,&cut_complex[i]); return; } break; case BT_LBENDER: dir = DIR_CW(dir); break; case BT_MIR225: { static const int dirtbl[DIR__N][DIR__N] /* beam: R UR U UL L DL D DR */ ={/*R */{ DIR_UR,DIR_R,DIR_DR,DIR_D,DIR_DL,DIR_L,DIR_UL,DIR_U }, /*UR*/{ DIR_UL,DIR_U,DIR_UR,DIR_R,DIR_DR,DIR_D,DIR_DL,DIR_L }, /*U */{ DIR_DL,DIR_L,DIR_UL,DIR_U,DIR_UR,DIR_R,DIR_DR,DIR_D }, /*UL*/{ DIR_DR,DIR_D,DIR_DL,DIR_L,DIR_UL,DIR_U,DIR_UR,DIR_R }}; dir = dirtbl[i][dir]; } break; case BT_SLIME: break; case BT_MINE: break; } } } static void anim_end(void *cv) { BCELL *c; c = cv; c->animstate = ANIM_NO; } static void anim_no(BCELL *c) { if (c->c.type != BT_COIN) return; switch (c->animstate) { case ANIM_YES: c->animfuse = add_fuse(((c->animoff+16-anim)&15)*ANIMDIV,anim_end,c); c->animstate = ANIM_ENDING; break; } } static void anim_yes(BCELL *c) { if (c->c.type != BT_COIN) return; switch (c->animstate) { case ANIM_NO: c->animstate = ANIM_YES; c->animoff = anim; break; case ANIM_ENDING: cancel_fuse(c->animfuse); c->animstate = ANIM_YES; break; } } static void animcheck(BCELL *c) { int i; static const unsigned long int mulvals[4] = { (1<c.type) { case BT_COIN: for (i=0;i<4;i++) { if (c->beams == c->c.color*mulvals[i]) { anim_yes(c); return; } } complete = 0; break; } anim_no(c); } static void clear_beams(void) { int x; int y; BCELL *c; for (x=0;xibeams = 0; c->obeams = 0; c->beams = 0; switch (c->c.type) { case BT_TNT: c->c.info = 0; break; } } } static void clear_mining(void) { int x; int y; for (x=0;xc.type != BT_TNT) abort(); if (c->c.info) return; c->c.info = 1; xy = malloc(sizeof(XYPAIR)); xy->x = x; xy->y = y; add_fuse(5+(rnd()&3),explode_neighbors,xy); if (! exploding) { discardcarry(); stopplaying(); complete = 0; exploding = 1; } } static void explode_neighbors(void *xyv) { XYPAIR *xy; BCELL *c; int i; int x; int y; if (exploding) { xy = xyv; for (i=0;i<8;i++) { y = xy->y + dir_d[i][1]; if ((y < 0) || (y >= GRIDY)) continue; x = xy->x + dir_d[i][0]; if ((x < 0) || (x >= GRIDX)) continue; c = &board[x][y]; if (c->c.type == BT_TNT) explodetnt(x,y); } } free(xyv); } static void redo_beams(void) { int x; int y; static void dontexplode(int x, int y) { board[x][y].c.info = 2; } exploding = 0; clear_beams(); tntfn = editing ? &dontexplode : &explodetnt; complete = !carrying; for (x=0;xf; if (! levelfiles_f) abort(); have_npfile = !!levelfiles_f->flink; newmouseloc(); droploc = 0; } static void queue_event(int ev) { if (((evqh-evqt) & (EVQ_SIZE-1)) == (EVQ_SIZE-1)) { write(1,"evq full\n",9); } else { evq[evqh] = ev; evqh = (evqh+1) & (EVQ_SIZE-1); } } static int checkkb(void) { struct firm_event ev; int r; r = read(kbfd,&ev,sizeof(ev)); if (r == sizeof(ev)) { rnd_tweak(&ev,sizeof(ev)); queue_event(EVT_KBD|(ev.id&0x7f)|((ev.value==VKEY_UP)?EVK_UP:EVK_DN)); return(1); } return(0); } static int checkms(void) { struct firm_event ev; int r; int v; r = read(msfd,&ev,sizeof(ev)); if (r == sizeof(ev)) { rnd_tweak(&ev,sizeof(ev)); switch (ev.id) { case MS_LEFT: v = EVM_BUT_L; if (0) { case MS_MIDDLE: v = EVM_BUT_M; } if (0) { case MS_RIGHT: v = EVM_BUT_R; } queue_event(EVT_MOUSE|EVM_T_BUT|v|((ev.value==VKEY_UP)?EVM_UP:EVM_DN)); break; case LOC_X_DELTA: v = EVM_T_DX; if (0) { case LOC_Y_DELTA: v = EVM_T_DY; } if (ev.value < 0) { queue_event(EVT_MOUSE|v|EVM_S_NEG|(EVM_DELTA&-ev.value)); } else { queue_event(EVT_MOUSE|v|EVM_S_POS|(EVM_DELTA&ev.value)); } break; default: printf("id %#x ignored from mouse\n",ev.id); break; } return(1); } return(0); } static int checktick(void) { int ht; ht = hardtime; if (softtime != ht) { queue_event(EVT_TICK); softtime ++; if ((softtime == ht) && (softtime >= drawtime)) queue_event(EVT_DRAW); return(1); } return(0); } static int dequeue_event(void) { int ev; if (evqh == evqt) return(EVT_NIL); ev = evq[evqt]; evqt = (evqt+1) & (EVQ_SIZE-1); return(ev); } static void check_fuses(void) { FUSE *f; while ((fuses_n > 0) && (fuses[0]->when <= queuetime)) { f = fuses[0]; if (f->fn) (*f->fn)(f->arg); free(f); fuses_n --; if (fuses_n > 0) { fuses[0] = fuses[fuses_n]; fuse_bubble_down(); } } } static void clearmsgfooter(void *arg __attribute__((__unused__))) { msgfooter = 0; } static void setmsgfooter(const char *msg) { if (msgfooter) cancel_fuse(msgfooter_fuse); msgfooter = msg; if (msg) msgfooter_fuse = add_fuse(100,clearmsgfooter,0); } static void mayberot(BCELL *cp, int dir) { if (cp->c.type == BT_BLANK) return; if (!cp->c.canrot && !editing) { setmsgfooter("This piece doesn't rotate"); return; } switch (cp->c.type) { case BT_LASER: case BT_MIRROR: case BT_PRISM: case BT_SPLITTER: case BT_DIODE: case BT_THREEWAY: case BT_RECOLOR: case BT_SELECTOR: case BT_COMPLEX: cp->c.info = dir ? DIR_CW(cp->c.info) : DIR_CCW(cp->c.info); wantredo = 1; break; case BT_DBLMIR: case BT_DBLSLIT: case BT_MIR225: cp->c.info = dir ? BDIR_CW(cp->c.info) : BDIR_CCW(cp->c.info); wantredo = 1; break; case BT_REFRACT: cp->c.info = dir ? BI_R_NEXT(cp->c.info) : BI_R_PREV(cp->c.info); wantredo = 1; break; case BT_WALL: cp->c.info = (cp->c.info + (dir?1:15)) & 15; wantredo = 1; break; case BT_FILTER: if (editing) { if (dir) { if (cp->c.info == 0) cp->c.info = BI_FILTER_ALL; else cp->c.info --; } else { if (cp->c.info == BI_FILTER_ALL) cp->c.info = 0; else cp->c.info ++; } } else { if (cp->c.info != BI_FILTER_ALL) { cp->c.info = dir ? BDIR_CW(cp->c.info) : BDIR_CCW(cp->c.info); } } wantredo = 1; break; case BT_BLOCK: cp->c.info = (cp->c.info + (dir?1:15)) & 15; break; } } static __inline__ int docopy(int, int) __attribute__((__const__)); static int docopy(int v, int old) { return((v==COPY)?old:v); } static void editset(int ev, int type) { if (! editing) return; if (carrying) { anim_abort(&carrycell); typespec_free(&carrycell); carrycell.c.type = type; limit_info(&carrycell); if (type == BT_BLANK) carrying = 0; } else if (mousec) { LCELL new; new.type = type; #define DEFINX(what,old,new) def##what[def##what##x[old]][def##what##x[new]] new.color = docopy(DEFINX(col,mousec->c.type,type),mousec->c.color); new.info = docopy(DEFINX(info,mousec->c.type,type),mousec->c.info); new.canrot = docopy(DEFINX(rot,mousec->c.type,type),mousec->c.canrot); new.mobile = docopy(DEFINX(mov,mousec->c.type,type),mousec->c.mobile); #undef DEFINX anim_abort(mousec); typespec_free(mousec); mousec->c = new; typespec_init(mousec); editmousec(); stickycode = ev & EVK_CODE; stickyclone = mousec; stickyloc = mousec; wantredo = 1; } } static void editcolor(int cbit) { if (!editing || (kbflags & KBF_S)) { flashrgb |= cbit; return; } if (carrying) { carrycell.c.color ^= cbit; limit_info(&carrycell); } else if (mousec) { mousec->c.color ^= cbit; editmousec(); wantredo = 1; } } static void editmodmove(void) { if (!editing || (kbflags & KBF_S)) { flashmov = 1; return; } if (carrying) { carrycell.c.mobile = ! carrycell.c.mobile; } else if (mousec) { mousec->c.mobile = ! mousec->c.mobile; editmousec(); } } static void editmodrot(void) { if (!editing || (kbflags & KBF_S)) { flashrot = 1; return; } if (carrying) { carrycell.c.canrot = ! carrycell.c.canrot; } else if (mousec) { mousec->c.canrot = ! mousec->c.canrot; editmousec(); } } static void editclone(int ev) { if (! editing) return; if (carrying && mousec) { copybcell(&carrycell,mousec); editmousec(); stickycode = ev & EVK_CODE; stickyclone = &carrycell; stickyloc = mousec; wantredo = 1; } } static void copytoreset(void) { int x; int y; for (x=0;x= B_XSIZE) || (y2 >= B_YSIZE)) continue; if (board[x2][y2].c.type != type) continue; if (board[x2][y2].beams) continue; anim_abort(&board[x][y]); typespec_free(&board[x][y]); setblank(&board[x][y].c); anim_abort(&board[x2][y2]); typespec_free(&board[x2][y2]); setblank(&board[x2][y2].c); return(1); } return(0); } static __inline__ int slime_isclr(SLIME *s, int x, int y, int hdg) { x += (y * B_XSIZE); return(!((s->map[x>>3]>>(((x&7)<<2)+hdg))&1)); } static int slime_canmove(int x, int y) { return( (x >= 0) && (y >= 0) && (x < B_XSIZE) && (y < B_YSIZE) && (board[x][y].c.type == BT_BLANK) && (board[x][y].beams == 0) ); } static __inline__ void slime_set(SLIME *s, int x, int y, int hdg) { x += (y * B_XSIZE); s->map[x>>3] |= 1UL << (((x&7)<<2)+hdg); } static void slime_move(int x, int y, int dir) { int x2; int y2; x2 = x + dir_d[dir][0]; y2 = y + dir_d[dir][1]; if ( (x2 < 0) || (y2 < 0) || (x2 >= B_XSIZE) || (y2 >= B_YSIZE) || (board[x2][y2].c.type != BT_BLANK) ) abort(); anim_abort(&board[x][y]); board[x2][y2].c = board[x][y].c; board[x2][y2].typespec = board[x][y].typespec; setblank(&board[x][y].c); typespec_moved(&board[x2][y2]); } static __inline__ int slime_allclr(SLIME *s, int x, int y) { x += (y * B_XSIZE); return(!((s->map[x>>3]>>((x&7)<<2))&15)); } static __inline__ void slime_clrall(SLIME *s, int x, int y) { x += (y * B_XSIZE); s->map[x>>3] &= ~(15UL << ((x&7)<<2)); } static void slime_tick(void *arg __attribute__((__unused__))) { int x; int y; BCELL *c; SLIME *s; int h; int hd; for (x=0;xc.type == BT_SLIME) { ((SLIME *)c->typespec)->done = 0; } } for (x=0;xc.type == BT_SLIME) { s = c->typespec; if (s->done) continue; if ( slime_eat(x,y,BT_MIRROR) || slime_eat(x,y,BT_TNT) ) continue; retry:; hd = slimehdg_to_dir[s->hdg]; if ( slime_isclr(s,x,y,s->hdg) && slime_canmove(x+dir_d[hd][0],y+dir_d[hd][1]) ) { slime_set(s,x,y,s->hdg); slime_move(x,y,hd); s->done = 1; continue; } for (h=(s->hdg+1)&3;h!=s->hdg;h=(h+1)&3) { hd = slimehdg_to_dir[h]; if ( slime_isclr(s,x,y,h) && slime_canmove(x+dir_d[hd][0],y+dir_d[hd][1]) ) break; } if (h != s->hdg) { s->hdg = (s->hdg + 3) & 3; s->done = 1; continue; } if (slime_allclr(s,x,y)) { s->done = 1; continue; } slime_clrall(s,x,y); goto retry; } } slimefuse = add_fuse(SLIME_TICKS,slime_tick,0); } static int anyslimes(void) { int x; int y; for (x=0;xcells[x][y]; typespec_init(&board[x][y]); } exploding = 0; ldirty = 0; wantredo = 1; if (! editing) startplaying(); } static void edittoggle(void) { if (! canedit) { setmsgfooter("Can't edit"); return; } if (levelsel) { if (lscarry) { setmsgfooter("Must dispose of the level you're carrying first"); return; } editing = ! editing; if (! curlf->f) { setmsgfooter("Note: can't edit this file"); } } else { if (carrying) { setmsgfooter("Must get rid of the piece you're carrying first"); return; } if (ldirty) { setmsgfooter("Must save or revert level first"); return; } if (! editing) stopplaying(); clear_mining(); editing = ! editing; if (! editing) startplaying(); if (editing) { copytoreset(); exploding = 0; } } } static int lnamelen(const char *lnbuf) { int i; for (i=LEVNAME_MAX-1;i>=0;i--) { if (lnbuf[i] != ' ') break; } return(i+1); } static void enameend(void) { enamecurs = lnamelen(&lname[0]); } static void editlevname(void) { if (! editing) return; if (enamecurs < 0) enameend(); ename = 1; } static void freesmall(LEVEL *l) { if (l->small) { free(l->small); l->small = 0; } } static void setleveldirty(LEVEL *l) { l->dirty = 1; l->fromfile->dirty = 1; freesmall(l); } static void stopautorepeat(void) { autorepeat = 0; if (autorepeat_fuse) { cancel_fuse(autorepeat_fuse); autorepeat_fuse = 0; } } static void enamedone(void) { int l; l = lnamelen(&lname[0]); curlevel->name = malloc(l+1); bcopy(&lname[0],curlevel->name,l); curlevel->name[l] = '\0'; setleveldirty(curlevel); stopautorepeat(); ename = 0; } static void enameleft(void) { if (enamecurs > 0) enamecurs --; } static void enameright(void) { if (enamecurs < LEVNAME_MAX) enamecurs ++; } static void enameins(char ch) { if (enamecurs >= LEVNAME_MAX) return; if (enamecurs < LEVNAME_MAX-1) bcopy(&lname[enamecurs],&lname[enamecurs+1],LEVNAME_MAX-1-enamecurs); lname[enamecurs] = ch; enameright(); } static void enamedell(void) { if (enamecurs < 1) return; bcopy(&lname[enamecurs],&lname[enamecurs-1],LEVNAME_MAX-enamecurs); lname[LEVNAME_MAX-1] = ' '; enameleft(); } static void enamedelr(void) { if (enamecurs < LEVNAME_MAX-1) bcopy(&lname[enamecurs+1],&lname[enamecurs],LEVNAME_MAX-1-enamecurs); lname[LEVNAME_MAX-1] = ' '; } static void uselevel(LEVEL *l) { int x; int y; for (x=0;xcells[x][y]; board[x][y].animstate = ANIM_NO; board[x][y].mined = 0; typespec_init(&board[x][y]); } setlevname(l->name); curlevel = l; exploding = 0; ldirty = 0; complete = 0; enamecurs = -1; wantredo = 1; } static void add_level_to_levelfile(LEVEL *lev, LEVELFILE *lf, int at) { int i; if (at < 0) at = lf->nlevels; lev->fromfile = lf; lev->fileinx = at; lf->nlevels ++; if (lf->nlevels > lf->alevels) { lf->levels = realloc(lf->levels,(lf->alevels=lf->nlevels)*sizeof(LEVEL *)); } for (i=lf->nlevels-1;i>at;i--) { lf->levels[i] = lf->levels[i-1]; lf->levels[i]->fileinx = i; } lf->levels[at] = lev; } static LEVEL *alloclevel(void) { LEVEL *l; l = malloc(sizeof(LEVEL)); l->name = 0; l->fromfile = 0; l->fileinx = 0; l->dirty = 1; l->small = 0; return(l); } static void newlevel(void) { int x; int y; lscarry = alloclevel(); for (x=0;xcells[x][y]); lscarry->name = strdup(""); } static LEVEL *clone_level(LEVEL *l) { LEVEL *n; n = alloclevel(); bcopy(&l->cells,&n->cells,sizeof(l->cells)); n->name = strdup(l->name); n->fromfile = 0; n->fileinx = 0; n->dirty = 1; n->small = 0; return(n); } static void lscopy(void) { if (levelsel && editing && (mouselfi >= 0) && (mouselfi < curlf->nlevels)) { lscarry = clone_level(curlf->levels[mouselfi]); } } static void delete_level_from_levelfile(LEVEL *l) { LEVELFILE *lf; int i; lf = l->fromfile; i = l->fileinx; lf->nlevels --; for (;inlevels;i++) { lf->levels[i] = lf->levels[i+1]; lf->levels[i]->fileinx = i; } l->fromfile = 0; l->fileinx = 0; } static void lsmove(void) { if (levelsel && editing && curlf->f && (mouselfi >= 0) && (mouselfi < curlf->nlevels)) { lscarry = curlf->levels[mouselfi]; lscarry->fromfile->dirty = 1; delete_level_from_levelfile(lscarry); } } static void levsel_click(int ev) { int x; int max; if ((mousecx < 0) || (mousecy < 0) || (mousecx > 3) || (mousecy > 3)) return; x = mousecx + (mousecy * 4); max = 15; if (have_npfile) { if (x == 0) { if (curlf->blink) curlf = curlf->blink; return; } if (x == max) { if (curlf->flink) curlf = curlf->flink; return; } x --; max -= 2; } if (have_nplev()) { if (x == 0) { curlf->inx -= 4; if (curlf->inx < 0) curlf->inx = 0; return; } if (x == max) { if (morelevsbelow()) curlf->inx += 4; return; } x --; max -= 2; } if (lscarry) { int prevhnpl; if (mouselfi < 0) { setmsgfooter("Must discard or click over a level space"); return; } if (! curlf->f) { setmsgfooter("This level file isn't editable"); return; } prevhnpl = have_nplev(); add_level_to_levelfile( lscarry, curlf, (mouselfi >= curlf->nlevels) ? curlf->nlevels : mouselfi ); if (have_nplev() && !prevhnpl) curlf->inx += 4; curlf->dirty = 1; lscarry = 0; return; } if ((mouselfi >= 0) && (mouselfi < curlf->nlevels)) { if (editing) { switch (ev & EVM_BUTID) { case EVM_BUT_L: if (! curlf->f) { setmsgfooter("This file isn't editable"); return; } lsmove(); return; break; case EVM_BUT_M: lscopy(); return; break; case EVM_BUT_R: break; } if (! curlf->f) { setmsgfooter("This file isn't editable"); return; } } uselevel(curlf->levels[mouselfi]); mousex = ((mousex - ((mousecx * LEVSELW) + 1)) * 4) + 1; mousey = ((mousey - ((mousecy * LEVSELH) + 1)) * 4) + 1; if (! editing) startplaying(); levelsel = 0; newmouseloc(); } } static void tosel(void) { int i; if (ldirty) { setmsgfooter("Must save or revert the level first"); return; } if (carrying && editing) { setmsgfooter("Must drop the piece you're carrying first"); return; } if (! editing) stopplaying(); while (curlf->inx > curlevel->fileinx) { curlf->inx -= 4; if (curlf->inx < 0) curlf->inx = 0; } while (curlf->inx+16-(have_npfile?2:0)-(have_nplev()?2:0) < curlevel->fileinx) { curlf->inx += 4; } i = (curlevel->fileinx - curlf->inx) + (have_npfile?1:0) + (have_nplev()?1:0); mousex = ((mousex - 1) / 4) + ((i & 3) * LEVSELW) + 1; mousey = ((mousey - 1) / 4) + ((i >> 2) * LEVSELH) + 1; levelsel = 1; carrying = 0; newmouseloc(); } static void savelevel(void) { int x; int y; if (! ldirty) return; if (!canedit || !curlevel->fromfile->f) abort(); for (x=0;xcells[x][y] = resetboard[x][y]; } setleveldirty(curlevel); ldirty = 0; } static void writelevelfile(LEVELFILE *lf) { int lno; void *h; h = write_file_header(lf->f,VERS_UNSPEC); for (lno=0;lnonlevels;lno++) { write_file_level(h,&lf->levels[lno]->cells[0],lf->levels[lno]->name); lf->levels[lno]->dirty = 0; } write_file_done(h); fflush(lf->f); ftruncate(fileno(lf->f),ftell(lf->f)); lf->dirty = 0; } static void savelevelfile(void) { if (! curlf->dirty) return; if (! curlf->f) abort(); fseek(curlf->f,0,SEEK_SET); writelevelfile(curlf); } static void carrydrop(void) { movebcell(&carrycell,mousec); carrying = 0; if (editing) editmousec(); } static void inlevel_click(int ev) { switch (ev & EVM_BUTID) { case EVM_BUT_L: if (mousec) { if (carrying) { if (mousec->c.type == BT_BLANK) { carrydrop(); } else if ((mousec->c.type == BT_MINE) && !editing) { droploc = mousec; } else if (editing || mousec->c.mobile) { swapbcell(mousec,&carrycell); if (editing) editmousec(); if ((kbflags & KBF_S) && (carryfrom->c.type == BT_BLANK)) { mousec = carryfrom; carrydrop(); } } wantredo = 1; } else if ( (editing || mousec->c.mobile) && (mousec->c.type != BT_BLANK) && !exploding ) { carryx = mousecx; carryy = mousecy; movebcell(mousec,&carrycell); carryfrom = mousec; carrying = 1; if (editing) editmousec(); wantredo = 1; } } break; case EVM_BUT_M: if (carrying) { mayberot(&carrycell,0); } else if (mousec && !exploding) { mayberot(mousec,0); if (editing) editmousec(); } break; case EVM_BUT_R: if (carrying) { mayberot(&carrycell,1); } else if (mousec && !exploding) { mayberot(mousec,1); if (editing) editmousec(); } break; } } static void confirm(const char *msg, void (*fn)(int, void *), void *arg) { confirming = msg; confirm_fn = fn; confirm_arg = arg; } static void free_level(LEVEL *l) { freesmall(l); free(l->name); free(l); } static void reallydelete(int really, void *arg) { if (! really) return; ((LEVEL *)arg)->fromfile->dirty = 1; delete_level_from_levelfile(arg); free_level(arg); } static void deletelevel(void) { if (levelsel && editing && curlf->f && (mouselfi >= 0) && (mouselfi < curlf->nlevels)) { confirm("Delete this level?",reallydelete,curlf->levels[mouselfi]); } } static void confirm_it(int how) { void (*fn)(int, void *); if (how < 0) { setmsgfooter("Y to confirm, N to cancel"); return; } fn = confirm_fn; confirming = 0; confirm_fn = 0; (*fn)(how,confirm_arg); } static void lsnew(void) { if (levelsel && editing && curlf->f && !lscarry) newlevel(); } static void kbd_confirm(int ev) { if ((ev & EVK_UPDN) == EVK_UP) return; switch (ev & EVK_CODE) { case 59: confirm_it(1); break; case 105: confirm_it(0); break; default: confirm_it(-1); break; } } static void abort_lscarry(int really, void *arg __attribute__((__unused__))) { if (! really) return; free_level(lscarry); lscarry = 0; } static void kbd_levelsel(int ev) { if ((ev & EVK_UPDN) == EVK_UP) return; if (lscarry) { switch (ev & EVK_CODE) { case 101: /* x */ confirm("Discard the level you're carrying?",abort_lscarry,0); break; } } else { switch (ev & EVK_CODE) { case 56: edittoggle(); break; /* e */ case 79: deletelevel(); break; /* d */ case 97: savelevelfile(); break; /* L10 */ case 102: lscopy(); break; /* c */ case 105: lsnew(); break; /* n */ case 106: lsmove(); break; /* m */ } } } static void ename_type(char ch) { if (ch < 32) { switch (ch) { case 1: enamecurs = 0; break; /* ^A */ case 2: enameleft(); break; /* ^B */ case 4: enamedelr(); break; /* ^D */ case 5: enameend(); break; /* ^E */ case 6: enameright(); break; /* ^F */ case 8: enamedell(); break; /* ^H */ case 10: enamedone(); break; /* ^J */ case 13: enamedone(); break; /* ^M */ } } else { enameins(ch); } } static void autorepeat_dup(void *arg __attribute__((__unused__))) { if (ename && autorepeat) { ename_type(autorepeat); autorepeat_fuse = add_fuse(6,autorepeat_dup,0); } else { autorepeat_fuse = 0; } } static void kbd_ename(int ev) { char ch; ch = '\0'; stopautorepeat(); if ((ev & EVK_UPDN) == EVK_UP) return; switch (ev & EVK_CODE) { default: printf("enk: %d\n",ev&EVK_CODE); break; #define NSC(nrm,shf,ctl) ( (kbflags & KBF_C) \ ? (ctl) \ : (kbflags & KBF_S) \ ? (shf) \ : (nrm) ) case 30: ch = NSC('1','!',0); break; case 31: ch = NSC('2','@',0); break; case 32: ch = NSC('3','#',0); break; case 33: ch = NSC('4','$',0); break; case 34: ch = NSC('5','%',0); break; case 35: ch = NSC('6','^',0); break; case 36: ch = NSC('7','&',0); break; case 37: ch = NSC('8','*',0); break; case 38: ch = NSC('9','(',0); break; case 39: ch = NSC('0',')',0); break; case 40: ch = NSC('-','_',0); break; case 41: ch = NSC('=','+',0); break; case 42: ch = NSC('`','~',0); break; case 54: ch = NSC('q','Q',17); break; case 55: ch = NSC('w','W',23); break; case 56: ch = NSC('e','E',5); break; case 57: ch = NSC('r','R',18); break; case 58: ch = NSC('t','T',20); break; case 59: ch = NSC('y','Y',25); break; case 60: ch = NSC('u','U',21); break; case 61: ch = NSC('i','I',9); break; case 62: ch = NSC('o','O',15); break; case 63: ch = NSC('p','P',16); break; case 64: ch = NSC('[',']',0); break; case 65: ch = NSC('{','}',0); break; case 77: ch = NSC('a','A',1); break; case 78: ch = NSC('s','S',19); break; case 79: ch = NSC('d','D',4); break; case 80: ch = NSC('f','F',6); break; case 81: ch = NSC('g','G',7); break; case 82: ch = NSC('h','H',8); break; case 83: ch = NSC('j','J',10); break; case 84: ch = NSC('k','K',11); break; case 85: ch = NSC('l','L',12); break; case 86: ch = NSC(';',':',0); break; case 87: ch = NSC('\'','"',0); break; case 88: ch = NSC('\\','|',0); break; case 89: ch = 10; break; /* RETURN */ case 91: ch = 2; break; /* <- */ case 93: ch = 6; break; /* -> */ case 100: ch = NSC('z','Z',26); break; case 101: ch = NSC('x','X',24); break; case 102: ch = NSC('c','C',3); break; case 103: ch = NSC('v','V',22); break; case 104: ch = NSC('b','B',2); break; case 105: ch = NSC('n','N',14); break; case 106: ch = NSC('m','M',13); break; case 107: ch = NSC(',','<',0); break; case 108: ch = NSC('.','>',0); break; case 109: ch = NSC('/','?',0); break; case 111: ch = 8; break; /* DELETE */ case 121: ch = NSC(' ',' ',0); break; } if (ch) { autorepeat = ch; autorepeat_fuse = add_fuse(50,autorepeat_dup,0); ename_type(ch); } } static void norm_space(void) { if (canedit) { editset(121,BT_BLANK); } else if (complete) { LEVELFILE *lf; int x; stopplaying(); lf = curlevel->fromfile; x = curlevel->fileinx; x ++; while (x >= lf->nlevels) { x = 0; lf = lf->flink; if (lf == 0) return; curlf = lf; } uselevel(lf->levels[x]); startplaying(); } else if (exploding) { resetlevel(); } } static void sweep(void) { int dx; int dy; int x; int y; BCELL *c; LCELL tmp; #define ADV(xvar,yvar) do { yvar ++; if (yvar >= B_YSIZE) { yvar = 0; xvar ++; } } while (0) if (exploding) return; dx = 0; dy = 0; x = 0; y = 0; do { c = &board[x][y]; if (c->c.mobile && (c->beams == 0)) { anim_abort(c); typespec_free(c); tmp = c->c; setblank(&c->c); while ((board[dx][dy].c.type != BT_BLANK) || board[dx][dy].beams) ADV(dx,dy); board[dx][dy].c = tmp; typespec_init(&board[dx][dy]); if (editing) { resetboard[x][y].type = BT_BLANK; resetboard[dx][dy] = tmp; ldirty = 1; } } ADV(x,y); } while (x < B_XSIZE); wantredo = 1; #undef ADV } static void kbd_normal(int ev) { if ((ev & EVK_UPDN) == EVK_UP) { if ((ev & EVK_CODE) == stickycode) { stickycode = -1; stickyclone = 0; stickyloc = 0; } switch (ev & EVK_CODE) { case 58: flashrot = 0; break; /* t */ case 103: flashmov = 0; break; /* v */ case 57: flashrgb &= ~COL_R; break; /* r */ case 81: flashrgb &= ~COL_G; break; /* g */ case 104: flashrgb &= ~COL_B; break; /* b */ } return; } switch (ev & EVK_CODE) { case 1: tosel(); break; /* L1 */ case 3: resetlevel(); break; /* L2 */ #if 0 /* unused keys: */ case 31: /* 2 */ case 32: /* 3 */ case 35: /* 6 */ case 36: /* 7 */ case 37: /* 8 */ case 38: /* 9 */ case 39: /* 0 */ case 40: /* - */ case 41: /* = */ case 42: /* ` */ case 60: /* u */ case 61: /* i */ case 62: /* o */ case 64: /* [ */ case 65: /* { *//*}*/ case 83: /* j */ case 86: /* ; */ case 87: /* ' */ case 88: /* \ */ case 107: /* , */ case 108: /* . */ #endif case 30: editset(ev,BT_DIODE); break; /* 1 */ case 33: editset(ev,BT_SELECTOR); break; /* 4 */ case 34: editset(ev,BT_COMPLEX); break; /* 5 */ case 54: editset(ev,BT_LBENDER); break; /* q */ case 55: editset(ev,BT_WALL); break; /* w */ case 56: edittoggle(); break; /* e */ case 57: editcolor(COL_R); break; /* r */ case 58: editmodrot(); break; /* t */ case 59: editset(ev,BT_THREEWAY); break; /* y */ case 63: editset(ev,BT_PRISM); break; /* p */ case 77: editset(ev,BT_REFRACT); break; /* a */ case 78: /* s */ editset(ev,(kbflags&KBF_S)?BT_SLIME:BT_SPLITTER); break; case 79: /* d */ editset(ev,(kbflags&KBF_S)?BT_DBLSLIT:BT_DBLMIR); break; case 80: editset(ev,BT_FILTER); break; /* f */ case 81: editcolor(COL_G); break; /* g */ case 82: editset(ev,BT_RECOLOR); break; /* h */ case 84: editset(ev,BT_BLOCK); break; /* k */ case 85: editset(ev,BT_LASER); break; /* l */ case 95: sweep(); break; /* L9 */ case 97: savelevel(); break; /* L10 */ case 100: editclone(ev); break; /* z */ case 101: /* x */ editset(ev,(kbflags&KBF_S)?BT_MINE:BT_TNT); break; case 102: editset(ev,BT_COIN); break; /* c */ case 103: editmodmove(); break; /* v */ case 104: editcolor(COL_B); break; /* b */ case 105: editlevname(); break; /* n */ case 106: editset(ev,BT_MIRROR); break; /* m */ case 109: editset(ev,BT_MIR225); break; /* / */ case 121: norm_space(); break; /* space */ case 25: break; /* L3 */ case 26: break; /* L4 */ case 49: break; /* L5 */ case 51: break; /* L6 */ case 72: break; /* L7 */ case 73: break; /* L8 */ } } static void selfsuspend(void) { unsigned long int ht; unsigned long int v; int i; sigset_t mask; sigset_t omask; drain(); close(fbfd); close(kbfd); close(msfd); munmap(fbmap,fbmaplen); kill(0,SIGTSTP); setupfb(); setupkb(); setupms(); sigemptyset(&mask); sigaddset(&mask,SIGALRM); sigprocmask(SIG_BLOCK,&mask,&omask); sigdelset(&omask,SIGALRM); ht = hardtime; for (i=0;i<25;i++) { while (1) { v = hardtime; if (v != ht) break; sigsuspend(&omask); } ht = v; } sigprocmask(SIG_SETMASK,&omask,0); } static void process_evq(void) { int ev; slimechk(); while (1) { ev = dequeue_event(); switch (ev & EV_TYPE) { case EVT_NIL: return; break; case EVT_KBD: if (showkbd) printf("%d %s\n",ev&EVK_CODE,((ev&EVK_UPDN)==EVK_UP)?"up":"dn"); switch (ev & (EVK_CODE|EVK_UPDN)) { case 76|EVK_DN: kbflags |= KBF_C; continue;break; /* Control */ case 76|EVK_UP: kbflags &=~KBF_C; continue;break; case 99|EVK_DN: kbflags |= KBF_SL; continue;break; /* L Shift */ case 99|EVK_UP: kbflags &=~KBF_SL; continue;break; case 110|EVK_DN: kbflags |= KBF_SR; continue;break; /* R Shift */ case 110|EVK_UP: kbflags &=~KBF_SR; continue;break; case 5|EVK_DN: debug ++; continue;break; /* F1 */ case 23|EVK_DN: selfsuspend(); break; /* R3 */ case 29|EVK_DN: exit(0); break; /* ESC */ } if (confirming) kbd_confirm(ev); else if (levelsel) kbd_levelsel(ev); else if (ename) kbd_ename(ev); else kbd_normal(ev); break; case EVT_TICK: queuetime ++; animinc ++; if (animinc > ANIMDIV) { animinc = 0; anim = (anim + 1) & 15; } check_fuses(); break; case EVT_DRAW: wantrender = 1; break; case EVT_MOUSE: switch (ev & EVM_TYPE) { case EVM_T_DX: switch (ev & EVM_SIGN) { case EVM_S_NEG: mousex -= ev & EVM_DELTA; if (mousex < 0) mousex = 0; break; case EVM_S_POS: mousex += ev & EVM_DELTA; if (mousex >= MAXX) mousex = MAXX - 1; break; } newmouseloc(); break; case EVM_T_DY: switch (ev & EVM_SIGN) { case EVM_S_NEG: mousey += ev & EVM_DELTA; if (mousey >= MAXY) mousey = MAXY - 1; break; case EVM_S_POS: mousey -= ev & EVM_DELTA; if (mousey < 0) mousey = 0; break; } newmouseloc(); break; case EVM_T_BUT: switch (ev & EVM_UPDN) { case EVM_DN: if (levelsel) { levsel_click(ev); } else { inlevel_click(ev); } break; case EVM_UP: break; } break; } break; } } } static void process_bitmap(BITMAP *b) { int c; int x; int y; int need; unsigned long int *pd; const char *dp; b->pcols = how_many(b->w,32); x = 18 * b->pcols * b->h; pd = malloc(x*sizeof(unsigned long int)); bzero(pd,x*sizeof(unsigned long int)); need = 0; dp = b->data; for (y=0;yh;y++) for (x=0;xw;x++) { switch (*dp++) { case '.': c = -1; break; case '1': c = CMAP_BMCOLOR_1; break; case 'n': c = CMAP_HEADER; break; case 'e': c = CMAP_CELLEDGE; break; case '-': c = CMAP_BG; break; case 'k': c = CMAP_RGBBASE + COL_K; break; case 'r': c = CMAP_RGBBASE + COL_R; break; case 'g': c = CMAP_RGBBASE + COL_G; break; case 'b': c = CMAP_RGBBASE + COL_B; break; case 'c': c = CMAP_RGBBASE + COL_C; break; case 'm': c = CMAP_RGBBASE + COL_M; break; case 'y': c = CMAP_RGBBASE + COL_Y; break; case 'w': c = CMAP_RGBBASE + COL_W; break; case '*': c = CMAP_RGBBASE + COL_PC; break; case '~': c = CMAP_RGBBASE + COL_CPC; break; default: fprintf(stderr,"%s: invalid character `%c' in bitmap data\n",__progname,dp[-1]); abort(); break; } if (c != -1) { pd[(((c*b->pcols)+(x>>5))*b->h)+y] |= 1 << (31 - (x & 31)); need |= 1 << c; } } b->processed = 1; b->need = need; b->pdata = pd; } static void draw_bits_1(int x, int y, BITMAP *bm, int o) { unsigned long int *pb; int c; int wl; int r; pb = bm->pdata + (o * bm->pcols * bm->h); wl = bm->w; for (c=0;cpcols;c++) { fb->x0 = x; fb->x1 = x + ((wl > 31) ? 31 : wl); fb->y0 = y; for (r=bm->h;r>0;r--) fb->font = *pb++; x += 32; wl -= 32; } } static void draw_bits_2(int x, int y, BITMAP *bm, int o1, int o2) { unsigned long int *pb1; unsigned long int *pb2; int c; int wl; int r; pb1 = bm->pdata + (o1 * bm->pcols * bm->h); pb2 = bm->pdata + (o2 * bm->pcols * bm->h); wl = bm->w; for (c=0;cpcols;c++) { fb->x0 = x; fb->x1 = x + ((wl > 31) ? 31 : wl); fb->y0 = y; for (r=bm->h;r>0;r--) fb->font = *pb1++ | *pb2++; x += 32; wl -= 32; } } static void draw_bitmap(int x, int y, BITMAP *bm, int color) { int c; if (! bm->processed) process_bitmap(bm); for (c=0;c<16;c++) { if (c == CMAP_RGBBASE+color) { if (bm->need & ((1 << c) | (1 << (CMAP_RGBBASE+COL_PC)))) { setmode(MODE_COLOR1); setalu((ALU_FG&ALU_SRC)|(ALU_DST&~ALU_SRC)); setfg(c); draw_bits_2(x,y,bm,c,16); } } else if (c == CMAP_RGBBASE+(color^7)) { if (bm->need & ((1 << c) | (1 << (CMAP_RGBBASE+COL_CPC)))) { setmode(MODE_COLOR1); setalu((ALU_FG&ALU_SRC)|(ALU_DST&~ALU_SRC)); setfg(c); draw_bits_2(x,y,bm,c,17); } } else { if (bm->need & (1 << c)) { setmode(MODE_COLOR1); setalu((ALU_FG&ALU_SRC)|(ALU_DST&~ALU_SRC)); setfg(c); draw_bits_1(x,y,bm,c); } } } } static void render_cell(BCELL *c, int x, int y, int small, void (*fn)(int, int, BITMAP *, int)) { switch (c->c.type) { case BT_BLANK: if (c->mined) (*fn)(x,y,&mined_bitmap,COL_K); break; case BT_LASER: (*fn)(x,y,&laser_bitmap[c->c.canrot][c->c.info][anim][small],c->c.color); break; case BT_MIRROR: (*fn)(x,y,&mirror_bitmap[c->c.info][small],COL_K); break; case BT_DBLMIR: (*fn)(x,y,&dblmir_bitmap[c->c.info][small],COL_K); break; case BT_PRISM: (*fn)(x,y,&prism_bitmap[c->c.info][small],COL_K); break; case BT_SPLITTER: (*fn)(x,y,&splitter_bitmap[c->c.info][small],COL_K); break; case BT_REFRACT: (*fn)(x,y,&refract_bitmap[c->c.info][small],COL_K); break; case BT_COIN: switch (c->animstate) { case ANIM_YES: case ANIM_ENDING: (*fn)(x,y,&coin_bitmap[(anim+16-c->animoff)&15][small],c->c.color); if ((rnd() & 127) == 0) c->animoff = (c->animoff + 1) & 15; break; case ANIM_NO: (*fn)(x,y,&coin_bitmap[0][small],c->c.color); break; } break; case BT_WALL: (*fn)(x,y,&wall_bitmap[c->c.info][small],COL_K); break; case BT_FILTER: (*fn)(x,y,&filter_bitmap[c->c.info][small],c->c.color); break; case BT_BLOCK: (*fn)(x,y,&block_bitmap[c->c.info][small],COL_K); break; case BT_DIODE: (*fn)(x,y,&diode_bitmap[c->c.info][small],COL_K); break; case BT_THREEWAY: (*fn)(x,y,&threeway_bitmap[c->c.info][small],COL_K); break; case BT_RECOLOR: (*fn)(x,y,&recolor_bitmap[c->c.info][small],COL_K); break; case BT_DBLSLIT: (*fn)(x,y,&dblslit_bitmap[c->c.info][small],COL_K); break; case BT_TNT: switch (c->c.info) { case 0: (*fn)(x,y,&tnt_bitmap[small],COL_K); break; case 1: (*fn)(x,y,&explosion_bitmap,COL_W); break; case 2: (*fn)(x,y,&tnt_bitmap[small],COL_W); break; } break; case BT_SELECTOR: (*fn)(x,y,&selector_bitmap[c->c.info][small],c->c.color); break; case BT_COMPLEX: (*fn)(x,y,&complex_bitmap[c->c.info][small],c->c.color); break; case BT_LBENDER: (*fn)(x,y,&lbender_bitmap[small],COL_K); break; case BT_MIR225: (*fn)(x,y,&mir225_bitmap[c->c.info][small],c->c.color); break; case BT_SLIME: if (small) { (*fn)(x,y,&slime_s_bitmap,COL_K); } else { (*fn)(x,y,&slime_bitmap[((SLIME *)c->typespec)->hdg],COL_K); } break; case BT_MINE: (*fn)(x,y,&mine_bitmap[small],COL_K); break; } if (mousec && (mousec->c.type == BT_SLIME)) { int i; for (i=0;i<4;i++) { extern BITMAP slime_mrk_bitmap[4]; if (!slime_isclr(mousec->typespec,x,y,i)) (*fn)(x,y,&slime_mrk_bitmap[i],COL_K); } } } static void makesmall(LEVEL *l) { BITMAP *b; char *d; int x; int y; BCELL *c; static void copy_small(int tox, int toy, BITMAP *bm, int color) { int x; int y; char ch; tox *= CELLW/4; toy *= CELLH/4; for (y=0;yh;y++) for (x=0;xw;x++) { ch = bm->data[x+(y*bm->w)]; if (ch == '*') ch = colorchar[color]; d[tox+x+((toy+y)*b->w)] = ch; } } static void smallbeam(int x, int y, int beams, int dir) { int i; char fc; int o; int oi; beams = (beams >> BB_SHIFT(dir)) & COL_W; if (beams == COL_K) return; fc = colorchar[beams]; o = (x*12)+5 + (((y*12)+5) * b->w); oi = dir_d[dir][0] + (dir_d[dir][1] * b->w); for (i=0;i<6;i++) { d[o] = fc; d[o+1] = fc; d[o+b->w] = fc; d[o+b->w+1] = fc; o += oi; } } static void smallfontstring(int x, int y, const char *s, int len) { const FONT_ROW *dp; static const FONT_ROW zeroes[FONT_SY]; int r; FONT_ROW rv; for (;len>0;len--,s++) { dp = font_bits[(unsigned char)*s][1]; if (! dp) dp = &zeroes[0]; for (r=0;rw) ] = (rv & 8) ? 'n' : '-'; d[x+((y+r)*b->w)+1] = (rv & 4) ? 'n' : '-'; d[x+((y+r)*b->w)+2] = (rv & 2) ? 'n' : '-'; d[x+((y+r)*b->w)+3] = (rv & 1) ? 'n' : '-'; } x += FONT_SX; } } static void dot_to_e(char *cp) { if (*cp == '.') *cp = 'e'; } b = malloc(sizeof(BITMAP)+(LEVSELW*LEVSELH)); b->w = LEVSELW; b->h = LEVSELH; d = (void *) b; d += sizeof(BITMAP); memset(d,'.',LEVSELW*LEVSELH); b->data = d; uselevel(l); redo_beams(); for (x=0;xbeams,DIR_U); smallbeam(x,y,c->beams,DIR_R); smallbeam(x,y,c->beams,DIR_D); smallbeam(x,y,c->beams,DIR_L); smallbeam(x,y,c->beams,DIR_UR); smallbeam(x,y,c->beams,DIR_DR); smallbeam(x,y,c->beams,DIR_DL); smallbeam(x,y,c->beams,DIR_UL); } smallfontstring(0,0,&lname[0],lnamelen(&lname[0])); for (x=0;xprocessed = 0; l->small = b; } static void draw_mouse_bitmap(int x __attribute__((__unused__)), int y __attribute__((__unused__)), BITMAP *bm, int color) { draw_bitmap(XOFF+mousex-24,YOFF+mousey-24,bm,color); } static void rendermouse(void) { int i; int m; int r; const unsigned short int (*bitp)[16]; const int *offp; if (carrying) { render_cell(&carrycell,-1,-1,0,draw_mouse_bitmap); return; } if (lscarry && (mouselfi >= 0)) { if (! lscarry->small) makesmall(lscarry); draw_bitmap(XOFF+mousex-(LEVSELW/2),YOFF+mousey-(LEVSELH/2),lscarry->small,COL_K); return; } r = mousec ? mousec->c.canrot : 0; m = mousec ? mousec->c.mobile : 0; if (editing && !r && !m) { bitp = &mouse_editor_bits[0]; offp = &mouse_editor_off[0]; } else { bitp = &mouse_bits[m][r][0]; offp = &mouse_off[m][r][0]; } setmode(MODE_COLOR1); setalu((ALU_FG&ALU_SRC)|(ALU_DST&~ALU_SRC)); fb->incx = 0; fb->incy = 1; setfg(CMAP_BG); fb->x0 = XOFF + mousex - offp[0]; fb->y0 = YOFF + mousey - offp[1]; fb->x1 = XOFF + mousex - offp[0] + 31; for (i=0;i<16;i++) fb->font = bitp[0][i] << 16; setfg(CMAP_MOUSE); fb->x0 = XOFF + mousex - offp[0]; fb->y0 = YOFF + mousey - offp[1]; fb->x1 = XOFF + mousex - offp[0] + 31; for (i=0;i<16;i++) fb->font = bitp[1][i] << 16; } #if (B_XCELL != 48) || (B_YCELL != 48) #error Fix beam drawing for B_XCELL and B_YCELL #endif static void process_cut_mask(BITMAP *m) { unsigned long int *pd; char space[58*52]; char *sp; int x; int y; int d; unsigned long int v; pd = malloc(8*32*sizeof(unsigned long int)); memset(&space[0],'.',58*52); for (y=0;y<48;y++) bcopy(&m->data[y*48],&space[((y+2)*58)+2],48); for (d=0;d> x; break; case 'x': break; default: fprintf(stderr,"%s: invalid character `%c' in cut mask data\n",__progname,sp[-1]); abort(); break; } } pd[(d*32)+y] = v; } } m->pdata = pd; m->processed = 1; } static void draw_masked(int basex, int basey, int dir, int col, BITMAP *mask, int alu) { unsigned long int *mp; unsigned long int *bp; int x; int y; int n; if (col == COL_K) return; setmode(MODE_COLOR1); setfg(CMAP_RGBBASE+col); setalu(alu); if (mask) { if (! mask->processed) process_cut_mask(mask); mp = mask->pdata + (dir * 32); } fb->incx = 0; fb->incy = 1; x = basex + beam_xoff[dir]; y = basey + beam_yoff[dir]; n = beam_nv[dir]; switch (dir) { case DIR_U: bp = &beam_v[anim][0]; break; case DIR_D: bp = &beam_v[anim][0]; break; case DIR_L: bp = &beam_h[anim][0]; break; case DIR_R: bp = &beam_h[anim][0]; break; case DIR_UR: bp = &beam_ur_dl[anim][0]; break; case DIR_DR: bp = &beam_ul_dr[anim][0]; break; case DIR_DL: bp = &beam_ur_dl[anim][0]; break; case DIR_UL: bp = &beam_ul_dr[anim][0]; break; } fb->x0 = x; fb->x1 = x + 31; fb->y0 = y; if (mask) for (;n>0;n--) fb->font = *bp++ & *mp++; else for (;n>0;n--) fb->font = *bp++; } #define ALU_SET (( ALU_FG & ALU_SRC) | (ALU_DST & ~ALU_SRC)) #define ALU_OR (( (ALU_FG|ALU_DST) & ALU_SRC) | (ALU_DST & ~ALU_SRC)) #define ALU_BLACK (( 0 & ALU_SRC) | (ALU_DST & ~ALU_SRC)) static void drawbeam(int basex, int basey, BCELL *c, int dir) { int unmasked; int masked; masked = ((c->ibeams&c->icut&~c->obeams) >> BB_SHIFT(dir)) & COL_W; unmasked = (c->beams >> BB_SHIFT(dir)) & COL_W & ~masked; basex = XOFF + (basex * CELLW) + 1; basey = YOFF + (basey * CELLH) + 1; if (unmasked) { draw_masked(basex,basey,dir,unmasked,0,ALU_SET); } else if (! masked) { return; } switch (masked) { BITMAP **cp; case 0: break; #define ONEBIT(b) case 1<cutbm[BB_SHIFT(dir)+b],unmasked?ALU_OR:ALU_SET); break; ONEBIT(0) ONEBIT(1) ONEBIT(2) #undef ONEBIT #define TWOBIT(a,b) case (1<cutbm[BB_SHIFT(dir)]; \ if (cp[a] == cp[b]) draw_masked(basex,basey,dir,(1<cutbm[BB_SHIFT(dir)]; if (cp[0] == cp[1]) { if (cp[0] == cp[2]) { draw_masked(basex,basey,dir,7,cp[0],unmasked?ALU_OR:ALU_SET); } else { if (! unmasked) { draw_masked(basex,basey,dir,3,cp[0],ALU_BLACK); draw_masked(basex,basey,dir,4,cp[2],ALU_BLACK); } draw_masked(basex,basey,dir,3,cp[0],ALU_OR); draw_masked(basex,basey,dir,4,cp[2],ALU_OR); } } else if (cp[0] == cp[2]) { if (! unmasked) { draw_masked(basex,basey,dir,5,cp[0],ALU_BLACK); draw_masked(basex,basey,dir,2,cp[1],ALU_BLACK); } draw_masked(basex,basey,dir,5,cp[0],ALU_OR); draw_masked(basex,basey,dir,2,cp[1],ALU_OR); } else if (cp[1] == cp[2]) { if (! unmasked) { draw_masked(basex,basey,dir,1,cp[0],ALU_BLACK); draw_masked(basex,basey,dir,6,cp[1],ALU_BLACK); } draw_masked(basex,basey,dir,1,cp[0],ALU_OR); draw_masked(basex,basey,dir,6,cp[1],ALU_OR); } else { if (! unmasked) { draw_masked(basex,basey,dir,1,cp[0],ALU_BLACK); draw_masked(basex,basey,dir,2,cp[1],ALU_BLACK); draw_masked(basex,basey,dir,4,cp[2],ALU_BLACK); } draw_masked(basex,basey,dir,1,cp[0],ALU_OR); draw_masked(basex,basey,dir,2,cp[1],ALU_OR); draw_masked(basex,basey,dir,4,cp[2],ALU_OR); } break; } } static void draw_cell_bitmap(int x, int y, BITMAP *bm, int color) { draw_bitmap(XOFF+(x*CELLW)+1,YOFF+(y*CELLH)+1,bm,color); } static int color_meaningful(int type) { switch (type) { case BT_LASER: case BT_COIN: case BT_FILTER: case BT_SELECTOR: case BT_COMPLEX: return(1); break; } return(0); } static void renderboard(void) { int x; int y; BCELL *c; fbrlines(CMAP_CELLEDGE,4,0,0,MAXX-1,0,0,MAXY-1,-(MAXX-1),0,0,-(MAXY-1)); for (x=0;xc.canrot) || (flashmov && (anim & 4) && c->c.mobile) || ((flashrgb & c->c.color) && (anim & 4) && color_meaningful(c->c.type)) ) continue; render_cell(&board[x][y],x,y,0,draw_cell_bitmap); } for (x=0;xx0 = x; fb->x1 = x + FONT_X; fb->y0 = y; for (r=0;rfont = bp[r] << FONT_SHIFT; } x += FONT_X; } } static void renderfooter(void) { char fl[1024]; char *flp; static void appstr(const char *s) { strcpy(flp,s); flp += strlen(s); } if (msgfooter) { render_fontstring(CMAP_MSGFOOTER,XOFF,YOFF+MAXY,msgfooter,strlen(msgfooter),-1); return; } flp = &fl[0]; if (ename) { appstr("Type text; ^A ^B ^D ^E ^F ^H <- -> to edit, RETURN when done"); } else if (confirming) { appstr(confirming); } else if (levelsel) { appstr("Exit:ESC "); if (lscarry) { appstr("Discard:x "); if (curlf->f) appstr("Click to place"); } else { if (curlf->dirty) appstr("Save:L10 "); if (editing && curlf->f) { appstr("New:n "); if ((mouselfi >= 0) && (mouselfi < curlf->nlevels)) { appstr("Delete:d Move:m Copy:c "); } } if (canedit) appstr(editing?"Play:e ":"Edit:e "); if ((mouselfi >= 0) && (mouselfi < curlf->nlevels)) { if (editing) { if (curlf->f) appstr("Click right to edit"); } else { appstr("Click to play"); } } } } else { appstr("Exit:ESC "); if (! (ldirty || (carrying && editing))) appstr("Levels:L1 "); if (ldirty) appstr("Revert:L2 Save:L10 "); if (! editing) appstr("Reset:L2 "); if (canedit && !carrying && !ldirty) { appstr(editing?"Play:e ":"Edit:e "); } if (complete) { if (canedit) { appstr("[Solved] "); } else if (anim & 4) { appstr(" Level solved!"); if ( curlevel->fromfile->flink || (curlevel->fileinx < curlevel->fromfile->nlevels-1) ) { appstr(" Next:space"); } } } } render_fontstring(CMAP_FOOTER,XOFF,YOFF+MAXY,&fl[0],flp-&fl[0],-1); } static void selbitmap(int x, int y, BITMAP *bm) { draw_bitmap(LEVSELX+(x*LEVSELW),LEVSELY+(y*LEVSELH),bm,COL_K); } static void rendersel(void) { int x; int y; int i; int n; LEVEL *l; x = 0; n = 16; if (have_npfile) { selbitmap(x,0,(curlf->blink)?&prevfile_bitmap:&nobutton_bitmap); selbitmap(3-x,3,curlf->flink?&nextfile_bitmap:&nobutton_bitmap); x ++; n -= 2; } if (have_nplev()) { selbitmap(x,0,curlf->inx?&prevlev_bitmap:&nobutton_bitmap); selbitmap(3-x,3,morelevsbelow()?&nextlev_bitmap:&nobutton_bitmap); x ++; n -= 2; } y = 0; for (i=0;(iinx+inlevels);i++) { l = curlf->levels[curlf->inx+i]; if (! l->small) makesmall(l); selbitmap(x,y,l->small); x ++; y += x >> 2; x &= 3; } } static void renderheader(void) { if (levelsel) { int ndirty; LEVELFILE *lf; if (curlf->fn) { render_fontstring(CMAP_HEADER,NAMEX,NAMEY,curlf->fn,strlen(curlf->fn),-1); } else { render_fontstring(CMAP_HEADER,NAMEX,NAMEY,"Aargon for UNIX",15,-1); } ndirty = 0; for (lf=levelfiles_f;lf;lf=lf->flink) if (lf->dirty) ndirty++; if (ndirty) { char ndbuf[16]; int ndl; ndl = sprintf(&ndbuf[0],"%d",ndirty); render_fontstring(CMAP_HEADER,XOFF,NAMEY,&ndbuf[0],ndl,-1); } } else { render_fontstring(CMAP_HEADER,NAMEX,NAMEY,&lname[0],LEVNAME_MAX,ename?enamecurs:-1); } } #define RFOK_DO 1 #define RFOK_DONT 2 #define RFOK_ABORT 3 static void region_fill(int x, int y, int (*ok)(int, int), void (*doit)(int, int)) { BCELL *c; int i; static const int dirs[4] = { DIR_R, DIR_L, DIR_U, DIR_D }; XYPAIR *pending; XYPAIR **tail; XYPAIR *t; int xx; int yy; pending = malloc(sizeof(XYPAIR)); pending->link = 0; pending->x = x; pending->y = y; tail = &pending->link; for (x=0;xmark = 0; } while (pending) { x = pending->x; y = pending->y; t = pending->link; free(pending); pending = t; if (! t) tail = &pending; c = &board[x][y]; if (c->mark) continue; c->mark = 1; (*doit)(x,y); for (i=0;i<4;i++) { xx = x + dir_d[dirs[i]][0]; yy = y + dir_d[dirs[i]][1]; if ((xx < 0) || (yy < 0) || (xx >= B_XSIZE) || (yy >= B_YSIZE)) continue; switch ((*ok)(xx,yy)) { case RFOK_DO: break; case RFOK_DONT: continue; break; case RFOK_ABORT: while (pending) { t = pending->link; free(pending); pending = t; } return; break; default: abort(); break; } t = malloc(sizeof(XYPAIR)); t->x = xx; t->y = yy; t->link = 0; *tail = t; tail = &t->link; } } } static int minemark_ok(int x, int y) { BCELL *c; c = &board[x][y]; switch (c->c.type) { case BT_TNT: explodetnt(x,y); return(RFOK_ABORT); break; case BT_BLANK: case BT_MINE: if (! c->beams) return(RFOK_DO); break; } return(RFOK_DONT); } static void minemark_do(int x, int y) { board[x][y].mined = 1; } static void domines(void) { int x; int y; BCELL *c; int n; XYPAIR *loclist; XYPAIR *xy; int pickx; int picky; static int pickspot_ok(int x, int y) { return(board[x][y].mined?RFOK_DO:RFOK_DONT); } static void pickspot_do(int x, int y) { if (board[x][y].c.type != BT_BLANK) return; n ++; if ((rnd() % n) == 0) { pickx = x; picky = y; } } if (levelsel || exploding || editing) return; if (debug) printf("domines\n"); clear_mining(); loclist = 0; for (x=0;xc.type != BT_MINE) continue; if (! c->mined) { if (debug) printf("mining from %d,%d\n",x,y); region_fill(x,y,minemark_ok,minemark_do); } if (exploding) { if (debug) printf("exploding\n"); return; } xy = malloc(sizeof(XYPAIR)); xy->x = x; xy->y = y; xy->link = loclist; loclist = xy; } for (xy=loclist;xy;xy=xy->link) setblank(&board[xy->x][xy->y].c); for (xy=loclist;xy;xy=xy->link) { x = xy->x; y = xy->y; n = 0; pickx = -1; if (debug) printf("picking for %d,%d\n",x,y); region_fill(x,y,pickspot_ok,pickspot_do); if (debug) printf("picked %d,%d\n",pickx,picky); if (pickx < 0) continue; c = &board[pickx][picky]; c->c.type = BT_MINE; } while (loclist) { xy = loclist->link; free(loclist); loclist = xy; } if (debug) debug --; } static void mayberender(void) { if (! wantrender) return; domines(); wantrender = 0; drain(); fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; setmode(MODE_COLOR8); setalu(ALU_FG); setpm(drawpm); fbrrect(CMAP_RGBBASE+COL_K,0,0,1151,899); fbrrect(CMAP_BG,XOFF,YOFF,MAXX-1,MAXY-1); fbrrect(CMAP_BORDER,NAMEX,NAMEY,NAMEW-1,NAMEH-1); fb->clipminx = XOFF; fb->clipminy = YOFF; fb->clipmaxx = XOFF + MAXX - 1; fb->clipmaxy = YOFF + MAXY - 1; drain(); if (levelsel) { rendersel(); } else { renderboard(); } fb->clipminx = 0; fb->clipminy = 0; fb->clipmaxx = 1151; fb->clipmaxy = 899; renderheader(); renderfooter(); rendermouse(); drain(); setcmap(drawbit); drawbit = ! drawbit; drawpm = drawbit ? 0xf0 : 0x0f; } static void step(void) { struct pollfd pfd[2]; process_evq(); if (wantredo) { wantredo = 0; redo_beams(); return; } if (droploc) { if ((mousec != droploc) || levelsel || editing || !carrying) { droploc = 0; } else if (droploc->c.type == BT_BLANK) { droploc = 0; carrydrop(); } } mayberender(); if (checkkb()) return; if (checkms()) return; if (checktick()) return; pfd[0].fd = kbfd; pfd[0].events = POLLIN | POLLRDNORM; pfd[1].fd = msfd; pfd[1].events = POLLIN | POLLRDNORM; if (poll(&pfd[0],2,INFTIM) < 0) { if (errno == EINTR) return; fprintf(stderr,"%s: poll: %s\n",__progname,strerror(errno)); exit(1); } } static void initfuses(void) { fuses = 0; fuses_n = 0; fuses_a = 0; } static void mungbitmap(BITMAP *b1, BITMAP *b2) { int x; int y; int w; int h; char *d1; const char *d2; w = b2->h; h = b2->w; b1->w = w; b1->h = h; d1 = malloc(w*h); b1->data = d1; d2 = b2->data + h - 1; for (y=0;yname = lname; bcopy(&cells,&lev->cells,sizeof(cells)); if (lf) add_level_to_levelfile(lev,lf,-1); lev->dirty = 0; break; case RFL_EOF: lev = 0; break; case RFL_ERR: fprintf(stderr,"%s: at %d in %s: %s\n",__progname,(int)ftell(f),name,lname); free(lname); read_file_done(fh); return; } } while (lev); read_file_done(fh); } static void loadlevels_file(const char *fn) { FILE *f; LEVELFILE *lf; int savef; if (editing) { savef = 1; f = fopen(fn,"r+"); if (f == 0) { f = fopen(fn,"r"); if (f) { fprintf(stderr,"%s: can't open %s read/write, can't edit it\n",__progname,fn); savef = 0; } } } else { f = fopen(fn,"r"); savef = 0; } if (f == 0) { fprintf(stderr,"%s: can't open %s: %s\n",__progname,fn,strerror(errno)); exit(1); } lf = malloc(sizeof(LEVELFILE)); lf->n = nlevelfiles++; lf->inx = 0; lf->fn = strdup(fn); lf->nlevels = 0; lf->alevels = 0; lf->levels = 0; lf->f = savef ? f : 0; if (! levelfiles_f) { levelfiles_f = lf; } else { levelfiles_b->flink = lf; } lf->blink = levelfiles_b; levelfiles_b = lf; lf->flink = 0; loadlevels_stream(f,fn,lf); lf->dirty = 0; if (! savef) fclose(f); } static void handleargs(int ac, char **av) { int errs; int skip; errs = 0; skip = 0; for (ac--,av++;ac;ac--,av++) { if (skip > 0) { skip --; continue; } if (0) { needarg:; fprintf(stderr,"%s: %s needs another argument\n",__progname,*av); errs ++; continue; } #define WANTARG() do { if (++skip >= ac) goto needarg; } while (0) if (!strcmp(*av,"-edit")) { editing = 1; canedit = 1; } else if (!strcmp(*av,"-play")) { editing = 0; } else if (!strcmp(*av,"-showkbd")) { showkbd = 1; } else if (!strcmp(*av,"-fb") || !strcmp(*av,"-fbpath")) { WANTARG(); fbpath = av[skip]; } else if (!strcmp(*av,"-kbd") || !strcmp(*av,"-kb") || !strcmp(*av,"-kbpath")) { WANTARG(); kbpath = av[skip]; } else if (!strcmp(*av,"-mouse") || !strcmp(*av,"-ms") || !strcmp(*av,"-mspath")) { WANTARG(); mspath = av[skip]; } else if (**av == '-') { fprintf(stderr,"%s: unrecognized flag %s\n",__progname,*av); errs ++; } else { loadlevels_file(*av); } #undef WANTARG } if (errs) exit(1); } static void setupdeflevels(void) { FILE *f; int p; static int r(void *cookie __attribute__((__unused__)), char *buf, int len) { if (p >= deflevsize) return(0); if (p+len > deflevsize) len = deflevsize - p; bcopy(&deflevdata[p],buf,len); p += len; return(len); } if (levelfiles_f) return; levelfiles_f = malloc(sizeof(LEVELFILE)); levelfiles_f->n = nlevelfiles++; levelfiles_f->inx = 0; levelfiles_f->fn = 0; levelfiles_f->nlevels = 0; levelfiles_f->alevels = 0; levelfiles_f->levels = 0; levelfiles_f->f = 0; levelfiles_f->flink = 0; levelfiles_f->blink = 0; levelfiles_b = levelfiles_f; p = 0; f = fropen(0,&r); loadlevels_stream(f,"default level data",levelfiles_f); fclose(f); } int main(int, char **); int main(int ac, char **av) { handleargs(ac,av); setupfb(); setupkb(); setupms(); initms(); setuptimer(); initevq(); initfuses(); initrandom(); mungbitmaps(); setupdeflevels(); initgame(); wantrender = 1; while (1) step(); exit(0); }