/*** * Screen - The actual point of this godforsaken project * * This file's goal is to "render" a slot machine that the soon-to-be unlucky victim must play to get their * files back. To do this, I am using curses and probably the menu library to create the TUI. Once I figure * out how to actually do this, everything should work hopefully maybe * * DEAR HACKER, PLEASE PLEASE DO NOT BOTHER LEARNING CURSES FOR A JOKE. IT WAS A BAD IDEA AND IF YOU'RE RESTARDED * LIKE ME SUNKEN COST WILL KICK IN AND IT WILL NAG AT YOU UNTIL IT'S DONE. DO NOT MAKE THE SAME MISTAKE I MADE. * RUN, RUN FOR THE SAKE OF ALL THAT'S HOLY AND OTHERWISE */ #define _GNU_SOURCE #include "screen.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #define TESTING //////////////////////////////////// SPECIFICALLY USEFUL FUNCS //////////////////////////////////// void catcher(int signum, siginfo_t *info, void *ucontext) { // This is retarded lol, but makes gcc happy info->si_code = info->si_code; ucontext = ucontext; switch(signum) { case SIGINT: endwin(); error(0, 0, "[VX-GAMBLEGROUND] Caught interrupt"); exit(0); case SIGWINCH: endwin(); error(1, 0, "[VX-GAMBLEGROUND] User changed window size and I haven't implemented code to handle it yet"); abort(); // Makes gcc happy (angry about implicit fallthrough) default: abort(); } return; } // Initialize sodium, curses, and set the proper locale. Exits on error, returns 0 otherwise int doinit(const struct sigaction *handler) { if(sodium_init() < 0) error(1, errno, "[VX-GAMBLEGROUND] Could not initialize sodium"); if(setlocale(LC_ALL, "") == NULL) // Clear out the locale so it doesn't default to ncurses' ISO-8859-1 setting error(1, errno, "[VX-GAMBLEGROUND] Could not set proper locale"); if(initscr() == NULL) // Initialize curses error(1, errno, "[VX-GAMBLEGROUND] Could not init standard screen"); if(sigaction(SIGINT, handler, NULL) < 0 || sigaction(SIGWINCH, handler, NULL) < 0) error(1, errno, "[VX-GAMBLEGROUND] Could not set up signal handlers"); cbreak(); // Disables character buffering noecho(); // Disable echoing characters curs_set(0); // Stop the cursor from blinking return 0; } // Initialize colors & define a few custom colors & color pairs. Exits on error, returns 0 otherwise int docolors(void) { // Idk what possessed me to put this entire thing in an if-statement instead of using an early return // Whatever, it's fixed now if(!has_colors() && !can_change_color()) { endwin(); error(1, ENOTSUP, "[VX-GAMBLEGROUND] Colors are not supported on your terminal"); } // Necessary for color start_color(); // Init everything init_rgb_color(CC_RED, 255, 0, 0); init_rgb_color(CC_ORANGE, 255, 128, 0); init_rgb_color(CC_YELLOW, 255, 255, 0); init_rgb_color(CC_GREEN, 0, 255, 0); init_rgb_color(CC_BLUE, 0, 0, 255); init_rgb_color(CC_PURPLE, 128, 0, 255); init_rgb_color(CC_MAGENTA, 255, 0, 255); init_rgb_color(CC_WHITE, 255, 255, 255); init_rgb_color(CC_BLACK, 0, 0, 0); init_rgb_color(CC_WINNING, 232, 185, 35); // Create pairs init_pair(CCP_TESTING, CC_RED, CC_WHITE); init_pair(CCP_BANNER, CC_WHITE, CURSES_BLUE); init_pair(CCP_RED, CC_WHITE, CC_RED); init_pair(CCP_ORANGE, CC_BLACK, CC_ORANGE); init_pair(CCP_YELLOW, CC_BLACK, CC_YELLOW); init_pair(CCP_GREEN, CC_BLACK, CC_GREEN); init_pair(CCP_BLUE, CC_WHITE, CC_BLUE); init_pair(CCP_PURPLE, CC_WHITE, CC_PURPLE); init_pair(CCP_MAGENTA, CC_WHITE, CC_MAGENTA); init_pair(CCP_WHITE, CC_BLACK, CC_WHITE); init_pair(CCP_WINNING1, CC_WHITE, CC_WINNING); init_pair(CCP_WINNING2, CC_WINNING, CC_WHITE); return 0; } // I will figure out how to properly pass a void pointer eventually (if I care enough) int init_items(ITEM *items[], const char *menuopts[], size_t menuopts_size, struct funcholder usrptrs[]) { for(size_t i = 0; i < menuopts_size; i++) { items[i] = new_item(menuopts[i], NULL); set_item_userptr(items[i], (void*)&usrptrs[i]); } items[menuopts_size] = NULL; return 0; } int init_slotholder(struct slotholder *slots) { mvwaddstr(slots->slotwin, 0, 1, "Spins: 3, Price: 1"); wnoutrefresh(slots->slotwin); getmaxyx(slots->slotwin, slots->sloty, slots->slotx); for(size_t i = 0; i < STATIC_ARRSIZE(slots->subslot); i++) { slots->subslot[i] = derwin(slots->slotwin, slots->sloty, slots->slotx/3, 0, slots->slotx/3 * i); int mx = 0, my = 0; getmaxyx(slots->subslot[i], my, mx); const int height = my - 2, width = mx - 2; mvwcreate_box(slots->subslot[i], 1, 1, height, width, NULL); for(int j = 0; j < 3; j++) { slots->slotchar[i][j] = randombytes_uniform('~' - '!' + 1) + '!'; mvwcreate_box(slots->subslot[i], 2 + (j * (height / 3)), (width / 4) - 1, height / 3, (width / 2) + 5 /*???????????*/, NULL); } wnoutrefresh(slots->subslot[i]); } // Not getting rid of the magic numbers. SUck it return 0; } int init_custom_menu_format(WINDOW *menuholder, MENU *menu, const int fmtdim[2], Menu_Options toggleon, Menu_Options toggleoff) { // Set menu options & format set_menu_format(menu, fmtdim[0], fmtdim[1]); menu_opts_on(menu, toggleon); menu_opts_off(menu, toggleoff); int holder1 = -1, holder2 = -1; getmaxyx(menuholder, holder1, holder2); if(holder1 < 0 || holder2 < 0) { endwin(); error(1, errno, "[VX-GAMBLEGROUND] Could not get bounds for menu subwindow"); } set_menu_win(menu, menuholder); set_menu_sub(menu, derwin(menuholder, holder1, holder2, 0, 0)); set_menu_mark(menu, NULL); post_menu(menu); wbkgd(menuholder, COLOR_PAIR(CCP_BANNER)); set_menu_back(menu, COLOR_PAIR(CCP_BANNER)); wnoutrefresh(menuholder); return 0; } WINDOW* create_banner(int col, int randomnum, const char *passphrase) { // Create the banner window WINDOW *phrase = newwin(1, col, 0, 0); if(phrase == NULL) { endwin(); error(1, errno, "[VX-GAMBLEGROUND] Could not create banner window"); } wbkgd(phrase, COLOR_PAIR(CCP_BANNER)); mvwaddstr(phrase, 0, 1, "VX-GAMBLEGROUND: "); waddstr(phrase, phrases[randomnum]); char *pass = NULL; if(asprintf(&pass, "Passphrase=%s", passphrase) < 0) error(1, errno, "[VX-GAMBLEGROUND] asprintf broke"); mvwaddnstr(phrase, 0, col - strlen(pass) - 2, pass, strlen(pass)); free(pass); wnoutrefresh(phrase); return phrase; } int handle_menuitem(MENU *menu, struct params *params) { struct funcholder *p = (struct funcholder *)item_userptr(current_item(menu)); switch(p->type) { case FH_SPIN: case FH_BUY: p->callback((void*)params); break; case FH_QUIT: p->callback(NULL); break; default: endwin(); error(1, ENOTSUP, "SHIT BROKE"); } return 0; } int handle_input(WINDOW *menuholder, MENU *menu, struct params *params) { int c; // Get user input and deal with the menu while((c = wgetch(menuholder)) != KEY_F(4)) { switch(c) { case KEY_DOWN: menu_driver(menu, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(menu, REQ_UP_ITEM); break; case KEY_LEFT: menu_driver(menu, REQ_LEFT_ITEM); break; case KEY_RIGHT: menu_driver(menu, REQ_RIGHT_ITEM); break; case KEY_ENTER: case FUCKED_UP_ENTER: // Enter handle_menuitem(menu, params); break; default: break; } } return 0; } // Spin the wheel int spin(void *params) { struct params *p = (struct params *)params; // Replace this with a proper game-over anim p->numspins -= 1; if(p->numspins < 0) { endwin(); error(1, 0, "[VX-GAMBLEGROUND] You ran out of spins! Game Over!"); } char *newstr = NULL; if(asprintf(&newstr, "Spins: %d, Price: %d", p->numspins, p->price) < 0) { endwin(); error(1, errno, "[VX-GAMBLEGROUND] asprintf broke"); } mvwaddstr(p->slots->slotwin, 0, 1, newstr); free(newstr); static const struct timespec sleeper = { .tv_sec = 0, .tv_nsec = 1000000000 /* Nanoseconds in 1 second */ / NUMCOLORPAIRS }; for(int color = CCP_RED, i = 0; i < (NUMCOLORPAIRS * NUMCOLORCYCLE); color = rangemod(color, 1, CCP_RED, CCP_WHITE), i++) { // Change the color to testing for the banner wbkgd(p->bannerwin, COLOR_PAIR(color)); wnoutrefresh(p->bannerwin); // Change the color to testing for the menu wbkgd(p->menuholder, COLOR_PAIR(color)); set_menu_back(p->menu, COLOR_PAIR(color)); wnoutrefresh(p->menuholder); for(size_t subs = 0; subs < STATIC_ARRSIZE(p->slots->subslot); subs++) { /* Previous solution fucked it by changing the actual color when it's supposed to be the default color to revert back to // This works better, but is also more ugly. So be it */ wbkgd(p->slots->subslot[subs], COLOR_PAIR(rangemod(CCP_CURSES_DEFAULT, i + CCP_RED, CCP_RED, CCP_WHITE))); #ifndef TESTING p->slots->slotchar[subs][2] = p->slots->slotchar[subs][1]; p->slots->slotchar[subs][1] = p->slots->slotchar[subs][0]; p->slots->slotchar[subs][0] = randombytes_uniform('~' - '!' + 1) + '!'; #endif #ifdef TESTING p->slots->slotchar[subs][1] = '7'; #endif // Update characters & draw them int my, mx; getmaxyx(p->slots->subslot[subs], my, mx); for(int j = 0; j < 3; j++) { mvwaddch(p->slots->subslot[subs], 2 + ((my - 2) / 6) + (((my - 2) / 3) * j), (mx - 1) / 2, p->slots->slotchar[subs][j]); } wnoutrefresh(p->slots->subslot[subs]); } doupdate(); nanosleep(&sleeper, NULL); } // Check to see if user has won a jackpot int winning = 0; for(size_t i = 0; i < STATIC_ARRSIZE(p->slots->subslot); i++) { if(p->slots->slotchar[i][1] == '7') winning++; } if(winning == 3) { // Do multithreading here thrd_t decryptor; if(thrd_create(&decryptor, p->decrypt_callback, p->decrypt_args) != thrd_success) { endwin(); error(1, 0, "Couldn't spawn thread to decrypt files"); } mvaddch(0, 0, 'J'); for(int i = 0, color = CCP_WINNING1;; i++, color = rangemod(color, 1, CCP_WINNING1, CCP_WINNING2)) { bkgd(COLOR_PAIR(color)); addch("JACKPOT"[rangemod(i, 1, 0, 6)]); refresh(); nanosleep(&sleeper, NULL); } thrd_join(decryptor, NULL); } // Revert colors back to normal wbkgd(p->bannerwin, COLOR_PAIR(CCP_BANNER)); wnoutrefresh(p->bannerwin); wbkgd(p->menuholder, COLOR_PAIR(CCP_BANNER)); set_menu_back(p->menu, COLOR_PAIR(CCP_BANNER)); wnoutrefresh(p->menuholder); for(size_t i = 0; i < STATIC_ARRSIZE(p->slots->subslot); i++) { wbkgd(p->slots->subslot[i], COLOR_PAIR(CCP_CURSES_DEFAULT)); wnoutrefresh(p->slots->subslot[i]); } doupdate(); return 0; } // Increase number of spins int buy(void *params) { struct params *p = (struct params *)params; if(p->numspins >= 100) return 0; p->numspins += 3; if(p->price <= 2000000) p->price *= 2; char *newstring = NULL; if(asprintf(&newstring, "Spins: %d, Price: %d", p->numspins, p->price) < 0) { endwin(); error(1, errno, "[VX-GAMBLEGROUND] Could not allocate space for spin/price string"); } mvwaddstr(p->slots->slotwin, 0, 1, newstring); free(newstring); wnoutrefresh(p->slots->slotwin); doupdate(); return 0; } // Quit out int quit(void *params) { params = params; // Once agian, useless but makes gcc happy endwin(); error(0, 0, "quit"); exit(0); return 0; } //////////////////////////////////// GENERALLY USEFUL FUNCTIONS //////////////////////////////////// float normalize(float value, float oldmin, float oldmax, float newmin, float newmax) { // x(normal) = (b - a) * ((x - x(min)) / (max x - min x)) + a, where [a, b] is the new range return (newmax - newmin) * ((value - oldmin) / (oldmax - oldmin)) + newmin; } int rangemod(int x, int offset, int min, int max) { return ((x - min + offset) % (max - min + 1)) + min; } int init_rgb_color(int colornum, int red, int green, int blue) { int nred = normalize(red, RGB_MIN, RGB_MAX, CURSESCOLOR_MIN, CURSESCOLOR_MAX); int ngreen = normalize(green, RGB_MIN, RGB_MAX, CURSESCOLOR_MIN, CURSESCOLOR_MAX); int nblue = normalize(blue, RGB_MIN, RGB_MAX, CURSESCOLOR_MIN, CURSESCOLOR_MAX); return init_color(colornum, nred, ngreen, nblue); } int mvwcreate_box(WINDOW *win, int y, int x, int height, int width, const chtype chars[6]) { const chtype * realchars = chars; if(chars == NULL) realchars = (const chtype []){ACS_VLINE, ACS_HLINE, ACS_ULCORNER, ACS_URCORNER, ACS_LLCORNER, ACS_LRCORNER}; // Vertical lines mvwvline(win, y, x, realchars[0], height); mvwvline(win, y, x + width - 1, realchars[0], height); // Horizontal lines mvwhline(win, y, x, realchars[1], width - 1); mvwhline(win, y + height - 1, x, realchars[1], width) - 1; // Corners mvwaddch(win, y, x, realchars[2]); // Upper left corner mvwaddch(win, y, x + width - 1, realchars[3]); // Upper right corner mvwaddch(win, y + height - 1, x, realchars[4]); // Lower left corner mvwaddch(win, y + height - 1, x + width - 1, realchars[5]); // Lower right corner // Yeah I'm not happy about the magic numbers either, but this combo of shit makes the box draw correctly return 0; } //////////////////////////////////// MAIN //////////////////////////////////// // Use this as an example for implementing screen's functions in another file // int main() { // // I have no fucking clue why gcc complains that this isn't properly bracketed. Maybe im rarted // const struct sigaction handler = { // .sa_flags = SA_SIGINFO, // .sa_mask = SIGINT | SIGWINCH, // .sa_sigaction = catcher, // }; // doinit(&handler); // docolors(); // // Variable definitions // ITEM *items[STATIC_ARRSIZE(menu_choices) + 1]; // An array of ITEM pointers large enough to store all the menu items // struct params params; // Function pointer used for callbacks in the menu driver // WINDOW *menuholder = NULL; // The window for displaying the menu // int row = -1, col = -1; // The rows and columns of the main screen // uint32_t randomnum; // A random number for getting the banner phrase // MENU *menu; // The actual menu object // struct slotholder slots; // getmaxyx(stdscr, row, col); // randomnum = randombytes_uniform(STATIC_ARRSIZE(phrases) + 1); // WINDOW *banner = create_banner(col, randomnum); // init_items(items, menu_choices, STATIC_ARRSIZE(menu_choices), userfuncs); // // No point in moving this into a function // menu = new_menu(items); // if(menu == NULL) { // endwin(); // error(1, errno, "Could not create menu"); // } // // Set up the menuholder & init everything // menuholder = newwin(1, col, row - 1, 0); // keypad(menuholder, TRUE); // init_custom_menu_format(menuholder, menu, (int []){1, col}, O_ONEVALUE | O_IGNORECASE, O_SHOWDESC | O_NONCYCLIC); // slots.slotwin = newwin(row - 2, col, 1, 0); // if(slots.slotwin == NULL) { // endwin(); // error(1, errno, "[VX-GAMBLEGROUND] Could not create slots window"); // } // init_slotholder(&slots); // doupdate(); // params.bannerwin = banner; // params.menu = menu; // params.menuholder = menuholder; // params.numspins = 3; // params.price = 1; // params.slots = &slots; // handle_input(menuholder, menu, ¶ms); // // Clean up the menu // unpost_menu(menu); // free_menu(menu); // for(long unsigned int i = 0; i < STATIC_ARRSIZE(menu_choices); i++) // free_item(items[i]); // //*/ // endwin(); // Clean up curses // return 0; // }