Added most of the support for dynamic changes in the game. Step through the changes for now to debug.

This commit is contained in:
Jeremy Rand 2016-07-20 23:39:06 -05:00
parent 79609ebe86
commit 2b92b2684a
4 changed files with 399 additions and 44 deletions

View File

@ -9,11 +9,14 @@
#include <stdbool.h>
#include <stdlib.h>
#include <string.h>
#include <conio.h>
#include "game.h"
#define MIN_MATCHING 3
#define STAR_MATCH 4
#define SPECIAL_MATCH 5
#define GEM_TYPE_AT_SQUARE(square) gGameState.squareStates[square].gemType
#define GEM_STARRED_AT_SQUARE(square) gGameState.squareStates[square].isStarred
@ -35,6 +38,7 @@ typedef struct tGameState {
tGameState gGameState;
tSquareRefreshCallback gSquareRefresh = NULL;
static tGemType randomGem(void)
@ -43,7 +47,31 @@ static tGemType randomGem(void)
}
static uint8_t numMatchingUpDownAtSquare(tSquare square, tGemType gemType)
static void explodeStarAtSquare(tSquare square)
{
tPos x = SQUARE_TO_X(square);
tPos y = SQUARE_TO_Y(square);
tPos minX = (x == 0 ? 0 : x - 1);
tPos maxX = (x == (BOARD_SIZE - 1) ? (BOARD_SIZE - 1) : x + 1);
tPos minY = (y == 0 ? 0 : y - 1);
tPos maxY = (y == (BOARD_SIZE - 1) ? (BOARD_SIZE - 1) : y + 1);
GEM_STARRED_AT_SQUARE(square) = false;
for (x = minX; x <= maxX; x++) {
for (y = minY; y <= maxY; y++) {
square = XY_TO_SQUARE(x, y);
GEM_TYPE_AT_SQUARE(square) = GEM_NONE;
gSquareRefresh(square);
}
}
// DEBUG
cgetc();
// DBEUG
}
static uint8_t numMatchingUpDownAtSquare(tSquare square, tGemType gemType, bool update)
{
tPos x = SQUARE_TO_X(square);
tPos y;
@ -51,7 +79,6 @@ static uint8_t numMatchingUpDownAtSquare(tSquare square, tGemType gemType)
uint8_t result = 1;
tPos lowerY = (startY < MIN_MATCHING ? 0 : startY - (MIN_MATCHING - 1));
tPos upperY = (startY > (BOARD_SIZE - MIN_MATCHING) ? (BOARD_SIZE - 1) : startY + (MIN_MATCHING - 1));
bool isStarred = GEM_STARRED_AT_SQUARE(square);
if (gemType == GEM_NONE)
gemType = GEM_TYPE_AT_SQUARE(square);
@ -59,45 +86,50 @@ static uint8_t numMatchingUpDownAtSquare(tSquare square, tGemType gemType)
if (startY > 0) {
for (y = startY - 1; y >= lowerY; y--) {
square = XY_TO_SQUARE(x, y);
if (gemType != GEM_TYPE_AT_SQUARE(square))
if (gemType != GEM_TYPE_AT_SQUARE(square)) {
lowerY = y + 1;
break;
}
result++;
if (!isStarred)
isStarred = GEM_STARRED_AT_SQUARE(square);
}
}
if (startY < BOARD_SIZE - 1) {
for (y = startY + 1; y <= upperY; y++) {
square = XY_TO_SQUARE(x, y);
if (gemType != GEM_TYPE_AT_SQUARE(square))
if (gemType != GEM_TYPE_AT_SQUARE(square)) {
upperY = y - 1;
break;
}
result++;
if (!isStarred)
isStarred = GEM_STARRED_AT_SQUARE(square);
}
}
if (result < MIN_MATCHING) {
result = 0;
isStarred = false;
} else if (update) {
for (y = lowerY; y <= upperY; y++) {
square = XY_TO_SQUARE(x, y);
GEM_TYPE_AT_SQUARE(square) = GEM_NONE;
gSquareRefresh(square);
}
}
return result;
}
static uint8_t numMatchingRightLeftAtSquare(tSquare square, tGemType gemType)
static uint8_t numMatchingRightLeftAtSquare(tSquare square, tGemType gemType, bool update)
{
tPos x;
tPos y = SQUARE_TO_Y(square);
tPos startX = SQUARE_TO_X(square);
uint8_t result = 1;
tPos leftX = (startX < MIN_MATCHING ? 0 : startX - (MIN_MATCHING - 1));
tPos rightX = (startX > (BOARD_SIZE - MIN_MATCHING) ? (BOARD_SIZE - 1) : startX + (MIN_MATCHING - 1));
bool isStarred = GEM_STARRED_AT_SQUARE(square);
if (gemType == GEM_NONE)
gemType = GEM_TYPE_AT_SQUARE(square);
@ -105,30 +137,35 @@ static uint8_t numMatchingRightLeftAtSquare(tSquare square, tGemType gemType)
if (startX > 0) {
for (x = startX - 1; x >= leftX; x--) {
square = XY_TO_SQUARE(x, y);
if (gemType != GEM_TYPE_AT_SQUARE(square))
if (gemType != GEM_TYPE_AT_SQUARE(square)) {
leftX = x + 1;
break;
}
result++;
if (!isStarred)
isStarred = GEM_STARRED_AT_SQUARE(square);
}
}
if (startX < BOARD_SIZE - 1) {
for (x = startX + 1; x <= rightX; x++) {
square = XY_TO_SQUARE(x, y);
if (gemType != GEM_TYPE_AT_SQUARE(square))
if (gemType != GEM_TYPE_AT_SQUARE(square)) {
rightX = x - 1;
break;
}
result++;
if (!isStarred)
isStarred = GEM_STARRED_AT_SQUARE(square);
}
}
if (result < MIN_MATCHING) {
result = 0;
isStarred = false;
} else if (update) {
for (x = leftX; x <= rightX; x++) {
square = XY_TO_SQUARE(x, y);
GEM_TYPE_AT_SQUARE(square) = GEM_NONE;
gSquareRefresh(square);
}
}
return result;
@ -141,17 +178,19 @@ static void initSquare(tSquare square)
do {
gemType = randomGem();
} while ((numMatchingUpDownAtSquare(square, gemType) != 0) ||
(numMatchingRightLeftAtSquare(square, gemType) != 0));
} while ((numMatchingUpDownAtSquare(square, gemType, false) != 0) ||
(numMatchingRightLeftAtSquare(square, gemType, false) != 0));
gGameState.squareStates[square].gemType = gemType;
}
void initGame(void)
void initGame(tSquareRefreshCallback callback)
{
tSquare square;
gSquareRefresh = callback;
memset(&gGameState, 0, sizeof(gGameState));
gGameState.level = 1;
@ -206,10 +245,10 @@ bool gameIsOver(void)
otherGemType = GEM_TYPE_AT_SQUARE(otherSquare);
if (gemType != otherGemType) {
if (numMatchingUpDownAtSquare(otherSquare, gemType) > 0)
if (numMatchingUpDownAtSquare(otherSquare, gemType, false) > 0)
return false;
if (numMatchingUpDownAtSquare(square, otherGemType) > 0)
if (numMatchingUpDownAtSquare(square, otherGemType, false) > 0)
return false;
}
@ -217,10 +256,10 @@ bool gameIsOver(void)
otherGemType = GEM_TYPE_AT_SQUARE(otherSquare);
if (gemType != otherGemType) {
if (numMatchingRightLeftAtSquare(otherSquare, gemType) > 0)
if (numMatchingRightLeftAtSquare(otherSquare, gemType, false) > 0)
return false;
if (numMatchingRightLeftAtSquare(square, otherGemType) > 0)
if (numMatchingRightLeftAtSquare(square, otherGemType, false) > 0)
return false;
}
}
@ -228,3 +267,203 @@ bool gameIsOver(void)
return true;
}
static bool explodeGems(void)
{
tSquare square;
bool result = false;
for (square = MIN_SQUARE; square <= MAX_SQUARE; square++) {
if (GEM_TYPE_AT_SQUARE(square) != GEM_NONE)
continue;
if (!GEM_STARRED_AT_SQUARE(square))
continue;
explodeStarAtSquare(square);
result = true;
}
return result;
}
static bool actOnMatchAtSquare(tSquare square)
{
tGemType gemType = GEM_TYPE_AT_SQUARE(square);
bool starred = GEM_STARRED_AT_SQUARE(square);
bool result = false;
uint8_t matchesUD;
uint8_t matchesRL;
if (gemType == GEM_NONE)
return result;
matchesUD = numMatchingUpDownAtSquare(square, gemType, true);
matchesRL = numMatchingRightLeftAtSquare(square, gemType, true);
if (matchesUD > 0)
result = true;
if (matchesRL > 0)
result = true;
if (!starred) {
if ((matchesUD == SPECIAL_MATCH) ||
(matchesRL == SPECIAL_MATCH)) {
GEM_TYPE_AT_SQUARE(square) = GEM_SPECIAL;
gSquareRefresh(square);
} else if ((matchesUD == STAR_MATCH) ||
(matchesRL == STAR_MATCH)) {
GEM_TYPE_AT_SQUARE(square) = gemType;
GEM_STARRED_AT_SQUARE(square) = true;
gSquareRefresh(square);
} else if ((matchesUD == MIN_MATCHING) &&
(matchesRL == MIN_MATCHING)) {
GEM_TYPE_AT_SQUARE(square) = gemType;
GEM_STARRED_AT_SQUARE(square) = true;
gSquareRefresh(square);
}
}
// DEBUG
if (result)
cgetc();
// DBEUG
return result;
}
static bool dropGems(void)
{
bool result = false;
tPos x;
tPos y;
tPos destY;
tSquare square;
tSquare destSquare;
tGemType gemType;
for (x = 0; x < BOARD_SIZE; x++) {
destSquare = NUM_SQUARES;
for (y = BOARD_SIZE - 1; y >= 0; y--) {
square = XY_TO_SQUARE(x, y);
gemType = GEM_TYPE_AT_SQUARE(square);
if (destSquare == NUM_SQUARES) {
if (gemType == GEM_NONE) {
destSquare = square;
destY = y;
}
} else {
if (gemType != GEM_NONE) {
GEM_TYPE_AT_SQUARE(destSquare) = gemType;
GEM_STARRED_AT_SQUARE(destSquare) = GEM_STARRED_AT_SQUARE(square);
gSquareRefresh(destSquare);
destY--;
destSquare = XY_TO_SQUARE(x, destY);
}
}
}
if (destSquare != NUM_SQUARES) {
// DEBUG
if (result)
cgetc();
// DBEUG
for (y = destY; y >= 0; y--) {
square = XY_TO_SQUARE(x, y);
GEM_TYPE_AT_SQUARE(square) = randomGem();
GEM_STARRED_AT_SQUARE(square) = false;
gSquareRefresh(destSquare);
}
// DEBUG
if (result)
cgetc();
// DBEUG
}
}
for (x = 0; x < BOARD_SIZE; x++) {
for (y = 0; y < BOARD_SIZE; y++) {
square = XY_TO_SQUARE(x, y);
if (actOnMatchAtSquare(square))
result = true;
}
}
if (result) {
while (explodeGems())
;
}
return result;
}
void moveSquareInDir(tSquare square, tDirection dir)
{
tPos x = SQUARE_TO_X(square);
tPos y = SQUARE_TO_Y(square);
tSquare otherSquare;
tGemType gemType = GEM_TYPE_AT_SQUARE(square);
tGemType otherGemType;
bool starred = GEM_STARRED_AT_SQUARE(square);
bool otherStarred;
bool goodMove = false;
switch (dir) {
case DIR_UP:
y--;
break;
case DIR_DOWN:
y++;
break;
case DIR_LEFT:
x--;
break;
case DIR_RIGHT:
x++;
break;
}
otherSquare = XY_TO_SQUARE(x, y);
otherGemType = GEM_TYPE_AT_SQUARE(otherSquare);
otherStarred = GEM_STARRED_AT_SQUARE(otherSquare);
// Actually do the fun stuff here...
GEM_TYPE_AT_SQUARE(square) = otherGemType;
GEM_STARRED_AT_SQUARE(square) = otherStarred;
GEM_TYPE_AT_SQUARE(otherSquare) = gemType;
GEM_STARRED_AT_SQUARE(otherStarred) = starred;
gSquareRefresh(square);
gSquareRefresh(otherSquare);
if (actOnMatchAtSquare(square))
goodMove = true;
if (actOnMatchAtSquare(otherSquare))
goodMove = true;
if (!goodMove) {
GEM_TYPE_AT_SQUARE(square) = gemType;
GEM_STARRED_AT_SQUARE(square) = starred;
GEM_TYPE_AT_SQUARE(otherSquare) = otherGemType;
GEM_STARRED_AT_SQUARE(otherStarred) = otherStarred;
gSquareRefresh(square);
gSquareRefresh(otherSquare);
} else {
while (explodeGems())
;
while (dropGems())
;
}
}

