/** * ASCII explosion from squeamish ossifrage at: * https://codegolf.stackexchange.com/questions/24462/display-the-explosion-of-a-star-in-ascii-art/24554#24554 */ #include "colors.h" #include "list.h" #include "globe.h" #include #include #include #include #include #include #include #include #define NUM_FRAMES 100 #define NUM_BLOBS 800 #define PERSPECTIVE 50.0 #define ESCDELAY 10 typedef struct { double x,y,z; } spaceblob; double prng() { static long long s=1; s = s * 1488248101 + 981577151; return ((s % 65536) - 32768) / 32768.0; } static void sighandler(int sig) { (void)sig; curs_set(1); endwin(); exit(EXIT_FAILURE); } int color_ramp1[] = {1,1,1,2,2,2,3,3,3,1,1, -1}; int bold_ramp1[] = {1,1,0,1,0,0,1,0,0,0,0, -1}; int color_ramp2[] = {1,1,1,1,2,2,2,2,2,3,3,3,3,3,1,1,1,1,1,1, -1}; int bold_ramp2[] = {1,1,0,0,1,1,0,0,0,1,1,0,0,0,0,0,0,0,0,0, -1}; void draw_frame(int i, int midx, int midy, spaceblob* blobs) { int rows,cols; getmaxyx(stdscr,rows,cols); int maxx,minx,maxy,miny; minx = -midx; maxx = cols+minx-1; miny = -midy; maxy = rows+miny-1; chtype line[cols+1]; for (int y=miny; y<=maxy; y++) { int row = y+midy; for (int x=minx; x<=maxx; x++) { int col = x+midx; /* Show expanding star in next 7 frames */ if (i<8) { double r = sqrt(x*x + 4*y*y); if (r < i*2) mvaddch(row,col,'@'); continue; } /* Otherwise show blast wave */ double r = sqrt(x*x + 4*y*y) * (0.5 + (prng()/3.0)*cos(16.*atan2(y*2.+0.01,x+0.01))*.3); int v = i - r - 7; if (v<0) { if (i<19) { int attr = 0;//color_ramp1[i-8]; line[col] = "%@W#H=+~-:."[i-8] | attr; } else { line[col] = ' '; } } else if (v<20) { int attr = 0;//color_ramp2[v]; line[col] = " .:!HIOMW#%$&@08O=+-"[v] | attr; } else { line[col] = ' '; } } if (i >= 8) { line[cols+1] = '\0'; mvaddchstr(row,0,line); } } /* Add blobs with perspective effect */ if (i>6) { int i0 = i-6; for (int j=0; jPERSPECTIVE) continue; int x = midx + bx * PERSPECTIVE / (bz+PERSPECTIVE); int y = midy + by * PERSPECTIVE / (bz+PERSPECTIVE); if (x>=0 && x=0 && y40) ? '.' : (bz>-20) ? 'o' : '@'); } } } } int unlink_cb(const char *fpath, const struct stat *sb, int typeflag, struct FTW *ftwbuf) { int rv = remove(fpath); if (rv) perror(fpath); return rv; } int rmrf(char *path) { return nftw(path, unlink_cb, 64, FTW_DEPTH | FTW_PHYS); } int main(int argc, char *argv[]) { if (argc > 1 && strcmp(argv[1], "--help") == 0) { printf("nuke: Nuke files from orbit.\nUsage: nuke [files...]\n"); return EXIT_SUCCESS; } char *failure_message = "Did not delete."; int rows,cols; int delay=1E5; spaceblob *blobs; int capacity = 32, num_files= 0; char **files = malloc(sizeof(char*)*capacity); for (int i = 1; i < argc; i++) { add_files(argv[i], &files, &num_files, &capacity); } /* Initialize ncurses and get window dimensions */ //initscr(); char* term_type = getenv("TERM"); if (term_type == NULL || *term_type == '\0') { term_type = "unknown"; } FILE* term_in = fopen("/dev/tty", "r"); if (term_in == NULL) { perror("fopen(/dev/tty)"); exit(EXIT_FAILURE); } SCREEN* main_screen = newterm(term_type, stdout, term_in); set_term(main_screen); signal(SIGINT, sighandler); start_color(); init_pair(WHITE, COLOR_WHITE, COLOR_BLACK); init_pair(YELLOW, COLOR_YELLOW, COLOR_BLACK); init_pair(RED, COLOR_RED, COLOR_BLACK); init_pair(BLUE, COLOR_BLUE, COLOR_BLACK); init_pair(GREEN, COLOR_GREEN, COLOR_BLACK); init_pair(BLACK, COLOR_BLACK, COLOR_BLACK); for (int i = 0; color_ramp1[i] >= 0; i++) color_ramp1[i] = COLOR_PAIR(color_ramp1[i]) | (bold_ramp1[i] ? A_BOLD : 0); for (int i = 0; color_ramp2[i] >= 0; i++) color_ramp2[i] = COLOR_PAIR(color_ramp2[i]) | (bold_ramp2[i] ? A_BOLD : 0); const int BLACK_ON_RED = 7, BLACK_ON_GREEN = 8; init_pair(BLACK_ON_RED, COLOR_BLACK, COLOR_RED); init_pair(BLACK_ON_GREEN, COLOR_BLACK, COLOR_GREEN); getmaxyx(stdscr,rows,cols); /* Generate random blob coordinates */ blobs = (spaceblob*)malloc(NUM_BLOBS * sizeof(spaceblob)); for (int i=0; i max_line) max_line = len; } erase(); int padwidth = max_line < cols*3/4 ? max_line : cols*3/4; int padheight = num_files < rows*3/4 ? num_files : rows*3/4; int padframer = rows/2-padheight/2-1; int padframec = cols/2-padwidth/2-1; WINDOW *padframe = newwin(padheight+2, padwidth+2, padframer, padframec); if (!padframe) { failure_message = "Couldn't create pad frame"; goto exit_failure; } wattron(padframe, COLOR_PAIR(YELLOW) | A_BOLD); box(padframe, 0, 0); WINDOW *pad = newpad(padheight, max_line); if (!pad) { failure_message = "Couldn't create pad"; goto exit_failure; } /* Display confirmation */ attron(COLOR_PAIR(BLACK_ON_RED)); char description[] = " TARGET: "; if (num_files > 1) { description[13] = 'S', description[14] = ':'; } mvprintw(padframer-2, cols/2 - strlen(description)/2, "%s", description); attron(COLOR_PAIR(BLACK_ON_RED) | A_BLINK); const char confirm[] = " FIRE NUKE? y/n "; mvprintw(padframer+padheight+3, cols/2 - strlen(confirm)/2, "%s", confirm); attroff(COLOR_PAIR(BLACK_ON_RED) | A_BLINK); refresh(); //immedok(pad, 1); int scrollx = 0, scrolly = 0; timeout(10); while (1) { // Draw scroll bar if (padheight < num_files) { mvaddch(padframer, padframec+padwidth+2, ACS_UARROW); mvaddch(padframer+padheight+1, padframec+padwidth+2, ACS_DARROW); for (int i = 1; i <= padheight; i++) mvaddch(padframer+i, padframec+padwidth+2, ACS_VLINE); for (int i = scrolly*padheight/num_files; i <= scrolly*padheight/num_files+padheight*padheight/num_files; i++) mvaddch(padframer+1+i, padframec+padwidth+2, ACS_CKBOARD); } box(padframe, 0, 0); if (wrefresh(padframe) == ERR) goto exit_failure; // Redo this each time so that pad doesn't have to hold everything in memory werase(pad); for (int f = scrolly; f < scrolly+padheight; f++) { mvwprintw(pad,f-scrolly,0,"%s",files[f]); } if (prefresh(pad, 0, scrollx, padframer+1, padframec+1, padframer+padheight, padframec+padwidth) == ERR) goto exit_failure; //prefresh(pad, scrolly, scrollx, 1, 1, 1+padheight, 1+padwidth); //prefresh(pad, scrolly, scrollx, rows/2-padheight/2, cols/2-padwidth/2, rows/2+padheight/2, cols/2+padwidth/2); refresh(); get_input: switch(getch()) { case 'y': goto do_the_nuking; case 'n': case 'q': case 27: goto exit_failure; case KEY_DOWN: case 'j': case ' ': scrolly++; break; case KEY_UP: case 'k': scrolly--; break; case KEY_RIGHT: case 'l': scrollx++; break; case KEY_LEFT: case 'h': scrollx--; break; case 'J': case KEY_NPAGE: scrolly += num_files/20+1; break; case 'K': case KEY_PPAGE: scrolly -= num_files/20+1; break; case KEY_SRIGHT: case 'L': scrollx += 10; break; case KEY_SLEFT: case 'H': scrollx -= 10; break; case KEY_HOME: case 'g': scrolly = 0; break; case KEY_END: case 'G': scrolly = num_files-padheight; break; default: goto get_input; } if (scrolly < 0) scrolly = 0; if (scrolly > num_files-padheight) scrolly = num_files-padheight; if (scrollx < 0) scrollx = 0; if (scrollx > max_line-padwidth) scrollx = max_line-padwidth; } do_the_nuking: ; double zoom = .8; // percent of viewport globe will fill const double targeting_time = 2.5; const double anticipation = 0.5; const double firing_time = 1.0; const double nuking_time = .5; const double aftermath = 100.0; int f = 0; int targetr, targetc; double t = 0.0; for (; t < targeting_time + anticipation + firing_time; t += 1./30.) { erase(); draw_stars(t); draw_globe(t, zoom); if (get_target_pos(t, zoom, &targetr, &targetc)) { // If visible draw '*' on globe attron(COLOR_PAIR(YELLOW)); mvaddch(targetr,targetc, '*' | A_BOLD); attroff(COLOR_PAIR(YELLOW)); } draw_clouds(t, zoom); // Draw crosshair double wobble = t > targeting_time ? 0. : targeting_time - t; int r = targetr, c = targetc; if (wobble > .01) { r = mix(r, rows*hillnoise(784,5.*t), wobble); c = mix(c, cols*hillnoise(-784,5.*t), wobble); } int attr = COLOR_PAIR(RED); attron(attr); mvaddch(r-1,c-2,ACS_ULCORNER | A_BOLD); mvaddch(r-1,c-1,ACS_HLINE | A_BOLD); mvaddch(r-1,c+1,ACS_HLINE | A_BOLD); mvaddch(r-1,c+2,ACS_URCORNER | A_BOLD); mvaddch(r+1,c+2,ACS_LRCORNER | A_BOLD); mvaddch(r+1,c+1,ACS_HLINE | A_BOLD); mvaddch(r+1,c-1,ACS_HLINE | A_BOLD); mvaddch(r+1,c-2,ACS_LLCORNER | A_BOLD); mvaddch(r,c,'X' | A_BOLD); attroff(attr); // Draw label if (get_target_pos(t, zoom, &targetr, &targetc)) { attron(COLOR_PAIR(RED)); mvaddch(targetr-1,targetc+1,'/'); attroff(COLOR_PAIR(RED)); attron(COLOR_PAIR(BLACK_ON_RED)); mvprintw(targetr-2,targetc+2,"%s", argc > 1 ? argv[f+1] : "target"); attroff(COLOR_PAIR(BLACK_ON_RED)); if (argc > 2) f = (f + 1) % (argc - 1); } // Draw nuke if (t > targeting_time + anticipation) { double k = (t-targeting_time-anticipation)/firing_time; int nuker = mix(rows, targetr, k), nukec = mix(cols/2, targetc, k); attron(COLOR_PAIR(WHITE) | A_BOLD); mvaddch(nuker, nukec, "=-. "[(int)(k*4.)]); attroff(COLOR_PAIR(WHITE) | A_BOLD); } refresh(); // Check for input int ch = getch(); if (ch == 'q' || ch == 27) { if (t <= targeting_time + anticipation) { goto exit_failure; } else { goto exit_success; } } usleep(33333); // 30 FPS } t += nuking_time; for (int i=1; i= 0; i--) { double rad = 4./31.*i; double a = i*2*M_PI*GOLDEN_RATIO; int r = targetr+(int)(rad*sin(a)/2), c = targetc+(int)(rad*cos(a)); if ((r-rows/2)*(r-rows/2) + (c/2-cols/4)*(c/2-cols/4) <= (zoom*rows/2)*(zoom*rows/2)) mvaddch(r, c, " #*."[i*4/31]); } attroff(COLOR_PAIR(BLACK) | A_BOLD); /* for (double =target_lat mvprintw(targetr-1,targetc-1,"****"); mvprintw(targetr,targetc-2, "** **"); mvprintw(targetr+1,targetc-1,"****"); */ } draw_clouds(t, zoom); if (get_target_pos(t, zoom, &targetr, &targetc)) { // Draw label attron(COLOR_PAIR(GREEN)); mvaddch(targetr-1,targetc+1,'/'); attroff(COLOR_PAIR(GREEN)); attron(COLOR_PAIR(BLACK_ON_GREEN)); mvprintw(targetr-2,targetc+2," DELETED "); attroff(COLOR_PAIR(BLACK_ON_GREEN)); } attron(COLOR_PAIR(BLACK_ON_GREEN)); const char *any_key = " PRESS ANY KEY TO EXIT "; mvprintw(rows-2, cols/2-strlen(any_key)/2, any_key); attroff(COLOR_PAIR(BLACK_ON_GREEN)); refresh(); if (getch() != -1) goto exit_success; usleep(33333); // 30 FPS } exit_success: curs_set(1); /* unhide cursor */ endwin(); /* Exit ncurses */ for (int i = 1; i < argc; i++) { if (rmrf(argv[i]) == 0) { printf("deleted %s\n", argv[i]); } else { printf("unable to delete %s\n", argv[i]); return EXIT_FAILURE; } } return EXIT_SUCCESS; exit_failure: curs_set(1); /* unhide cursor */ endwin(); /* Exit ncurses */ printf("%s\n",failure_message); return EXIT_FAILURE; }