#!/usr/local/bin/perl # eval 'exec /usr/local/bin/perl -S $0 ${1+"$@"}' # if $running_under_some_shell; require "getopts.pl"; &Getopts('o:'); # die "Usage: per2g [-o outfile] [infile]\n" if @ARGV > 1; # # Get stdout set up and the default module name # if ( $opt_o ) { # # If they give us an output file name, open it # and use it as the module name (minus path and extension). # open(STDOUT, ">$opt_o") || die "Couldn't open $opt_o for output: $!\n"; ($m = $opt_o) =~ s#(.*/)?(.*)\.g$#$2#; } elsif (@ARGV) { # # If they give us an input file, # use it as the output file name (minus path and extension plus .g) # and use it as the module name (minus path and extension). # ($m = $ARGV[0]) =~ s#(.*/)?(.*)\.per$#$2#; unless ( -e "$m.g" ) { open(STDOUT, ">$m.g") || die "Couldn't open $m.g for output: $!\n"; } } else { # # OK, we got nothin', output is stdout and module name is junk. # $m = 'xxx'; } $c_prefix = ';FIXME '; %drop = ( 'attrition-damage', 1, 'dark', 1, 'discipline-effect', 1, 'first-unit', 1, 'first-product', 1, 'maker', 1, 'named', 1, 'neutrality', 1, 'random-move', 1, 'scale', 1, 'nuke-hit', 1, 'accident-message', 0, 'alt-roughness', 0, 'wet-roughness', 0, 'attack-worth', 0, 'attrition-message', 0, 'conceal', 0, 'defense-worth', 0, 'destroy-message', 0, 'disaster-message', 0, 'explore-worth', 0, 'font-name', 0, 'make', 0, 'min-region-size', 0, 'neutral', 0, 'nuked', 0, 'research', 0, 'siege', 0, 'starve-message', 0, ); %vars = ( 'all-seen', 'see-all', 'edge-terrain', 'edge-terrain', 'country-size', 'country-radius-min', 'country-min-distance', 'country-separation-min', 'country-max-distance', 'country-separation-max', 'spy-chance', 'spy-chance', 'spy-quality', 'spy-quality', ); %props = ( 'already-seen', 'already-seen', 'always-seen', 'see-always', 'changes-side', 'acp-to-change-side', 'hold-volume', 'capacity', 'hp', 'hp-max', 'in-country', 'start-with', 'max-alt', 'alt-percentile-max', 'max-wet', 'wet-percentile-max', 'min-alt', 'alt-percentile-min', 'min-wet', 'wet-percentile-min', 'revolt', 'revolt-chance', 'see-best', 'vision-at-max-range', 'see-range', 'vision-at', 'see-worst', 'vision-range', 'self-destruct', 'acp-to-detonate', 'territory', 'point-value', 'max-quality', 'cxp-max', 'skill-effect', 'cxp-hit-effect', 'discipline-effect', 'cxp-hit-effect', ); %tables = ( 'accident', 'accident-hit-chance', 'disaster', 'accident-vanish-chance', 'alter-mobility', 'mp-per-occupant', 'attrition', 'attrition', 'bridge', 'ferry-on-entry', 'capacity', 'occupant-max', 'capture', 'capture-chance', 'consume', 'base-consumption', 'damage', 'damage', 'defense', 'defend-terrain-effect', 'enter-time', 'mp-to-enter-unit', 'favored', 'favored-terrain', 'hit', 'hit-chance', 'hit-by', 'hit-by', 'hits-with', 'consumption-per-attack', 'in-length', 'in-length', 'leave-time', 'mp-to-leave-unit', 'moves', 'mp-to-enter-terrain', 'out-length', 'out-length', 'produce', 'base-production', 'productivity', 'productivity', 'protect', 'protection', 'repair', 'hp-per-repair', 'stockpile', 'supply-on-completion', 'storage', 'unit-storage-x', 'to-make', 'material-to-build', 'to-move', 'consumption-per-move', ); %lists = ( 'can-counter', 'acp-to-defend', 'can-disband', 'hp-per-disband', 'combat-time', 'acp-to-attack', 'consume-as-occupant', 'consumption-as-occupant', 'crippled', 'hp-at-min-speed', 'density', 'independent-density', 'occupant-produce', 'occupant-base-production', 'retreat', 'withdraw-chance-per-attack', 'speed', 'speed', 'startup', 'tp-to-build', 'surrender', 'surrender-chance', 'survival', 'hp-per-starve', 'visibility', 'visibility', 'volume', 'unit-size-as-occupant', ); %comments = ( 'attack-worth', "dunno if this is still useful for AIs", 'defense-worth', "dunno if this is still useful for AIs", 'explore-worth', "dunno if this is still useful for AIs", 'min-region-size', "dunno if this is still useful for AIs", 'alt-roughness', "this is broken into alt-blob-size, etc. etc.", 'wet-roughness', "this is broken into wet-blob-size, etc. etc.", 'accident', "accident is U T -> .01N chance that an accident happens to U\n; and you can set accident-damage", 'acp-to-defend', "acp-to-defend is U1 U2 -> ACP, set to 0 to disable counter-attacks", 'attrition', "attrition is U T -> .01HP (rate of loss, hp/turn)", 'bridge', "ferry-on-entry is U1 U2 -> FTYPE how much terrain U2 crosses to board U1", 'can-disband', "hp-per-disband is U1 U2 -> HP lost in a disband action performed by U2\n; you might add U1 acp-to-disband U2 as well, U1 U2 -> ACP", 'capacity', "occupant-max is U1 U2 -> N upper limit on occupants by type", 'combat-time', "acp-to-attack U1 U2 -> ACP for U1 to attack U2", 'conceal', "conceal is now visibility, you should subtr these numbers from that table", 'crippled', "in addition you can set hp-to-repair and other things to cripple a unit", 'hold-volume', "capacity is N, upper limit on total occupants by size", 'make', "make is replaced by acp-to-create, cp-per-build and friends", 'moves', "moves is mp-to-{enter|leave}-terrain U T -> MP", 'nuked', "I guess nuked is damaged-terrain now, T1 T2 -> N", 'occupant-produce', "occupant-base-production is U M -> N of M that U produces as occupant", 'repair', "hp-per-repair is U1 U2 -> .01HP that U1 restores to U2 per repair action\n; ...and you have to add...\n; acp-to-repair is U1 U2 -> ACP to do one repair action", 'research', "this is handled by tech level and research now...", 'retreat', "U1 U2 -> % that U2 withdraws before U1 attacks", 'see-best', "vision-at is N, coverage afforded by unit in its own hex", 'see-worst', "vision-at-max-range is N, coverage afforded by unit at max range", 'speed', "don't forget to add acp-per-turn for non-movers!", 'spy-chance', "spy-chance is now on a per unit basis...\n; and spy-range specifies how far a unit can spy", 'spy-quality', "spy-quality is U1 U2 -> % that U1 returns info about U2", 'startup', "tp-to-build is U1 U2 -> TP that U1 needs before building U2\n; you also need UnitProperty acp-to-toolup and Table tp-per-toolup", 'stockpile', "this used to be % now it is a raw number.", 'surrender', "surrender is U1 U2 -> .01N chance that U1 surrenders to U2\n; and surrender-range is distance at which it can occur", 'survival', "survival is now hp-per-starve U M -> HP", 'visibility', "visibility is U T -> N, U's % visibility in T", 'volume', "unit-size-as-occupant is U1 U2 -> N U1's size as occupant of U2", ); $\ = "\n"; # automatically add newline on print LINE: while (<>) { # strip leading/trailing whitespace (and the newline). s/^\s+//; s/\s+$//; # transform () to [] tr/[]/()/; # change r* (resources) to m* (materials) s/r\*/m*/g; # Grab the comment off the end of the line... s/\s*(;.*)$//; $trail = "$1"; # blank line... unless ( $_ ) { # ...it may be a terminator for sname or uname... print('))'), $in_name = 0 if $in_namer; # ...actually it coulda been a comment. print "$trail"; next LINE; } if (/^Xconq . [\+-]+ (.*)$/) { # This is the file starter. # Now we KNOW we're in the right kinda file. print qq/(game-module "$m"\n (blurb "$1")\n)/; next LINE; } elsif (/(.*) period-name$/) { print qq/(game-module (title $1))/, ($trail)? "\t$trail" : ''; next LINE; } elsif ( /Period [01]/ ) { next LINE; } elsif ( /begin{notes}/ ) { print("(game-module (notes"); ++$seen_key{'notes'}; while (<>) { print("))"), last if /end{notes}/; } next LINE; } elsif (/\s*"(.)"\s+"(.*)"\s+"(.*)"\s+(.)type$/) { if ( $4 eq 'u' ) { $u = $1; # ($u = $2) =~ y/A-Z/a-z/; $utype{$1} = $u; if ( $defines{'u*'} ) { $defines{'u*'} .= " $1"; } else { $defines{'u*'} = "$1"; } print "$trail" if $trail; print qq/(unit-type $u (name "$2") (char "$1")\n (help "$3")\n)/; } elsif ( $4 eq 'r' ) { print qq/(material-type |$2| (help "$3"))/, ($trail)? "\t$trail" : ''; } elsif ( $4 eq 't' ) { print qq/(terrain-type |$2| (char "$1") (color "$3"))/, ($trail)? "\t$trail" : ''; } next LINE; } elsif (/(.*)\s+(.*)\s+icon-name$/) { print "(add $utype{$2} image-name $1)", ($trail)? "\t$trail" : ''; next LINE; } elsif (/(.*)\s+"(.*)"\s+define$/) { $defines{$2} = $1; print "(define $2 $1)", ($trail)? "\t$trail" : ''; next LINE; } elsif (/clear-(\S*)-names$/) { print "(namer $1-names (random", ($trail)? "\t$trail" : ''; ++$in_namer; next LINE; } elsif (/[su]name/) { s/[su]name\s?//g; s/\*/ /g; print; next LINE; } elsif (/^end$/) { # ain't no mo... last; } # # strip the last word off the line and see if we can # find it in our list of keywords. # split; $key = pop(@_); next LINE if $drop{$key}; print $c_prefix, $comments{$key} if $comments{$key} && !$seen_key{$key}++; if ( $vars{$key} ) { m/^(.*) $key$/; # These are special cases that don't quite match # or need additional processing... if ($key eq 'spy-chance') { local($val) = ($1 eq 'true')? 10 : ($1 eq 'false')? 0 : $1; print "(add u* $vars{$key} $1)", ($trail)? "\t$trail" : ''; next LINE; } elsif ($key eq 'spy-quality') { local($val) = ($1 eq 'true')? 10 : ($1 eq 'false')? 0 : $1; print "(table $vars{$key} (u* u* $1))", ($trail)? "\t$trail" : ''; next LINE; } print "(set $vars{$key} $1)", ($trail)? "\t$trail" : ''; next LINE; } elsif ( $props{$key} ) { m/(^[^ ()]*|\(.*\))\s+([^ ()]*|\(.*\))\s+$key$/; local($val) = ($1 eq 'true')? 1 : ($1 eq 'false')? 0 : $1; # These are special cases that don't quite match # or need additional processing... if ($key eq 'revolt') { push(@random_events, 'units-revolt'); } print "(add $2 $props{$key} $val)", ($trail)? "\t$trail" : ''; next LINE; } elsif ( $lists{$key} ) { m/(^[^ ()]*|\(.*\))\s+([^ ()]*|\(.*\))\s+$key$/; # @vals = split(/\s+/, ($defines{$1})? $defines{$1} : $1); # @typs = split(/\s+/, ($defines{$2})? $defines{$2} : $2); # shift(@vals), pop(@vals) if @vals[0] eq '('; # shift(@typs), pop(@typs) if @typs[0] eq '('; # These are special cases that don't quite match # or need additional processing... if ($key eq 'surrender') { push(@random_events, 'units-surrender') unless $seen_key{$key}++; } elsif ($key eq 'consume-as-occupant' || $key eq 'survival') { print "(table $lists{$key} add ($2 m* $1))", ($trail)?"\t$trail":''; next LINE; } elsif ($key eq 'startup' || $key eq 'retreat') { print "(table $lists{$key} add (u* $2 $1))", ($trail)?"\t$trail":''; next LINE; } elsif ($key eq 'can-disband') { print "; (table $lists{$key} add ($2 u* 100))", ($trail)?"\t$trail":''; next LINE; } elsif ($key eq 'occupant-produce') { local($v) = ($1 =~ /true/i)? 1 : 0; print "(table $lists{$key} add ($2 m* $v))", ($trail)?"\t$trail":''; next LINE; } elsif ($key eq 'visibility' || $key eq 'density') { print "(table $lists{$key} add ($2 t* $1))", ($trail)?"\t$trail":''; next LINE; } elsif ($key eq 'crippled') { print "(add $2 $lists{$key} $1)"; next LINE; } elsif ($key eq 'speed') { print "(add $2 acp-per-turn $1)\n(add $2 $lists{$key} 100)"; next LINE; } print "(table $lists{$key} add ($2 u* $1))", $trail ? "\t$trail" : ''; next LINE; } elsif ( $tables{$key} ) { m/^([^ ()]*|\(.*\))\s+([^ ()]*|\(.*\))\s+([^ ()]*|\(.*\))\s+$key$/; local($val) = $1; # These are special cases that don't quite match # or need additional processing... if ($key eq 'attrition') { push(@random_events, 'attrition-in-terrain') unless $seen_key{$key}++; } elsif ($key eq 'accident') { push(@random_events, 'accidents-in-terrain') unless $seen_key{$key}++; } elsif ($key eq 'bridge') { $val = 'over-all'; } elsif ($key eq 'defense' || $key eq 'protect') { local(@vals, $i); $val =~ s/\s*[()]\s*//g; @vals = split(/\s+/, $val); foreach $i (@vals) { $i = 100 - $i; } $val = join(' ', @vals); $val =~ s/^(.*)$/($1)/ if @vals > 1; } elsif ($key eq 'moves') { local(@vals, $i); $val =~ s/\s*[()]\s*//g; @vals = split(/\s+/, $val); foreach $i (@vals) { if ( $i < 0 ) { $i = 99; } else { ++$i; } } $val = join(' ', @vals); $val =~ s/^(.*)$/($1)/ if @vals > 1; } elsif ($key eq 'repair') { print "(table acp-to-repair add ($3 $2 1))"; local(@vals, $i); if ( $val =~ /[()]/ ) { @vals = split(/\s+/, $val); for ($i = 1; $i < @vals - 1; ++$i) { if ( @vals[$i] == 0 ) { @vals[$i] = 1; } @vals[$i] = int(100 / @vals[$i]); } $val = join(' ', @vals); } else { if ( $val == 0 ) { $val = 1; } $val = int(100 / $val); } } print "(table $tables{$key} add ($3 $2 $val))", ($trail)?"\t$trail":''; next LINE; } elsif ( !defined($drop{$key}) ) { print STDERR "Unknown keyword: $key" unless $unkey{$key}++; } # turn everything else into a comment, # so that we don't throw any important bits away. print $c_prefix, $_, ($trail)? "\t$trail" : ''; } print "\n;(set random-events (@random_events))" if @random_events; print " (game-module (instructions ( ))) (game-module (design-notes ( )))"; print "(game-module (notes (\n)))" unless $seen_key{'notes'}; exit(0);