Download
105 lines 3 KiBCModified 2019-02-05 raw
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
/**
  * 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 <curses.h>
#include <math.h>
#include <stdlib.h>

#define NUM_BLOBS 800
#define PERSPECTIVE 50.0

typedef struct {
    double x,y,z;
} spaceblob_t;

static double prng() {
    static long long s=1;
    s = s * 1488248101 + 981577151;
    return ((s % 65536) - 32768) / 32768.0;
}

void draw_explosion(int i, int midx, int midy) {
    static spaceblob_t blobs[NUM_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;

    if (i == 0) {
        /* Generate random blob coordinates */
        for (int i=0; i<NUM_BLOBS; i++) {
            double bx,by,bz,br;
            bx = prng();
            by = prng();
            bz = prng();
            br = sqrt(bx*bx + by*by + bz*bz);
            blobs[i].x = (bx / br) * (1.3 + 0.2 * prng());
            blobs[i].y = (0.5 * by / br) * (1.3 + 0.2 * prng());;
            blobs[i].z = (bz / br) * (1.3 + 0.2 * prng());;
        }
        /* Flash on the first frame */
        bkgd(COLOR_PAIR(WHITE_BG));
        erase();
        return;
    }

    bkgd(0);
    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; 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' : '@');
            }
        }
    }
}