#!/usr/bin/perl -w
#
# Doohickey with possibly no purpose.
# But it sure is neat.
# (C) 2013 Pegasus Epsilon <pegasus@pimpninjas.org>
# Distribute Unmodified - http://pegasus.pimpninjas.org/license
use strict;
use POSIX;
use Math::Trig qw(pi);
select((select(STDOUT), $| = 1)[0]);
my %term = (
color => [],
colors => `tput colors`,
clearline => `tput ed`,
cursorpos => `tput cup`,
cursorposinc => 0
);
if (256 == $term{colors}) {
$term{color}->[$_] = `tput setaf $_` for (0..$term{colors});
} else {
$term{color}->[$_] = (
$_ > 7 ? `tput bold` : `tput sgr0`
).`tput setaf \$(($_%8))` for (0..15);
}
$term{cursorpos} =~ s/%p(.)%d/%$1\$d/g;
$term{cursorposinc} = ($term{cursorpos} =~ s/%i//g);
sub gotoyx {
@_ = map { $_+1 } @_ if $term{cursorposinc};
printf $term{cursorpos}, $_[0], $_[1];
}
sub status {
gotoyx(28, 0);
print shift;
print $term{clearline};
}
sub cleanup {
system("setterm -cursor on");
system("stty echo");
gotoyx(100, 0);
exit;
}
$SIG{INT} = \&cleanup;
my @course = do {
my $top = (90 - 72) * pi / 180;
my $bottom = (72 / 2) * pi / 180;
(
[-cos($bottom), sin($bottom)],
[sin($top), -cos($top)],
[sin($top), cos($top)],
[-cos($bottom), -sin($bottom)],
[1,0]
);
};
sub iterator {
my @array = @_;
my $index = 0;
{
next => sub {
$index = 0 if ++$index >= $#array;
$array[$index]
},
this => sub { $array[$index] }
};
}
my @ship = (1.07274097990668, 0.307505277269499);
my @velocity = (-0.0216722136452807, 0.0376918336507429);
my ($velocity, @stack, @count);
my @colors = (15, 11, 3, 1, 8, 0);
my $angle = 0;
my ($columns, $lines, $yscale, $yshift, $xscale, $xshift);
sub winch {
@stack = ([], [], [], [], [], []);
@count = ();
($columns, $lines) = do {
use Term::ReadKey;
GetTerminalSize();
};
$yscale = $lines * .38;
$yshift = $lines * .88;
$xscale = $yscale * 2;
$xshift = $columns / 2 - $xscale;
system("tput", "clear");
}
$SIG{WINCH} = \&winch;
winch;
system("setterm -cursor off");
system("stty -echo");
my $letter = iterator split //, "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
for (;;) {
for my $dest (@course) {
$dest = do {
$angle = fmod($angle + 143.8 * pi / 180, 2 * pi);
[cos($angle), sin($angle)];
};
my (@dist, $dist, $olddist);
@dist = ($dest->[0] - $ship[0], $dest->[1] - $ship[1]);
$dist = sqrt($dist[0] ** 2 + $dist[1] ** 2);
do {
$olddist = $dist;
# draw smoke
for (0..$#stack) {
if ($#{$stack[$_]} > 115) {
my ($y, $x) = (shift @{$stack[$_]}, shift @{$stack[$_]});
unless (--$count[$_][$y][$x]) {
gotoyx $y, $x;
print $term{color}->[$colors[$_]].$letter->{this}();
}
push @{$stack[$_+1]}, $y, $x if ($_ < $#stack);
}
}
# draw flames
my ($y, $x) = (
int($yshift - ($ship[0] + 1) * $yscale),
int($xshift + ($ship[1] + 1) * $xscale)
);
# only if on the screen
if ($y >= 0 && $y < $lines && $x >= 0 && $x < $columns) {
$count[$_][$y][$x]++ for (0..$#stack);
push @{$stack[0]}, $y, $x;
gotoyx $y, $x;
print $term{color}->[14].$letter->{next}();
}
# calculate velocity vector
my @slope = do {
my $angle = atan2($dist[0], $dist[1]);
(sin($angle), cos($angle));
};
$velocity[0] += .0025 * sin(atan2($dist[0], abs($velocity[0]))) * abs($slope[0]);
$velocity[1] += .0025 * sin(atan2($dist[1], abs($velocity[1]))) * abs($slope[1]);
$velocity = sqrt($velocity[0] ** 2 + $velocity[1] ** 2);
$velocity[0] /= 40 * $velocity;
$velocity[1] /= 40 * $velocity;
# do movement tick
$ship[0] += $velocity[0];
$ship[1] += $velocity[1];
# calculate new distances
@dist = ($dest->[0] - $ship[0], $dest->[1] - $ship[1]);
$dist = sqrt($dist[0] ** 2 + $dist[1] ** 2);
#status "$ship[0], $ship[1], $velocity[0], $velocity[1]";
select '', '', '', 1/60/10;
} while ($dist && $dist > .2 || $olddist >= $dist);
}
}