Advertisement
SwissAndOr

main.cpp (Polyis)

Apr 27th, 2015
318
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
C++ 33.93 KB | None | 0 0
  1. #include <SDL.h>
  2. #include <SDL_image.h>
  3. #include <SDL_ttf.h>
  4.  
  5. #include <algorithm>
  6. #include <chrono>
  7. #include <iterator>
  8. #include <stdio.h>
  9. #include <random>
  10. #include <string>
  11. #include <vector>
  12.  
  13. #include "Shape.h"
  14. #include "Text.h"
  15.  
  16. typedef std::vector<int> intArray;
  17. typedef std::vector<float> floatArray;
  18. typedef std::vector<std::vector<Tile>> gridArray;
  19. typedef std::vector<Text> textArray;
  20.  
  21. enum fallState {
  22.     FELL,
  23.     PLACED,
  24. };
  25.  
  26. enum gameState {
  27.     PLAYING,
  28.     ENDED,
  29.     PAUSED,
  30.     MAIN_MENU
  31. };
  32.  
  33. bool handleEvents();
  34. bool update(float deltaTime);
  35. void paintGame();
  36. void paintMenu(float deltaTime);
  37.  
  38. fallState fall();
  39. void addShape();
  40. void newShape();
  41.  
  42. bool init();
  43. void close();
  44.  
  45. SDL_Window* window;
  46. SDL_Renderer* renderer;
  47.  
  48. Text scoreT, scoreNumT, linesT, linesNumT, levelT, levelNumT, nextT, menuT, holdT;
  49.  
  50. int tileLength = 34, tiles = 4, width = 10, height = 22, gridLineWidth = 2;
  51. int screenWidth = tileLength * (width + 12), screenHeight = tileLength * (height - 2);
  52.  
  53. int selectedMenuIndex = 0, selectedSubmenuIndex = 0;
  54.  
  55. Shape* currentShape;
  56. intArray shapeIndexes;
  57. intArray nextShapeIndexes;
  58. int currentShapeIndex = 0, heldIndex = -1;
  59. gridArray grid(height, std::vector<Tile>(width));
  60.  
  61. unsigned int score = 0, lines = 0, level = 1, lineClearCombos = 0, startingLevel = 1;
  62. floatArray lineClearPoints = {100, 300, 500, 800, 1.5, 50};
  63. bool lastClearDifficult = false;
  64.  
  65. float fastSpeed = 30.0F, normalSpeed = (float) level, fastFallTime = 0.0F, normalFallTime = 0.0F, lockTime = 0.0F, lockDelay = .25F;
  66. int nextShapes = 3; // No more than 7
  67. bool isFast = false, canHold = true, isLocking = false, menuFocus = true, debugShowDataArea = false;
  68.  
  69. gameState state = MAIN_MENU;
  70.  
  71. Text title;
  72.  
  73. struct menuOption {
  74.     Text text;
  75.     float y, size = (float) Text::defaultSize;
  76. } mainSubs[5];
  77.  
  78. int playX = 0, playY = 0;
  79. textArray playOptions(10);
  80.  
  81. enum displayType {
  82.     BOOLEAN,
  83.     INTEGER,
  84.     FLOAT,
  85.     STRING
  86. };
  87.  
  88. struct customOption {
  89.     Text text, valueText;
  90.     displayType type;
  91.     int currentOption;
  92.  
  93.     int Imin, Imax;
  94.     float Fmin, Fmax;
  95.     std::vector<std::string> strings;
  96. } custom[11], options[9];
  97.  
  98. struct controlOption {
  99.     Text text, keyText;
  100.     SDL_Keycode key;
  101. } controls[9];
  102. int currentEditingIndex = -1;
  103.  
  104. int wmain() {
  105.     init();
  106.  
  107.     Uint32 lastTime, currentTime = SDL_GetTicks();
  108.     float deltaTime;
  109.  
  110.     while (true) {
  111.         lastTime = currentTime;
  112.         currentTime = SDL_GetTicks();
  113.         deltaTime = (currentTime - lastTime) / 1000.0f;
  114.  
  115.         if (!handleEvents()) break;
  116.         if (!update(deltaTime)) break;
  117.     }
  118.  
  119.     close();
  120.     return 0;
  121. }
  122.  
  123. bool handleEvents() {
  124.     SDL_Event e;
  125.  
  126.     while (SDL_PollEvent(&e) != 0) {
  127.         switch (e.type) {
  128.         case SDL_QUIT:
  129.             return false;
  130.         case SDL_WINDOWEVENT:
  131.             if ((e.window.event == SDL_WINDOWEVENT_MOVED || e.window.event == SDL_WINDOWEVENT_FOCUS_LOST) && state == PLAYING) {
  132.                 state = PAUSED;
  133.             }
  134.             break;
  135.         case SDL_KEYDOWN:
  136.             switch (state) {
  137.             case PLAYING:
  138.                 if (e.key.keysym.sym == controls[0].key || e.key.keysym.sym == controls[1].key) {
  139.                     if (currentShape->move(grid, e.key.keysym.sym == controls[1].key))
  140.                         lockTime = 0;
  141.                 }
  142.  
  143.                 if (e.key.keysym.sym == controls[4].key || e.key.keysym.sym == controls[5].key) {
  144.                     if (currentShape->rotate(grid, e.key.keysym.sym == controls[4].key))
  145.                         lockTime = 0;
  146.                 }
  147.  
  148.                 if (e.key.keysym.sym == controls[2].key && e.key.repeat == 0) {
  149.                     isFast = true;
  150.                 }
  151.  
  152.                 if (e.key.keysym.sym == controls[3].key && e.key.repeat == 0) {
  153.                     while (fall() == FELL) {
  154.                         score += 2;
  155.                         scoreNumT.change(std::to_string(score));
  156.                     }
  157.                     lockTime = lockDelay;
  158.                 }
  159.  
  160.                 if (e.key.keysym.sym == controls[6].key && canHold) {
  161.                     int p = currentShapeIndex;
  162.                     bool first = heldIndex == -1;
  163.                     if (first) newShape(); else currentShapeIndex = heldIndex;
  164.                     heldIndex = p;
  165.  
  166.                     if (!first) {
  167.                         if (currentShape != NULL) delete[] currentShape; // Breaks here if held
  168.                         currentShape = new Shape;
  169.  
  170.                         currentShape->data = Shape::shapes[currentShapeIndex];
  171.                     }
  172.                     canHold = false;
  173.                 }
  174.  
  175.                 if (e.key.keysym.sym == controls[7].key || e.key.keysym.sym == SDLK_ESCAPE) {
  176.                     state = PAUSED;
  177.                 }
  178.  
  179.                 if (e.key.keysym.sym == controls[8].key) {
  180.                     debugShowDataArea = !debugShowDataArea;
  181.                 }
  182.                 break;
  183.             case PAUSED:
  184.                 if (e.key.keysym.sym == controls[7].key || e.key.keysym.sym == SDLK_ESCAPE) {
  185.                     state = PLAYING;
  186.                 }
  187.  
  188.                 if (e.key.keysym.sym == SDLK_RETURN || e.key.keysym.sym == SDLK_RETURN2) {
  189.                     state = MAIN_MENU; // TODO: Fix Pause menu
  190.                 }
  191.                 break;
  192.             case MAIN_MENU:
  193.                 if (selectedMenuIndex == 3 && currentEditingIndex >= 0) {
  194.                     controls[currentEditingIndex].key = e.key.keysym.sym;
  195.                     currentEditingIndex = -1;
  196.                 } else {
  197.                     if (e.key.keysym.sym == SDLK_UP && e.key.repeat == 0) {
  198.                         if (menuFocus) {
  199.                             selectedMenuIndex = std::max(0, std::min(4, selectedMenuIndex - 1));
  200.                             playX = playY = selectedSubmenuIndex = 0;
  201.                         } else {
  202.                             switch (selectedMenuIndex) {
  203.                             case 0:
  204.                                 playY = std::max(0, std::min(1, playY - 1));
  205.                                 break;
  206.                             case 1:
  207.                                 if (currentEditingIndex < 0)
  208.                                     selectedSubmenuIndex = std::max(0, std::min(10, selectedSubmenuIndex - 1));
  209.                                 else {
  210.                                     switch (custom[currentEditingIndex].type) {
  211.                                     case BOOLEAN:
  212.                                         custom[currentEditingIndex].currentOption = 1 - custom[currentEditingIndex].currentOption;
  213.                                         break;
  214.                                     case INTEGER:
  215.                                         custom[currentEditingIndex].currentOption = std::min(custom[currentEditingIndex].Imax, std::max(custom[currentEditingIndex].Imin, custom[currentEditingIndex].currentOption + 1));
  216.                                         break;
  217.                                     case FLOAT:
  218.                                         custom[currentEditingIndex].currentOption = std::min((int) log2(custom[currentEditingIndex].Fmax), std::max((int) log2(custom[currentEditingIndex].Fmin), custom[currentEditingIndex].currentOption + 1));
  219.                                         break;
  220.                                     case STRING:
  221.                                         custom[currentEditingIndex].currentOption++;
  222.                                         if (custom[currentEditingIndex].currentOption >= custom[currentEditingIndex].strings.size()) custom[currentEditingIndex].currentOption = 0;
  223.                                     }
  224.                                 }
  225.                                 break;
  226.                             case 2:
  227.                                 if (currentEditingIndex < 0)
  228.                                     selectedSubmenuIndex = std::max(0, std::min(4, selectedSubmenuIndex - 1));
  229.                                 else {
  230.                                     switch (options[currentEditingIndex].type) {
  231.                                     case BOOLEAN:
  232.                                         options[currentEditingIndex].currentOption = 1 - options[currentEditingIndex].currentOption;
  233.                                         break;
  234.                                     case INTEGER:
  235.                                         options[currentEditingIndex].currentOption = std::min(options[currentEditingIndex].Imax, std::max(options[currentEditingIndex].Imin, options[currentEditingIndex].currentOption + 1));
  236.                                         break;
  237.                                     }
  238.                                 }
  239.                                 break;
  240.                             case 3:
  241.                                 selectedSubmenuIndex = std::max(0, std::min(8, selectedSubmenuIndex - 1));
  242.                                 break;
  243.                             }
  244.                         }
  245.                     }
  246.  
  247.                     if (e.key.keysym.sym == SDLK_DOWN && e.key.repeat == 0) {
  248.                         if (menuFocus) {
  249.                             selectedMenuIndex = std::max(0, std::min(4, selectedMenuIndex + 1));
  250.                             playX = playY = selectedSubmenuIndex = 0;
  251.                         } else {
  252.                             switch (selectedMenuIndex) {
  253.                             case 0:
  254.                                 playY = std::max(0, std::min(1, playY + 1));
  255.                                 break;
  256.                             case 1:
  257.                                 if (currentEditingIndex < 0)
  258.                                     selectedSubmenuIndex = std::max(0, std::min(10, selectedSubmenuIndex + 1));
  259.                                 else {
  260.                                     switch (custom[currentEditingIndex].type) {
  261.                                     case BOOLEAN:
  262.                                         custom[currentEditingIndex].currentOption = 1 - custom[currentEditingIndex].currentOption;
  263.                                         break;
  264.                                     case INTEGER:
  265.                                         custom[currentEditingIndex].currentOption = std::min(custom[currentEditingIndex].Imax, std::max(custom[currentEditingIndex].Imin, custom[currentEditingIndex].currentOption - 1));
  266.                                         break;
  267.                                     case FLOAT:
  268.                                         custom[currentEditingIndex].currentOption = std::min((int) log2(custom[currentEditingIndex].Fmax), std::max((int) log2(custom[currentEditingIndex].Fmin), custom[currentEditingIndex].currentOption - 1));
  269.                                         break;
  270.                                     case STRING:
  271.                                         custom[currentEditingIndex].currentOption--;
  272.                                         if (custom[currentEditingIndex].currentOption < 0) custom[currentEditingIndex].currentOption = custom[currentEditingIndex].strings.size() - 1;
  273.                                     }
  274.                                 }
  275.                                 break;
  276.                             case 2:
  277.                                 if (currentEditingIndex < 0)
  278.                                     selectedSubmenuIndex = std::max(0, std::min(4, selectedSubmenuIndex + 1));
  279.                                 else {
  280.                                     switch (options[currentEditingIndex].type) {
  281.                                     case BOOLEAN:
  282.                                         options[currentEditingIndex].currentOption = 1 - options[currentEditingIndex].currentOption;
  283.                                         break;
  284.                                     case INTEGER:
  285.                                         options[currentEditingIndex].currentOption = std::min(options[currentEditingIndex].Imax, std::max(options[currentEditingIndex].Imin, options[currentEditingIndex].currentOption + 1));
  286.                                         break;
  287.                                     }
  288.                                 }
  289.                                 break;
  290.                             case 3:
  291.                                 selectedSubmenuIndex = std::max(0, std::min(8, selectedSubmenuIndex + 1));
  292.                                 break;
  293.                             }
  294.                         }
  295.                     }
  296.  
  297.                     if (e.key.keysym.sym == SDLK_LEFT && !menuFocus) {
  298.                         switch (selectedMenuIndex) {
  299.                         case 0:
  300.                             if (playX - 1 < 0) {
  301.                                 menuFocus = true;
  302.                             } else {
  303.                                 playX = std::max(0, std::min(4, playX - 1));
  304.                             }
  305.                             break;
  306.                         case 1:
  307.                             if (currentEditingIndex < 0)
  308.                                 menuFocus = true;
  309.                             else {
  310.                                 switch (custom[currentEditingIndex].type) {
  311.                                 case BOOLEAN:
  312.                                     custom[currentEditingIndex].currentOption = 1 - custom[currentEditingIndex].currentOption;
  313.                                     break;
  314.                                 case INTEGER:
  315.                                     custom[currentEditingIndex].currentOption = std::min(custom[currentEditingIndex].Imax, std::max(custom[currentEditingIndex].Imin, custom[currentEditingIndex].currentOption - 1));
  316.                                     break;
  317.                                 case FLOAT:
  318.                                     custom[currentEditingIndex].currentOption = std::min((int) log2(custom[currentEditingIndex].Fmax), std::max((int) log2(custom[currentEditingIndex].Fmin), custom[currentEditingIndex].currentOption - 1));
  319.                                     break;
  320.                                 case STRING:
  321.                                     custom[currentEditingIndex].currentOption--;
  322.                                     if (custom[currentEditingIndex].currentOption < 0) custom[currentEditingIndex].currentOption = custom[currentEditingIndex].strings.size() - 1;
  323.                                 }
  324.                             }
  325.                             break;
  326.                         case 2:
  327.                             if (currentEditingIndex < 0)
  328.                                 menuFocus = true;
  329.                             else {
  330.                                 switch (options[currentEditingIndex].type) {
  331.                                 case BOOLEAN:
  332.                                     options[currentEditingIndex].currentOption = 1 - options[currentEditingIndex].currentOption;
  333.                                     break;
  334.                                 case INTEGER:
  335.                                     options[currentEditingIndex].currentOption = std::min(options[currentEditingIndex].Imax, std::max(options[currentEditingIndex].Imin, options[currentEditingIndex].currentOption - 1));
  336.                                     break;
  337.                                 }
  338.                             }
  339.                             break;
  340.                         case 3:
  341.                             menuFocus = true;
  342.                             break;
  343.                         }
  344.                     }
  345.  
  346.                     if (e.key.keysym.sym == SDLK_RIGHT && !menuFocus) {
  347.                         switch (selectedMenuIndex) {
  348.                         case 0:
  349.                             playX = std::max(0, std::min(4, playX + 1));
  350.                             break;
  351.                         case 1:
  352.                             switch (custom[currentEditingIndex].type) {
  353.                             case BOOLEAN:
  354.                                 custom[currentEditingIndex].currentOption = 1 - custom[currentEditingIndex].currentOption;
  355.                                 break;
  356.                             case INTEGER:
  357.                                 custom[currentEditingIndex].currentOption = std::min(custom[currentEditingIndex].Imax, std::max(custom[currentEditingIndex].Imin, custom[currentEditingIndex].currentOption + 1));
  358.                                 break;
  359.                             case FLOAT:
  360.                                 custom[currentEditingIndex].currentOption = std::min((int) log2(custom[currentEditingIndex].Fmax), std::max((int) log2(custom[currentEditingIndex].Fmin), custom[currentEditingIndex].currentOption + 1));
  361.                                 break;
  362.                             case STRING:
  363.                                 custom[currentEditingIndex].currentOption++;
  364.                                 if (custom[currentEditingIndex].currentOption >= custom[currentEditingIndex].strings.size()) custom[currentEditingIndex].currentOption = 0;
  365.                             }
  366.                             break;
  367.                         case 2:
  368.                             switch (options[currentEditingIndex].type) {
  369.                             case BOOLEAN:
  370.                                 options[currentEditingIndex].currentOption = 1 - options[currentEditingIndex].currentOption;
  371.                                 break;
  372.                             case INTEGER:
  373.                                 options[currentEditingIndex].currentOption = std::min(options[currentEditingIndex].Imax, std::max(options[currentEditingIndex].Imin, options[currentEditingIndex].currentOption + 1));
  374.                                 break;
  375.                             }
  376.                             break;
  377.                         }
  378.                     }
  379.  
  380.                     if ((e.key.keysym.sym == SDLK_RETURN || e.key.keysym.sym == SDLK_RETURN2) && !menuFocus) {
  381.                         switch (selectedMenuIndex) {
  382.                         case 0:
  383.                             startingLevel = 1 + playX + playY * 5;
  384.                             level = startingLevel;
  385.  
  386.                             levelNumT.change(std::to_string(level));
  387.                             normalSpeed = 0.3F * (float) pow(level, 1.5F) + 0.7F;
  388.                             lockDelay = (float) (sqrt(level) + 2) / 6;
  389.                             fastSpeed = std::max(fastSpeed, normalSpeed);
  390.  
  391.                             state = PLAYING;
  392.                             break;
  393.                         case 1:
  394.                         case 2:
  395.                         case 3:
  396.                             if (currentEditingIndex >= 0) {
  397.                                 if (selectedMenuIndex == 2 && currentEditingIndex == 3) tileLength = options[3].currentOption;
  398.                                 currentEditingIndex = -1;
  399.                             } else {
  400.                                 currentEditingIndex = selectedSubmenuIndex;
  401.                             }
  402.                             break;
  403.                         }
  404.                     }
  405.  
  406.                     if ((e.key.keysym.sym == SDLK_RETURN || e.key.keysym.sym == SDLK_RETURN2 || e.key.keysym.sym == SDLK_RIGHT) && menuFocus) {
  407.                         if (selectedMenuIndex == 4) {
  408.                             if (e.key.keysym.sym != SDLK_RIGHT)
  409.                                 return false;
  410.                         } else {
  411.                             menuFocus = false;
  412.                         }
  413.                     }
  414.                 }
  415.                 break;
  416.             default:
  417.                 break;
  418.             }
  419.             break;
  420.         case SDL_KEYUP:
  421.             if (e.key.keysym.sym == SDLK_DOWN) {
  422.                 isFast = false;
  423.             }
  424.         default:
  425.             break;
  426.         }
  427.     }
  428.  
  429.     return true;
  430. }
  431.  
  432. bool update(float deltaTime) {
  433.     if (state == PLAYING) {
  434.         if (isLocking) {
  435.             lockTime += deltaTime;
  436.             if (lockTime >= lockDelay) {
  437.                 addShape();
  438.                 isLocking = false;
  439.                 lockTime = 0;
  440.             } else if (currentShape->fall(grid, false)) {
  441.                 isLocking = false;
  442.                 lockTime = 0;
  443.             }
  444.         } else {
  445.             (isFast ? fastFallTime : normalFallTime) += deltaTime;
  446.  
  447.             if ((isFast ? fastFallTime : normalFallTime) >= 1 / (isFast ? fastSpeed : normalSpeed)) {
  448.                 (isFast ? fastFallTime : normalFallTime) -= 1 / (isFast ? fastSpeed : normalSpeed);
  449.                 if (isFast) {
  450.                     score++;
  451.                     scoreNumT.change(std::to_string(score));
  452.                 }
  453.  
  454.                 fall();
  455.             }
  456.         }
  457.     }
  458.  
  459.     if (state == MAIN_MENU) paintMenu(deltaTime);
  460.     else paintGame();
  461.  
  462.     SDL_RenderPresent(renderer);
  463.     return true;
  464. }
  465.  
  466. void paintGame() {
  467.     if (state != PAUSED) {
  468.         int one = state == ENDED ? 208 : 64;
  469.         SDL_SetRenderDrawColor(renderer, one, one, one, 255);
  470.         SDL_RenderClear(renderer);
  471.  
  472.         int ghostY = currentShape->y;
  473.         bool stop = false;
  474.         do {
  475.             ghostY++;
  476.             for (int y = 0; y < tiles && !stop; y++) {
  477.                 for (int x = 0; x < tiles && !stop; x++) {
  478.                     if (currentShape->data[y][x].exists) {
  479.                         stop = (ghostY + y > 21 || grid[ghostY + y][currentShape->x + x].exists);
  480.                     }
  481.                 }
  482.             }
  483.         } while (!stop);
  484.  
  485.         for (int y = 0; y < tiles; y++) {
  486.             for (int x = 0; x < tiles; x++) {
  487.                 if (currentShape->data[y][x].exists) {
  488.                     SDL_Rect tile = {tileLength * (x + currentShape->x + 6), tileLength * (y - 3 + ghostY), tileLength, tileLength};
  489.                     SDL_SetRenderDrawColor(renderer, 96, 96, 96, 255);
  490.                     SDL_RenderFillRect(renderer, &tile);
  491.                 }
  492.             }
  493.         }
  494.  
  495.         for (int y = 0; y < height; y++) {
  496.             for (int x = 0; x < width; x++) {
  497.                 if (grid[y][x].exists) {
  498.                     SDL_Rect tile = {tileLength * (x + 6), tileLength * (y - 2), tileLength, tileLength};
  499.                     if (state == PLAYING) {
  500.                         SDL_SetRenderDrawColor(renderer, grid[y][x].r, grid[y][x].g, grid[y][x].b, 255);
  501.                     } else {
  502.                         SDL_SetRenderDrawColor(renderer, (grid[y][x].r + 765) / 4, (grid[y][x].g + 765) / 4, (grid[y][x].b + 765) / 4, 255);
  503.                     }
  504.                     SDL_RenderFillRect(renderer, &tile);
  505.                 }
  506.             }
  507.         }
  508.  
  509.         for (int y = 0; y < tiles; y++) {
  510.             for (int x = 0; x < tiles; x++) {
  511.                 if (!currentShape->data[y][x].exists && !debugShowDataArea) continue;
  512.  
  513.                 SDL_Rect tile = {tileLength * (x + currentShape->x + 6), tileLength * (y - 2 + currentShape->y), tileLength, tileLength};
  514.  
  515.                 if (debugShowDataArea)
  516.                     SDL_SetRenderDrawColor(renderer, 255, 255, 255, 255);
  517.  
  518.                 if (currentShape->data[y][x].exists || !debugShowDataArea) {
  519.                     if (state == PLAYING) {
  520.                         SDL_SetRenderDrawColor(renderer, (Uint8) ((1 - (lockTime / lockDelay)) * currentShape->data[y][x].r + (72 * (lockTime / lockDelay))), (Uint8) ((1 - (lockTime / lockDelay)) * currentShape->data[y][x].g + (72 * (lockTime / lockDelay))), (Uint8) ((1 - (lockTime / lockDelay)) * currentShape->data[y][x].b + (72 * (lockTime / lockDelay))), 255);
  521.                     } else {
  522.                         SDL_SetRenderDrawColor(renderer, (currentShape->data[y][x].r + 765) / 4, (currentShape->data[y][x].g + 765) / 4, (currentShape->data[y][x].b + 765) / 4, 255);
  523.                     }
  524.                 }
  525.  
  526.                 SDL_RenderFillRect(renderer, &tile);
  527.             }
  528.         }
  529.  
  530.         int two = state == ENDED ? 224 : 128;
  531.  
  532.         SDL_SetRenderDrawColor(renderer, two, two, two, 255);
  533.  
  534.         for (int x = 0; x < width; x++) {
  535.             SDL_Rect line = {tileLength * (6 + x) - gridLineWidth / 2, 0, gridLineWidth, screenHeight};
  536.             SDL_RenderFillRect(renderer, &line);
  537.         }
  538.  
  539.         for (int y = 1; y < height - 2; y++) {
  540.             SDL_Rect line = {tileLength * 6, tileLength * y - gridLineWidth / 2, screenWidth - (tileLength * 6), gridLineWidth};
  541.             SDL_RenderFillRect(renderer, &line);
  542.         }
  543.     }
  544.  
  545.     if (state != PLAYING) {
  546.         if (state == ENDED) {
  547.             SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255);
  548.             SDL_Rect pauseBox = {(int) (tileLength * 7.5), (int) (tileLength * 8.5), tileLength * 7, tileLength * 3};
  549.             SDL_RenderFillRect(renderer, &pauseBox);
  550.         } else {
  551.             SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
  552.             SDL_RenderClear(renderer);
  553.         }
  554.  
  555.         menuT.change(state == ENDED ? "Game Over" : "Paused");
  556.         menuT.paint(tileLength * 11, (int) (tileLength * 9.5));
  557.     }
  558.  
  559.     SDL_Rect bar = {0, 0, tileLength * 6, tileLength * 20};
  560.     SDL_SetRenderDrawColor(renderer, 0, 0, 0, 255);
  561.     SDL_RenderFillRect(renderer, &bar);
  562.  
  563.     bar = {tileLength * 16, 0, tileLength * 6, tileLength * 20};
  564.     SDL_RenderFillRect(renderer, &bar);
  565.  
  566.     scoreT.paint(tileLength * 3, tileLength / 2);
  567.     scoreNumT.paint(tileLength * 3, tileLength * 2);
  568.  
  569.     linesT.paint(tileLength * 3, (int) (tileLength * 3.5));
  570.     linesNumT.paint(tileLength * 3, tileLength * 5);
  571.  
  572.     levelT.paint(tileLength * 3, (int) (tileLength * 6.5));
  573.     levelNumT.paint(tileLength * 3, tileLength * 8);
  574.  
  575.     nextT.paint(tileLength * 19, tileLength / 2);
  576.  
  577.     SDL_Rect next = {(int) (tileLength * 16.5), (int) (tileLength * 2.5), tileLength * 5, tileLength * (3 * nextShapes)};
  578.     SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255);
  579.     SDL_RenderFillRect(renderer, &next);
  580.  
  581.     int nextShapeIndex = shapeIndexes.size();
  582.  
  583.     for (unsigned x = 0; x < shapeIndexes.size(); x++) {
  584.         if (shapeIndexes[x] != -1) {
  585.             nextShapeIndex = x;
  586.             break;
  587.         }
  588.     }
  589.  
  590.     for (int n = 0; n < nextShapes; n++) {
  591.         int nextShape;
  592.         gridArray shape(tiles, std::vector<Tile>(tiles));
  593.         if (nextShapeIndex + n >= (int) shapeIndexes.size()) {
  594.             nextShape = nextShapeIndexes[nextShapeIndex + n - shapeIndexes.size()];
  595.         } else {
  596.             nextShape = shapeIndexes[nextShapeIndex + n];
  597.         }
  598.  
  599.         shape = Shape::shapes[nextShape];
  600.  
  601.         float dx = (nextShape == 0 || nextShape == 3 ? 17 : 17.5F);
  602.         float dy = (nextShape == 3 ? 1 : (nextShape == 0 ? 0.5F : 0));
  603.  
  604.         for (int y = 0; y < tiles; y++) {
  605.             for (int x = 0; x < tiles; x++) {
  606.                 if (!shape[y][x].exists) continue;
  607.                 SDL_Rect tile = {(int) (tileLength * (x + dx)), (int) (tileLength * (3 + y + (n * 3) - dy)), tileLength, tileLength};
  608.  
  609.                 SDL_SetRenderDrawColor(renderer, shape[y][x].r, shape[y][x].g, shape[y][x].b, 255);
  610.                 SDL_RenderFillRect(renderer, &tile);
  611.             }
  612.         }
  613.     }
  614.  
  615.     holdT.paint(tileLength * 3, tileLength * 11);
  616.  
  617.     SDL_Rect hold = {tileLength / 2, (int) (tileLength * 12.5), tileLength * 5, tileLength * 5};
  618.     SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255);
  619.  
  620.     SDL_RenderFillRect(renderer, &hold);
  621.  
  622.     if (heldIndex >= 0) {
  623.         gridArray shape(tiles, std::vector<Tile>(tiles));
  624.         shape = Shape::shapes[heldIndex];
  625.  
  626.         float dx = (heldIndex == 0 || heldIndex == 3 ? 1 : 1.5F);
  627.         float dy = (heldIndex == 3 ? 1 : (heldIndex == 0 ? 0.5F : 0));
  628.         for (int y = 0; y < tiles; y++) {
  629.             for (int x = 0; x < tiles; x++) {
  630.                 if (!shape[y][x].exists) continue;
  631.                 SDL_Rect tile = {(int) (tileLength * (x + dx)), (int) (tileLength * (14 + y - dy)), tileLength, tileLength};
  632.  
  633.                 SDL_SetRenderDrawColor(renderer, shape[y][x].r, shape[y][x].g, shape[y][x].b, 255);
  634.                 SDL_RenderFillRect(renderer, &tile);
  635.             }
  636.         }
  637.     }
  638. }
  639.  
  640. void paintMenu(float deltaTime) {
  641.     SDL_SetRenderDrawColor(renderer, 64, 64, 64, 255);
  642.     SDL_RenderClear(renderer);
  643.  
  644.     title.paint(screenWidth * 5 / 8, tileLength);
  645.  
  646.     for (int y = 0; y < 5; y++) {
  647.         if (y == selectedMenuIndex) {
  648.             float oldSize = mainSubs[y].size;
  649.             mainSubs[y].size = std::min(1.75F, mainSubs[y].size + deltaTime * 6);
  650.  
  651.             if (menuFocus) {
  652.                 SDL_Color selected = {255, selectedMenuIndex == 4 ? 192 : 255, 192};
  653.                 mainSubs[y].text.change(mainSubs[y].text.text, (int) (tileLength * mainSubs[y].size), selected);
  654.             } else {
  655.                 mainSubs[y].text.change(mainSubs[y].text.text, (int) (tileLength * mainSubs[y].size));
  656.             }
  657.  
  658.             if (mainSubs[y].y > 0) {
  659.                 mainSubs[y].y = std::max(0.0F, mainSubs[y].y - deltaTime * 18);
  660.             } else if (mainSubs[y].y < 0) {
  661.                 mainSubs[y].y = std::min(0.0F, mainSubs[y].y + deltaTime * 18);
  662.             }
  663.         } else {
  664.             float oldSize = mainSubs[y].size;
  665.             mainSubs[y].size = std::max(1.0F, mainSubs[y].size - deltaTime * 6);
  666.  
  667.             if (oldSize != mainSubs[y].size)
  668.                 mainSubs[y].text.change(mainSubs[y].text.text, (int) (tileLength * mainSubs[y].size));
  669.  
  670.             float targetY = 2.0F * (y - selectedMenuIndex);
  671.             if (y > selectedMenuIndex) targetY++;
  672.  
  673.             if (mainSubs[y].y > targetY) {
  674.                 mainSubs[y].y = std::max(targetY, mainSubs[y].y - deltaTime * 18);
  675.             } else if (mainSubs[y].y < targetY) {
  676.                 mainSubs[y].y = std::min(targetY, mainSubs[y].y + deltaTime * 18);
  677.             }
  678.         }
  679.  
  680.         mainSubs[y].text.paint(tileLength * 4, (int) (tileLength * (10.5 + mainSubs[y].y)));
  681.     }
  682.  
  683.     if (selectedMenuIndex != 0 && selectedMenuIndex != 4) {
  684.         SDL_Rect box = {(int) (tileLength * 7.5), (int) (tileLength * (5.75 + 1.25 * (float) selectedSubmenuIndex)), tileLength * 13, (int) (tileLength * 1.25)};
  685.         if (menuFocus) {
  686.             SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
  687.         } else {
  688.             SDL_SetRenderDrawColor(renderer, 128, 0, 255, 255);
  689.         }
  690.         SDL_RenderFillRect(renderer, &box);
  691.     }
  692.  
  693.     switch (selectedMenuIndex) {
  694.     case 0: // PLAY
  695.         for (int n = 0; n < 10; n++) {
  696.             SDL_Rect box = {(int) (tileLength * 7.25 + tileLength * 3 * (n < 5 ? n : n - 5)), (int) (tileLength * 9.75 + (n < 5 ? 0 : tileLength * 3)), (int) (tileLength * 2.25), (int) (tileLength * 2.25)};
  697.             if (playX + playY * 5 == n && !menuFocus)
  698.                 SDL_SetRenderDrawColor(renderer, 128, 0, 255, 255);
  699.             else
  700.                 SDL_SetRenderDrawColor(renderer, 128, 128, 128, 255);
  701.             SDL_RenderFillRect(renderer, &box);
  702.  
  703.             playOptions[n].paint((int) (tileLength * 8.25 + tileLength * 3 * (n < 5 ? n : n - 5)), tileLength * 10 + (n < 5 ? 0 : tileLength * 3));
  704.         }
  705.         break;
  706.     case 1: // CUSTOM
  707.         for (int n = 0; n < 11; n++) {
  708.             custom[n].text.paint(tileLength * 8, (int) (tileLength * (6 + 1.25 * (float) n)), LEFT);
  709.             switch (custom[n].type) {
  710.             case BOOLEAN:
  711.                 if (custom[n].currentOption == 0) {
  712.                     custom[n].valueText.change("Disabled", (int) (tileLength * .6));
  713.                 } else {
  714.                     custom[n].valueText.change("Enabled", (int) (tileLength * .6));
  715.                 }
  716.                 break;
  717.             case INTEGER:
  718.                 custom[n].valueText.change(std::to_string(custom[n].currentOption), (int) (tileLength * .6));
  719.                 break;
  720.             case FLOAT:
  721.                 custom[n].valueText.change((custom[n].currentOption < 0 ? "1 / " : "") + (std::to_string((int) pow(2, abs(custom[n].currentOption)))), (int) (tileLength * .6));
  722.                 break;
  723.             case STRING:
  724.                 custom[n].valueText.change(custom[n].strings[custom[n].currentOption], (int) (tileLength * .6));
  725.                 break;
  726.             default:
  727.                 break;
  728.             }
  729.             if (n == currentEditingIndex) {
  730.                 SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
  731.                 SDL_Rect box = {(int) (tileLength * 19.9 - custom[n].valueText.getWidth()), (int) (tileLength * (5.9 + 1.25 * (float) n)), custom[n].valueText.getWidth() + (int) (tileLength * 0.3), (int) (tileLength * 0.95)};
  732.                 SDL_RenderFillRect(renderer, &box);
  733.             }
  734.             custom[n].valueText.paint(tileLength * 20, (int) (tileLength * (6 + 1.25 * (float) n)), RIGHT);
  735.         }
  736.         break;
  737.     case 2: // OPTIONS
  738.         for (int n = 0; n < 9; n++) {
  739.             options[n].text.paint(tileLength * 8, (int) (tileLength * (6 + 1.25 * (float) n)), LEFT);
  740.             switch (options[n].type) {
  741.             case BOOLEAN:
  742.                 if (options[n].currentOption == 0) {
  743.                     options[n].valueText.change("Disabled", (int) (tileLength * .6));
  744.                 } else {
  745.                     options[n].valueText.change("Enabled", (int) (tileLength * .6));
  746.                 }
  747.                 break;
  748.             case INTEGER:
  749.                 options[n].valueText.change(std::to_string(options[n].currentOption), (int) (tileLength * .6));
  750.                 break;
  751.             default:
  752.                 break;
  753.             }
  754.             if (n == currentEditingIndex) {
  755.                 SDL_SetRenderDrawColor(renderer, 255, 0, 0, 255);
  756.                 SDL_Rect box = {(int) (tileLength * 19.9 - options[n].valueText.getWidth()), (int) (tileLength * (5.9 + 1.25 * (float) n)), options[n].valueText.getWidth() + (int) (tileLength * 0.3), (int) (tileLength * 0.95)};
  757.                 SDL_RenderFillRect(renderer, &box);
  758.             }
  759.             options[n].valueText.paint(tileLength * 20, (int) (tileLength * (6 + 1.25 * (float) n)), RIGHT);
  760.         }
  761.         break;
  762.     case 3: // CONTROLS
  763.         for (int n = 0; n < 9; n++) {
  764.             controls[n].text.paint(tileLength * 8, (int) (tileLength * (6 + 1.25 * (float) n)), LEFT);
  765.             controls[n].keyText.change(n == currentEditingIndex ? "" : SDL_GetKeyName(controls[n].key), (int) (tileLength * .6));
  766.             controls[n].keyText.paint(tileLength * 20, (int) (tileLength * (6 + 1.25 * (float) n)), RIGHT);
  767.         }
  768.         break;
  769.     case 4: // EXIT
  770.         break;
  771.     default:
  772.         while (true) {
  773.             new int;
  774.         } // TODO: YES
  775.     }
  776. }
  777.  
  778. fallState fall() {
  779.     if (!currentShape->fall(grid, true)) {
  780.         isLocking = true;
  781.         return PLACED;
  782.     }
  783.     return FELL;
  784. }
  785.  
  786. void addShape() {
  787.     for (int x = 0; x < tiles; x++) {
  788.         for (int y = 0; y < tiles; y++) {
  789.             if (currentShape->data[y][x].exists) {
  790.                 grid[currentShape->y + y][currentShape->x + x] = currentShape->data[y][x];
  791.             }
  792.         }
  793.     }
  794.  
  795.     int yMin = 0, linesCleared = 0;
  796.     for (int y = height - 1; y >= yMin;) {
  797.         bool blank = false;
  798.  
  799.         for (int x = 0; x < width; x++) {
  800.             if (!grid[y][x].exists) {
  801.                 blank = true;
  802.                 break;
  803.             }
  804.         }
  805.  
  806.         if (!blank) {
  807.             linesCleared++;
  808.             lines++;
  809.  
  810.             linesNumT.change(std::to_string(lines));
  811.  
  812.             yMin++;
  813.  
  814.             for (int yy = y; yy >= 1; yy--) {
  815.                 for (int x = 0; x < width; x++) {
  816.                     grid[yy][x] = grid[yy - 1][x];
  817.                 }
  818.             }
  819.  
  820.             for (int x = 0; x < width; x++) {
  821.                 grid[0][x].exists = false;
  822.             }
  823.         } else {
  824.             y--;
  825.         }
  826.     }
  827.  
  828.     if (linesCleared > 0) {
  829.         score += (int) (lineClearPoints[linesCleared - 1] * level * (linesCleared == 4 && lastClearDifficult ? lineClearPoints[4] : 1) + lineClearPoints[5] * lineClearCombos * level);
  830.  
  831.         scoreNumT.change(std::to_string(score));
  832.  
  833.         lastClearDifficult = linesCleared == 4;
  834.         lineClearCombos++;
  835.         level = lines / 10 + startingLevel;
  836.         levelNumT.change(std::to_string(level));
  837.         linesNumT.change(std::to_string(lines));
  838.         normalSpeed = 0.3F * (float) pow(level, 1.5F) + 0.7F;
  839.         lockDelay = (float) (sqrt(level) + 2.0F) / 6.0F;
  840.         fastSpeed = std::max(fastSpeed, normalSpeed);
  841.     } else {
  842.         lineClearCombos = 0;
  843.     }
  844.  
  845.     newShape();
  846. }
  847.  
  848. void newShape() {
  849.     for (unsigned i = 0; i < shapeIndexes.size(); i++) {
  850.         if (shapeIndexes[i] == -1) continue;
  851.  
  852.         if (currentShape != NULL) {
  853.             delete[] currentShape; // This is where it breaks to in the error
  854.         }
  855.         currentShape = new Shape;
  856.  
  857.         currentShape->data = Shape::shapes[shapeIndexes[i]];
  858.         currentShapeIndex = shapeIndexes[i];
  859.  
  860.         shapeIndexes[i] = -1;
  861.  
  862.         for (int x = 0; x < tiles; x++) {
  863.             for (int y = 0; y < tiles; y++) {
  864.                 if (currentShape->data[y][x].exists) {
  865.                     if (grid[currentShape->y + y][currentShape->x + x].exists) {
  866.                         state = ENDED;
  867.                         return;
  868.                     }
  869.                 }
  870.             }
  871.         }
  872.         isFast = false;
  873.         canHold = true;
  874.  
  875.         return;
  876.     }
  877.  
  878.     shapeIndexes = nextShapeIndexes;
  879.  
  880.     for (int i = 0; i < 7; i++) nextShapeIndexes[i] = i;
  881.  
  882.     std::random_shuffle(nextShapeIndexes.begin(), nextShapeIndexes.end());
  883.  
  884.     newShape();
  885. }
  886.  
  887. bool init() {
  888.     if (SDL_INIT_VIDEO < 0) {
  889.         printf("Error: Failed to initiate SDL Video Subsystem. SDL_Error: %s\n", SDL_GetError());
  890.         return false;
  891.     }
  892.  
  893.     window = SDL_CreateWindow("Polyis", SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, screenWidth, screenHeight, NULL);
  894.     if (window == NULL) {
  895.         printf("Error: Failed to create window. SDL Error: %s\n", SDL_GetError());
  896.         return false;
  897.     }
  898.  
  899.     renderer = SDL_CreateRenderer(window, -1, SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
  900.     if (renderer == NULL) {
  901.         printf("Error: Failed to create renderer. SDL Error: %s\n", SDL_GetError());
  902.         return false;
  903.     }
  904.  
  905.     int imgFlags = IMG_INIT_PNG;
  906.     if (!(IMG_Init(imgFlags) & imgFlags)) {
  907.         printf("Error: Failed to initiate Image Subsystem. SDL_IMG Error: %s\n", IMG_GetError());
  908.         return false;
  909.     }
  910.  
  911.     if (TTF_Init() == -1) {
  912.         printf("Error: Failed to initiate TTF Subsystem. SDL_TTF Error: %s\n", TTF_GetError());
  913.         return false;
  914.     }
  915.  
  916.     Text::defaultSize = tileLength;
  917.     Text::renderer = renderer;
  918.  
  919.     SDL_Surface* icon = IMG_Load("icon.png");
  920.     if (icon == NULL) {
  921.         printf("Error: Failed to instatiate icon. Error: %s", IMG_GetError());
  922.     }
  923.     SDL_SetWindowIcon(window, icon);
  924.  
  925.     for (unsigned i = 0; i < Shape::shapes.size(); i++) {
  926.         nextShapeIndexes.push_back(i);
  927.     }
  928.  
  929.     std::random_shuffle(nextShapeIndexes.begin(), nextShapeIndexes.end());
  930.  
  931.     newShape();
  932.  
  933.     title.change("POLYIS", tileLength * 3, {0, 255, 0});
  934.     mainSubs[0].text.change("Play", tileLength * 2);
  935.     mainSubs[1].text.change("Custom");
  936.     mainSubs[2].text.change("Options");
  937.     mainSubs[3].text.change("Controls");
  938.     mainSubs[4].text.change("Exit");
  939.  
  940.     mainSubs[0].size = 2;
  941.     for (int i = 1; i < 5; i++) {
  942.         mainSubs[i].y = 2.0F * i + 1.0F;
  943.     }
  944.  
  945.     for (int i = 0; i < 10; i++) {
  946.         playOptions[i].change(std::to_string(i + 1), (int) (tileLength * 1.5));
  947.     }
  948.  
  949.     options[0].text.change("Master Volume", (int) (tileLength * .6));
  950.     options[1].text.change("Music Volume", (int) (tileLength * .6));
  951.     options[2].text.change("Sound FX Volume", (int) (tileLength * .6));
  952.     options[3].text.change("Game Resolution", (int) (tileLength * .6));
  953.     options[4].text.change("Ghost Piece", (int) (tileLength * .6));
  954.  
  955.     options[0].type = INTEGER;
  956.     options[1].type = INTEGER;
  957.     options[2].type = INTEGER;
  958.     options[3].type = INTEGER;
  959.     options[4].type = BOOLEAN;
  960.  
  961.     options[0].Imax = 100;
  962.     options[1].Imax = 100;
  963.     options[2].Imax = 100;
  964.     options[3].Imax = 40;
  965.  
  966.     options[0].currentOption = 100;
  967.     options[1].currentOption = 100;
  968.     options[2].currentOption = 100;
  969.     options[3].currentOption = 34;
  970.     options[4].currentOption = 1;
  971.  
  972.     custom[0].text.change("Tiles per Polyomino", (int) (tileLength * .6));
  973.     custom[1].text.change("Grid Width", (int) (tileLength * .6));
  974.     custom[2].text.change("Grid Height", (int) (tileLength * .6));
  975.     custom[3].text.change("Grid Shape", (int) (tileLength * .6));
  976.     custom[4].text.change("Gravity Multiplier", (int) (tileLength * .6));
  977.     custom[5].text.change("Gravity Direction", (int) (tileLength * .6));
  978.     custom[6].text.change("Flood Fill Gravity", (int) (tileLength * .6));
  979.     custom[7].text.change("Lives", (int) (tileLength * .6));
  980.     custom[8].text.change("Shape Visibility", (int) (tileLength * .6));
  981.     custom[9].text.change("Lock Delay Time", (int) (tileLength * .6));
  982.     custom[10].text.change("Lines per Level", (int) (tileLength * .6));
  983.  
  984.     custom[0].type = INTEGER;
  985.     custom[1].type = INTEGER;
  986.     custom[2].type = INTEGER;
  987.     custom[3].type = STRING;
  988.     custom[4].type = FLOAT;
  989.     custom[5].type = STRING;
  990.     custom[6].type = BOOLEAN;
  991.     custom[7].type = INTEGER;
  992.     custom[8].type = STRING;
  993.     custom[9].type = FLOAT;
  994.     custom[10].type = INTEGER;
  995.  
  996.     custom[0].Imin = 1;
  997.     custom[0].Imax = 15;
  998.     custom[1].Imin = 1;
  999.     custom[1].Imax = 255;
  1000.     custom[2].Imin = 1;
  1001.     custom[2].Imax = 255;
  1002.     custom[3].strings = {"Rectangle", "Circle", "Triangle", "Hexagon", "Arrow"};
  1003.     custom[4].Fmin = 0.125F;
  1004.     custom[4].Fmax = 16;
  1005.     custom[5].strings = {"Down", "Up", "Left", "Right"};
  1006.     custom[7].Imax = 15;
  1007.     custom[8].strings = {"Always", "On Ground Only", "Falling Only", "After Falling (Momentary)", "Never", "LSD Mode"};
  1008.     custom[9].Fmin = 0.125F;
  1009.     custom[9].Fmax = 16;
  1010.     custom[10].Imin = 2;
  1011.     custom[10].Imax = 255;
  1012.  
  1013.     custom[0].currentOption = 4;
  1014.     custom[1].currentOption = 10;
  1015.     custom[2].currentOption = 22;
  1016.     custom[10].currentOption = 10;
  1017.  
  1018.     controls[0].text.change("Move Left", (int) (tileLength * .6));
  1019.     controls[1].text.change("Move Right", (int) (tileLength * .6));
  1020.     controls[2].text.change("Soft Drop (Move down)", (int) (tileLength * .6));
  1021.     controls[3].text.change("Hard Drop", (int) (tileLength * .6));
  1022.     controls[4].text.change("Rotate Clockwise", (int) (tileLength * .6));
  1023.     controls[5].text.change("Rotate Counterclockwise", (int) (tileLength * .6));
  1024.     controls[6].text.change("Hold Shape", (int) (tileLength * .6));
  1025.     controls[7].text.change("Pause", (int) (tileLength * .6));
  1026.     controls[8].text.change("Debug Mode", (int) (tileLength * .6));
  1027.  
  1028.     controls[0].key = SDLK_LEFT;
  1029.     controls[1].key = SDLK_RIGHT;
  1030.     controls[2].key = SDLK_DOWN;
  1031.     controls[3].key = SDLK_SPACE;
  1032.     controls[4].key = SDLK_UP;
  1033.     controls[5].key = SDLK_z;
  1034.     controls[6].key = SDLK_c;
  1035.     controls[7].key = SDLK_p;
  1036.     controls[8].key = SDLK_F7;
  1037.  
  1038.     scoreT.change("Score");
  1039.     scoreNumT.change("0");
  1040.     linesT.change("Lines");
  1041.     linesNumT.change("0");
  1042.     levelT.change("Level");
  1043.     levelNumT.change("1");
  1044.     nextT.change("Next");
  1045.     holdT.change("Hold");
  1046.  
  1047.     return true;
  1048. }
  1049.  
  1050. void close() {
  1051.     SDL_DestroyWindow(window);
  1052.     SDL_DestroyRenderer(renderer);
  1053.  
  1054.     window = NULL;
  1055.     renderer = NULL;
  1056.  
  1057.     IMG_Quit();
  1058.     TTF_Quit();
  1059.     SDL_Quit();
  1060. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement