19#ifndef puzzle_ASSET_DIR
20#define puzzle_ASSET_DIR "."
95 int t1 =
c1, t2 =
c2, t3 =
c3;
127 block.color.randcolor();
151 void addScore(
const std::string &name,
int score) {
152 scores.push_back({name, score});
155 if (scores.size() > 10) {
160 std::sort(scores.begin(), scores.end());
164 if (scores.size() < 10)
166 return score > scores.back().score;
175 for (
int i = 0; i < 10; ++i)
176 scores.push_back(
Score(
"Anonymous", (10 - i) * 100));
181 file.open(
"./scores.dat", std::ios::in);
182 if (!file.is_open()) {
183 std::cout <<
"No scores file.\n";
189 while (std::getline(file, input)) {
192 if (input.length() > 0) {
193 auto pos = input.find(
":");
194 if (pos != std::string::npos) {
195 std::string left = input.substr(0, pos);
196 std::string right = input.substr(pos + 1);
197 scores.push_back(
Score(left, std::strtol(right.c_str(), 0, 10)));
207 file.open(
"./scores.dat", std::ios::out);
208 if (!file.is_open()) {
209 std::cerr <<
"Could not open score file..\n";
212 for (
auto &s : scores) {
213 file << s.name <<
":" << s.score << std::endl;
219 std::vector<Score> scores;
224 std::string current_path;
233 int optionsCursor = 0;
234 int difficultySetting = 1;
235 bool shaderEffectsEnabled =
true;
236 bool enteringName =
false;
237 std::string playerName;
242 int lastFontSize = 0;
243 bool flashActive =
false;
244 Uint32 flashStartTime = 0;
246 std::vector<mxvk::VK_Sprite *> grid_blocks;
251 SDL_Gamepad *gamepad =
nullptr;
252 SDL_JoystickID gamepadId = 0;
253 static constexpr Sint16 JOYSTICK_DEAD_ZONE = 12000;
254 Uint32 joyRepeatLeft = 0;
255 Uint32 joyRepeatRight = 0;
256 Uint32 joyRepeatDown = 0;
257 Uint32 joyRepeatUp = 0;
258 static constexpr Uint32 JOY_REPEAT_DELAY = 150;
263 current_path((path.empty() || path ==
".") ? std::string(
puzzle_ASSET_DIR) : path),
268 srand((
unsigned int)time(0));
269 lastTick = SDL_GetTicks();
273 if (gamepad !=
nullptr) {
274 SDL_CloseGamepad(gamepad);
280 std::string vertShader = current_path +
"/data/sprite_vert.spv";
281 std::string fragShader = current_path +
"/data/sprite_kaleidoscope.spv";
283 "sprite_kaleidoscope.spv",
284 "sprite_kaleidoscope2.spv",
285 "sprite_kaleidoscope3.spv",
286 "sprite_kaleidoscope4.spv"};
288 gamebg[i] =
createSprite(current_path +
"/data/gamebg.png", vertShader, current_path +
"/data/" + fragShaders[i]);
290 introScreen =
createSprite(current_path +
"/data/intro.png", current_path +
"/data/sprite_vert.spv", current_path +
"/data/sprite_bubble.spv");
291 startScreen =
createSprite(current_path +
"/data/universe.png", current_path +
"/data/sprite_vert.spv", fragShader);
292 creditScreen =
createSprite(current_path +
"/data/logo.png", current_path +
"/data/sprite_vert.spv", current_path +
"/data/sprite_time.spv");
293 scoresBackground =
createSprite(current_path +
"/data/bg.png", current_path +
"/data/sprite_vert.spv", current_path +
"/data/sprite_time.spv");
295 const char *blockFiles[] = {
296 "block_black.png",
"block_yellow.png",
"block_orange.png",
"block_ltblue.png",
297 "block_dblue.png",
"block_purple.png",
"block_pink.png",
"block_gray.png",
298 "block_red.png",
"block_green.png",
"block_clear.png"};
300 grid_blocks.push_back(
createSprite(current_path +
"/data/" + blockFiles[i], current_path +
"/data/sprite_vert.spv", current_path +
"/data/sprite_frag.spv"));
306 int fontSize = (int)(20.0f * ((
float)h / 480.0f));
307 fontSize = std::max(16, std::min(128, fontSize));
308 if (fontSize != lastFontSize) {
309 lastFontSize = fontSize;
310 setFont(current_path +
"/data/font.ttf", fontSize);
316 if (gamepad !=
nullptr && gamepadId ==
id) {
319 if (gamepad !=
nullptr) {
320 SDL_CloseGamepad(gamepad);
324 gamepad = SDL_OpenGamepad(
id);
325 if (gamepad ==
nullptr) {
333 if (gamepad !=
nullptr) {
337 SDL_JoystickID *ids = SDL_GetGamepads(&count);
338 if (ids ==
nullptr || count <= 0) {
339 if (ids !=
nullptr) {
351 gamebg[i]->setEffectsEnabled(shaderEffectsEnabled);
354 introScreen->setEffectsEnabled(shaderEffectsEnabled);
356 startScreen->setEffectsEnabled(shaderEffectsEnabled);
358 creditScreen->setEffectsEnabled(shaderEffectsEnabled);
359 if (scoresBackground)
360 scoresBackground->setEffectsEnabled(shaderEffectsEnabled);
361 for (
auto *block : grid_blocks) {
363 block->setEffectsEnabled(shaderEffectsEnabled);
368 return (
int)(lastFontSize * 0.5f);
372 return (
int)(40.0f * ((float)h / 480.0f));
376 return (
int)(baseY * ((float)h / 480.0f));
382 return w / 2 - width / 2;
384 return w / 2 - (int)(strlen(text) *
getCharWidth() / 2);
389 SDL_GetWindowSizeInPixels(
window.get(), &w, &h);
391 if (startScreen ==
nullptr) {
395 switch (currentScreen) {
422 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
423 introScreen->setShaderParams(time_f, 1.0f, 0.8f, 1.2f);
424 introScreen->drawSpriteRect(0, 0, w, h);
426 Uint32 currentTick = SDL_GetTicks();
427 if (currentTick - lastTick > 5000) {
429 lastTick = currentTick;
435 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
436 startScreen->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
437 startScreen->drawSpriteRect(0, 0, w, h);
440 int menuStartY =
scaleY(180);
442 const char *title =
"Liquid Acid Drop";
444 const char *menuItems[] = {
"New Game",
"High Scores",
"Options",
"Credits",
"Quit"};
445 for (
int i = 0; i < 5; i++) {
446 SDL_Color col = (i == cursorPos) ? SDL_Color{255, 255, 0, 255} : SDL_Color{255, 255, 255, 255};
447 printText(menuItems[i],
centerX(menuItems[i]), menuStartY + i * spacing, col);
449 printText(
">>",
centerX(menuItems[cursorPos]) -
scaleY(30), menuStartY + cursorPos * spacing, {255, 255, 0, 255});
460 if (gamebg[shaderLevel]) {
461 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
462 gamebg[shaderLevel]->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
463 gamebg[shaderLevel]->drawSpriteRect(0, 0, w, h);
466 const char *gameOverText =
"GAME OVER!";
467 printText(gameOverText,
centerX(gameOverText), h / 2 - 80, {255, 0, 0, 255});
469 std::ostringstream stream;
470 stream <<
"Final Score: " <<
matrix.Game.score;
471 std::string scoreStr = stream.str();
472 printText(scoreStr.c_str(),
centerX(scoreStr.c_str()), h / 2 - 20, {255, 255, 255, 255});
475 stream <<
"Tabs: " <<
matrix.Game.lines;
476 std::string linesStr = stream.str();
477 printText(linesStr.c_str(),
centerX(linesStr.c_str()), h / 2 + 40, {255, 255, 255, 255});
479 const char *returnText =
"Press ENTER to view High Scores";
480 printText(returnText,
centerX(returnText), h / 2 + 120, {255, 255, 0, 255});
484 finalScore =
matrix.Game.score;
486 enteringName = scores.qualifiesForHighScore(finalScore);
492 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
493 startScreen->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
494 startScreen->drawSpriteRect(0, 0, w, h);
498 int optStartY =
scaleY(180);
501 const char *optTitle =
"OPTIONS";
504 const char *difficultyLabels[] = {
"Easy",
"Normal",
"Hard"};
505 std::string diffText = std::string(
"< Difficulty: ") + difficultyLabels[difficultySetting] +
" >";
506 SDL_Color diffColor = (optionsCursor == 0) ? SDL_Color{255, 255, 0, 255} : SDL_Color{255, 255, 255, 255};
507 printText(diffText.c_str(),
centerX(diffText.c_str()), optStartY, diffColor);
508 if (optionsCursor == 0) {
509 int diffWidth, diffHeight;
511 diffWidth =
static_cast<int>(diffText.size()) *
getCharWidth();
513 printText(
">>", w / 2 - diffWidth / 2 -
scaleY(30), optStartY, {255, 255, 0, 255});
516 std::string fxText = std::string(
"< Shader Effects: ") + (shaderEffectsEnabled ?
"On" :
"Off") +
" >";
517 SDL_Color fxColor = (optionsCursor == 1) ? SDL_Color{255, 255, 0, 255} : SDL_Color{255, 255, 255, 255};
518 printText(fxText.c_str(),
centerX(fxText.c_str()), optStartY + spacing, fxColor);
519 if (optionsCursor == 1) {
520 int fxWidth, fxHeight;
522 fxWidth =
static_cast<int>(fxText.size()) *
getCharWidth();
524 printText(
">>", w / 2 - fxWidth / 2 -
scaleY(30), optStartY + spacing, {255, 255, 0, 255});
527 const char *backText =
"Back";
528 SDL_Color backColor = (optionsCursor == 2) ? SDL_Color{255, 255, 0, 255} : SDL_Color{255, 255, 255, 255};
530 if (optionsCursor == 2) {
531 int backWidth, backHeight;
533 backWidth =
static_cast<int>(std::strlen(backText)) *
getCharWidth();
535 printText(
">>", w / 2 - backWidth / 2 -
scaleY(30), optStartY + spacing * 2, {255, 255, 0, 255});
538 const char *instructions =
"UP/DOWN: Select LEFT/RIGHT: Change ENTER: Confirm";
544 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
545 creditScreen->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
546 creditScreen->drawSpriteRect(0, 0, w, h);
549 const char *credReturn =
"Press Return to return";
555 if (scoresBackground) {
556 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
557 scoresBackground->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
558 scoresBackground->drawSpriteRect(0, 0, w, h);
562 int listStartY =
scaleY(90);
563 int lineHeight =
scaleY(32);
565 const char *title =
"HIGH SCORES";
568 const auto &scoreList = scores.getScores();
569 for (
size_t i = 0; i < scoreList.size() && i < 10; ++i) {
570 std::ostringstream stream;
571 stream << (i + 1) <<
". " << scoreList[i].name <<
" " << scoreList[i].score;
572 std::string scoreStr = stream.str();
574 SDL_Color color = {255, 0, 150, 255};
576 if (enteringName && finalScore > 0) {
579 for (
size_t j = 0; j < scoreList.size(); ++j) {
580 if (finalScore > scoreList[j].score) {
586 if ((
int)i == rank) {
587 color = {0, 255, 0, 255};
591 printText(scoreStr.c_str(),
scaleY(100), listStartY + (
int)i * lineHeight, color);
597 std::ostringstream stream;
598 stream <<
"Your Score: " << finalScore;
599 std::string yourScore = stream.str();
600 printText(yourScore.c_str(),
centerX(yourScore.c_str()), entryY - lineHeight * 2, {255, 255, 0, 255});
602 const char *prompt =
"Enter your name:";
603 printText(prompt,
centerX(prompt), entryY - lineHeight, {255, 255, 255, 255});
605 std::string displayName = playerName +
"_";
606 printText(displayName.c_str(),
centerX(displayName.c_str()), entryY, {0, 255, 255, 255});
608 const char *instructions =
"Type name, ENTER to confirm, BACKSPACE to delete or Escape/Back";
609 printText(instructions,
centerX(instructions), entryY + lineHeight, {200, 0, 150, 255});
611 const char *returnText =
"Press ENTER to return to menu";
617 float scaleX = (float)w / 640.0f;
618 float scaleY = (float)h / 480.0f;
619 if (gamebg[shaderLevel]) {
620 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
621 gamebg[shaderLevel]->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
622 gamebg[shaderLevel]->drawSpriteRect(0, 0, w, h);
627 std::ostringstream stream;
628 stream <<
"Score:" <<
matrix.Game.score;
629 printText(stream.str().c_str(), (
int)(200 * scaleX), (
int)(80 *
scaleY) - (lastFontSize + (lastFontSize / 4)), {255, 255, 255, 255});
632 stream <<
"Tabs:" <<
matrix.Game.lines;
633 printText(stream.str().c_str(), (
int)(310 * scaleX), (
int)(80 *
scaleY) - (lastFontSize + (lastFontSize / 4)), {255, 255, 255, 255});
636 const char *pausedText =
"PAUSED - Press P to Continue";
637 int pausedWidth, pausedHeight;
639 pausedWidth =
static_cast<int>(std::strlen(pausedText)) *
getCharWidth();
641 printText(pausedText, w / 2 - pausedWidth / 2, h / 2, {255, 255, 0, 255});
646 Uint32 now = SDL_GetTicks();
647 bool showFlash = flashActive && ((now - flashStartTime) / 50 % 2 == 0);
651 int blockType =
matrix.grid[i][j];
653 static_cast<size_t>(blockType) < grid_blocks.size()) {
657 if (flashActive && flashGrid[i][j] && !showFlash) {
661 if (grid_blocks[blockType]) {
662 grid_blocks[blockType]->drawSpriteRect(
663 (
int)(x * scaleX), (
int)(y *
scaleY) + 10,
672 int c1 =
matrix.block.color.c1;
673 int c2 =
matrix.block.color.c2;
674 int c3 =
matrix.block.color.c3;
676 if (
matrix.block.horizontal) {
679 for (
int i = 0; i < 3; i++) {
680 int color = (i == 0) ? c1 : (i == 1) ? c2
684 color > 0 && color <
BLOCK_COUNT && grid_blocks[color]) {
685 grid_blocks[color]->drawSpriteRect(
686 (
int)(bx * scaleX), (
int)(screenY *
scaleY),
694 int y1 =
matrix.block.y + 1;
695 int y2 =
matrix.block.y + 2;
697 if (y0 >= 0 && c1 > 0 && c1 <
BLOCK_COUNT && grid_blocks[c1]) {
699 grid_blocks[c1]->drawSpriteRect(
700 (
int)(bx * scaleX), (
int)(screenY *
scaleY),
703 if (y1 >= 0 && c2 > 0 && c2 <
BLOCK_COUNT && grid_blocks[c2]) {
705 grid_blocks[c2]->drawSpriteRect(
706 (
int)(bx * scaleX), (
int)(screenY *
scaleY),
709 if (y2 >= 0 && c3 > 0 && c3 <
BLOCK_COUNT && grid_blocks[c3]) {
711 grid_blocks[c3]->drawSpriteRect(
712 (
int)(bx * scaleX), (
int)(screenY *
scaleY),
723 int c1 =
matrix.nextblock.color.c1;
724 int c2 =
matrix.nextblock.color.c2;
725 int c3 =
matrix.nextblock.color.c3;
727 if (c1 > 0 && c1 <
BLOCK_COUNT && grid_blocks[c1]) {
728 grid_blocks[c1]->drawSpriteRect(
729 (
int)(bx * scaleX), (
int)(by *
scaleY),
732 if (c2 > 0 && c2 <
BLOCK_COUNT && grid_blocks[c2]) {
733 grid_blocks[c2]->drawSpriteRect(
737 if (c3 > 0 && c3 <
BLOCK_COUNT && grid_blocks[c3]) {
738 grid_blocks[c3]->drawSpriteRect(
745 static Uint32 lastMove = 0;
746 Uint32 now = SDL_GetTicks();
762 if (now - lastMove > (Uint32)(
matrix.Game.speed * 50)) {
790 if (
matrix.block.horizontal) {
794 for (
int i = 0; i < 3; i++) {
802 if (
matrix.grid[bx][by + 3] > 0)
812 int bx =
matrix.block.x - 1;
815 if (
matrix.block.horizontal) {
835 if (
matrix.block.horizontal) {
839 int bx =
matrix.block.x + 3;
846 int bx =
matrix.block.x + 1;
862 if (
matrix.block.horizontal) {
885 memset(flashGrid,
false,
sizeof(flashGrid));
886 bool foundMatch =
false;
891 if (
matrix.grid[i][j] > 0) {
892 int color =
matrix.grid[i][j];
899 for (
int k = 0; k < count; k++) {
900 flashGrid[i + k][j] =
true;
915 if (
matrix.grid[i][j] > 0) {
916 int color =
matrix.grid[i][j];
923 for (
int k = 0; k < count; k++) {
924 flashGrid[i][j + k] =
true;
939 if (
matrix.grid[i][j] > 0) {
940 int color =
matrix.grid[i][j];
943 matrix.grid[i + count][j + count] == color) {
947 for (
int k = 0; k < count; k++) {
948 flashGrid[i + k][j + k] =
true;
963 if (
matrix.grid[i][j] > 0) {
964 int color =
matrix.grid[i][j];
966 while (i - count >= 0 && j + count <
GRID_HEIGHT &&
967 matrix.grid[i - count][j + count] == color) {
971 for (
int k = 0; k < count; k++) {
972 flashGrid[i - k][j + k] =
true;
990 flashStartTime = SDL_GetTicks();
996 if (flashGrid[i][j]) {
1002 matrix.Game.score += matchBonus;
1007 if (newLevel != shaderLevel) {
1008 shaderLevel = newLevel;
1009 std::cout <<
"level increased to: " << shaderLevel << std::endl;
1011 memset(flashGrid,
false,
sizeof(flashGrid));
1024 if (
matrix.grid[i][j] > 0 &&
matrix.grid[i][j + 1] == 0) {
1037 matrix.nextblock.color.randcolor();
1040 matrix.block.horizontal =
false;
1046 if (
matrix.grid[i][1] > 0) {
1053 if (
matrix.grid[i][j] == 0) {
1064 int baseSpeeds[] = {30, 20, 10};
1065 matrix.Game.speed = baseSpeeds[difficultySetting];
1096 if (
matrix.block.horizontal) {
1125 if (e.type == SDL_EVENT_QUIT || (currentScreen ==
SCREEN_START && e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE)) {
1130 if (e.type == SDL_EVENT_KEY_DOWN) {
1132 }
else if (e.type == SDL_EVENT_TEXT_INPUT) {
1136 if (e.type == SDL_EVENT_GAMEPAD_ADDED) {
1138 }
else if (e.type == SDL_EVENT_GAMEPAD_REMOVED) {
1139 if (gamepad !=
nullptr && e.gdevice.which == gamepadId) {
1140 SDL_CloseGamepad(gamepad);
1144 }
else if (e.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
1150 switch (currentScreen) {
1152 if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_START) {
1157 if (button == SDL_GAMEPAD_BUTTON_DPAD_UP) {
1158 cursorPos = (cursorPos - 1 + 5) % 5;
1159 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) {
1160 cursorPos = (cursorPos + 1) % 5;
1161 }
else if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_START) {
1162 if (cursorPos == 0) {
1168 matrix.block.horizontal =
false;
1170 }
else if (cursorPos == 1) {
1172 enteringName =
false;
1174 }
else if (cursorPos == 2) {
1176 }
else if (cursorPos == 3) {
1178 }
else if (cursorPos == 4) {
1181 }
else if (button == SDL_GAMEPAD_BUTTON_EAST) {
1186 if (button == SDL_GAMEPAD_BUTTON_DPAD_LEFT) {
1188 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_RIGHT) {
1190 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) {
1192 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_UP) {
1193 matrix.block.color.shiftcolor(
true);
1194 }
else if (button == SDL_GAMEPAD_BUTTON_SOUTH) {
1196 }
else if (button == SDL_GAMEPAD_BUTTON_EAST) {
1197 matrix.block.color.shiftcolor(
false);
1198 }
else if (button == SDL_GAMEPAD_BUTTON_NORTH) {
1200 }
else if (button == SDL_GAMEPAD_BUTTON_START) {
1202 }
else if (button == SDL_GAMEPAD_BUTTON_BACK) {
1207 if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_START) {
1209 }
else if (button == SDL_GAMEPAD_BUTTON_EAST) {
1214 if (button == SDL_GAMEPAD_BUTTON_DPAD_UP) {
1215 optionsCursor = (optionsCursor - 1 + 3) % 3;
1216 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) {
1217 optionsCursor = (optionsCursor + 1) % 3;
1218 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_LEFT) {
1219 if (optionsCursor == 0)
1220 difficultySetting = (difficultySetting - 1 + 3) % 3;
1221 if (optionsCursor == 1) {
1222 shaderEffectsEnabled = !shaderEffectsEnabled;
1225 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_RIGHT) {
1226 if (optionsCursor == 0)
1227 difficultySetting = (difficultySetting + 1) % 3;
1228 if (optionsCursor == 1) {
1229 shaderEffectsEnabled = !shaderEffectsEnabled;
1232 }
else if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_START) {
1233 if (optionsCursor == 2)
1235 }
else if (button == SDL_GAMEPAD_BUTTON_EAST) {
1240 if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_EAST || button == SDL_GAMEPAD_BUTTON_START) {
1245 if (!enteringName) {
1246 if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_EAST || button == SDL_GAMEPAD_BUTTON_START) {
1249 }
else if (enteringName) {
1250 if (button == SDL_GAMEPAD_BUTTON_BACK)
1258 if (gamepad ==
nullptr)
1260 Uint32 now = SDL_GetTicks();
1263 Sint16 lx = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
1264 Sint16 ly = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
1266 if (lx < -JOYSTICK_DEAD_ZONE) {
1267 if (now - joyRepeatLeft > JOY_REPEAT_DELAY) {
1269 joyRepeatLeft = now;
1274 if (lx > JOYSTICK_DEAD_ZONE) {
1275 if (now - joyRepeatRight > JOY_REPEAT_DELAY) {
1277 joyRepeatRight = now;
1282 if (ly > JOYSTICK_DEAD_ZONE) {
1283 if (now - joyRepeatDown > JOY_REPEAT_DELAY) {
1285 joyRepeatDown = now;
1290 if (ly < -JOYSTICK_DEAD_ZONE) {
1291 if (now - joyRepeatUp > JOY_REPEAT_DELAY) {
1292 matrix.block.color.shiftcolor(
true);
1302 switch (currentScreen) {
1304 if (key == SDLK_RETURN) {
1309 if (key == SDLK_UP) {
1310 cursorPos = (cursorPos - 1 + 5) % 5;
1311 }
else if (key == SDLK_DOWN) {
1312 cursorPos = (cursorPos + 1) % 5;
1313 }
else if (key == SDLK_RETURN) {
1314 if (cursorPos == 0) {
1320 matrix.block.horizontal =
false;
1322 }
else if (cursorPos == 1) {
1324 enteringName =
false;
1326 }
else if (cursorPos == 2) {
1328 }
else if (cursorPos == 3) {
1330 }
else if (cursorPos == 4) {
1336 if (key == SDLK_LEFT) {
1338 }
else if (key == SDLK_RIGHT) {
1340 }
else if (key == SDLK_DOWN) {
1342 }
else if (key == SDLK_UP) {
1343 matrix.block.color.shiftcolor(
true);
1344 }
else if (key == SDLK_SPACE) {
1346 }
else if (key == SDLK_Z) {
1347 matrix.block.color.shiftcolor(
false);
1348 }
else if (key == SDLK_P) {
1350 }
else if (key == SDLK_L) {
1355 }
else if (key == SDLK_ESCAPE) {
1360 if (key == SDLK_RETURN) {
1362 }
else if (key == SDLK_ESCAPE) {
1367 if (key == SDLK_UP) {
1368 optionsCursor = (optionsCursor - 1 + 3) % 3;
1369 }
else if (key == SDLK_DOWN) {
1370 optionsCursor = (optionsCursor + 1) % 3;
1371 }
else if (key == SDLK_LEFT) {
1372 if (optionsCursor == 0) {
1373 difficultySetting = (difficultySetting - 1 + 3) % 3;
1374 }
else if (optionsCursor == 1) {
1375 shaderEffectsEnabled = !shaderEffectsEnabled;
1378 }
else if (key == SDLK_RIGHT) {
1379 if (optionsCursor == 0) {
1380 difficultySetting = (difficultySetting + 1) % 3;
1381 }
else if (optionsCursor == 1) {
1382 shaderEffectsEnabled = !shaderEffectsEnabled;
1385 }
else if (key == SDLK_RETURN) {
1386 if (optionsCursor == 2) {
1392 if (key == SDLK_RETURN) {
1398 if (key == SDLK_RETURN && !playerName.empty()) {
1400 scores.addScore(playerName, finalScore);
1401 enteringName =
false;
1402 }
else if (key == SDLK_BACKSPACE && !playerName.empty()) {
1403 playerName.pop_back();
1404 }
else if (key == SDLK_ESCAPE) {
1405 enteringName =
false;
1408 if (key == SDLK_RETURN || key == SDLK_ESCAPE) {
1419 if (playerName.length() < 15) {
1432 SDL_Log(
"mxvk: Exception: %s\n", e.
text().c_str());
1433 return EXIT_FAILURE;
1435 std::cerr << std::format(
"mxvk: Argument Exception: {}\n", e.
text());
1436 return EXIT_FAILURE;
1438 return EXIT_SUCCESS;
constexpr int NEXT_PANEL_Y
constexpr int FLASH_DURATION
constexpr int BLOCK_HEIGHT
constexpr int SHADER_LEVEL_LINES
constexpr int BLOCK_SPACING
constexpr int GRID_HEIGHT
constexpr int SHADER_LEVEL_COUNT
constexpr int NEXT_PANEL_X
Lightweight, header-only, template command-line argument parser.
Arguments proc_args(int &argc, char **argv)
Parse standard libmx2 command-line options from main()'s argv.
Exception thrown by Argz::proc() on unrecognised or malformed options.
bool qualifiesForHighScore(int score)
void addScore(const std::string &name, int score)
const std::vector< Score > & getScores() const
void handleControllerButton(Uint8 button)
void clearFlashedBlocks()
void proc() override
Execute one processing/update step.
void drawblock(float scaleX, float scaleY)
void tryOpenFirstGamepad()
void gameKeypress(SDL_Keycode key)
bool openGamepad(SDL_JoystickID id)
void handleTextInput(const char *text)
void event(SDL_Event &e) override
Handle one SDL event.
void drawnext(float scaleX, float scaleY)
int centerX(const char *text)
virtual ~MasterPieceWindow()
void drawmatrix(float scaleX, float scaleY)
void applyShaderEffectsToggle()
MasterPieceWindow(const std::string &path, int wx, int wy, bool full, bool enable_vsync)
Main Vulkan window wrapper for MXVK.
void loop()
Run the main event/render loop.
VK_Sprite * createSprite(const std::string &pngPath, const std::string &vertexShaderPath="", const std::string &fragmentShaderPath="")
Create a sprite from a PNG file and register it with this window.
bool getTextDimensions(const std::string &text, int &width, int &height)
Measure text dimensions in pixels.
void clearTextQueue()
Clear all queued text draw calls for the current frame.
std::unique_ptr< SDL_Window, SDLWindowDeleter > window
void exit()
Request loop termination.
VK_Window()=default
Construct an empty window object.
void setFont(const std::string &fontPath, int fontSize=24)
Set the active text-render font.
void printText(const std::string &text, int x, int y, const SDL_Color &col)
Queue a text string for rendering during the current frame.
Utilities for loading and saving PNG images.
Plain data structure returned by proc_args() with all common libmx2 CLI options.
bool fullscreen
Whether fullscreen mode was requested.
bool enable_vsync
Enable FIFO present mode / v-sync (--enable-vsync).
int height
Viewport height in pixels (default: 720).
std::string path
Asset root; proc_args() defaults it to the executable directory.
int width
Viewport width in pixels (default: 1280).
void shiftcolor(bool dir)
auto operator<=>(const Score &s) const
Score(std::string name, int score)
int grid[GRID_WIDTH][GRID_HEIGHT]