From 0adbd9b6870fa958eee32c5f5ba1b5052b6e8e4f Mon Sep 17 00:00:00 2001
From: Bruce Hill <bruce@bruce-hill.com>
Date: Thu, 3 Jan 2019 01:51:33 -0800
Subject: [PATCH] Added globe and lots of fanciness.

---
 Makefile |   4 +-
 colors.h |   4 +
 globe.h  | 187 +++++++++++++++++++++++++++
 list.h   |  52 ++++++++
 nuke.c   | 379 ++++++++++++++++++++++++++++++-------------------------
 5 files changed, 454 insertions(+), 172 deletions(-)
 create mode 100644 colors.h
 create mode 100644 globe.h
 create mode 100644 list.h

diff --git a/Makefile b/Makefile
index a696551..272d335 100644
--- a/Makefile
+++ b/Makefile
@@ -3,8 +3,8 @@ PREFIX=
 
 all: nuke
 
-nuke: nuke.c
-	cc nuke.c -lncurses -O3 -o nuke
+nuke: *.h *.c
+	cc nuke.c -lncurses -g -o nuke
 
 clean:
 	rm -f nuke
diff --git a/colors.h b/colors.h
new file mode 100644
index 0000000..a962f56
--- /dev/null
+++ b/colors.h
@@ -0,0 +1,4 @@
+#ifndef __colors
+#define __colors
+const int WHITE = 1, YELLOW = 2, RED = 3, BLUE = 4, GREEN = 5, BLACK = 6;
+#endif
diff --git a/globe.h b/globe.h
new file mode 100644
index 0000000..fd4bddb
--- /dev/null
+++ b/globe.h
@@ -0,0 +1,187 @@
+/**
+ * ASCII spinning glboe
+ */
+
+#include "colors.h"
+#include <curses.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <signal.h>
+#include <string.h>
+#include <math.h>
+#include <poll.h>
+
+const double GOLDEN_RATIO = 1.6180339887498948482045868343656381;
+const int NUM_WAVES = 7;
+const double OFFSETS[2*NUM_WAVES] = {
+  0.5459919526, 0.6072439135, 0.6217563193, 0.5444045324, 0.8923452588,
+  0.4626828607, 0.9422234679,
+
+  0.7870886548, 0.7425605127, 0.1510923405, 0.3889282293, 0.3730024274,
+  0.1450487012, 0.9051931355,
+};
+const double AMPLITUDES[NUM_WAVES] = {
+  //0.9, 0.81, 0.729, 0.6561, 0.59049, 0.531441, 0.4782969
+  0.83, 0.6889, 0.571787, 0.47458321, 0.3939040643, 0.326940373369, 0.27136050989627
+};
+
+static double hillnoise(double x, double y)
+{
+  double noise = 0;
+  double sigma = 0;
+  for (int i = 0; i < NUM_WAVES; i++) {
+      // Rotate coordinates
+      double rotation = fmod(((float)i)*GOLDEN_RATIO, 1.0)*2.0*M_PI;
+      double u = x*cos(rotation) - y*sin(rotation);
+      double v = -x*sin(rotation) - y*cos(rotation);
+      double size = AMPLITUDES[i];
+      double offsetx = OFFSETS[2*i];
+      double offsety = OFFSETS[2*i+1];
+      noise += (size/2.)*(sin(u/size + offsetx) + sin(v/size + offsety));
+      sigma += size*size;
+  }
+  sigma = sqrt(sigma)/2.;
+  noise /= 2.*sigma;
+  return (0.5*(noise < 0 ? -1. : 1.)*sqrt(1 - exp(-2./M_PI * noise*noise)) + 0.5);
+}
+
+static double mix(double a, double b, double amount)
+{
+  return (1.-amount)*a + amount*b;
+}
+
+void draw_stars()
+{
+  int rows,cols;
+  getmaxyx(stdscr,rows,cols);
+  attron(COLOR_PAIR(WHITE));
+  for (int r = 0; r < rows; r++) {
+    for (int c = 0; c < cols; c++) {
+      double n = hillnoise(r*100,c*200);
+      if (n > .8) {
+        mvaddch(r,c,n > .9 ? '*' : '.');
+      }
+    }
+  }
+  attroff(COLOR_PAIR(WHITE));
+}
+
+void draw_globe(double t, double zoom)
+{
+  int rows,cols;
+  getmaxyx(stdscr,rows,cols);
+  double rotation = t * (2*M_PI)/10. + M_PI;
+  const double rho = rows/2.;
+  for (int r = 0; r < rows; r++) {
+    for (int c = 0; c < cols; c++) {
+      double y = (c - cols/2) * 0.5 / zoom;
+      double z = (r - rows/2) * 1.0 / zoom;
+      double x = sqrt(rho*rho - z*z - y*y);
+
+      if (z*z + y*y > rho*rho) {
+        continue;
+      }
+
+      double theta = atan2(z, sqrt(x*x + y*y));
+      double phi = fmod(atan2(y, x) + rotation, 2.*M_PI);
+      double elevation = hillnoise(theta*5., phi*5.);
+      double clouds = hillnoise(theta*5., phi*5. - 1.*rotation - 100.);
+      int color;
+      int ch;
+      if ((fabs(z)/rho) > .9) {
+        elevation = elevation + mix(.0, 1., 10.*(fabs(z)/rho - .9)) > .6 ? 1. : 0.;
+      }
+      if (clouds < .4) {
+        ch = (clouds < .3 ? '0' : '%') | A_BOLD;
+        color = COLOR_PAIR(WHITE);
+      } else if (elevation < .55) {
+        ch = '~';
+        color = COLOR_PAIR(BLUE);
+      } else if (elevation < .6) {
+        ch = ':';
+        color = COLOR_PAIR(YELLOW);
+      } else if (elevation < .85) {
+        ch = 'S';
+        color = COLOR_PAIR(GREEN);
+      } else {
+        ch = '#';
+        color = COLOR_PAIR(WHITE);
+      }
+      attron(color);
+      mvaddch(r,c,ch);
+      attroff(color);
+    }
+  }
+}
+
+void draw_scorch(double t, double zoom, int *targetr, int *targetc)
+{
+  int rows,cols;
+  getmaxyx(stdscr,rows,cols);
+  double rotation = t * (2*M_PI)/10. + M_PI*1.4;
+  const double rho = rows/2.;
+
+  double theta = M_PI/2*1.1;
+  double phi = M_PI + rotation;
+  double x = rho*sin(theta)*cos(phi);
+  double y = rho*sin(theta)*sin(phi);
+  double z = rho*cos(theta);
+  int r = z / (1.0/zoom) + rows/2;
+  int c = y / (.5/zoom) + cols/2;
+  *targetr = r;
+  *targetc = c;
+
+  attron(COLOR_PAIR(BLACK) | A_BOLD);
+  mvprintw(r-1,c-1,"****");
+  mvprintw(r,c-2, "******");
+  mvprintw(r+1,c-1,"****");
+  attroff(COLOR_PAIR(BLACK) | A_BOLD);
+}
+
+void draw_target(double t, double zoom, int *targetr, int *targetc)
+{
+  int rows,cols;
+  getmaxyx(stdscr,rows,cols);
+  double rotation = t * (2*M_PI)/10. + M_PI*1.4;
+  const double rho = rows/2.;
+
+  double theta = M_PI/2*1.1;
+  double phi = M_PI + rotation;
+  double x = rho*sin(theta)*cos(phi);
+  double y = rho*sin(theta)*sin(phi);
+  double z = rho*cos(theta);
+  int r = z / (1.0/zoom) + rows/2;
+  int c = y / (.5/zoom) + cols/2;
+  *targetr = r;
+  *targetc = c;
+
+  if (x < 0) {
+    attron(COLOR_PAIR(YELLOW));
+    mvaddch(r,c, '*' | A_BOLD);
+    attroff(COLOR_PAIR(YELLOW));
+  }
+
+  double wobble = t > 2.5 ? 0. : 2.5 - t;
+  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-0,ACS_HLINE | A_BOLD);
+  mvaddch(r-1,c+1,ACS_HLINE | A_BOLD);
+  mvaddch(r-1,c+2,ACS_URCORNER | A_BOLD);
+  //mvaddch(r-0,c+2,ACS_VLINE | A_BOLD);
+  mvaddch(r+1,c+2,ACS_LRCORNER | A_BOLD);
+  mvaddch(r+1,c+1,ACS_HLINE | A_BOLD);
+  //mvaddch(r+1,c+0,ACS_HLINE | A_BOLD);
+  mvaddch(r+1,c-1,ACS_HLINE | A_BOLD);
+  mvaddch(r+1,c-2,ACS_LLCORNER | A_BOLD);
+  //mvaddch(r+0,c-2,ACS_VLINE | A_BOLD);
+
+  mvaddch(r,c,'X' | A_BOLD);
+  attroff(attr);
+}
diff --git a/list.h b/list.h
new file mode 100644
index 0000000..a090f8d
--- /dev/null
+++ b/list.h
@@ -0,0 +1,52 @@
+#include <dirent.h>
+#include <string.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+static void add_file(char *name, char ***files, int *size, int *capacity)
+{
+  if (*size == *capacity) {
+    *capacity *= 2;
+    *files = realloc(*files, sizeof(char*) * (*capacity));
+  }
+  (*files)[*size] = strdup(name);
+  (*size)++;
+}
+
+static void add_files(char *name, char ***files, int *size, int *capacity)
+{
+  DIR *dir;
+  struct dirent *entry;
+
+  add_file(name, files, size, capacity);
+  if (!(dir = opendir(name))) {
+    return;
+  }
+
+  while ((entry = readdir(dir)) != NULL) {
+    char path[1024];
+    if (entry->d_type == DT_DIR) {
+      if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+        continue;
+      snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
+      add_files(path, files, size, capacity);
+    } else {
+      snprintf(path, sizeof(path), "%s/%s", name, entry->d_name);
+      add_file(path, files, size, capacity);
+    }
+  }
+  closedir(dir);
+}
+
+/*int main(int argc, char *argv[]) {
+  int capacity = 32, size = 0;
+  char **files = malloc(sizeof(char*)*capacity);
+  for (int i = 1; i < argc; i++) {
+    add_files(argv[i], &files, &size, &capacity);
+  }
+
+  for (int f = 0; f < size; f++) {
+    printf("%s\n", files[f]);
+  }
+  return 0;
+}*/
diff --git a/nuke.c b/nuke.c
index 8de112d..094aa7e 100644
--- a/nuke.c
+++ b/nuke.c
@@ -3,15 +3,19 @@
  * 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 <curses.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <signal.h>
