#include #include #include #include #include #include #ifndef MEM32 # define MEM32 0 // set to 1 for 64 bits #endif // Game controller bits (actual controllers in kit have negative output) // +----------------------------------------+ // | Up B* | // | Left Right B A* | // | Down Select Start A | // +----------------------------------------+ *=Auto fire #define BUTTON_RIGHT 0xfe #define BUTTON_LEFT 0xfd #define BUTTON_DOWN 0xfb #define BUTTON_UP 0xf7 #define BUTTON_START 0xef #define BUTTON_SELECT 0xdf #define BUTTON_B 0xbf #define BUTTON_A 0x7f // length of the queue for automatic uncovering of game fields. // It is an alternative to a recursive function. // I am afraid of stack problems with recursive functions. #define MAXQ 40 #define REPETITION 6 // speed for automatic cursor movement #if MEM32 #define MAXX 26 // max 26 #define MAXY 17 // max 17 #define TOP 2 #else #define MAXX 26 // max 26 #define MAXY 17 // max 17 #define TOP 0 #endif #define SFREE 0 #define S1 1 #define S2 2 #define S3 3 #define S4 4 #define S5 5 #define S6 6 #define S7 7 #define S8 8 #define SBOMB 9 #define SBOMBTRIGGERED 10 #define SCURSOR 11 #define SHIDDEN 12 #define SMARKER 13 #define BHIDDEN 0x10 #define BMARKER 0x20 __nohop const char sfree[]={ 44,44,44,44,44,46, 44,44,44,44,44,46, 44,44,44,44,44,46, 44,44,44,44,44,46, 44,44,44,44,44,46, 46,46,46,46,46,46, 250}; // 0 __nohop const char s1[]={ 44,44,48,48,44,46, 44,44,44,48,44,46, 44,44,44,48,44,46, 44,44,44,48,44,46, 44,44,44,48,44,46, 46,46,46,46,46,46, 250}; // 1 __nohop const char s2[]={ 44,8,8,8,44,46, 44,44,44,44,8,46, 44,44,8,8,44,46, 44,8,44,44,44,46, 44,8,8,8,8,46, 46,46,46,46,46,46, 250}; // 2 __nohop const char s3[]={ 44,35,35,35,44,46, 44,44,44,44,35,46, 44,44,35,35,44,46, 44,44,44,44,35,46, 44,35,35,35,44,46, 46,46,46,46,46,46, 250}; // 3 __nohop const char s4[]={ 44,33,44,44,44,46, 44,33,44,44,44,46, 44,33,44,33,44,46, 44,33,33,33,33,46, 44,44,44,33,44,46, 46,46,46,46,46,46, 250}; // 4 __nohop const char s5[]={ 44,6,6,6,6,46, 44,6,44,44,44,46, 44,44,6,6,44,46, 44,44,44,44,6,46, 44,6,6,6,44,46, 46,46,46,46,46,46, 250}; // 5 __nohop const char s6[]={ 44,44,57,57,44,46, 44,57,44,44,44,46, 44,57,57,57,44,46, 44,57,44,44,57,46, 44,44,57,57,44,46, 46,46,46,46,46,46, 250}; // 6 __nohop const char s7[]={ 44,16,16,16,16,46, 44,44,44,44,16,46, 44,44,44,16,44,46, 44,44,16,44,44,46, 44,44,16,44,44,46, 46,46,46,46,46,46, 250}; // 7 __nohop const char s8[]={ 44,44,37,37,44,46, 44,37,44,44,37,46, 44,44,37,37,44,46, 44,37,44,44,37,46, 44,44,37,37,44,46, 46,46,46,46,46,46, 250}; // 8 __nohop const char sbomb[]={ 16,44,16,44,16,46, 44,61,16,16,44,46, 16,16,16,16,16,46, 44,16,16,16,44,46, 16,44,16,44,16,46, 46,46,46,46,46,46, 250}; // 9 __nohop const char sbombtriggered[]={ 16,19,16,19,16,19, 19,62,16,16,19,19, 16,16,16,16,16,19, 19,16,16,16,19,19, 16,19,16,19,16,19, 19,19,19,19,19,19, 250}; // 10 [0x0a] __nohop const char shidden[]={ 58,58,58,58,58,50, 58,58,58,58,58,50, 58,58,58,58,58,50, 58,58,58,58,58,50, 58,58,58,58,58,50, 50,50,50,50,50,50, 250}; // 12 [0x0c] __nohop const char smarker[]={ 58,58,19,19,58,50,58, 19,19,19,58,50,58,58, 19,19,58,50,58,58,58, 1,58,50,58,58,1,1,1, 50,50,50,50,50,50,50, 250}; // 13 [0x0d] __nohop const char bigcursor[]={ 35,35,35,35,35,35,35,35, 35, 0, 0, 0, 0, 0, 0,35, 35, 0, 0, 0, 0, 0, 0,35, 35, 0, 0, 0, 0, 0, 0,35, 35, 0, 0, 0, 0, 0, 0,35, 35, 0, 0, 0, 0, 0, 0,35, 35, 0, 0, 0, 0, 0, 0,35, 35,35,35,35,35,35,35,35,250}; typedef enum { BEGINNER, ADVANCED, EXPERT } levels; struct game_level_s { char fieldsX, fieldsY; int fields; char numberBomb, topMargin; } game_level; __near char leftMargin; __near char markerCount; // counter for marked fields __near int revealedFields; // counter for revealed fields __near char queuePointer; // pointer to queue __near char gameOver; // flag, end of game reached __near char newGame; // Flag, start new game without closing the old one __near char firstClick; // Flag for start of the clock __near unsigned int colors; __near char bottonLevel; __near unsigned int ticks; __near unsigned int seconds; // elapsed seconds unsigned int queue[MAXQ]; // queue for automatic uncovering of game fields char field[MAXY][MAXX]; // byte array for playing field, lower nibble sprite id, upper nibble flags char backup[64]; void setLevel(struct game_level_s *data, levels level) { static struct game_level_s advanced = { 16, 16, 256, 40, 20 }, expert = { MAXX, MAXY, MAXX*MAXY, MAXX*MAXY/5, 17+(MEM32?1:0) }, beginner = { 9, 9, 81, 10, 27}; struct game_level_s *lvl = &beginner; if (level == ADVANCED) lvl = &advanced; else if (level == EXPERT) lvl = &expert; *data = *lvl; } void printCursor(char *addr, char *dest){ // int ii, zz, vv; zz = vv = ii = 0; while(addr[vv] < 128){ if(addr[vv] > 0){ backup[vv] = dest[zz + ii]; dest[zz + ii] = addr[vv]; } vv++; ii++; if(ii > 7){ ii = 0; zz += 256; } } } void restoreCursor(char *addr, char *dest){ // int ii, zz, vv; zz = vv = ii = 0; while(addr[vv] < 128){ if(addr[vv] > 0){ dest[zz + ii] = backup[vv]; } vv++; ii++; if(ii > 7){ ii = 0; zz += 256; } } } void printSprite(int val, int xx, int yy) // val is the id of the sprite, xx,yy is the x,y position in the playfield { static const char* ptrChars[] = { sfree, s1, s2, s3, s4, s5, s6, s7, s8, sbomb, sbombtriggered, sfree, shidden, smarker }; const char* ptrChar; int sprnum; sprnum = val & 0x0f; if(val >= BHIDDEN) sprnum = SHIDDEN; if(val >= BMARKER) sprnum = SMARKER; ptrChar = sfree; if (sprnum >= 0 && sprnum <= SMARKER) ptrChar = ptrChars[sprnum]; SYS_Sprite6(ptrChar, (char*)(yy*6+game_level.topMargin<<8)+6*xx+leftMargin); } void initialize() { int i,x,y; for( y=0; y 0) ? field[y-1] : 0; char *fieldRowBelow = (y < game_level.fieldsY-1) ? field[y+1] : 0; for( x=0; x 0 ){ // left edge if(fieldRow[x-1] == (SBOMB | BHIDDEN)) fieldRow[x]++; // right if(fieldRowBelow && fieldRowBelow[x-1] == (SBOMB | BHIDDEN)) fieldRow[x]++; // bottom right if(fieldRowAbove && fieldRowAbove[x-1] == (SBOMB | BHIDDEN)) fieldRow[x]++; // top right } if(fieldRowBelow && fieldRowBelow[x] == (SBOMB | BHIDDEN)) fieldRow[x]++; // bottom if(fieldRowAbove && fieldRowAbove[x] == (SBOMB | BHIDDEN)) fieldRow[x]++; // top } } } } int getInput(void) { static __near char fc; static __near char last = 0xff; register int c, b; if ((b = buttonState ^ 0xff)) { c = serialRaw; fc = frameCount + 16; if (last == 0xff) { /* clean press */ if (b == 0x10) /* - report buttonStart like a key */ return last = 0xef; if (c < 127) { /* - looks like a key */ if ((c+1) & c) /* - also report type b codes as buttons */ buttonState = 0xff; return last = c; } } b &= 0xef; /* - ignore buttonStart */ b = (-b) & b; /* - pick one button only */ if (b) { buttonState |= b; /* - mark button as processed */ return last = b ^ 0xff; /* - return */ } } if (serialRaw == 0xff) { /* nothing pressed. */ last = 0xff; /* - next is a clean press */ return -1; } if (last != 0xff && (signed char)(frameCount - fc) >= 0) { fc = frameCount + 8; return last; /* autorepeat */ } return -1; } #define ADDR0(cx) (char*)(((8+TOP)<<8)+cx*6) // screen address for top line #define ADDR(cy,cx) (char*)(((8+cy*8)<<8)+cx*6) // screen address for line cy void cprint(char *addr, const char *s) { _console_printchars(0x200a, addr, s, -1); } void cprintr(char *addr, const char *s) { _console_printchars(0x30a, addr, s, 1); _console_printchars(0x200a, addr+6, s+1, -1); } void cprintu(register char *addr, register unsigned int x) { char buffer[8]; register char *s = utoa(x, buffer, 10); while (s > buffer+sizeof(buffer)-4) *--s = ' '; _console_printchars(0x20a, addr, s, 8); } int main() { char cursorX, cursorY; // cursor in the playing field char i, x1, y1, tx, ty; // help variables int x, y; // help variables bottonLevel = BEGINNER; setLevel(&game_level, bottonLevel); SYS_SetMode(2); for(;;){ _console_clear(ADDR0(0), 0x3f38, 120-8-TOP); videoTop_v5 = 224; seconds = 0; markerCount = 0; gameOver = 0; newGame = 0; firstClick = 0; revealedFields = 0; seconds = 0; leftMargin = (160 - 6*game_level.fieldsX)/2; initialize(); for( y=0; y EXPERT) bottonLevel = BEGINNER; gameOver = 1; newGame = 1; setLevel(&game_level, bottonLevel); break; case 'n': // start new game case 'N': gameOver = 1; newGame = 1; break; case 'b': // new game beginner case 'B': gameOver = 1; newGame = 1; setLevel(&game_level, BEGINNER); break; case 'a': // new game advanced case 'A': gameOver = 1; newGame = 1; setLevel(&game_level, ADVANCED); break; case 'e': // new game expert case 'E': gameOver = 1; newGame = 1; setLevel(&game_level, EXPERT); break; case BUTTON_B: case 0x20: // set,unset marker with space if((field[cursorY][cursorX] & BHIDDEN) == BHIDDEN){ // only on covered fields if((field[cursorY][cursorX] & BMARKER) == BMARKER){ field[cursorY][cursorX] = field[cursorY][cursorX] & 0x1f; markerCount--; }else{ if(markerCount < game_level.numberBomb){ // only so many as bombs field[cursorY][cursorX] = field[cursorY][cursorX] | 0x20; markerCount++; } } restoreCursor((char*)bigcursor, (char*)(cursorY*6-1+game_level.topMargin<<8) + 6 * cursorX-1 + leftMargin); printSprite((field[cursorY][cursorX]), cursorX, cursorY); printCursor((char*)bigcursor, (char*)(cursorY*6-1+game_level.topMargin<<8) + 6 * cursorX-1 + leftMargin); } break; case BUTTON_A: case 0x0a: // uncover game field with enter key if(field[cursorY][cursorX] < 0x10) continue; // is already uncovered if(firstClick == 0){ // first click, start clock firstClick = 1; ticks = _clock(); } if(field[cursorY][cursorX] < 0x20){ // marker protects field if((field[cursorY][cursorX] & 0x0f) == SBOMB){ // game over gameOver = 1; field[cursorY][cursorX] = SBOMBTRIGGERED; for( y=0; y