diff --git a/.gitattributes b/.gitattributes index 7b97055..c83208d 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,2 +1,3 @@ *.xcf filter=lfs diff=lfs merge=lfs -text *.jpg filter=lfs diff=lfs merge=lfs -text +*.ttf filter=lfs diff=lfs merge=lfs -text diff --git a/Warehouse Title with Layers.xcf b/Warehouse Title with Layers.xcf new file mode 100644 index 0000000..464066e --- /dev/null +++ b/Warehouse Title with Layers.xcf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4b31a77aac2b2d6afce711c2258635c0d8914bd2e438fea482df2f61e908da2a +size 71860 diff --git a/font/Aero Matics Stencil Bold.ttf b/font/Aero Matics Stencil Bold.ttf new file mode 100644 index 0000000..12b7dbb --- /dev/null +++ b/font/Aero Matics Stencil Bold.ttf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3a4a238cc90e8ea9a501efbdaedd87f4622e0d6d3bd18314c6f78dd68f00b395 +size 32472 diff --git a/warehouse/backgrnd.xcf b/warehouse/backgrnd.xcf new file mode 100644 index 0000000..d378a60 --- /dev/null +++ b/warehouse/backgrnd.xcf @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4d57fc78efe117634e9504b9ebe1b77374c98923256f36ad2c8f11dd025e16f5 +size 130558 diff --git a/warehouse/build-IIgs.sh b/warehouse/build-IIgs.sh index da4529d..2ad40d6 100755 --- a/warehouse/build-IIgs.sh +++ b/warehouse/build-IIgs.sh @@ -1,7 +1,7 @@ #!/bin/bash -e -PROJECT=warehouse -DATA=(font.img font.stn kanga.img tiles.img ../puzzles.dat ../index.dat) +PROJECT=Warehouse +DATA=(font.img kanga.img tiles.img backgrnd.img ../puzzles.dat ../index.dat) #SOURCE=(*.c *.h) SOURCE=() diff --git a/warehouse/main.c b/warehouse/main.c index a5affef..1e911fe 100644 --- a/warehouse/main.c +++ b/warehouse/main.c @@ -85,6 +85,9 @@ static byte avatarY; static byte avatarXLast; static byte avatarYLast; +static byte crateCount; +static byte cratesOnTarget; + static char puzzleChars[] = { "_# .$@+*" }; static CoordT tileLookup[TILE_COUNT] = { @@ -100,10 +103,18 @@ static CoordT tileLookup[TILE_COUNT] = { void drawAvatar(void); +byte drawMenu(char *menu[], byte width, byte *height, byte *offsetX, byte *offsetY); void drawPuzzle(void); +void forceFullRedraw(void); void loadPuzzle(jint16 number); +bool menu(void); +void moveCrate(byte sx, byte sy, byte dx, byte dy); +void play(void); void printPuzzle(char *message, byte which[MAX_WIDTH][MAX_HEIGHT]); void printAt(jlImgT *font, jint16 cx, jint16 cy, const char *what, ...); +void redraw(void); +void showPalette(void); +void title(void); void drawAvatar(void) { @@ -122,6 +133,72 @@ void drawAvatar(void) { } +byte drawMenu(char *menu[], byte width, byte *height, byte *offsetX, byte *offsetY) { + + jint16 count = 0; + jint16 lx = ((byte)221 % 40) << 3; // Left-hand block ASCII + jint16 ly = ((byte)221 / 40) << 3; + jint16 rx = ((byte)222 % 40) << 3; // Right-hand block ASCII + jint16 ry = ((byte)222 / 40) << 3; + jint16 tx = ((byte)223 % 40) << 3; // Top-half block ASCII + jint16 ty = ((byte)223 / 40) << 3; + jint16 bx = ((byte)220 % 40) << 3; // Bottom-half block ASCII + jint16 by = ((byte)220 / 40) << 3; + jint16 x1; + jint16 y1; + jint16 x2; + jint16 y2; + jint16 y3; + + // 222 223 221 + // 222 220 221 + + // Calculate height and offsets from menu count. + while (menu[count]) { + count++; + } + *height = 13 + count; + *offsetX = 20 - width / 2; + *offsetY = 11 - *height / 2; + + // Clear area behind menu. Slightly higher and lower to add borders to the non-bordered ASCII characters. + jlDrawBoxFilled(*offsetX * 8, *offsetY * 8 - 4, (*offsetX + width + 1) * 8, (*offsetY + *height) * 8 + 4); + + // Draw sides. + x1 = *offsetX * 8; + x2 = (*offsetX + width) * 8; + for (y1=(*offsetY * 8); y1<(*offsetY + *height) * 8; y1+=8) { + jlDrawBlit8x8(jlImgSurfaceGet(fontI), rx, ry, x1, y1); + jlDrawBlit8x8(jlImgSurfaceGet(fontI), lx, ly, x2, y1); + } + + // Draw horizontal lines. + y1 = *offsetY * 8; + y2 = (*offsetY + 4) * 8; + y3 = (*offsetY + *height - 1) * 8; + for (x1=(*offsetX + 1) * 8; x1<(*offsetX + width) * 8; x1+=8) { + jlDrawBlit8x8(jlImgSurfaceGet(fontI), tx, ty, x1, y1); + jlDrawBlit8x8(jlImgSurfaceGet(fontI), bx, by, x1, y2); + jlDrawBlit8x8(jlImgSurfaceGet(fontI), bx, by, x1, y3); + } + + printAt(fontI, 16, *offsetY + 2, "Main Menu"); + + // Draw menu. + x1 = *offsetX + 5; + y1 = *offsetY + 7; + count = 0; + while (menu[count]) { + printAt(fontI, x1, y1, menu[count]); + y1+=2; + count++; + } + + // Returns number of menu items. + return count; +} + + void drawPuzzle(void) { byte bx = 0; // Board coordinates. byte by = 0; @@ -147,6 +224,12 @@ void drawPuzzle(void) { } +void forceFullRedraw(void) { + // Clear "displayed" board so it has to redraw. + memset(&puzzleBefore, TILE_NOTHING, sizeof(byte) * MAX_WIDTH * MAX_HEIGHT); +} + + void loadPuzzle(jint16 number) { FILE *in = NULL; byte x = 0; @@ -157,6 +240,9 @@ void loadPuzzle(jint16 number) { in = fopen("data/puzzles.dat", "rb"); if (!in) jlUtilDie("Unable to open puzzle database!"); + crateCount = 0; + cratesOnTarget = 0; + // Skip to requested puzzle. fseek(in, puzzleIndex[number - 1], SEEK_SET); // Load width of puzzle @@ -191,6 +277,14 @@ void loadPuzzle(jint16 number) { avatarX = x + 1; avatarY = y; } + // Get crate tallys. + if ((puzzle.puzzle[x][y] == TILE_CRATE) || (puzzle.puzzle[x + 1][y] == TILE_CRATE)) { + crateCount++; + } + if ((puzzle.puzzle[x][y] == TILE_CRATE_ON_GOAL) || (puzzle.puzzle[x + 1][y] == TILE_CRATE_ON_GOAL)) { + crateCount++; + cratesOnTarget++; + } } } @@ -200,11 +294,244 @@ void loadPuzzle(jint16 number) { puzzle.offsetX = (10 - puzzle.width / 2) * 2; puzzle.offsetY = (6 - puzzle.height / 2) * 2; - // Make copie for our rendering array. + // Make copy for our rendering array. memcpy(&puzzleNow, puzzle.puzzle, sizeof(byte) * MAX_WIDTH * MAX_HEIGHT); - // Clear "displayed" board so it has to redraw. - memset(&puzzleBefore, TILE_NOTHING, sizeof(byte) * MAX_WIDTH * MAX_HEIGHT); + forceFullRedraw(); +} + + +bool menu(void) { + + char *menu[] = { "About", "How to Play", "Select Level", "Reset Level", "Exit", 0 }; + byte count = 0; + byte height; + byte offsetX; + byte offsetY; + byte inMenuYOffset = 7; + byte key; + jint16 rx = ((byte)175 % 40) << 3; // Right Arrows ASCII + jint16 ry = ((byte)175 / 40) << 3; + jint16 sx = ((byte)32 % 40) << 3; // Space ASCII + jint16 sy = ((byte)32 / 40) << 3; + jint16 xpos; + jint16 ypos; + jint16 selected; + jint16 last; + jint16 lastY; + bool inMenu = true; + bool keepPlayingn = true; + + count = drawMenu(menu, 20, &height, &offsetX, &offsetY); + + inMenuYOffset += offsetY; + xpos = (offsetX + 3) * 8; + ypos = inMenuYOffset * 8; + lastY = ypos; + selected = 0; + last = 1; + while (inMenu && !jlUtilMustExit()) { + if (jlKeyPressed()) { + while (jlKeyPressed()) { + key = jlKeyRead(); + } + switch (key) { + case 27: + inMenu = false; + forceFullRedraw(); + jlDrawClear(); + break; + + case 13: + switch (selected) { + case 4: // Exit + inMenu = false; + keepPlayingn = false; + break; + } + break; + + case 'I': + case 'i': + if (selected > 0) { + selected--; + ypos -= 16; + } else { + selected = count - 1; + ypos = (inMenuYOffset + (count - 1) * 2) * 8; + } + break; + + case 'M': + case 'm': + if (selected < count - 1) { + selected++; + ypos += 16; + } else { + selected = 0; + ypos = inMenuYOffset * 8; + } + break; + } + } + if (selected != last) { + jlDrawBlit8x8(jlImgSurfaceGet(fontI), sx, sy, xpos, lastY); + jlDrawBlit8x8(jlImgSurfaceGet(fontI), rx, ry, xpos, ypos); + jlDisplayPresent(); + lastY = ypos; + last = selected; + } + } + + // Return 'false' to exit the game. + return keepPlayingn; +} + + +void moveCrate(byte sx, byte sy, byte dx, byte dy) { + + if (puzzleNow[sx][sy] == TILE_CRATE) { + puzzleNow[sx][sy] = TILE_FLOOR; + } else { + puzzleNow[sx][sy] = TILE_GOAL; + cratesOnTarget--; + } + + if (puzzleNow[dx][dy] == TILE_FLOOR) { + puzzleNow[dx][dy] = TILE_CRATE; + } else { + puzzleNow[dx][dy] = TILE_CRATE_ON_GOAL; + cratesOnTarget++; + } +} + + +void play(void) { + jint16 current = 1; + jint16 last = 0; + char key = 0; + bool playing = true; + byte tile = 0; + + // Force tile palette + jlImgDisplay(tilesI); + + // Show menu on entry + playing = menu(); + + while (playing && !jlUtilMustExit()) { + if (jlKeyPressed()) { + while (jlKeyPressed()) { + key = jlKeyRead(); + } + avatarXLast = avatarX; + avatarYLast = avatarY; + switch (key) { + case 27: + playing = menu(); + if (playing) redraw(); + break; + + case 'Q': + case 'q': + current--; + if (current < 1) { + current = puzzleCount; + } + break; + + case 'W': + case 'w': + current++; + if (current >= puzzleCount) { + current = 1; + } + break; + + case 'I': + case 'i': + // Can we move up? + tile = puzzleNow[avatarX][avatarY - 1]; + if ((tile == TILE_FLOOR) || (tile == TILE_GOAL)) { + avatarY--; + } + // Can we push up? + if ((tile == TILE_CRATE) || (tile == TILE_CRATE_ON_GOAL)) { + tile = puzzleNow[avatarX][avatarY - 2]; + if ((tile == TILE_FLOOR) || (tile == TILE_GOAL)) { + avatarY--; + moveCrate(avatarX, avatarY, avatarX, avatarY - 1); + } + } + break; + + case 'J': + case 'j': + // Can we move left? + tile = puzzleNow[avatarX - 1][avatarY]; + if ((tile == TILE_FLOOR) || (tile == TILE_GOAL)) { + avatarX--; + } + // Can we push left? + if ((tile == TILE_CRATE) || (tile == TILE_CRATE_ON_GOAL)) { + tile = puzzleNow[avatarX - 2][avatarY]; + if ((tile == TILE_FLOOR) || (tile == TILE_GOAL)) { + avatarX--; + moveCrate(avatarX, avatarY, avatarX - 1, avatarY); + } + } + break; + + case 'K': + case 'k': + // Can we move right? + tile = puzzleNow[avatarX + 1][avatarY]; + if ((tile == TILE_FLOOR) || (tile == TILE_GOAL)) { + avatarX++; + } + // Can we push right? + if ((tile == TILE_CRATE) || (tile == TILE_CRATE_ON_GOAL)) { + tile = puzzleNow[avatarX + 2][avatarY]; + if ((tile == TILE_FLOOR) || (tile == TILE_GOAL)) { + avatarX++; + moveCrate(avatarX, avatarY, avatarX + 1, avatarY); + } + } + break; + + case 'M': + case 'm': + // Can we move down? + tile = puzzleNow[avatarX][avatarY + 1]; + if ((tile == TILE_FLOOR) || (tile == TILE_GOAL)) { + avatarY++; + } + // Can we push down? + if ((tile == TILE_CRATE) || (tile == TILE_CRATE_ON_GOAL)) { + tile = puzzleNow[avatarX][avatarY + 2]; + if ((tile == TILE_FLOOR) || (tile == TILE_GOAL)) { + avatarY++; + moveCrate(avatarX, avatarY, avatarX, avatarY + 1); + } + } + break; + } + } + // Load new level? + if (last != current) { + last = current; + loadPuzzle(current); + avatarXLast = -1; + avatarYLast = -1; + jlDrawClear(); + printAt(fontI, 0, 24, "%d puzzles. Showing #%d", puzzleCount, current); + } + // Redraw? + if ((avatarX != avatarXLast) || (avatarY != avatarYLast)) { + puzzleBefore[avatarXLast][avatarYLast] = TILE_NOTHING; + redraw(); + } + } } @@ -241,33 +568,64 @@ void printAt(jlImgT *font, jint16 cx, jint16 cy, const char *what, ...) { ty = cy << 3; for (counter=0; counter<(int)strlen(msg); counter++) { - x = (msg[counter] % 40) << 3; - y = (msg[counter] / 40) << 3; + x = ((byte)msg[counter] % 40) << 3; + y = ((byte)msg[counter] / 40) << 3; jlDrawBlit8x8(jlImgSurfaceGet(font), x, y, tx, ty); tx += 8; } } -int main(void) { - FILE *in = NULL; - jint16 current = 1; - jint16 last = 0; - char key = 0; - bool playing = true; +void redraw(void) { + //printPuzzle("Now", puzzleNow); + //printPuzzle("Before", puzzleBefore); + drawPuzzle(); + drawAvatar(); + printAt(fontI, 30, 24, "%d/%d ", cratesOnTarget, crateCount); + jlDisplayPresent(); +} - jlUtilStartup("Warehouse"); - // Get something on the screen as quickly as possible. +void showPalette(void) { + byte x; + for (x=0; x<16; x++) { + jlDrawColorSet(x); + jlDrawBoxFilled(x * 20, 179, x * 20 + 19, 199); + } +} + + +void title(void) { + + char *images[] = { "kanga", "backgrnd", 0 }; + byte count = 0; + jlDrawColorSet(0); jlDisplayBorder(BORDER_BLACK); jlDrawClear(); - // For splash screens, reuse tilesI to save memory. - jlImgLoad(tilesI, "kanga"); - if (!tilesI) jlUtilDie("Unable to load kanga!"); - jlImgDisplay(tilesI); - jlDisplayPresent(); + while (images[count] && !jlUtilMustExit()) { + // For splash screens, reuse tilesI to save memory. + jlImgLoad(tilesI, images[count]); + jlImgDisplay(tilesI); + //showPalette(); + jlDisplayPresent(); + jlUtilSleep(20); + jlDrawClear(); + jlDisplayPresent(); + jlUtilSleep(3); + count++; + } +} + + +int main(void) { + FILE *in = NULL; + + jlUtilStartup("Warehouse"); + + // Get something on the screen as quickly as possible. + //title(); // Load the rest of our data. jlImgLoad(tilesI, "tiles"); @@ -303,85 +661,7 @@ int main(void) { memset(saveGame.solved, 0, saveGame.solvedSize); } - // Force tile palette - jlImgDisplay(tilesI); - - while (playing && !jlUtilMustExit()) { - if (jlKeyPressed()) { - while (jlKeyPressed()) { - key = jlKeyRead(); - } - avatarXLast = avatarX; - avatarYLast = avatarY; - switch (key) { - case 27: - playing = false; - break; - - case 'Q': - case 'q': - current--; - if (current < 1) { - current = puzzleCount; - } - break; - - case 'W': - case 'w': - current++; - if (current >= puzzleCount) { - current = 1; - } - break; - - case 'I': - case 'i': - if (puzzleNow[avatarX][avatarY - 1] == TILE_FLOOR) { - avatarY--; - } - break; - - case 'J': - case 'j': - if (puzzleNow[avatarX - 1][avatarY] == TILE_FLOOR) { - avatarX--; - } - break; - - case 'K': - case 'k': - if (puzzleNow[avatarX + 1][avatarY] == TILE_FLOOR) { - avatarX++; - } - break; - - case 'M': - case 'm': - if (puzzleNow[avatarX][avatarY + 1] == TILE_FLOOR) { - avatarY++; - } - break; - } - } - // Load new level? - if (last != current) { - last = current; - loadPuzzle(current); - avatarXLast = -1; - avatarYLast = -1; - jlDrawClear(); - printAt(fontI, 0, 24, "%d puzzles found. Showing #%d", puzzleCount, current); - } - // Redraw? - if ((avatarX != avatarXLast) || (avatarY != avatarYLast)) { - puzzleBefore[avatarXLast][avatarYLast] = TILE_NOTHING; - //printPuzzle("Now", puzzleNow); - //printPuzzle("Before", puzzleBefore); - drawPuzzle(); - drawAvatar(); - jlDisplayPresent(); - } - } + play(); jlFree(saveGame.solved); jlFree(puzzleIndex);