View File

@ -28,7 +28,10 @@
#define SCORE_PER_LEVEL 240
void initGame(void);
typedef void (*tSquareRefreshCallback)(tSquare square);
void initGame(tSquareRefreshCallback callback);
void moveSquareInDir(tSquare square, tDirection dir);

Binary file not shown.

View File

@ -16,6 +16,9 @@
#include "game.h"
#define BTN1 0xC062
static tSquare gSelectedSquare = 0;
static bool gPlaySounds = true;
@ -27,6 +30,13 @@ static void initUI(void)
}
static void badThingHappened(void)
{
if (gPlaySounds)
printf("\007");
}
void printInstructions(void)
{
@ -41,8 +51,8 @@ void printInstructions(void)
" Apple Jeweled\n"
"\n"
" Use I-J-K-M or the arrow keys to move\n"
" your selection. Hold the Apple key and\n"
" move your selection to swap two jewels\n"
" your selection. Hold the closed apple key\n"
" and move your selection to swap two jewels\n"
" and match 3 or more jewels.\n"
"\n"
" Play ends when no more matches can be\n"
@ -106,13 +116,19 @@ static void drawGemAtSquare(tSquare square)
}
static void refreshSquare(tSquare square)
{
drawBgSquare(square);
drawGemAtSquare(square);
}
static void drawBoard(void)
{
tSquare square;
for (square = MIN_SQUARE; square <= MAX_SQUARE; square++) {
drawBgSquare(square);
drawGemAtSquare(square);
refreshSquare(square);
}
selectSquare(gSelectedSquare);
@ -141,8 +157,7 @@ static void moveUp(void)
gSelectedSquare = XY_TO_SQUARE(x, y);
drawBgSquare(oldSquare);
drawGemAtSquare(oldSquare);
refreshSquare(oldSquare);
selectSquare(gSelectedSquare);
}
@ -160,8 +175,7 @@ static void moveDown(void)
gSelectedSquare = XY_TO_SQUARE(x, y);
drawBgSquare(oldSquare);
drawGemAtSquare(oldSquare);
refreshSquare(oldSquare);
selectSquare(gSelectedSquare);
}
@ -179,8 +193,7 @@ static void moveLeft(void)
gSelectedSquare = XY_TO_SQUARE(x, y);
drawBgSquare(oldSquare);
drawGemAtSquare(oldSquare);
refreshSquare(oldSquare);
selectSquare(gSelectedSquare);
}
@ -198,46 +211,142 @@ static void moveRight(void)
gSelectedSquare = XY_TO_SQUARE(x, y);
drawBgSquare(oldSquare);
drawGemAtSquare(oldSquare);
refreshSquare(oldSquare);
selectSquare(gSelectedSquare);
}
static void swapUp(void)
{
tPos y = SQUARE_TO_Y(gSelectedSquare);
if (y == 0) {
badThingHappened();
return;
}
moveSquareInDir(gSelectedSquare, DIR_UP);
selectSquare(gSelectedSquare);
}
static void swapDown(void)
{
tPos y = SQUARE_TO_Y(gSelectedSquare);
if (y == BOARD_SIZE - 1) {
badThingHappened();
return;
}
moveSquareInDir(gSelectedSquare, DIR_DOWN);
selectSquare(gSelectedSquare);
}
static void swapLeft(void)
{
tPos x = SQUARE_TO_X(gSelectedSquare);
if (x == 0) {
badThingHappened();
return;
}
moveSquareInDir(gSelectedSquare, DIR_LEFT);
selectSquare(gSelectedSquare);
}
static void swapRight(void)
{
tPos x = SQUARE_TO_X(gSelectedSquare);
if (x == BOARD_SIZE - 1) {
badThingHappened();
return;
}
moveSquareInDir(gSelectedSquare, DIR_RIGHT);
selectSquare(gSelectedSquare);
}
static bool isAppleButtonPressed(void)
{
static uint8_t temp;
__asm__("LDA %w", BTN1);
__asm__("STA %v", temp);
return ((temp > 127) ? true : false);
}
static void endGame(void)
{
unshowDblLoRes();
videomode(VIDEOMODE_80x24);
clrscr();
printf("GAME OVER!!!\n");
}
void playGame(void)
{
initGame();
initGame(refreshSquare);
initUI();
drawBoard();
while (true) {
uint8_t ch;
if (gameIsOver()) {
endGame();
return;
}
while (!kbhit()) {
// Maybe do some animation stuff here...
}
switch (cgetc()) {
ch = cgetc();
switch (ch) {
case 'i':
case 'I':
case CH_CURS_UP:
moveUp();
if (isAppleButtonPressed())
swapUp();
else
moveUp();
break;
case 'j':
case 'J':
case CH_CURS_LEFT:
moveLeft();
if (isAppleButtonPressed())
swapLeft();
else
moveLeft();
break;
case 'k':
case 'K':
case CH_CURS_RIGHT:
moveRight();
if (isAppleButtonPressed())
swapRight();
else
moveRight();
break;
case 'm':
case 'M':
case CH_CURS_DOWN:
moveDown();
if (isAppleButtonPressed())
swapDown();
else
moveDown();
break;
case CH_ESC:
@ -260,6 +369,10 @@ void playGame(void)
printInstructions();
drawBoard();
break;
default:
badThingHappened();
break;
}
}
}