-#include <string.h>
+#include <ftw.h>
 #include <math.h>
 #include <poll.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
 
-#define NUM_FRAMES 150
+#define NUM_FRAMES 120
 #define NUM_BLOBS 800
 #define PERSPECTIVE 50.0
 #define ESCDELAY 10
@@ -33,75 +37,98 @@ static void sighandler(int sig) {
   exit(EXIT_FAILURE);
 }
 
-static char* get_piped_input() {
-  struct pollfd desc;
-  desc.fd = STDIN_FILENO;
-  desc.events = POLLIN;
-  int ret = poll(&desc, 1, 50);
-  if (ret == 0) {
-    return NULL;
-  } else if (ret < 0) {
-    perror("poll");
-    raise(SIGINT);
-  }
-  size_t chunk = 1024;
-  size_t capacity = chunk;
-  size_t size = 0;
-  char *input = malloc(capacity);
-  for (size_t consumed; (consumed = fread(&input[size], 1, chunk, stdin)); size += consumed) {
-    if (consumed == chunk) {
-      chunk *= 2;
-      capacity += chunk;
-      input = realloc(input, capacity);
-    }
-  }
-  return input;
-}
+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};
 
-/* Populate `lines` with (at most `max_lines`) lines from stdin, each at most
- * `max_line` characters long.
- * Return length of the longest line on success, -1 otherwise.
- * *
-static int get_piped_lines(char **lines[], size_t *max_lines, ssize_t *max_line) {
-  struct pollfd desc;
-  desc.fd = STDIN_FILENO;
-  desc.events = POLLIN;
-  int ret = poll(&desc, 1, 50);
-  if (ret > 0) {
-    ssize_t num_lines, longest_line = 0;
-    for (num_lines = 0; num_lines < *max_lines; num_lines++) {
-      size_t n = *max_line;
-      lines[num_lines] = (char*)malloc(n+1);
-      ssize_t line_len = getline(&lines[num_lines], &n, stdin);
-      while (lines[num_lines][line_len-1] == '\n')
-        lines[num_lines][--line_len] = '\0';
-      if (line_len == -1) break;
-      if (line_len > longest_line) {
-        longest_line = line_len > *max_line ? *max_line : line_len;
+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] = ' ';
       }
     }
-    *max_lines = num_lines;
-    *max_line = longest_line;
-    return 0;
-  } else if (ret < 0) {
-    perror("poll");
-    raise(SIGINT);
+    if (i >= 8) {
+      line[cols+1] = '\0';
+      mvaddchstr(row,0,line);
+    }
   }
-  *max_lines = 0;
-  *max_line = 0;
-  return 0;
-}
-*/
 
