#include #include #include #include #include #include "Level.h" #include "Editor.h" #include "Gameplay.h" #include "HighScoresList.h" #include "GuiElement.h" #include "InputCallback.h" #include "InputCheckBox.h" #include "InputDismissWindow.h" #include "InputLabel.h" #include "InputMenu.h" #include "InputRadioButtonSet.h" #include "InputScrollbar.h" #include "InputScrollingMenu.h" #include "InputText.h" #include "InputWindow.h" #include "csv.h" #include "wildcards.h" #include "constant.h" #include "smalldat.h" #include "bigdat.h" using namespace std; static DATAFILE *data; PALETTE currentColorPalette; PALETTE energizerPalette; RGB black = {0, 0, 0}; RGB blue = {0, 0, 63}; RGB white = {63, 63, 63}; RGB red = {63, 0, 0}; RGB pink = {63, 32, 63}; RGB cyan = {0, 63, 63}; RGB orange = {63, 32, 0}; RGB purplishBlue = {32, 32, 63}; RGB green = {0, 63, 0}; RGB yellow = {63, 63, 21}; RGB purple = {63, 0, 63}; RGB lightBlue = {32, 32, 63}; RGB darkGray = {32, 32, 32}; RGB lightGreen = {32, 63, 32}; RGB yellowGreen = {32, 63, 0}; RGB reddishPurple = {63, 0, 32}; RGB darkRed = {32, 0, 0}; RGB darkGreen = {0, 32, 0}; RGB darkBlue = {0, 0, 32}; RGB darkYellow = {32, 32, 0}; RGB blueGreen = {48, 0, 48}; RGB darkBlueGreen = {0, 32, 32}; RGB darkPurple = {32, 0, 32}; RGB brown = {48, 32, 16}; RGB gray = {48, 48, 48}; RGB offWhite = {56, 56, 56}; RGB tanColor = {56, 48, 32}; const int wallColorSequenceLength = 25; const RGB* wallColorSequence[wallColorSequenceLength] = { /* 1. */ &blue, /* 2. */ &green, /* 3. */ &yellow, /* 4. */ &purple, /* 5. */ &red, /* 6. */ &brown, /* 7. */ &pink, /* 8. */ &cyan, /* 9. */ &orange, /* 10. */ &yellowGreen, /* 11. */ &lightBlue, /* 12. */ &tanColor, /* 13. */ &reddishPurple, /* 14. */ &darkGray, /* 15. */ &lightGreen, /* 16. */ &purplishBlue, /* 17. */ &darkGreen, /* 18. */ &darkYellow, /* 19. */ &gray, /* 20. */ &blueGreen, /* 21. */ &darkBlueGreen, /* 22. */ &darkPurple, /* 23. */ &darkBlue, /* 24. */ &darkRed, /* 25. */ &offWhite }; char oldPauseKey; char oldMenuKey; int installMouseReturnValue; int oldMousePos; int oldMouseB; bool joystickInstalled; int joystickId; int joystickStickId; int joystickMedium; float joystickThreshold; int enableJoystick; InputLabel *joyLitPointer; InputText *joyIdControlPointer; InputText *joyStickControlPointer; InputRadioButtonSet *joyMediumControlPointer; int installSoundReturnValue; int soundFx, music; RLE_SPRITE *wall[0x20]; RLE_SPRITE *enemy[4]; RLE_SPRITE *enemyReward[4]; RLE_SPRITE *bonus[40]; FONT *joystix; FONT *pacmania; SAMPLE *startSound; SAMPLE *dieSound; SAMPLE *dotSound; SAMPLE *energizerSound; SAMPLE *enemySound; SAMPLE *bonusSound; SAMPLE *gainSound; MIDI *popcorn; bool blitWalls, blitEnemies, blitEnemyRewards; BITMAP *vramWall[0x20]; BITMAP *vramEnemy[4]; BITMAP *vramEnemyReward[4]; BITMAP *tileImage; graphicsBufferingTechnique bestGfxTechnique, currentGfxTechnique; int currentVideoPageIndex; BITMAP *videoPage[3]; int layerCount; BITMAP *layer[maxLayers]; bool forgotScreen; BITMAP *layerBackup[maxLayers]; static vector bitmapInventory; static const int mainMenuLength = 7; static const char *mainMenuCommand[mainMenuLength] = { "Play files listed in CSV file", " Use wildcard specification ", " View high scores ", " View credits ", " Editor ", " Settings ", " Quit " }; static const int mainMenuAcceleratorKey[mainMenuLength] = { 21, 5, 12, 15, 12, 11, 13 }; static const int badLevelFileMenuLength = 3; static const char *badLevelFileMenuCommand[badLevelFileMenuLength] = { " Skip level ", " End game ", " Retry " }; static const int badLevelFileMenuAcceleratorKey[badLevelFileMenuLength] = { 15, 15, 12 }; static const int badLevelMenuLength = 4; static const char *badLevelMenuCommand[badLevelMenuLength] = { " Skip level ", " End game ", " Fix level ", " Reload " }; static const int badLevelMenuAcceleratorKey[badLevelMenuLength] = { 15, 15, 10, 12 }; int gfxTechniqueOfChoice; static const int gfxTechniqueMenuLength = 3; static const char *gfxTechniqueMenuCommand[gfxTechniqueMenuLength] = { "Triple buffering", "Double buffering", "Neither" }; static const int gfxTechniqueMenuAcceleratorKey[gfxTechniqueMenuLength] = { 0, 0, 0 }; static const int joyMediumMenuLength = 2; static const char *joyMediumMenuCommand[joyMediumMenuLength] = { "Analogue", "Digital" }; static const int joyMediumMenuAcceleratorKey[joyMediumMenuLength] = { 0, 0 }; bool christmasTime; extern const char *csvProblem; extern const char *wildcardProblem; int lives, gains, score, levelNumber; int fnFilesLength; char **fnFilesCommand; bool fnWildcardError; InputText *fnQueryFieldPointer; InputLabel *fnProblemFieldPointer; InputScrollingMenu *fnFilesPointer; InputScrollbar *fnScrollPointer; char *fnActiveQuery; extern Level dummyLevel; extern int editorBonusIndex; volatile bool heartBeat; volatile int countUp; void unload() { if (installMouseReturnValue != -1) show_mouse(NULL); unload_datafile(data); for (vector::iterator i = bitmapInventory.begin(); i < bitmapInventory.end(); i++) destroy_bitmap(*i); if (set_gfx_mode(GFX_TEXT, 0, 0, 0, 0)) exit(2); } void createMutableSprite(BITMAP **sprite, int width, int height, bool memorable) { *sprite = (!memorable && (gfx_capabilities & GFX_HW_VRAM_BLIT)) ? create_video_bitmap(width, height) : NULL; if (!*sprite) { *sprite = (gfx_capabilities & GFX_HW_SYS_TO_VRAM_BLIT) ? create_system_bitmap(width, height) : NULL; if (!*sprite) { *sprite = create_bitmap(width, height); if (!*sprite) { unload(); allegro_message("Outrageous shortage of memory."); exit(0); } } } bitmapInventory.push_back(*sprite); } void createMaskedMutableSprite(BITMAP **sprite, int width, int height, bool memorable) { *sprite = (!memorable && (gfx_capabilities & GFX_HW_VRAM_BLIT_MASKED)) ? create_video_bitmap(width, height) : NULL; if (!*sprite) { *sprite = (gfx_capabilities & GFX_HW_SYS_TO_VRAM_BLIT_MASKED) ? create_system_bitmap(width, height) : NULL; if (!*sprite) { *sprite = create_bitmap(width, height); if (!*sprite) { unload(); allegro_message("Outrageous shortage of memory."); exit(0); } } } bitmapInventory.push_back(*sprite); } void drawSpritesForBlitting() { if (blitWalls) for (int i = 0x00; i < 0x20; i++) { clear_bitmap(vramWall[i]); draw_rle_sprite(vramWall[i], wall[i], 0, 0); } if (blitEnemies) for (int i = 0; i < 4; i++) { clear_bitmap(vramEnemy[i]); draw_rle_sprite(vramEnemy[i], enemy[i], 0, 0); } if (blitEnemyRewards) for (int i = 0; i < 4; i++) { clear_bitmap(vramEnemyReward[i]); draw_rle_sprite(vramEnemyReward[i], enemyReward[i], 0, 0); } } void showFrame() { switch (currentGfxTechnique) { case doubleBuffering: while (show_video_bitmap(videoPage[currentVideoPageIndex])); if (installMouseReturnValue != -1) show_mouse(videoPage[currentVideoPageIndex]); currentVideoPageIndex = !currentVideoPageIndex; break; case tripleBuffering: while (poll_scroll()); while (request_video_bitmap(videoPage[currentVideoPageIndex])); if (installMouseReturnValue != -1) show_mouse(videoPage[currentVideoPageIndex]); currentVideoPageIndex = (currentVideoPageIndex + 1) % 3; } } void changeGfxTechnique(graphicsBufferingTechnique desiredGfxTechnique) { currentGfxTechnique = desiredGfxTechnique; if (currentGfxTechnique == none) { while (show_video_bitmap(videoPage[currentVideoPageIndex])); if (installMouseReturnValue != -1) show_mouse(videoPage[currentVideoPageIndex]); } } void considerUserGfxChoice() { graphicsBufferingTechnique parsedGfxChoice; switch (gfxTechniqueOfChoice) { case 0: parsedGfxChoice = tripleBuffering; break; case 1: parsedGfxChoice = doubleBuffering; break; case 2: parsedGfxChoice = none; } changeGfxTechnique(bestGfxTechnique < parsedGfxChoice ? bestGfxTechnique : parsedGfxChoice); } void resumeExecution() { forgotScreen = get_display_switch_mode() == SWITCH_AMNESIA || get_display_switch_mode() == SWITCH_BACKAMNESIA; } void createGraphicsBackup(int layersWanted) { for (int i = 0; i < layersWanted; i++) if (is_video_bitmap(layer[i])) blit(layer[i], layerBackup[i], 0, 0, 0, 0, SCREEN_W, SCREEN_H); } void restoreGraphicsBackup(int layersWanted) { for (int i = 0; i < layersWanted; i++) if (is_video_bitmap(layer[i])) blit(layerBackup[i], layer[i], 0, 0, 0, 0, SCREEN_W, SCREEN_H); } void isItChristmasYet() { time_t rawNow; time(&rawNow); struct tm *localNow = localtime(&rawNow); christmasTime = localNow->tm_mon == 11 || localNow->tm_mon == 0 && localNow->tm_mday <= 6; } void generalDrawPacMan(direction headed, fixed jawBinaryAngle) { clear_bitmap(tileImage); if (jawBinaryAngle <= itofix(0)) circlefill(tileImage, halfTileSize, halfTileSize, halfTileSize, 14); else if (jawBinaryAngle < itofix(128)) { const fixed lipBinaryAngle1 = throatBinaryAngle[headed] + jawBinaryAngle; const fixed lipBinaryAngle2 = throatBinaryAngle[headed] + itofix(256) - jawBinaryAngle; arc(tileImage, halfTileSize, halfTileSize, lipBinaryAngle1, lipBinaryAngle2, halfTileSize, 14); line(tileImage, halfTileSize, halfTileSize, halfTileSize + fixtoi(halfTileSize * fixcos(lipBinaryAngle1)), halfTileSize - fixtoi(halfTileSize * fixsin(lipBinaryAngle1)), 14); line(tileImage, halfTileSize, halfTileSize, halfTileSize + fixtoi(halfTileSize * fixcos(lipBinaryAngle2)), halfTileSize - fixtoi(halfTileSize * fixsin(lipBinaryAngle2)), 14); switch (headed) { case up: floodfill(tileImage, halfTileSize, halfTileSize + halfTileSize - 1, 14); break; case left: floodfill(tileImage, halfTileSize + halfTileSize - 1, halfTileSize, 14); break; case right: floodfill(tileImage, halfTileSize - halfTileSize + 1, halfTileSize, 14); break; case down: floodfill(tileImage, halfTileSize, halfTileSize - halfTileSize + 1, 14); } } } void drawPupils(BITMAP *canvas, int x, int y, direction headed) { switch (headed) { case up: circlefill(canvas, x + leftEyeX, y + leftEyeY - pupilOffset, pupilRadius, 16); circlefill(canvas, x + rightEyeX, y + rightEyeY - pupilOffset, pupilRadius, 16); break; case left: circlefill(canvas, x + leftEyeX - pupilOffset, y + leftEyeY, pupilRadius, 16); circlefill(canvas, x + rightEyeX - pupilOffset, y + rightEyeY, pupilRadius, 16); break; case right: circlefill(canvas, x + leftEyeX + pupilOffset, y + leftEyeY, pupilRadius, 16); circlefill(canvas, x + rightEyeX + pupilOffset, y + rightEyeY, pupilRadius, 16); break; case down: circlefill(canvas, x + leftEyeX, y + leftEyeY + pupilOffset, pupilRadius, 16); circlefill(canvas, x + rightEyeX, y + rightEyeY + pupilOffset, pupilRadius, 16); } } void drawCredits(BITMAP *canvas) { clear_bitmap(canvas); textout_centre_ex(canvas, pacmania, "CREDITS", SCREEN_W / 2, 0, 14, -1); textout_ex(canvas, joystix, "Original Pac Man", 0, 100, 15, -1); textout_ex(canvas, joystix, "Toru Iwatani", 44, 120, 15, -1); textout_ex(canvas, joystix, "Programming & design", 0, 140, 15, -1); textout_ex(canvas, joystix, "Avery Musbach", 44, 160, 15, -1); textout_ex(canvas, joystix, "Allegro (cross-platform lib)", 0, 180, 15, -1); textout_ex(canvas, joystix, "Community effort, started", 44, 200, 15, -1); textout_ex(canvas, joystix, "by Shawn Hargreaves", 44, 220, 15, -1); textout_ex(canvas, joystix, "Joystix (TrueType font)", 0, 240, 15, -1); textout_ex(canvas, joystix, "Ray Larabie", 44, 260, 15, -1); textout_ex(canvas, joystix, "Pacmania (TrueType font)", 0, 280, 15, -1); textout_ex(canvas, joystix, "Neale Davidson", 44, 300, 15, -1); textout_ex(canvas, joystix, "Other graphics", 0, 320, 15, -1); textout_ex(canvas, joystix, "Avery Musbach", 44, 340, 15, -1); textout_ex(canvas, joystix, "Original Popcorn", 0, 360, 15, -1); textout_ex(canvas, joystix, "Gershon Kingsley", 44, 380, 15, -1); textout_ex(canvas, joystix, "Programming tools", 0, 400, 15, -1); textout_ex(canvas, joystix, "GNU", 44, 420, 15, -1); textout_ex(canvas, joystix, "trueSpace 5.1 (3D graphics)", 0, 440, 15, -1); textout_ex(canvas, joystix, "Caligari", 44, 460, 15, -1); } void drawFrame() { if (installMouseReturnValue != -1 && currentGfxTechnique == none) scare_mouse(); blit(layer[0], videoPage[currentVideoPageIndex], 0, 0, 0, 0, SCREEN_W, SCREEN_H); for (int i = 1; i < layerCount; i++) draw_sprite(videoPage[currentVideoPageIndex], layer[i], 0, 0); if (installMouseReturnValue != -1 && currentGfxTechnique == none) unscare_mouse(); } void go(int *x, int *y, int step, int xMax, int yMax, direction way) { switch (way) { case up: *y = (*y + yMax - step) % yMax; break; case left: *x = (*x + xMax - step) % xMax; break; case right: *x = (*x + step) % xMax; break; case down: *y = (*y + step) % yMax; } } void go(double *x, double *y, double step, int xMax, int yMax, direction way) { switch (way) { case up: *y -= step; if (*y < 0) *y += yMax; break; case left: *x -= step; if (*x < 0) *x += xMax; break; case right: *x += step; if (*x >= xMax) *x -= xMax; break; case down: *y += step; if (*y >= yMax) *y -= yMax; } } void bringRectangleInteriorOntoScreen(int *x, int *y, int width, int height) { if (*x < 1) *x = 1; else if (*x + width > SCREEN_W - 1) *x = SCREEN_W - width - 1; if (*y < 1) *y = 1; else if (*y + height > SCREEN_H - 1) *y = SCREEN_H - height - 1; } void loopingLine(BITMAP *canvas, int x1, int y1, int x2, int y2, int color) { const bool phone2 = y1 >= boardH * tileSize || y2 >= boardH * tileSize; const bool phone4 = x1 >= boardW * tileSize || x2 >= boardW * tileSize; const bool phone6 = x1 < 0 || x2 < 0; const bool phone8 = y1 < 0 || y2 < 0; const bool phone1 = phone2 && phone4; const bool phone3 = phone2 && phone6; const bool phone7 = phone4 && phone8; const bool phone9 = phone6 && phone8; if (phone1) line(canvas, x1 - boardW * tileSize, y1 - boardH * tileSize, x2 - boardW * tileSize, y2 - boardH * tileSize, color); if (phone2) line(canvas, x1, y1 - boardH * tileSize, x2, y2 - boardH * tileSize, color); if (phone3) line(canvas, x1 + boardW * tileSize, y1 - boardH * tileSize, x2 + boardW * tileSize, y2 - boardH * tileSize, color); if (phone4) line(canvas, x1 - boardW * tileSize, y1, x2 - boardW * tileSize, y2, color); line(canvas, x1, y1, x2, y2, color); // phone5 is assumed. if (phone6) line(canvas, x1 + boardW * tileSize, y1, x2 + boardW * tileSize, y2, color); if (phone7) line(canvas, x1 - boardW * tileSize, y1 + boardH * tileSize, x2 - boardW * tileSize, y2 + boardH * tileSize, color); if (phone8) line(canvas, x1, y1 + boardH * tileSize, x2, y2 + boardH * tileSize, color); if (phone9) line(canvas, x1 + boardW * tileSize, y1 + boardH * tileSize, x2 + boardW * tileSize, y2 + boardH * tileSize, color); } bool actorCollision(int x1, int y1, int x2, int y2, int threshold) { const int xDistance = x1 > x2 ? x1 - x2 : x2 - x1; const int yDistance = y1 > y2 ? y1 - y2 : y2 - y1; return (xDistance < threshold || boardW * tileSize - xDistance < threshold) && (yDistance < threshold || boardH * tileSize - yDistance < threshold); } void reportScore() { char buf[bufSizeForItoa]; itoa(score, buf, 10); rectfill(layer[0], scoreDisplayX1, scoreDisplayY1, scoreDisplayX2, scoreDisplayY2, 0); textout_right_ex(layer[0], joystix, buf, scoreDisplayX2, scoreDisplayY1, 15, -1); } void reportLives() { rectfill(layer[0], livesDisplayX1, livesDisplayY1, livesDisplayX2, livesDisplayY2, 0); if (lives > (livesDisplayX2 - livesDisplayX1 + 1) / tileSize) { char buf[bufSizeForItoa]; itoa(lives, buf, 10); textout_right_ex(layer[0], joystix, buf, livesDisplayX2, livesDisplayY1, 15, -1); } else { generalDrawPacMan(right, itofix(32)); for (int i = 0; i < lives; i++) draw_sprite(layer[0], tileImage, livesDisplayX2 + 1 - (i + 1) * tileSize, livesDisplayY1); } } int logoMenu(int length, const char **command, const int *acceleratorKey, const char *message1, const char *message2) { layerCount = 1; InputMenu menu(layer[0], 1, SCREEN_H - length * charHeight - 1, length, command, acceleratorKey, true, true); if (open_fli("bigdat.dat#LogoScreen") == FLI_ERROR) { unload(); allegro_message("Couldn't load the logo animation!"); return 0; } int nextReturnValue = next_fli_frame(0); if (nextReturnValue == FLI_ERROR) { unload(); allegro_message("Error playing logo animation!"); return 0; } if (nextReturnValue == FLI_NOT_OPEN) { unload(); allegro_message("Logo animation not open!"); return 0; } memcpy(currentColorPalette, fli_palette, PAL_SIZE * sizeof(RGB)); currentColorPalette[15] = white; currentColorPalette[16] = black; currentColorPalette[interactivityColor] = red; heartBeat = false; install_int(setHeartBeat, artificialLogoAnimationDelay); blit(fli_bitmap, layer[0], 0, 0, 0, 0, SCREEN_W, SCREEN_H); rect(layer[0], 0, SCREEN_H - length * charHeight - 2, SCREEN_W - 1, SCREEN_H - 1, 15); menu.draw(); textout_ex(layer[0], joystix, message1, logoMenuMessageX, logoMenuMessageY, 15, -1); textout_ex(layer[0], joystix, message2, logoMenuMessageX, logoMenuMessageY + charHeight, 15, -1); drawFrame(); showFrame(); set_palette(currentColorPalette); clear_keybuf(); do { do { bool somethingHappened = false; if (mouse_needs_poll()) if (poll_mouse()) { unload(); allegro_message("Couldn't poll the mouse!"); exit(0); } if (keypressed() && menu.acknowledgeKeyStroke(readkey())) somethingHappened = true; if (menu.acknowledgeKeyArray()) somethingHappened = true; if (installMouseReturnValue != -1 && menu.acknowledgeMouse()) somethingHappened = true; if (somethingHappened) menu.draw(); if (forgotScreen) { drawSpritesForBlitting(); blit(fli_bitmap, layer[0], 0, 0, 0, 0, SCREEN_W, SCREEN_H); rect(layer[0], 0, SCREEN_H - length * charHeight - 2, SCREEN_W - 1, SCREEN_H - 1, 15); menu.draw(); textout_ex(layer[0], joystix, message1, logoMenuMessageX, logoMenuMessageY, 15, -1); textout_ex(layer[0], joystix, message2, logoMenuMessageX, logoMenuMessageY + charHeight, 15, -1); drawFrame(); showFrame(); } } while (!heartBeat); heartBeat = false; nextReturnValue = next_fli_frame(0); if (nextReturnValue == FLI_ERROR) { unload(); allegro_message("Error playing logo animation!"); return 0; } if (nextReturnValue == FLI_NOT_OPEN) { unload(); allegro_message("Logo animation not open!"); return 0; } if (fli_bmp_dirty_from <= fli_bmp_dirty_to) { blit(fli_bitmap, layer[0], 0, fli_bmp_dirty_from, 0, fli_bmp_dirty_from, SCREEN_W, fli_bmp_dirty_to - fli_bmp_dirty_from + 1); rect(layer[0], 0, SCREEN_H - length * charHeight - 2, SCREEN_W - 1, SCREEN_H - 1, 15); menu.draw(); textout_ex(layer[0], joystix, message1, logoMenuMessageX, logoMenuMessageY, 15, -1); textout_ex(layer[0], joystix, message2, logoMenuMessageX, logoMenuMessageY + charHeight, 15, -1); drawFrame(); showFrame(); } } while (nextReturnValue != FLI_EOF && !menu.getCommitted()); remove_int(setHeartBeat); close_fli(); return menu.block(false); } void playMatch(int levelPackLength, char **levelPack) { lives = 2; gains = 0; score = 0; levelNumber = 0; Level currentLevel; while (lives >= 0) { const char *fn = levelPack[levelNumber % levelPackLength]; bool hopefulAboutFile = true; while (hopefulAboutFile && !currentLevel.open(fn)) switch (logoMenu(badLevelFileMenuLength, badLevelFileMenuCommand, badLevelFileMenuAcceleratorKey, currentLevel.getProblem(), fn)) { case 0: case -1: fade_out(fadeSpeed); hopefulAboutFile = false; levelNumber++; break; case 1: fade_out(fadeSpeed); hopefulAboutFile = false; lives = -1; break; case 2: fade_out(fadeSpeed); } if (hopefulAboutFile) { Gameplay currentGameplay(currentLevel, bonus[levelNumber % 40]); bool hopefulAboutLevel = true; while (hopefulAboutLevel && !currentGameplay.parse()) { switch (logoMenu(badLevelMenuLength, badLevelMenuCommand, badLevelMenuAcceleratorKey, "Invalid level.", fn)) { case 0: case -1: fade_out(fadeSpeed); hopefulAboutLevel = false; levelNumber++; break; case 1: fade_out(fadeSpeed); hopefulAboutLevel = false; lives = -1; break; case 2: fade_out(fadeSpeed); hopefulAboutLevel = false; memcpy(currentColorPalette, default_palette, PAL_SIZE * sizeof(RGB)); currentColorPalette[15] = white; currentColorPalette[16] = black; currentColorPalette[wallColor] = *wallColorSequence[levelNumber % wallColorSequenceLength]; currentColorPalette[interactivityColor] = red; editorBonusIndex = levelNumber % 40; isItChristmasYet(); edit(¤tLevel, fn); break; case 3: fade_out(fadeSpeed); hopefulAboutLevel = false; } if (hopefulAboutLevel) currentGameplay = Gameplay(currentLevel, bonus[levelNumber % 40]); } if (hopefulAboutLevel) { memcpy(currentColorPalette, default_palette, PAL_SIZE * sizeof(RGB)); currentColorPalette[wallColor] = *wallColorSequence[levelNumber % wallColorSequenceLength]; currentColorPalette[interactivityColor] = red; levelNumber++; isItChristmasYet(); currentGameplay.play(); } } } HighScoresList highScores; if (file_exists("Hiscores.csv", FA_ALL, NULL)) if (!highScores.load()) { unload(); allegro_message( "Problem loading high scores:\n%s\n\nYour score was: %d", highScores.getProblem(), score); exit(0); } layerCount = 2; clear_bitmap(layer[0]); clear_bitmap(layer[1]); highScores.judge(layer[0], 1, false); if (!highScores.save()) { unload(); allegro_message( "Problem saving the high scores:\n%s\n\nYour score was: %d", highScores.getProblem(), score); exit(0); } } void guiMessage(BITMAP *canvas, const char *msg) { const int msgW = strlen(msg) * charWidth; const int widthMandatedByMsg = msgW + 10 + 2; const int widthMandatedByTitleBar = titleBarOffset + 7 * charWidth + 5 + 150 + 5 + 1; const int w = widthMandatedByMsg > widthMandatedByTitleBar ? widthMandatedByMsg : widthMandatedByTitleBar; const int h = 100; const int x = SCREEN_W / 2 - w / 2; const int y = SCREEN_H / 2 - h / 2; InputLabel lit(canvas, x + w / 2 - msgW / 2, y + titleBarHeight + 2 + 5, msg); InputDismissWindow ok(canvas, NULL, 0, x + w / 2 - 150 / 2, y + h - 1 - 30, 150, 25, "OK"); InputDismissWindow close(canvas, NULL, -1, x + w - 1 - 155, y + 1, 150, 25, "Close"); GuiElement *controls[3] = {&lit, &ok, &close}; InputWindow window(canvas, 3, controls, x, y, w, h, "Message", true); ok.setWindow(&window); close.setWindow(&window); window.block(false); window.erase(); } void callbackForFnPrompt() { int fnFilesLengthBackup = fnFilesLength; char **fnFilesCommandBackup = fnFilesCommand; char *query = fnQueryFieldPointer->getValue(); fnWildcardError = !wildcards(&fnFilesLength, &fnFilesCommand, query, false); if (fnWildcardError) { fnProblemFieldPointer->setCaption(wildcardProblem); free(query); } else { fnProblemFieldPointer->setCaption(""); fnFilesPointer->setCommand(fnFilesLength, fnFilesCommand); destroyWildcards(fnFilesLengthBackup, fnFilesCommandBackup); fnScrollPointer->setLimit(fnFilesLength - 1); free(fnActiveQuery); fnActiveQuery = query; } } void callbackForFnPromptScrollbar() { if (fnFilesPointer->getScrollPosition() != fnScrollPointer->getValue()) fnFilesPointer->setScrollPosition(fnScrollPointer->getValue()); } void callbackForFnPromptScrollingMenu() { if (fnScrollPointer->getValue() != fnFilesPointer->getScrollPosition()) fnScrollPointer->setValue(fnFilesPointer->getScrollPosition()); } char* fnPrompt(BITMAP *canvas, int layerDonation, const char *title, const char *defaultQuery, bool blinking) { fnActiveQuery = (char*)malloc((strlen(defaultQuery) + 1) * sizeof(char)); if (!fnActiveQuery) { unload(); allegro_message("Out of memory."); exit(0); } strcpy(fnActiveQuery, defaultQuery); fnWildcardError = !wildcards(&fnFilesLength, &fnFilesCommand, fnActiveQuery, false); if (fnWildcardError) { fnFilesLength = 1; fnFilesCommand = (char**)malloc(sizeof(char*)); if (!fnFilesCommand) { unload(); allegro_message("Outrageous shortage of memory."); exit(0); } *fnFilesCommand = (char*)malloc(9 * sizeof(char)); if (!fnFilesCommand) { unload(); allegro_message("Outrageous shortage of memory."); exit(0); } strcpy(*fnFilesCommand, "*sheesh*"); } InputLabel directions(canvas, fnPromptDialogX + 1 + 5, fnPromptDialogY + titleBarHeight + 2 + 5, "Wildcard specification:"); InputText queryField(canvas, layerDonation, fnPromptDialogX + 1 + 5, fnPromptDialogY + titleBarHeight + 2 + 30, (fnPromptDialogW - 2 - 10) / charWidth, 4, 10, false, defaultQuery); InputLabel problemField(canvas, fnPromptDialogX + 1 + 5, fnPromptDialogY + titleBarHeight + 2 + 55, fnWildcardError ? wildcardProblem : "", interactivityColor); InputCallback update(canvas, fnPromptDialogX + 1 + 5, fnPromptDialogY + titleBarHeight + 2 + 80, 150, 25, "Update", &callbackForFnPrompt); InputScrollingMenu files(canvas, fnPromptDialogX + 1 + 5, fnPromptDialogY + titleBarHeight + 2 + 105, 15, 4, 4, fnFilesLength, fnFilesCommand, (fnPromptDialogW - 2 - 10 - 20) / charWidth, false, &callbackForFnPromptScrollingMenu); InputScrollbar scroll(canvas, fnPromptDialogX + fnPromptDialogW - 1 - 25, fnPromptDialogY + titleBarHeight + 2 + 105, 20, 15 * charHeight, fnFilesLength - 1, &callbackForFnPromptScrollbar); InputDismissWindow ok(canvas, NULL, 0, fnPromptDialogX + 1 + 5, fnPromptDialogY + fnPromptDialogH - 1 - 30, 150, 25, "OK"); InputDismissWindow cancel(canvas, NULL, -1, fnPromptDialogX + 1 + 160, fnPromptDialogY + fnPromptDialogH - 1 - 30, 150, 25, "Cancel"); InputDismissWindow close(canvas, NULL, -1, fnPromptDialogX + fnPromptDialogW - 1 - 155, fnPromptDialogY + 1, 150, 25, "Close"); GuiElement *fnPromptDialogControls[11] = {&directions, &queryField, &problemField, &update, &files, &scroll, scroll.getUpButtonPointer(), scroll.getDownButtonPointer(), &ok, &cancel, &close}; InputWindow fnPromptDialog(canvas, 11, fnPromptDialogControls, fnPromptDialogX, fnPromptDialogY, fnPromptDialogW, fnPromptDialogH, title, true); ok.setWindow(&fnPromptDialog); cancel.setWindow(&fnPromptDialog); close.setWindow(&fnPromptDialog); fnQueryFieldPointer = &queryField; fnProblemFieldPointer = &problemField; fnFilesPointer = &files; fnScrollPointer = &scroll; char *result; if (fnPromptDialog.block(blinking) == 0) { result = (char*)malloc(512); if (!result) { unload(); allegro_message("Outrageous shortage of memory."); exit(0); } replace_filename(result, fnActiveQuery, fnFilesCommand[files.getValue()], 512); } else result = NULL; destroyWildcards(fnFilesLength, fnFilesCommand); free(fnActiveQuery); return result; } float joyDistFromCenter() { const int xDiff = joy[joystickId].stick[joystickStickId].axis[0].pos; const int yDiff = joy[joystickId].stick[joystickStickId].axis[1].pos; return (float)sqrt(xDiff * xDiff + yDiff * yDiff); } const char* initializeJoystick(BITMAP *canvas, bool whiny) { remove_joystick(); joystickInstalled = !install_joystick(JOY_TYPE_AUTODETECT); if (joystickInstalled) if (num_joysticks < joystickId + 1 || joystickId < 0) { char buf[23 + intStringMaxLength] = "There's no joystick #"; itoa(joystickId + 1, buf + strlen(buf), 10); strcat(buf, "."); if (whiny) guiMessage(canvas, buf); joystickInstalled = false; return "Bad joystick number"; } else { if (joy[joystickId].num_sticks < joystickStickId + 1 || joystickStickId < 0) { if (whiny) { char buf[27 + intStringMaxLength + intStringMaxLength] = "Joystick #"; itoa(joystickId + 1, buf + strlen(buf), 10); strcat(buf, " has no stick #"); itoa(joystickStickId + 1, buf + strlen(buf), 10); strcat(buf, "."); guiMessage(canvas, buf); } joystickInstalled = false; return "Bad specific stick number"; } if (joy[joystickId].stick[joystickStickId].num_axis != 2) { if (whiny) guiMessage(canvas, "Not a 2D stick."); joystickInstalled = false; return "Not a 2D stick"; } switch (joystickMedium) { case 0: if (!(joy[joystickId].stick[joystickStickId].flags & (JOYFLAG_ANALOGUE | JOYFLAG_CALIB_ANALOGUE))) { if (whiny) guiMessage(canvas, "There's no analogue input."); joystickInstalled = false; return "Bad medium"; } break; case 1: if (!(joy[joystickId].stick[joystickStickId].flags & (JOYFLAG_DIGITAL | JOYFLAG_CALIB_DIGITAL))) { if (whiny) guiMessage(canvas, "There's no digital input."); joystickInstalled = false; return "Bad medium"; } } const char *instructions; while (instructions = calibrate_joystick_name(joystickId)) { guiMessage(canvas, instructions); if (calibrate_joystick(joystickId)) { guiMessage(canvas, "That didn't work."); remove_joystick(); joystickInstalled = false; return "Joystick calibration failed"; } } if (whiny) guiMessage(canvas, "Apparently it worked."); return "Joystick ready"; } else { if (whiny) guiMessage(canvas, "It didn't work."); return "Joystick input not working"; } } void callbackForJoystickSetup() { char *idText; idText = joyIdControlPointer->getValue(); joystickId = atoi(idText) - 1; free(idText); idText = joyStickControlPointer->getValue(); joystickStickId = atoi(idText) - 1; free(idText); joystickMedium = joyMediumControlPointer->getValue(); joyLitPointer->setCaption(initializeJoystick(layer[3], true)); set_config_int("AverysPacMan", "joystickId", joystickId); set_config_int("AverysPacMan", "joystickStickId", joystickStickId); set_config_int("AverysPacMan", "joystickMedium", joystickMedium); flush_config_file(); } void joyThresholdCallback() { if (joystickInstalled) if (!(joy[joystickId].stick[joystickStickId].flags & JOYFLAG_ANALOGUE)) guiMessage(layer[3], "There's no analogue input."); else if (poll_joystick()) guiMessage(layer[3], "Can't poll joystick!"); else { joystickThreshold = joyDistFromCenter(); set_config_float("AverysPacMan", "joystickThreshold", joystickThreshold); flush_config_file(); guiMessage(layer[3], "Analogue sensitivity set."); } else guiMessage(layer[3], "Joystick not configured."); } void callbackForJoystickDialog() { char buf[bufSizeForItoa]; itoa(joystickId + 1, buf, 10); joyIdControlPointer->setValue(buf); itoa(joystickStickId + 1, buf, 10); joyStickControlPointer->setValue(buf); joyMediumControlPointer->setValue(joystickMedium); InputLabel inputLit11(layer[2], joystickDialogX + 1 + 5, joystickDialogY + titleBarHeight + 2 + 25, "Which joystick to use:"); InputLabel inputLit12(layer[2], joystickDialogX + 1 + 5, joystickDialogY + titleBarHeight + 2 + 45, "Which stick to use:"); InputCallback joySetupButton(layer[2], joystickDialogX + 1 + 5, joystickDialogY + titleBarHeight + 2 + 120, joystickDialogW - 2 - 10, 25, "Configure joystick", &callbackForJoystickSetup); InputLabel inputLit13(layer[2], joystickDialogX + 1 + 5, joystickDialogY + titleBarHeight + 2 + 150, "(Center it first!)"); InputCallback joySensitivityButton(layer[2], joystickDialogX + 1 + 5, joystickDialogY + titleBarHeight + 2 + 175, joystickDialogW - 2 - 10, 25, "Set analogue sensitivity", &joyThresholdCallback); InputLabel inputLit14(layer[2], joystickDialogX + 1 + 5, joystickDialogY + titleBarHeight + 2 + 205, "(Position it first!)"); InputDismissWindow inputJoyClose(layer[2], NULL, -1, joystickDialogX + joystickDialogW - 2 - 155, joystickDialogY + 1, 150, 25, "Close"); GuiElement *joystickDialogControls[11] = {joyLitPointer, &inputLit11, joyIdControlPointer, &inputLit12, joyStickControlPointer, joyMediumControlPointer, &joySetupButton, &inputLit13, &joySensitivityButton, &inputLit14, &inputJoyClose}; InputWindow joystickDialog(layer[2], 11, joystickDialogControls, joystickDialogX, joystickDialogY, joystickDialogW, joystickDialogH, "Joystick settings", true); inputJoyClose.setWindow(&joystickDialog); joystickDialog.block(false); clear_bitmap(layer[2]); } void setHeartBeat() { heartBeat = true; } END_OF_FUNCTION(setHeartBeat) void incrementCountUp() { countUp++; } END_OF_FUNCTION(incrementCountUp) int main() { set_uformat(U_ASCII); if (allegro_init()) return 1; allegro_404_char = ' '; set_color_depth(8); if (set_gfx_mode(GFX_AUTODETECT, 640, 480, 0, 0)) { allegro_message("%s", allegro_error); return 0; } set_color_conversion(COLORCONV_NONE); LOCK_VARIABLE(heartBeat); LOCK_VARIABLE(countUp); LOCK_FUNCTION(setHeartBeat); LOCK_FUNCTION(incrementCountUp); srand(time(NULL)); forgotScreen = false; // If by some miracle none of these modes are available, then so be it. set_display_switch_mode(SWITCH_AMNESIA) && set_display_switch_mode(SWITCH_PAUSE) && set_display_switch_mode(SWITCH_NONE) && set_display_switch_mode(SWITCH_BACKAMNESIA) && set_display_switch_mode(SWITCH_BACKGROUND); // If by some miracle this fails, then so be it. set_display_switch_callback(SWITCH_IN, resumeExecution); if (install_keyboard()) { if (set_gfx_mode(GFX_TEXT, 0, 0, 0, 0)) return 2; allegro_message( "Couldn't install the Allegro keyboard interrupt handler."); return 0; } if (keyboard_needs_poll()) if (poll_keyboard()) { if (set_gfx_mode(GFX_TEXT, 0, 0, 0, 0)) return 2; allegro_message("Can't poll the keyboard!"); return 0; } oldPauseKey = key[KEY_PAUSE]; oldMenuKey = key[KEY_MENU]; if (install_timer()) { if (set_gfx_mode(GFX_TEXT, 0, 0, 0, 0)) return 2; allegro_message("Couldn't install the Allegro timer interrupt handler."); return 0; } installMouseReturnValue = install_mouse(); oldMousePos = 0x0; oldMouseB = 0x0; data = load_datafile("smalldat.dat"); if (!data) { if (set_gfx_mode(GFX_TEXT, 0, 0, 0, 0)) return 2; allegro_message("Error loading smalldat.dat"); return 0; } wall[0x00] = (RLE_SPRITE*)data[SMALLDAT_Wall00000].dat; wall[0x01] = (RLE_SPRITE*)data[SMALLDAT_Wall00001].dat; wall[0x02] = (RLE_SPRITE*)data[SMALLDAT_Wall00010].dat; wall[0x03] = (RLE_SPRITE*)data[SMALLDAT_Wall00011].dat; wall[0x04] = (RLE_SPRITE*)data[SMALLDAT_Wall00100].dat; wall[0x05] = (RLE_SPRITE*)data[SMALLDAT_Wall00101].dat; wall[0x06] = (RLE_SPRITE*)data[SMALLDAT_Wall00110].dat; wall[0x07] = (RLE_SPRITE*)data[SMALLDAT_Wall00111].dat; wall[0x08] = (RLE_SPRITE*)data[SMALLDAT_Wall01000].dat; wall[0x09] = (RLE_SPRITE*)data[SMALLDAT_Wall01001].dat; wall[0x0A] = (RLE_SPRITE*)data[SMALLDAT_Wall01010].dat; wall[0x0B] = (RLE_SPRITE*)data[SMALLDAT_Wall01011].dat; wall[0x0C] = (RLE_SPRITE*)data[SMALLDAT_Wall01100].dat; wall[0x0D] = (RLE_SPRITE*)data[SMALLDAT_Wall01101].dat; wall[0x0E] = (RLE_SPRITE*)data[SMALLDAT_Wall01110].dat; wall[0x0F] = (RLE_SPRITE*)data[SMALLDAT_Wall01111].dat; wall[0x10] = (RLE_SPRITE*)data[SMALLDAT_Wall10000].dat; wall[0x11] = (RLE_SPRITE*)data[SMALLDAT_Wall10001].dat; wall[0x12] = (RLE_SPRITE*)data[SMALLDAT_Wall10010].dat; wall[0x13] = (RLE_SPRITE*)data[SMALLDAT_Wall10011].dat; wall[0x14] = (RLE_SPRITE*)data[SMALLDAT_Wall10100].dat; wall[0x15] = (RLE_SPRITE*)data[SMALLDAT_Wall10101].dat; wall[0x16] = (RLE_SPRITE*)data[SMALLDAT_Wall10110].dat; wall[0x17] = (RLE_SPRITE*)data[SMALLDAT_Wall10111].dat; wall[0x18] = (RLE_SPRITE*)data[SMALLDAT_Wall11000].dat; wall[0x19] = (RLE_SPRITE*)data[SMALLDAT_Wall11001].dat; wall[0x1A] = (RLE_SPRITE*)data[SMALLDAT_Wall11010].dat; wall[0x1B] = (RLE_SPRITE*)data[SMALLDAT_Wall11011].dat; wall[0x1C] = (RLE_SPRITE*)data[SMALLDAT_Wall11100].dat; wall[0x1D] = (RLE_SPRITE*)data[SMALLDAT_Wall11101].dat; wall[0x1E] = (RLE_SPRITE*)data[SMALLDAT_Wall11110].dat; wall[0x1F] = (RLE_SPRITE*)data[SMALLDAT_Wall11111].dat; enemy[0] = (RLE_SPRITE*)data[SMALLDAT_Blinky].dat; enemy[1] = (RLE_SPRITE*)data[SMALLDAT_Pinky].dat; enemy[2] = (RLE_SPRITE*)data[SMALLDAT_Inky].dat; enemy[3] = (RLE_SPRITE*)data[SMALLDAT_Clyde].dat; enemyReward[0] = (RLE_SPRITE*)data[SMALLDAT_100].dat; enemyReward[1] = (RLE_SPRITE*)data[SMALLDAT_200].dat; enemyReward[2] = (RLE_SPRITE*)data[SMALLDAT_400].dat; enemyReward[3] = (RLE_SPRITE*)data[SMALLDAT_800].dat; // Fruit (screw the blood orange!) bonus[0] = (RLE_SPRITE*)data[SMALLDAT_Apple].dat; bonus[1] = (RLE_SPRITE*)data[SMALLDAT_Orange].dat; bonus[2] = (RLE_SPRITE*)data[SMALLDAT_Pear].dat; bonus[3] = (RLE_SPRITE*)data[SMALLDAT_Banana].dat; // Berries bonus[4] = (RLE_SPRITE*)data[SMALLDAT_Cherry].dat; bonus[5] = (RLE_SPRITE*)data[SMALLDAT_Blueberry].dat; bonus[6] = (RLE_SPRITE*)data[SMALLDAT_Strawberry].dat; bonus[7] = (RLE_SPRITE*)data[SMALLDAT_Pretzel].dat; // Popular lemon/lime combination bonus[8] = (RLE_SPRITE*)data[SMALLDAT_Lemon].dat; bonus[9] = (RLE_SPRITE*)data[SMALLDAT_Lime].dat; bonus[10] = (RLE_SPRITE*)data[SMALLDAT_Heart].dat; bonus[11] = (RLE_SPRITE*)data[SMALLDAT_AmericanFlag].dat; // Melons bonus[12] = (RLE_SPRITE*)data[SMALLDAT_Watermelon].dat; bonus[13] = (RLE_SPRITE*)data[SMALLDAT_HoneydewMelon].dat; bonus[14] = (RLE_SPRITE*)data[SMALLDAT_Penny].dat; bonus[15] = (RLE_SPRITE*)data[SMALLDAT_Smiley].dat; // Nuts (screw the hazelnut!) bonus[16] = (RLE_SPRITE*)data[SMALLDAT_Acorn].dat; bonus[17] = (RLE_SPRITE*)data[SMALLDAT_Coconut].dat; bonus[18] = (RLE_SPRITE*)data[SMALLDAT_CokeCan].dat; bonus[19] = (RLE_SPRITE*)data[SMALLDAT_ClownFace].dat; // Vehicles bonus[20] = (RLE_SPRITE*)data[SMALLDAT_Car].dat; bonus[21] = (RLE_SPRITE*)data[SMALLDAT_Train].dat; bonus[22] = (RLE_SPRITE*)data[SMALLDAT_Sailboat].dat; bonus[23] = (RLE_SPRITE*)data[SMALLDAT_FloppyDisk].dat; // Balls bonus[24] = (RLE_SPRITE*)data[SMALLDAT_Basketball].dat; bonus[25] = (RLE_SPRITE*)data[SMALLDAT_Baseball].dat; bonus[26] = (RLE_SPRITE*)data[SMALLDAT_TennisBall].dat; bonus[27] = (RLE_SPRITE*)data[SMALLDAT_BeachBall].dat; // Junk food bonus[28] = (RLE_SPRITE*)data[SMALLDAT_Lollipop].dat; bonus[29] = (RLE_SPRITE*)data[SMALLDAT_CandyCane].dat; bonus[30] = (RLE_SPRITE*)data[SMALLDAT_Donut].dat; bonus[31] = (RLE_SPRITE*)data[SMALLDAT_IceCream].dat; // More junk food, and brush your teeth when done eating junk food! bonus[32] = (RLE_SPRITE*)data[SMALLDAT_ChocolateChipCookie].dat; bonus[33] = (RLE_SPRITE*)data[SMALLDAT_FrostedDonutWithSprinkles].dat; bonus[34] = (RLE_SPRITE*)data[SMALLDAT_IceCreamSundaeWithChocolateSyrup].dat; bonus[35] = (RLE_SPRITE*)data[SMALLDAT_ToothpasteAndToothbrush].dat; // Potpourri bonus[36] = (RLE_SPRITE*)data[SMALLDAT_TeddyBear].dat; bonus[37] = (RLE_SPRITE*)data[SMALLDAT_CircuitBoard].dat; bonus[38] = (RLE_SPRITE*)data[SMALLDAT_Vase].dat; bonus[39] = (RLE_SPRITE*)data[SMALLDAT_PacMan].dat; joystix = (FONT*)data[SMALLDAT_Joystix].dat; pacmania = (FONT*)data[SMALLDAT_Pacmania].dat; startSound = (SAMPLE*)data[SMALLDAT_Start].dat; dieSound = (SAMPLE*)data[SMALLDAT_Die].dat; dotSound = (SAMPLE*)data[SMALLDAT_EatDot].dat; energizerSound = (SAMPLE*)data[SMALLDAT_EatEnergizer].dat; enemySound = (SAMPLE*)data[SMALLDAT_EatEnemy].dat; bonusSound = (SAMPLE*)data[SMALLDAT_EatBonus].dat; gainSound = (SAMPLE*)data[SMALLDAT_1Up].dat; popcorn = (MIDI*)data[SMALLDAT_Popcorn].dat; if (installMouseReturnValue != -1) { set_mouse_sprite((BITMAP*)data[SMALLDAT_Pointer].dat); set_mouse_speed(mouseSpeed, mouseSpeed); } gainSound->priority = 6; bonusSound->priority = 5; enemySound->priority = 4; energizerSound->priority = 3; dieSound->priority = 2; startSound->priority = 1; dotSound->priority = 0; installSoundReturnValue = install_sound(DIGI_AUTODETECT, MIDI_AUTODETECT, NULL); const char *soundLit = installSoundReturnValue ? "Sound is not working." : "Sound is working."; gfxTechniqueOfChoice = get_config_int("AverysPacMan", "gfxTechniqueOfChoice", 0); if (gfxTechniqueOfChoice < 0 || gfxTechniqueOfChoice > 2) { unload(); allegro_message("Configuration file gives invalid value for gfxTechniqueOfChoice."); return 0; } joystickId = get_config_int("AverysPacMan", "joystickId", 0); joystickStickId = get_config_int("AverysPacMan", "joystickStickId", 0); joystickMedium = get_config_int("AverysPacMan", "joystickMedium", 1); if (joystickMedium < 0 || joystickMedium > 1) { unload(); allegro_message("Configuration file gives invalid value for joystickMedium."); return 0; } joystickThreshold = get_config_float("AverysPacMan", "joystickThreshold", 0.0f); enableJoystick = get_config_int("AverysPacMan", "enableJoystick", 1); soundFx = get_config_int("AverysPacMan", "enableSoundFx", 1); music = get_config_int("AverysPacMan", "enableMusic", 1); char *videoPageLit1; char *videoPageLit2; char *videoPageLit3; currentVideoPageIndex = 0; videoPage[0] = create_video_bitmap(SCREEN_W, SCREEN_H); if (videoPage[0]) bitmapInventory.push_back(videoPage[0]); else { unload(); allegro_message("Outrageous shortage of memory."); return 0; } videoPage[1] = create_video_bitmap(SCREEN_W, SCREEN_H); if (videoPage[1]) { bitmapInventory.push_back(videoPage[1]); if ((gfx_capabilities & GFX_CAN_TRIPLE_BUFFER) || !enable_triple_buffer()) { videoPage[2] = create_video_bitmap(SCREEN_W, SCREEN_H); if (videoPage[2]) { bitmapInventory.push_back(videoPage[2]); bestGfxTechnique = tripleBuffering; videoPageLit1 = "Triple buffering will work"; videoPageLit2 = "fine on your video card."; videoPageLit3 = ""; } else { bestGfxTechnique = doubleBuffering; videoPageLit1 = "Your video card does triple"; videoPageLit2 = "buffering, but doesn't have"; videoPageLit3 = "the memory to do it in VGA."; } } else { bestGfxTechnique = doubleBuffering; videoPageLit1 = "Your video card does not do"; videoPageLit2 = "triple buffering. Double"; videoPageLit3 = "buffering will work."; } } else { bestGfxTechnique = none; videoPageLit1 = "You do not have enough"; videoPageLit2 = "VRAM for more than just"; videoPageLit3 = "one video memory page!!!"; } considerUserGfxChoice(); createMutableSprite(layer, SCREEN_W, SCREEN_H, false); for (int i = 1; i < maxLayers; i++) createMaskedMutableSprite(layer + i, SCREEN_W, SCREEN_H, false); if (is_video_bitmap(layer[0])) createMutableSprite(layerBackup, SCREEN_W, SCREEN_H, true); for (int i = 1; i < maxLayers; i++) if (is_video_bitmap(layer[i])) createMaskedMutableSprite(layerBackup + i, SCREEN_W, SCREEN_H, true); createMaskedMutableSprite(&tileImage, tileSize, tileSize, false); if (gfx_capabilities & GFX_HW_VRAM_BLIT_MASKED) { blitEnemies = true; for (int i = 0; i < 4; i++) { vramEnemy[i] = create_video_bitmap(tileSize, tileSize); if (!vramEnemy[i]) { blitEnemies = false; for (int j = 0; j < i; j++) destroy_bitmap(vramEnemy[j]); break; } } if (blitEnemies) for (int i = 0; i < 4; i++) bitmapInventory.push_back(vramEnemy[i]); blitEnemyRewards = true; for (int i = 0; i < 4; i++) { vramEnemyReward[i] = create_video_bitmap(tileSize, tileSize); if (!vramEnemyReward[i]) { blitEnemyRewards = false; for (int j = 0; j < i; j++) destroy_bitmap(vramEnemyReward[j]); break; } } if (blitEnemyRewards) for (int i = 0; i < 4; i++) bitmapInventory.push_back(vramEnemyReward[i]); } else { blitEnemies = false; blitEnemyRewards = false; } if (gfx_capabilities & GFX_HW_VRAM_BLIT) { blitWalls = true; for (int i = 0x00; i < 0x20; i++) { vramWall[i] = create_video_bitmap(tileSize, tileSize); if (!vramWall[i]) { blitWalls = false; for (int j = 0x00; j < i; j++) destroy_bitmap(vramWall[j]); break; } } if (blitWalls) for (int i = 0x00; i < 0x20; i++) bitmapInventory.push_back(vramWall[i]); } else blitWalls = false; drawSpritesForBlitting(); energizerPalette[blinkyColor] = blue; energizerPalette[pinkyColor] = blue; energizerPalette[inkyColor] = blue; energizerPalette[clydeColor] = blue; initializeEditor(); InputRadioButtonSet inputGfx(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 5, gfxTechniqueMenuLength, gfxTechniqueMenuCommand, gfxTechniqueMenuAcceleratorKey, true); InputLabel inputLit1(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 70, "If your video card does not"); InputLabel inputLit2(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 90, "support your choice, then"); InputLabel inputLit3(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 110, "this game will fall back on"); InputLabel inputLit4(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 130, "an inferior choice."); InputLabel inputLit5(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 170, videoPageLit1, interactivityColor); InputLabel inputLit6(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 190, videoPageLit2, interactivityColor); InputLabel inputLit7(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 210, videoPageLit3, interactivityColor); InputLabel inputLit8(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 250, "For your information, this"); InputLabel inputLit9(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 270, "game uses page flipping."); InputLabel inputAudioLit(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 310, soundLit, interactivityColor); InputCallback inputJoyStuff(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 335, settingsDialogW - 2 - 10, 25, "Configure joystick", &callbackForJoystickDialog); InputCheckBox inputWantJoy(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 365, "Use stick (if configured)"); InputCheckBox inputWantSoundFx(layer[1], settingsDialogX + 1 + 5, settingsDialogY + titleBarHeight + 2 + 390, "Sound FX"); InputCheckBox inputWantMusic(layer[1], settingsDialogX + 1 + 250, settingsDialogY + titleBarHeight + 2 + 390, "Music"); InputDismissWindow inputSettingsOk(layer[1], NULL, 0, settingsDialogX + 1 + 5, settingsDialogY + settingsDialogH - 2 - 30, 150, 25, "OK"); InputDismissWindow inputSettingsCancel(layer[1], NULL, -1, settingsDialogX + 1 + 160, settingsDialogY + settingsDialogH - 2 - 30, 150, 25, "Cancel"); InputDismissWindow inputSettingsClose(layer[1], NULL, -1, settingsDialogX + settingsDialogW - 2 - 155, settingsDialogY + 1, 150, 25, "Close"); GuiElement *settingsControls[18] = {&inputGfx, &inputLit1, &inputLit2, &inputLit3, &inputLit4, &inputLit5, &inputLit6, &inputLit7, &inputLit8, &inputLit9, &inputAudioLit, &inputJoyStuff, &inputWantJoy, &inputWantSoundFx, &inputWantMusic, &inputSettingsOk, &inputSettingsCancel, &inputSettingsClose}; InputWindow settingsDialog(layer[1], 18, settingsControls, settingsDialogX, settingsDialogY, settingsDialogW, settingsDialogH, "Settings", true); inputSettingsOk.setWindow(&settingsDialog); inputSettingsCancel.setWindow(&settingsDialog); inputSettingsClose.setWindow(&settingsDialog); InputLabel inputWildcardSpecificationPromptLit(layer[1], wildcardSpecificationPromptDialogX + 1 + 5, wildcardSpecificationPromptDialogY + titleBarHeight + 2 + 5, "Enter wildcard specification."); InputText inputWildcardSpecificationPromptMeat(layer[1], 2, wildcardSpecificationPromptDialogX + 1 + 5, wildcardSpecificationPromptDialogY + titleBarHeight + 2 + 30, (wildcardSpecificationPromptDialogW - 2 - 10) / charWidth, 4, 10, false); InputDismissWindow inputWildcardSpecificationPromptOk(layer[1], NULL, 0, wildcardSpecificationPromptDialogX + 1 + 5, wildcardSpecificationPromptDialogY + wildcardSpecificationPromptDialogH - 2 - 30, 150, 25, "OK"); InputDismissWindow inputWildcardSpecificationPromptCancel(layer[1], NULL, -1, wildcardSpecificationPromptDialogX + 1 + 160, wildcardSpecificationPromptDialogY + wildcardSpecificationPromptDialogH - 2 - 30, 150, 25, "Cancel"); InputDismissWindow inputWildcardSpecificationPromptClose(layer[1], NULL, -1, wildcardSpecificationPromptDialogX + wildcardSpecificationPromptDialogW - 2 - 155, wildcardSpecificationPromptDialogY + 1, 150, 25, "Close"); GuiElement *wildcardSpecificationPromptControls[5] = { &inputWildcardSpecificationPromptLit, &inputWildcardSpecificationPromptMeat, &inputWildcardSpecificationPromptOk, &inputWildcardSpecificationPromptCancel, &inputWildcardSpecificationPromptClose}; InputWindow wildcardSpecificationPromptDialog(layer[1], 5, wildcardSpecificationPromptControls, wildcardSpecificationPromptDialogX, wildcardSpecificationPromptDialogY, wildcardSpecificationPromptDialogW, wildcardSpecificationPromptDialogH, "Wildcard specification", true); inputWildcardSpecificationPromptOk.setWindow(&wildcardSpecificationPromptDialog); inputWildcardSpecificationPromptCancel.setWindow(&wildcardSpecificationPromptDialog); inputWildcardSpecificationPromptClose.setWindow(&wildcardSpecificationPromptDialog); InputLabel inputLit10(layer[2], joystickDialogX + 1 + 5, joystickDialogY + titleBarHeight + 2 + 5, NULL, interactivityColor); InputText inputJoyId(layer[2], 3, joystickDialogX + 1 + 500, joystickDialogY + titleBarHeight + 2 + 25, 4, 1, 1, false); InputText inputStickId(layer[2], 3, joystickDialogX + 1 + 500, joystickDialogY + titleBarHeight + 2 + 45, 4, 1, 1, false); InputRadioButtonSet inputJoyMedium(layer[2], joystickDialogX + 1 + 5, joystickDialogY + titleBarHeight + 2 + 70, joyMediumMenuLength, joyMediumMenuCommand, joyMediumMenuAcceleratorKey, true); joyLitPointer = &inputLit10; joyIdControlPointer = &inputJoyId; joyStickControlPointer = &inputStickId; joyMediumControlPointer = &inputJoyMedium; layerCount = 1; clear_bitmap(layer[0]); vsync(); set_color(interactivityColor, &red); inputLit10.setCaption(initializeJoystick(layer[0], false)); char *fn; vector > csv; bool hopefulAboutFileIo; bool startedSearch; bool continueReading; int levelPackLength; char **levelPack; HighScoresList highScores; while (true) { if (!installSoundReturnValue && soundFx) { stop_sample(startSound); play_sample(startSound, 255, 128, 1000, 0); } switch (logoMenu(mainMenuLength, mainMenuCommand, mainMenuAcceleratorKey, "MAIN MENU", "Welcome to Avery's Pac Man!")) { case 0: layerCount = 3; clear_bitmap(layer[1]); clear_bitmap(layer[2]); fn = fnPrompt(layer[1], 2, "Play CSV", "*.csv", false); if (fn) { hopefulAboutFileIo = loadCsv(fn, &csv); free(fn); if (hopefulAboutFileIo) { levelPackLength = 0; for (vector >::iterator i = csv.begin(); i != csv.end(); i++) levelPackLength += (*i).size(); levelPack = (char**)malloc(levelPackLength * sizeof(char*)); if (levelPack) { int arrayIndex = 0; for (vector >::iterator i = csv.begin(); i != csv.end(); i++) for (vector::iterator j = (*i).begin(); j != (*i).end(); j++) levelPack[arrayIndex++] = *j; fade_out(fadeSpeed); playMatch(levelPackLength, levelPack); free(levelPack); } else { guiMessage(layer[2], "Out of memory."); fade_out(fadeSpeed); } destroyCsv(&csv); } else { guiMessage(layer[2], csvProblem); fade_out(fadeSpeed); } } break; case 1: layerCount = 3; clear_bitmap(layer[1]); clear_bitmap(layer[2]); wildcardSpecificationPromptDialog.uncommit(); if (wildcardSpecificationPromptDialog.block(false) == 0) { char *wildcardSpecification = inputWildcardSpecificationPromptMeat.getValue(); hopefulAboutFileIo = wildcards(&levelPackLength, &levelPack, wildcardSpecification, true); free(wildcardSpecification); if (hopefulAboutFileIo) { fade_out(fadeSpeed); playMatch(levelPackLength, levelPack); destroyWildcards(levelPackLength, levelPack); } else guiMessage(layer[2], wildcardProblem); } break; case 2: fade_out(fadeSpeed); layerCount = 1; clear_bitmap(layer[0]); if (file_exists("Hiscores.csv", FA_ALL, NULL)) hopefulAboutFileIo = highScores.load(); else { highScores = HighScoresList(); hopefulAboutFileIo = true; } if (hopefulAboutFileIo) highScores.drawHighScores(layer[0]); else textout_centre_ex(layer[0], joystix, highScores.getProblem(), SCREEN_W / 2, SCREEN_H / 2, 15, -1); drawFrame(); showFrame(); fade_in(currentColorPalette, fadeSpeed); clear_keybuf(); do { if (forgotScreen) { clear_bitmap(layer[0]); if (hopefulAboutFileIo) highScores.drawHighScores(layer[0]); else textout_centre_ex(layer[0], joystix, highScores.getProblem(), SCREEN_W / 2, SCREEN_H / 2, 15, -1); drawFrame(); showFrame(); forgotScreen = false; } rest(0); } while (!keypressed()); fade_out(fadeSpeed); break; case 3: fade_out(fadeSpeed); currentColorPalette[14] = yellow; layerCount = 1; drawCredits(layer[0]); drawFrame(); showFrame(); fade_in(currentColorPalette, fadeSpeed); do { if (forgotScreen) { drawSpritesForBlitting(); drawCredits(layer[0]); drawFrame(); showFrame(); forgotScreen = false; } rest(0); } while (!keypressed()); fade_out(fadeSpeed); break; case 4: fade_out(fadeSpeed); memcpy(currentColorPalette, default_palette, PAL_SIZE * sizeof(RGB)); currentColorPalette[15] = white; currentColorPalette[16] = black; currentColorPalette[wallColor] = blue; currentColorPalette[interactivityColor] = red; editorBonusIndex = 0; isItChristmasYet(); edit(&dummyLevel, NULL); break; case 5: layerCount = 4; clear_bitmap(layer[1]); clear_bitmap(layer[2]); clear_bitmap(layer[3]); settingsDialog.uncommit(); inputGfx.setValue(gfxTechniqueOfChoice); inputWantJoy.setValue(enableJoystick); inputWantSoundFx.setValue(soundFx); inputWantMusic.setValue(music); if (settingsDialog.block(false) == 0) { gfxTechniqueOfChoice = inputGfx.getValue(); enableJoystick = inputWantJoy.getValue(); soundFx = inputWantSoundFx.getValue(); music = inputWantMusic.getValue(); set_config_int("AverysPacMan", "gfxTechniqueOfChoice", gfxTechniqueOfChoice); set_config_int("AverysPacMan", "enableJoystick", enableJoystick); set_config_int("AverysPacMan", "enableSoundFx", soundFx); set_config_int("AverysPacMan", "enableMusic", music); flush_config_file(); considerUserGfxChoice(); } break; case 6: case -1: fade_out(fadeSpeed); unload(); return 0; } } } END_OF_MAIN()