19#ifndef puzzle_ASSET_DIR
20#define puzzle_ASSET_DIR "."
36enum {
BLOCK_BLACK = 0,
BLOCK_YELLOW,
BLOCK_ORANGE,
BLOCK_LTBLUE,
BLOCK_DBLUE,
BLOCK_PURPLE,
BLOCK_PINK,
BLOCK_GRAY,
BLOCK_RED,
BLOCK_GREEN,
BLOCK_CLEAR,
BLOCK_COUNT };
74 int t1 =
c1, t2 =
c2, t3 =
c3;
124 void addScore(
const std::string &name,
int score) {
125 scores.push_back({name, score});
128 if (scores.size() > 10) {
132 void sort() { std::sort(scores.begin(), scores.end()); }
135 if (scores.size() < 10)
137 return score > scores.back().score;
140 const std::vector<Score> &
getScores()
const {
return scores; }
144 for (
int i = 0; i < 10; ++i)
145 scores.push_back(
Score(
"Anonymous", (10 - i) * 100));
150 file.open(
"./scores.dat", std::ios::in);
151 if (!file.is_open()) {
152 std::cout <<
"No scores file.\n";
158 while (std::getline(file, input)) {
161 if (input.length() > 0) {
162 auto pos = input.find(
":");
163 if (pos != std::string::npos) {
164 std::string left = input.substr(0, pos);
165 std::string right = input.substr(pos + 1);
166 scores.push_back(
Score(left, std::strtol(right.c_str(), 0, 10)));
176 file.open(
"./scores.dat", std::ios::out);
177 if (!file.is_open()) {
178 std::cerr <<
"Could not open score file..\n";
181 for (
auto &s : scores) {
182 file << s.name <<
":" << s.score << std::endl;
188 std::vector<Score> scores;
193 std::string current_path;
202 int optionsCursor = 0;
203 int difficultySetting = 1;
204 bool shaderEffectsEnabled =
true;
205 bool enteringName =
false;
206 std::string playerName;
211 int lastFontSize = 0;
212 bool flashActive =
false;
213 Uint32 flashStartTime = 0;
215 std::vector<mxvk::VK_Sprite *> grid_blocks;
220 SDL_Gamepad *gamepad =
nullptr;
221 SDL_JoystickID gamepadId = 0;
222 static constexpr Sint16 JOYSTICK_DEAD_ZONE = 12000;
223 Uint32 joyRepeatLeft = 0;
224 Uint32 joyRepeatRight = 0;
225 Uint32 joyRepeatDown = 0;
226 Uint32 joyRepeatUp = 0;
227 static constexpr Uint32 JOY_REPEAT_DELAY = 150;
230 MasterPieceWindow(
const std::string &path,
int wx,
int wy,
bool full,
bool enable_vsync) :
mxvk::
VK_Window(
"-[ Acid Drop - Vulkan ]-", wx, wy, full,
MXVK_VALIDATION, enable_vsync), current_path((path.empty() || path ==
".") ? std::string(
puzzle_ASSET_DIR) : path), w(wx), h(wy) {
233 srand((
unsigned int)time(0));
234 lastTick = SDL_GetTicks();
238 if (gamepad !=
nullptr) {
239 SDL_CloseGamepad(gamepad);
245 std::string vertShader = current_path +
"/data/sprite_vert.spv";
246 std::string fragShader = current_path +
"/data/sprite_kaleidoscope.spv";
247 const char *fragShaders[
SHADER_LEVEL_COUNT] = {
"sprite_kaleidoscope.spv",
"sprite_kaleidoscope2.spv",
"sprite_kaleidoscope3.spv",
"sprite_kaleidoscope4.spv"};
249 gamebg[i] =
createSprite(current_path +
"/data/gamebg.png", vertShader, current_path +
"/data/" + fragShaders[i]);
251 introScreen =
createSprite(current_path +
"/data/intro.png", current_path +
"/data/sprite_vert.spv", current_path +
"/data/sprite_bubble.spv");
252 startScreen =
createSprite(current_path +
"/data/universe.png", current_path +
"/data/sprite_vert.spv", fragShader);
253 creditScreen =
createSprite(current_path +
"/data/logo.png", current_path +
"/data/sprite_vert.spv", current_path +
"/data/sprite_time.spv");
254 scoresBackground =
createSprite(current_path +
"/data/bg.png", current_path +
"/data/sprite_vert.spv", current_path +
"/data/sprite_time.spv");
256 const char *blockFiles[] = {
"block_black.png",
"block_yellow.png",
"block_orange.png",
"block_ltblue.png",
"block_dblue.png",
"block_purple.png",
"block_pink.png",
"block_gray.png",
"block_red.png",
"block_green.png",
"block_clear.png"};
258 grid_blocks.push_back(
createSprite(current_path +
"/data/" + blockFiles[i], current_path +
"/data/sprite_vert.spv", current_path +
"/data/sprite_frag.spv"));
264 int fontSize = (int)(20.0f * ((
float)h / 480.0f));
265 fontSize = std::max(16, std::min(128, fontSize));
266 if (fontSize != lastFontSize) {
267 lastFontSize = fontSize;
268 setFont(current_path +
"/data/font.ttf", fontSize);
274 if (gamepad !=
nullptr && gamepadId ==
id) {
277 if (gamepad !=
nullptr) {
278 SDL_CloseGamepad(gamepad);
282 gamepad = SDL_OpenGamepad(
id);
283 if (gamepad ==
nullptr) {
291 if (gamepad !=
nullptr) {
295 SDL_JoystickID *ids = SDL_GetGamepads(&count);
296 if (ids ==
nullptr || count <= 0) {
297 if (ids !=
nullptr) {
309 gamebg[i]->setEffectsEnabled(shaderEffectsEnabled);
312 introScreen->setEffectsEnabled(shaderEffectsEnabled);
314 startScreen->setEffectsEnabled(shaderEffectsEnabled);
316 creditScreen->setEffectsEnabled(shaderEffectsEnabled);
317 if (scoresBackground)
318 scoresBackground->setEffectsEnabled(shaderEffectsEnabled);
319 for (
auto *block : grid_blocks) {
321 block->setEffectsEnabled(shaderEffectsEnabled);
329 int scaleY(
int baseY) {
return (
int)(baseY * ((float)h / 480.0f)); }
334 return w / 2 - width / 2;
336 return w / 2 - (int)(strlen(text) *
getCharWidth() / 2);
341 SDL_GetWindowSizeInPixels(
window.get(), &w, &h);
343 if (startScreen ==
nullptr) {
347 switch (currentScreen) {
374 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
375 introScreen->setShaderParams(time_f, 1.0f, 0.8f, 1.2f);
376 introScreen->drawSpriteRect(0, 0, w, h);
378 Uint32 currentTick = SDL_GetTicks();
379 if (currentTick - lastTick > 5000) {
381 lastTick = currentTick;
387 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
388 startScreen->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
389 startScreen->drawSpriteRect(0, 0, w, h);
392 int menuStartY =
scaleY(180);
394 const char *title =
"Liquid Acid Drop";
396 const char *menuItems[] = {
"New Game",
"High Scores",
"Options",
"Credits",
"Quit"};
397 for (
int i = 0; i < 5; i++) {
398 SDL_Color col = (i == cursorPos) ? SDL_Color{255, 255, 0, 255} : SDL_Color{255, 255, 255, 255};
399 printText(menuItems[i],
centerX(menuItems[i]), menuStartY + i * spacing, col);
401 printText(
">>",
centerX(menuItems[cursorPos]) -
scaleY(30), menuStartY + cursorPos * spacing, {255, 255, 0, 255});
412 if (gamebg[shaderLevel]) {
413 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
414 gamebg[shaderLevel]->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
415 gamebg[shaderLevel]->drawSpriteRect(0, 0, w, h);
418 const char *gameOverText =
"GAME OVER!";
419 printText(gameOverText,
centerX(gameOverText), h / 2 - 80, {255, 0, 0, 255});
421 std::ostringstream stream;
422 stream <<
"Final Score: " <<
matrix.Game.score;
423 std::string scoreStr = stream.str();
424 printText(scoreStr.c_str(),
centerX(scoreStr.c_str()), h / 2 - 20, {255, 255, 255, 255});
427 stream <<
"Tabs: " <<
matrix.Game.lines;
428 std::string linesStr = stream.str();
429 printText(linesStr.c_str(),
centerX(linesStr.c_str()), h / 2 + 40, {255, 255, 255, 255});
431 const char *returnText =
"Press ENTER to view High Scores";
432 printText(returnText,
centerX(returnText), h / 2 + 120, {255, 255, 0, 255});
436 finalScore =
matrix.Game.score;
438 enteringName = scores.qualifiesForHighScore(finalScore);
444 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
445 startScreen->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
446 startScreen->drawSpriteRect(0, 0, w, h);
450 int optStartY =
scaleY(180);
453 const char *optTitle =
"OPTIONS";
456 const char *difficultyLabels[] = {
"Easy",
"Normal",
"Hard"};
457 std::string diffText = std::string(
"< Difficulty: ") + difficultyLabels[difficultySetting] +
" >";
458 SDL_Color diffColor = (optionsCursor == 0) ? SDL_Color{255, 255, 0, 255} : SDL_Color{255, 255, 255, 255};
459 printText(diffText.c_str(),
centerX(diffText.c_str()), optStartY, diffColor);
460 if (optionsCursor == 0) {
461 int diffWidth, diffHeight;
463 diffWidth =
static_cast<int>(diffText.size()) *
getCharWidth();
465 printText(
">>", w / 2 - diffWidth / 2 -
scaleY(30), optStartY, {255, 255, 0, 255});
468 std::string fxText = std::string(
"< Shader Effects: ") + (shaderEffectsEnabled ?
"On" :
"Off") +
" >";
469 SDL_Color fxColor = (optionsCursor == 1) ? SDL_Color{255, 255, 0, 255} : SDL_Color{255, 255, 255, 255};
470 printText(fxText.c_str(),
centerX(fxText.c_str()), optStartY + spacing, fxColor);
471 if (optionsCursor == 1) {
472 int fxWidth, fxHeight;
474 fxWidth =
static_cast<int>(fxText.size()) *
getCharWidth();
476 printText(
">>", w / 2 - fxWidth / 2 -
scaleY(30), optStartY + spacing, {255, 255, 0, 255});
479 const char *backText =
"Back";
480 SDL_Color backColor = (optionsCursor == 2) ? SDL_Color{255, 255, 0, 255} : SDL_Color{255, 255, 255, 255};
482 if (optionsCursor == 2) {
483 int backWidth, backHeight;
485 backWidth =
static_cast<int>(std::strlen(backText)) *
getCharWidth();
487 printText(
">>", w / 2 - backWidth / 2 -
scaleY(30), optStartY + spacing * 2, {255, 255, 0, 255});
490 const char *instructions =
"UP/DOWN: Select LEFT/RIGHT: Change ENTER: Confirm";
496 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
497 creditScreen->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
498 creditScreen->drawSpriteRect(0, 0, w, h);
501 const char *credReturn =
"Press Return to return";
507 if (scoresBackground) {
508 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
509 scoresBackground->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
510 scoresBackground->drawSpriteRect(0, 0, w, h);
514 int listStartY =
scaleY(90);
515 int lineHeight =
scaleY(32);
517 const char *title =
"HIGH SCORES";
520 const auto &scoreList = scores.getScores();
521 for (
size_t i = 0; i < scoreList.size() && i < 10; ++i) {
522 std::ostringstream stream;
523 stream << (i + 1) <<
". " << scoreList[i].name <<
" " << scoreList[i].score;
524 std::string scoreStr = stream.str();
526 SDL_Color color = {255, 0, 150, 255};
528 if (enteringName && finalScore > 0) {
531 for (
size_t j = 0; j < scoreList.size(); ++j) {
532 if (finalScore > scoreList[j].score) {
538 if ((
int)i == rank) {
539 color = {0, 255, 0, 255};
543 printText(scoreStr.c_str(),
scaleY(100), listStartY + (
int)i * lineHeight, color);
549 std::ostringstream stream;
550 stream <<
"Your Score: " << finalScore;
551 std::string yourScore = stream.str();
552 printText(yourScore.c_str(),
centerX(yourScore.c_str()), entryY - lineHeight * 2, {255, 255, 0, 255});
554 const char *prompt =
"Enter your name:";
555 printText(prompt,
centerX(prompt), entryY - lineHeight, {255, 255, 255, 255});
557 std::string displayName = playerName +
"_";
558 printText(displayName.c_str(),
centerX(displayName.c_str()), entryY, {0, 255, 255, 255});
560 const char *instructions =
"Type name, ENTER to confirm, BACKSPACE to delete or Escape/Back";
561 printText(instructions,
centerX(instructions), entryY + lineHeight, {200, 0, 150, 255});
563 const char *returnText =
"Press ENTER to return to menu";
569 float scaleX = (float)w / 640.0f;
570 float scaleY = (float)h / 480.0f;
571 if (gamebg[shaderLevel]) {
572 float time_f =
static_cast<float>(SDL_GetTicks()) / 1000.0f;
573 gamebg[shaderLevel]->setShaderParams(time_f, 0.0f, 0.0f, 0.0f);
574 gamebg[shaderLevel]->drawSpriteRect(0, 0, w, h);
579 std::ostringstream stream;
580 stream <<
"Score:" <<
matrix.Game.score;
581 printText(stream.str().c_str(), (
int)(200 * scaleX), (
int)(80 *
scaleY) - (lastFontSize + (lastFontSize / 4)), {255, 255, 255, 255});
584 stream <<
"Tabs:" <<
matrix.Game.lines;
585 printText(stream.str().c_str(), (
int)(310 * scaleX), (
int)(80 *
scaleY) - (lastFontSize + (lastFontSize / 4)), {255, 255, 255, 255});
588 const char *pausedText =
"PAUSED - Press P to Continue";
589 int pausedWidth, pausedHeight;
591 pausedWidth =
static_cast<int>(std::strlen(pausedText)) *
getCharWidth();
593 printText(pausedText, w / 2 - pausedWidth / 2, h / 2, {255, 255, 0, 255});
598 Uint32 now = SDL_GetTicks();
599 bool showFlash = flashActive && ((now - flashStartTime) / 50 % 2 == 0);
603 int blockType =
matrix.grid[i][j];
604 if (blockType > 0 && blockType <
BLOCK_COUNT &&
static_cast<size_t>(blockType) < grid_blocks.size()) {
608 if (flashActive && flashGrid[i][j] && !showFlash) {
612 if (grid_blocks[blockType]) {
621 int c1 =
matrix.block.color.c1;
622 int c2 =
matrix.block.color.c2;
623 int c3 =
matrix.block.color.c3;
625 if (
matrix.block.horizontal) {
628 for (
int i = 0; i < 3; i++) {
629 int color = (i == 0) ? c1 : (i == 1) ? c2 : c3;
631 if (
matrix.block.x + i >= 0 &&
matrix.block.x + i < GRID_WIDTH && color > 0 && color <
BLOCK_COUNT && grid_blocks[color]) {
639 int y1 =
matrix.block.y + 1;
640 int y2 =
matrix.block.y + 2;
642 if (y0 >= 0 && c1 > 0 && c1 <
BLOCK_COUNT && grid_blocks[c1]) {
646 if (y1 >= 0 && c2 > 0 && c2 <
BLOCK_COUNT && grid_blocks[c2]) {
650 if (y2 >= 0 && c3 > 0 && c3 <
BLOCK_COUNT && grid_blocks[c3]) {
662 int c1 =
matrix.nextblock.color.c1;
663 int c2 =
matrix.nextblock.color.c2;
664 int c3 =
matrix.nextblock.color.c3;
666 if (c1 > 0 && c1 <
BLOCK_COUNT && grid_blocks[c1]) {
669 if (c2 > 0 && c2 <
BLOCK_COUNT && grid_blocks[c2]) {
672 if (c3 > 0 && c3 <
BLOCK_COUNT && grid_blocks[c3]) {
678 static Uint32 lastMove = 0;
679 Uint32 now = SDL_GetTicks();
695 if (now - lastMove > (Uint32)(
matrix.Game.speed * 50)) {
723 if (
matrix.block.horizontal) {
727 for (
int i = 0; i < 3; i++) {
735 if (
matrix.grid[bx][by + 3] > 0)
745 int bx =
matrix.block.x - 1;
748 if (
matrix.block.horizontal) {
768 if (
matrix.block.horizontal) {
772 int bx =
matrix.block.x + 3;
779 int bx =
matrix.block.x + 1;
795 if (
matrix.block.horizontal) {
818 memset(flashGrid,
false,
sizeof(flashGrid));
819 bool foundMatch =
false;
824 if (
matrix.grid[i][j] > 0) {
825 int color =
matrix.grid[i][j];
832 for (
int k = 0; k < count; k++) {
833 flashGrid[i + k][j] =
true;
848 if (
matrix.grid[i][j] > 0) {
849 int color =
matrix.grid[i][j];
856 for (
int k = 0; k < count; k++) {
857 flashGrid[i][j + k] =
true;
872 if (
matrix.grid[i][j] > 0) {
873 int color =
matrix.grid[i][j];
879 for (
int k = 0; k < count; k++) {
880 flashGrid[i + k][j + k] =
true;
895 if (
matrix.grid[i][j] > 0) {
896 int color =
matrix.grid[i][j];
898 while (i - count >= 0 && j + count <
GRID_HEIGHT &&
matrix.grid[i - count][j + count] == color) {
902 for (
int k = 0; k < count; k++) {
903 flashGrid[i - k][j + k] =
true;
921 flashStartTime = SDL_GetTicks();
927 if (flashGrid[i][j]) {
933 matrix.Game.score += matchBonus;
938 if (newLevel != shaderLevel) {
939 shaderLevel = newLevel;
940 std::cout <<
"level increased to: " << shaderLevel << std::endl;
942 memset(flashGrid,
false,
sizeof(flashGrid));
955 if (
matrix.grid[i][j] > 0 &&
matrix.grid[i][j + 1] == 0) {
968 matrix.nextblock.color.randcolor();
971 matrix.block.horizontal =
false;
977 if (
matrix.grid[i][1] > 0) {
984 if (
matrix.grid[i][j] == 0) {
995 int baseSpeeds[] = {30, 20, 10};
996 matrix.Game.speed = baseSpeeds[difficultySetting];
1027 if (
matrix.block.horizontal) {
1056 if (e.type == SDL_EVENT_QUIT || (currentScreen ==
SCREEN_START && e.type == SDL_EVENT_KEY_DOWN && e.key.key == SDLK_ESCAPE)) {
1061 if (e.type == SDL_EVENT_KEY_DOWN) {
1063 }
else if (e.type == SDL_EVENT_TEXT_INPUT) {
1067 if (e.type == SDL_EVENT_GAMEPAD_ADDED) {
1069 }
else if (e.type == SDL_EVENT_GAMEPAD_REMOVED) {
1070 if (gamepad !=
nullptr && e.gdevice.which == gamepadId) {
1071 SDL_CloseGamepad(gamepad);
1075 }
else if (e.type == SDL_EVENT_GAMEPAD_BUTTON_DOWN) {
1081 switch (currentScreen) {
1083 if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_START) {
1088 if (button == SDL_GAMEPAD_BUTTON_DPAD_UP) {
1089 cursorPos = (cursorPos - 1 + 5) % 5;
1090 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) {
1091 cursorPos = (cursorPos + 1) % 5;
1092 }
else if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_START) {
1093 if (cursorPos == 0) {
1099 matrix.block.horizontal =
false;
1101 }
else if (cursorPos == 1) {
1103 enteringName =
false;
1105 }
else if (cursorPos == 2) {
1107 }
else if (cursorPos == 3) {
1109 }
else if (cursorPos == 4) {
1112 }
else if (button == SDL_GAMEPAD_BUTTON_EAST) {
1117 if (button == SDL_GAMEPAD_BUTTON_DPAD_LEFT) {
1119 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_RIGHT) {
1121 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) {
1123 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_UP) {
1124 matrix.block.color.shiftcolor(
true);
1125 }
else if (button == SDL_GAMEPAD_BUTTON_SOUTH) {
1127 }
else if (button == SDL_GAMEPAD_BUTTON_EAST) {
1128 matrix.block.color.shiftcolor(
false);
1129 }
else if (button == SDL_GAMEPAD_BUTTON_NORTH) {
1131 }
else if (button == SDL_GAMEPAD_BUTTON_START) {
1133 }
else if (button == SDL_GAMEPAD_BUTTON_BACK) {
1138 if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_START) {
1140 }
else if (button == SDL_GAMEPAD_BUTTON_EAST) {
1145 if (button == SDL_GAMEPAD_BUTTON_DPAD_UP) {
1146 optionsCursor = (optionsCursor - 1 + 3) % 3;
1147 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_DOWN) {
1148 optionsCursor = (optionsCursor + 1) % 3;
1149 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_LEFT) {
1150 if (optionsCursor == 0)
1151 difficultySetting = (difficultySetting - 1 + 3) % 3;
1152 if (optionsCursor == 1) {
1153 shaderEffectsEnabled = !shaderEffectsEnabled;
1156 }
else if (button == SDL_GAMEPAD_BUTTON_DPAD_RIGHT) {
1157 if (optionsCursor == 0)
1158 difficultySetting = (difficultySetting + 1) % 3;
1159 if (optionsCursor == 1) {
1160 shaderEffectsEnabled = !shaderEffectsEnabled;
1163 }
else if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_START) {
1164 if (optionsCursor == 2)
1166 }
else if (button == SDL_GAMEPAD_BUTTON_EAST) {
1171 if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_EAST || button == SDL_GAMEPAD_BUTTON_START) {
1176 if (!enteringName) {
1177 if (button == SDL_GAMEPAD_BUTTON_SOUTH || button == SDL_GAMEPAD_BUTTON_EAST || button == SDL_GAMEPAD_BUTTON_START) {
1180 }
else if (enteringName) {
1181 if (button == SDL_GAMEPAD_BUTTON_BACK)
1189 if (gamepad ==
nullptr)
1191 Uint32 now = SDL_GetTicks();
1194 Sint16 lx = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTX);
1195 Sint16 ly = SDL_GetGamepadAxis(gamepad, SDL_GAMEPAD_AXIS_LEFTY);
1197 if (lx < -JOYSTICK_DEAD_ZONE) {
1198 if (now - joyRepeatLeft > JOY_REPEAT_DELAY) {
1200 joyRepeatLeft = now;
1205 if (lx > JOYSTICK_DEAD_ZONE) {
1206 if (now - joyRepeatRight > JOY_REPEAT_DELAY) {
1208 joyRepeatRight = now;
1213 if (ly > JOYSTICK_DEAD_ZONE) {
1214 if (now - joyRepeatDown > JOY_REPEAT_DELAY) {
1216 joyRepeatDown = now;
1221 if (ly < -JOYSTICK_DEAD_ZONE) {
1222 if (now - joyRepeatUp > JOY_REPEAT_DELAY) {
1223 matrix.block.color.shiftcolor(
true);
1233 switch (currentScreen) {
1235 if (key == SDLK_RETURN) {
1240 if (key == SDLK_UP) {
1241 cursorPos = (cursorPos - 1 + 5) % 5;
1242 }
else if (key == SDLK_DOWN) {
1243 cursorPos = (cursorPos + 1) % 5;
1244 }
else if (key == SDLK_RETURN) {
1245 if (cursorPos == 0) {
1251 matrix.block.horizontal =
false;
1253 }
else if (cursorPos == 1) {
1255 enteringName =
false;
1257 }
else if (cursorPos == 2) {
1259 }
else if (cursorPos == 3) {
1261 }
else if (cursorPos == 4) {
1267 if (key == SDLK_LEFT) {
1269 }
else if (key == SDLK_RIGHT) {
1271 }
else if (key == SDLK_DOWN) {
1273 }
else if (key == SDLK_UP) {
1274 matrix.block.color.shiftcolor(
true);
1275 }
else if (key == SDLK_SPACE) {
1277 }
else if (key == SDLK_Z) {
1278 matrix.block.color.shiftcolor(
false);
1279 }
else if (key == SDLK_P) {
1281 }
else if (key == SDLK_L) {
1286 }
else if (key == SDLK_ESCAPE) {
1291 if (key == SDLK_RETURN) {
1293 }
else if (key == SDLK_ESCAPE) {
1298 if (key == SDLK_UP) {
1299 optionsCursor = (optionsCursor - 1 + 3) % 3;
1300 }
else if (key == SDLK_DOWN) {
1301 optionsCursor = (optionsCursor + 1) % 3;
1302 }
else if (key == SDLK_LEFT) {
1303 if (optionsCursor == 0) {
1304 difficultySetting = (difficultySetting - 1 + 3) % 3;
1305 }
else if (optionsCursor == 1) {
1306 shaderEffectsEnabled = !shaderEffectsEnabled;
1309 }
else if (key == SDLK_RIGHT) {
1310 if (optionsCursor == 0) {
1311 difficultySetting = (difficultySetting + 1) % 3;
1312 }
else if (optionsCursor == 1) {
1313 shaderEffectsEnabled = !shaderEffectsEnabled;
1316 }
else if (key == SDLK_RETURN) {
1317 if (optionsCursor == 2) {
1323 if (key == SDLK_RETURN) {
1329 if (key == SDLK_RETURN && !playerName.empty()) {
1331 scores.addScore(playerName, finalScore);
1332 enteringName =
false;
1333 }
else if (key == SDLK_BACKSPACE && !playerName.empty()) {
1334 playerName.pop_back();
1335 }
else if (key == SDLK_ESCAPE) {
1336 enteringName =
false;
1339 if (key == SDLK_RETURN || key == SDLK_ESCAPE) {
1350 if (playerName.length() < 15) {
1363 SDL_Log(
"mxvk: Exception: %s\n", e.
text().c_str());
1364 return EXIT_FAILURE;
1366 std::cerr << std::format(
"mxvk: Argument Exception: {}\n", e.
text());
1367 return EXIT_FAILURE;
1369 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]