#!/usr/exp/bin/perl # # by kesinger@xxxxxxxxxxxx, see http://www.math.ttu.edu/~kesinger/freeciv/ # # I've changed some things to suit my taste - rp #civpow.pl: Shows the extent of power of various civilizations. #Requires perl 5, netpbm, and #gifsicle (http://www.pdos.lcs.mit.edu/~eddietwo/gifsicle/) #Directory in which to find pnmenlarge and ppmtogif $netpbm = '/usr/X11/bin/'; #Location of gifsicle executable $gifsicle = '/usr/exp/bin/gifsicle -O'; #Colors to represent the races. These are pretty arbitrary. @colors=("0 0 255", #Ocean "190 190 190", #Unclaimed land " 60 209 189 ", " 0 0 139 ", " 139 69 19 ", " 188 143 143 ", " 255 165 0 ", " 255 192 203 ", " 210 180 140 ", " 0 255 139" , " 144 238 144 ", " 132 112 255", " 139 165 0 ", " 139 0 0 ", " 127 255 212 ", " 0 0 0 "); #How far does the influence of each city spread? Default value $radius = 3; #How much should the map be enlarged? Default value $enlargement = 4; #Where should we write the final animated gif? $output = "final.gif"; #$output = "-"; # scripts shall write to stdout - rp # no can do because of stupid gifsicle! aaargh, Windows programmer alert sub usage { print STDERR join(' ',$0,'usage error:', @_), "\n\n" if @_; print STDERR </dev/null'; open(GIFFILE, "| $netpbm/pnmenlarge $enlargement " . "| $netpbm/ppmtogif $nojunk >$gif") || die "Can't open netpbm commands pipe to file $gif: $!\n"; if ($savorgif eq 'sav') { &feed_ppm; } else { while () { print GIFFILE $_; } } close(SAVFILE); close(GIFFILE); push (@gifs, $gif); } sub feed_ppm { #How many players are there? do { $_ = ; } until /nplayers/; chop($_); s/\D//g; $nplayers = $_; #Read in the map. do { $_ = ; } until $_ eq "[map]\n"; ($wkw,$width) = split(/=/,); chop($width); ($hkw,$height) = split(/=/,); chop($height); #Read the first line of the map. #@map is a two dimensional array. do { $_ = ; } until /^t000/; s/^t\d+//; s/\"//g; s/=//g; s/\n//g; $map[0] = [split(//)]; #Read the rest of the map. for($i=1;$i<$height;$i++){ $_= ; s/^t\d+//; s/\"//g; s/=//g; s/\n//g; @foo= split(//); $map[$i] = [@foo]; } #Initialize the ``distance chart.'' for ($i=0;$i<$width;$i++){ for($j=0;$j<$height;$j++){ $themap[$j][$i] = ''; } } #Find the city locations for each player. for ($playitr=0;$playitr<$nplayers;$playitr++) { #Find the next player do { $_ = ; } until /\[player/; $_ = ; #Read the name. $race = ; #Get the race. chop($race); $race =~ s/\D//g; #Find the city list. do { $_ = ; } until (/c=/||/^$/); next if /^$/; #Iterate over the cities, grabbing all possible influences. do { $_ = ; unless (/\}/){ @cityline = split(/,/); $x=$cityline[1]; $y=$cityline[2]; #Every city influences its own square $themap[$y][$x] = "d=0 r=$race"; #Now it gets tricky. We expand out in successive boxes. #For each point in the box we do the following: #0. Is this water? If so, ignore it. #1. If this land unclaimed? If so, claim it. #2. Is this land already claimed by us? If so, # a. Is this new city closer? If so, update the claim. # b. If not, ignore this claim. #3. Is this land already claimed by someone else? If so, # a. If we're closer, take their claim. # b. If they're closer, its theirs. # c. If we're equaliy close, it becomes a DMZ with the # current distance. #4. Is this land DMZ? If so, and this city is closer, # claim the land. for ($rad=1;$rad<=$radius;$rad++){ @inf = box($x,$y,$rad,$width,$height); foreach $point (@inf){ ($px,$py,@extra) = split(/ /, $point); #0. unless ($map[$py][$px] eq ' '){ #1. if ($themap[$py][$px] eq ''){ $themap[$py][$px] = "d=$rad r=$race"; } else { #2. if ($themap[$py][$px] =~ /r=$race/){ $olddist = &getdist($themap[$py][$px]); if ($olddist>$rad){ $themap[$py][$px] = "d=$rad r=$race"; } } #3/4 else { $olddist=&getdist($themap[$py][$px]); $oldrace=&getrace($themap[$py][$px]); $newdist=$olddist; #Let's do 4 here if ($oldrace==-1 && $olddist>$rad){ $newrace=$race; $newdist=$rad; } #Here comes #3. else { if ($olddist==$rad) { $newrace=-1; } elsif ($olddist<$rad){ $newrace=$oldrace; } else { $newrace=$race; $newdist=$rad; } } $themap[$px][$py]="d=$newdist r=$newrace"; } #Close #3/4 } #Close #2 } #Closes unless block. } #Closes point foreach loop } #Closes radius for loop. } #Closes extra block to avoid working on ``}'' line. } until /^\}$/; } #Close playitr loop print GIFFILE "P3\n$width\n$height\n24\n"; $tmdat = ''; for($j=0;$j<$height;$j++){ for($i=0;$i<$width;$i++){ if ($map[$j][$i] =~ / /){ $tmdat .= $colors[0] . "\n"; } #There's land here else { #It's not claimed if ($themap[$j][$i] =~ /^$/) { $tmdat .= $colors[1] . "\n"; } #It is claimed else { $tmdat .= $colors[&getrace($themap[$j][$i])+2] . "\n"; } } #Close land case } } print GIFFILE $tmdat; } #Now create the animated .gif #Why doesn't gifsicle take a sequence GIFs from stdin? stupid tmpfiles - rp if ($output eq '-') { die 'cannot write to stdout, please complain to gifsicle author'; $cranim = join(' ',$gifsicle, @gifs); } else { $cranim = join(' ',$gifsicle, @gifs, ">$output"); } `$cranim`; #Clean up after ourselves unlink split(/ /,$giflist) unless $keepgifs; #Grabs the race from a line in a dist element (``d=\d+ r=\d+'') sub getrace { $thisline = $_[0]; @thisline = split(/=/, $thisline); return $thisline[2]; } #Grabs the distance from a line in a dist element. (See above) sub getdist { $thisline = $_[0]; @tmp = split(/=/, $thisline); if ($#tmp<1) { $dis = 0; } else { $dis = $tmp[1]; $dis =~ s/\D//g; } return $dis; } #Find a box of a given radius around a point. #This still needs to be tweaked; it currently doesn't wrap around east/west. sub box { local ($x, $y, $rad, $width, $height, @extra) = @_; undef @perim; if ($x<0|$y<0||$x>($width-1)|$y>($height-1)){ return @perim; } $left = $x-$rad; $right=$x+$rad; $top = $y+$rad; $bottom = $y-$rad; @horiz=$left..$right; $newbo = ($bottom<0) ? 0 : $bottom; $newto = ($top>=$height) ? $height-1 : $top; $newle = $left % $width; $newri = $right % $width; @vert = $newbo..$newto ; foreach $ho (@horiz){ $nho = $ho % $width; push @perim ,"$nho $newbo"; push @perim ,"$nho $newto"; } foreach $ve (@vert){ push @perim ,"$newle $ve"; push @perim ,"$newri $ve"; } #The corner elements may have been included twice. Get rid of them. #From the perl FAQ, section 4 undef %saw; @trimmed = grep(!$saw{$_}++, @perim); return @trimmed; } sub numerically { return $a <=> $b; } #Sort save files in chronological (not numeric) order, according to filename sub civsavnum { ($c) = ($a =~ /civgame(-?\d+)\....$/); ($d) = ($b =~ /civgame(-?\d+)\....$/); return $c <=> $d; }