-int main(int argc, char *argv[]) {
-  char *frames[NUM_FRAMES], *frame;
-  int i,j,x,y,z,v,rows,cols,ith,i0;
-  int maxx,minx,maxy,miny,delay=1E5;
-  double bx,by,bz,br,r,th,t;
+  /* Add blobs with perspective effect */
+  if (i>6) {
+    int i0 = i-6;
+    for (int j=0; j<NUM_BLOBS; j++) {
+      double bx = blobs[j].x * i0;
+      double by = blobs[j].y * i0;
+      double bz = blobs[j].z * i0;
+      if (bz<5-PERSPECTIVE || bz>PERSPECTIVE) continue;
+      int x = midx + bx * PERSPECTIVE / (bz+PERSPECTIVE);
+      int y = midy + by * PERSPECTIVE / (bz+PERSPECTIVE);
+      if (x>=0 && x<cols && y>=0 && y<rows) {
+        int row = y, col = x;
+        mvaddch(row,col,(bz>40) ? '.' : (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[])
+{
+  int rows,cols;
+  int delay=1E5;
   spaceblob *blobs;
 
-  char *input = get_piped_input();
-  if (!input) goto exit_failure;
+  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();
@@ -120,17 +147,26 @@ int main(int argc, char *argv[]) {
   signal(SIGINT, sighandler);
 
   start_color();
-  const int BLACK_ON_RED = 1;
+  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);
-  minx = -cols / 2;
-  maxx = cols+minx-1;
-  miny = -rows / 2;
-  maxy = rows+miny-1;
 
   /* Generate random blob coordinates */
   blobs = (spaceblob*)malloc(NUM_BLOBS * sizeof(spaceblob));
-  for (i=0; i<NUM_BLOBS; i++) {
+  for (int i=0; i<NUM_BLOBS; i++) {
+    double bx,by,bz,br;
     bx = prng();
     by = prng();
     bz = prng();
@@ -140,118 +176,121 @@ int main(int argc, char *argv[]) {
     blobs[i].z = (bz / br) * (1.3 + 0.2 * prng());;
   }
 
-  /* Generate animation frames */
-  for (i=0; i<NUM_FRAMES; i++) {
-    t = (1. * i) / NUM_FRAMES;
-    frame = frames[i] = (char*)malloc(cols * rows + 1);
+  curs_set(0); /* hide text cursor */
+  noecho();
 
-    if (i == 0) {
-      memset(frame, ' ', cols*rows);
-
-      int num_lines = 1, max_line = 0;
-      int linelen = 0;
-      for (char *p = input; *p && (num_lines < rows); ++p) {
-        if (*p == '\n') {
-          if (linelen > max_line)
-            max_line = linelen;
-          linelen = 0;
-          num_lines++;
-        } else {
-          linelen++;
-        }
-      }
-      for (int l = 0, line = 0; input[l] && line < num_lines; line++) {
-        int eol = l;
-        while (input[eol] && input[eol] != '\n') eol++;
-
-        memcpy(&frame[(rows/2 - num_lines/2 + line)*cols + cols/2 - max_line/2],
-            &input[l], cols < eol-l ? cols : eol-l);
-
-        l = input[eol] == '\n' ? eol + 1 : eol;
-      }
-
-      frame += cols*rows;
-
-    } else {
-      char *frame0 = frames[0];
-      for (y=miny; y<=maxy; y++) {
-        for (x=minx; x<=maxx; x++) {
-          char frame0c = *(frame0++);
-          /* Show expanding star in next 7 frames */
-          if (i<8) {
-            r = sqrt(x*x + 4*y*y);
-            *frame++ = (r < i*2) ? '@' : frame0c;
-            continue;
-          }
-
-          /* Otherwise show blast wave */
-          r = sqrt(x*x + 4*y*y) * (0.5 + (prng()/3.0)*cos(16.*atan2(y*2.+0.01,x+0.01))*.3);
-          ith = 32 + th * 32. * M_1_PI;
-          v = i - r - 7;
-          if (v<0) *frame++ = (i<19)?"%@W#H=+~-:."[i-8]:frame0c; /* initial flash */
-          else if (v<20) *frame++ = " .:!HIOMW#%$&@08O=+-"[v];
-          else *frame++=' ';
-        }
-      }
-    }
-
-    /* Add blobs with perspective effect */
-    if (i>6) {
-      i0 = i-6;
-      for (j=0; j<NUM_BLOBS; j++) {
-        bx = blobs[j].x * i0;
-        by = blobs[j].y * i0;
-        bz = blobs[j].z * i0;
-        if (bz<5-PERSPECTIVE || bz>PERSPECTIVE) continue;
-        x = cols / 2 + bx * PERSPECTIVE / (bz+PERSPECTIVE);
-        y = rows / 2 + by * PERSPECTIVE / (bz+PERSPECTIVE);
-        if (x>=0 && x<cols && y>=0 && y<rows)
-          frames[i][x+y*cols] = (bz>40) ? '.' : (bz>-20) ? 'o' : '@';
-      }
-    }
-
-    /* Terminate the text string for this frame */
-    *frame = '\0';
+  // First frame
+  erase();
+  int max_line = 0;
+  for (int f = 0; f < num_files; f++) {
+    int len = strlen(files[f]);
+    if (len > max_line) max_line = len;
   }
 
-  /* Now play back the frames in sequence */
-  curs_set(0); /* hide text cursor (supposedly) */
-  noecho();
-  for (i=0; i<NUM_FRAMES; i++) {
-    erase();
-    mvaddstr(0,0,frames[i]);
-    refresh();
-    if (i == 0) {
-      /* Display confirmation */
-      attron(COLOR_PAIR(BLACK_ON_RED));
-      const char confirm[] = "    FIRE NUKE? y/n    ";
-      mvprintw((rows*3)/4, cols/2 - strlen(confirm)/2, "%s", confirm);
-      attroff(COLOR_PAIR(BLACK_ON_RED));
-      refresh();
-      if (getch() != 'y') {
-        goto exit_failure;
-      }
-      erase();
-      mvaddstr(0,0,frames[i]);
-      refresh();
-      timeout(10);
+  for (int f = 0; f < num_files; f++) {
+    mvprintw(rows/2-num_files/2+f, cols/2-max_line/2, "%s", files[f]);
+  }
+  refresh();
+  /* Display confirmation */
+  attron(COLOR_PAIR(BLACK_ON_RED));
+  const char confirm[] = "    FIRE NUKE? y/n    ";
+  mvprintw((rows*3)/4, cols/2 - strlen(confirm)/2, "%s", confirm);
+  attroff(COLOR_PAIR(BLACK_ON_RED));
+  refresh();
+
+
+  double zoom = .8; // percent of viewport globe will fill
+
+  /*
+  timeout(10);
+  chtype line[cols+1];
+  for (int f = 0; 1; f = (f + 1) % num_files) {
+    int i;
+    for (i = 0; files[f][i]; i++) {
+      line[i] = files[f][i];
     }
+    for (; i < max_line; i++) line[i] = ' ';
+    line[i] = '\0';
+    //mvprintw(rows/2, cols/2-max_line/2, "%s", files[f]);
+    mvaddchstr(rows/2, cols/2-max_line/2,line);
+    refresh();
+    int ch = getch();
+    if (ch == -1)
+      usleep(33333); // 30 FPS
+    else if (ch != 'y')
+      goto exit_failure;
+    else break;
+  }
+  */
+
+  if (getch() != 'y') {
+    goto exit_failure;
+  }
+  timeout(10);
+
+
+  int f = 0;
+  int targetr, targetc;
+  for (int i=0; i<30*3; i++) {
+    erase();
+    draw_stars();
+    draw_globe((double)i/30., zoom);
+    draw_target((double)i/30, 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", argv[f+1]);
+    attroff(COLOR_PAIR(BLACK_ON_RED));
+    f = (f + 1) % (argc - 1);
+    refresh();
+    int ch = getch();
+    if (ch == 'q' || ch == 27) {
+      goto exit_success;
+    }
+    usleep(33333); // 30 FPS
+  }
+
+  for (int i=1; i<NUM_FRAMES; i++) {
+    draw_frame(i, targetc, targetr, blobs);
+    refresh();
     /* Quit early? */
     int ch = getch();
     if (ch == 'q' || ch == 27) {
       goto exit_success;
     }
+    usleep(33333); // 30 FPS
+  }
 
-    usleep(delay);
-    delay=16666; /* Change to 60fps after first frame */
+  for (int i=30*3.5; i < 30*5; i++) {
+    erase();
+    draw_stars();
+    draw_globe((double)i/30., zoom);
+    draw_scorch((double)i/30, zoom, &targetr, &targetc);
+    attron(COLOR_PAIR(GREEN));
+    mvaddch(targetr-1,targetc+1,'/');
+    attroff(COLOR_PAIR(GREEN));
+    attron(COLOR_PAIR(BLACK_ON_GREEN));
+    mvprintw(targetr-2,targetc+2," <GONE> ");
+    attroff(COLOR_PAIR(BLACK_ON_GREEN));
+    refresh();
+    int ch = getch();
+    if (ch == 'q' || ch == 27) {
+      goto exit_success;
+    }
+    usleep(33333); // 30 FPS
   }
   
 exit_success:
   curs_set(1); /* unhide cursor */
   endwin(); /* Exit ncurses */
-  if (!isatty(fileno(stdout))) {
-    // Print stdin to stdout
-    puts(input);
+  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;