v50 Steam/Premium information for editors
  • v50 information can now be added to pages in the main namespace. v0.47 information can still be found in the DF2014 namespace. See here for more details on the new versioning policy.
  • Use this page to report any issues related to the migration.
This notice may be cached—the current version can be found here.

Editing User:Mortal

Jump to navigation Jump to search

Warning: You are not logged in.
Your IP address will be recorded in this page's edit history.


The edit can be undone. Please check the comparison below to verify that this is what you want to do, and then save the changes below to finish undoing the edit.

Latest revision Your text
Line 9: Line 9:
 
  use strict;
 
  use strict;
 
   
 
   
sub usage;
 
sub parsefiles;
 
 
  sub parsefile;
 
  sub parsefile;
 +
sub parsefile_;
 
  sub gettoken;
 
  sub gettoken;
  sub tabstops;
+
  sub fetchtemplates (_);
  sub find_object;
+
  sub fixstatenames (_);
sub find_by_key;
 
 
   
 
   
 
  sub usage {
 
  sub usage {
 
   print STDERR <<USAGE;
 
   print STDERR <<USAGE;
  $0                              List boolean keys and number of objects
+
  $0                              Display boolean keys
  $0 --all                        List all keys
+
  $0 key1 [key2 [...]]            Display items grouped by key
  $0 -h|-v|-V|--help|--version    This usage info
+
  $0 -h|-v|-V|--help|--version    Display usage
$0 sandy clay loam              Display info about a single object
 
$0 'nickel silver' 'rose gold'  Display info about several objects
 
$0 ITEMS_AMMO                  List objects by key
 
 
   
 
   
 
  rawparse.pl written by Mathias Rav, October 2010
 
  rawparse.pl written by Mathias Rav, October 2010
Line 30: Line 25:
 
  Run the script from the df/raw/objects/ directory
 
  Run the script from the df/raw/objects/ directory
 
  USAGE
 
  USAGE
}
 
 
{
 
  package Object;
 
  sub new {
 
    my ($class, $type, $id, @tokens) = @_;
 
    my $self = bless {type => $type, id => $id, tokens => \@tokens}, $class;
 
    $self->fetchtemplates();
 
    $self->fixstatenames();
 
    return $self;
 
  }
 
  sub matches {
 
    my ($token, $prefix) = @_;
 
    return 1 if $token eq $prefix;
 
    return substr($token, length($prefix)+1) if $prefix.':' eq substr($token, 0, length($prefix)+1);
 
    undef;
 
  }
 
  sub get {
 
    my ($self, $prefix) = @_;
 
    my @res;
 
    for my $token (@{$self->{tokens}}) {
 
      my $match = Object::matches($token, $prefix);
 
      push @res, $match if defined $match;
 
      return $res[0] if @res and !wantarray;
 
    }
 
    return @res;
 
  }
 
  sub remove {
 
    my ($self, $prefix) = @_;
 
    my @res;
 
    $self->{tokens} = [grep {
 
      my $match = Object::matches($_, $prefix);
 
      if (defined $match) {
 
        push @res, $match;
 
        0;
 
      } else {
 
        1;
 
      }
 
    } @{$self->{tokens}}];
 
    return @res;
 
  }
 
  sub set {
 
    my ($self, @vals) = @_;
 
    unshift @{$self->{tokens}}, @vals;
 
  }
 
  sub setdefault {
 
    my ($self, @vals) = @_;
 
    push @{$self->{tokens}}, @vals;
 
  }
 
  sub fetchtemplates {
 
    my ($self) = @_;
 
    my $id = $self->{id};
 
    my @templates = $self->remove($main::templateincludekey);
 
    $self->applytemplate($_) for @templates;
 
  }
 
  sub applytemplate {
 
    my ($self, $templatename) = @_;
 
    my $template = $main::templates{$templatename};
 
    unless (defined $template) {
 
      printf STDERR "Object %s references a template called $templatename, but it doesn't exist!\n", $self->id();
 
      return;
 
    }
 
    $self->setdefault(@{$template->{tokens}});
 
  }
 
  sub fixstatenames {
 
    my ($self) = @_;
 
    if ($self->get('IS_GEM') =~ /^([^:]+):[^:]+:OVERWRITE_SOLID/) {
 
      my $name = $1;
 
      $self->set("STATE_NAME_ADJ:ALL_SOLID:$name");
 
    }
 
    my @tokens = @{$self->{tokens}};
 
    for my $token (reverse @tokens) { # reverse so high priority tokens are set last
 
      next unless $token =~ /^STATE_([^:]+_[^:]+):(.*)/;
 
      my $states = $1;
 
      my $subkey = $2;
 
      while ($states =~ /([^_]+)/g) {
 
        $self->set("STATE_${1}:$subkey");
 
      }
 
    }
 
    @tokens = @{$self->{tokens}};
 
    for my $token (reverse @tokens) {
 
      next unless $token =~ /^(STATE_[^:]+:)ALL_SOLID(:.*)/;
 
      my $prefix = $1;
 
      my $suffix = $2;
 
      $self->set($prefix.'SOLID'.$suffix);
 
      $self->set($prefix.'SOLID_POWDER'.$suffix);
 
    }
 
  }
 
  sub id {
 
    my ($self) = @_;
 
    return $self->{id};
 
  }
 
  sub name {
 
    my ($self) = @_;
 
    return scalar($self->get('STATE_NAME:SOLID')) // scalar($self->get('STATE_ADJ:SOLID'));
 
  }
 
  sub type {
 
    my ($self) = @_;
 
    map {if (/^IS_([^:]+)/) {lc $1;} else {();}} @{$self->{tokens}};
 
  }
 
  sub layer {
 
    my ($self) = @_;
 
    my %layers = (
 
      SOIL => 'soil layer',
 
      SOIL_OCEAN => 'pelagic sediment layer',
 
      SEDIMENTARY => 'sedimentary layer',
 
      METAMORPHIC => 'metamorphic layer',
 
      IGNEOUS_EXTRUSIVE => 'igneous extrusive layer',
 
      SEDIMENTARY_OCEAN_SHALLOW => 'covers shallow ocean floors',
 
      IGNEOUS_INTRUSIVE => 'igneous intrusive layer',
 
      SEDIMENTARY_OCEAN_DEEP => 'covers deep ocean floors',
 
      LAVA => 'covers magma pools',
 
      DEEP_SURFACE => 'covers the deep surface',
 
      AQUIFER => 'can contain aquifer',
 
    );
 
    map {$layers{$_}} grep {$self->get($_)} keys %layers;
 
  }
 
  sub magmastatus {
 
    my ($self) = @_;
 
    if ($self->get('BOILING_POINT') <= 12000) {
 
      'boils in magma';
 
    } elsif ($self->get('MELTING_POINT') <= 12000) {
 
      'melts in magma';
 
    } else {
 
      'magma-safe';
 
    }
 
  }
 
  sub print {
 
    my ($self) = @_;
 
    $self->print_header;
 
    $self->print_uses;
 
    $self->print_location;
 
    #$self->print_raw;
 
  }
 
  sub print_header {
 
    my ($self) = @_;
 
    $self->print_title;
 
    $self->print_value;
 
  }
 
  sub print_title {
 
    my ($self) = @_;
 
    my $type = join '', map {", $_"} $self->type;
 
    my $layer = join '', map {", $_"} $self->layer;
 
    print ucfirst($self->name()), $type, $layer, ', ', $self->magmastatus, "\n";
 
  }
 
  sub print_location {
 
    my ($self) = @_;
 
    my $header = "== Location ==\n";
 
    for my $location ($self->get('ENVIRONMENT')) {
 
      my ($layer, $occurrence, $value) = split ':', $location;
 
      my %occurrences = (CLUSTER_SMALL => 'small clusters');
 
      if (defined $occurrences{$occurrence}) {
 
        $occurrence = $occurrences{$occurrence};
 
      } else {
 
        $occurrence = lc $occurrence;
 
        $occurrence =~ s/_/ /g;
 
      }
 
      $layer = lc $layer;
 
      $layer =~ s/_/ /g;
 
      printf "%sFound in %s layers as %s\n", $header, lc($layer), $occurrence;
 
      $header = ''
 
    }
 
    for my $location ($self->get('ENVIRONMENT_SPEC')) {
 
      my ($layer, $occurrence, $value) = split ':', $location;
 
      my %occurrences = (CLUSTER_SMALL => 'small clusters');
 
      if (defined $occurrences{$occurrence}) {
 
        $occurrence = $occurrences{$occurrence};
 
      } else {
 
        $occurrence = lc $occurrence;
 
        $occurrence =~ s/_/ /g;
 
      }
 
      printf "%sFound within %s as %s\n", $header, $main::objectsbyid{$layer}->name, $occurrence;
 
      $header = '';
 
    }
 
  }
 
  sub print_value {
 
    my ($self) = @_;
 
    printf "Material value %d\n", $self->get('MATERIAL_VALUE');
 
  }
 
  sub print_uses {
 
    my ($self) = @_;
 
    print "== Uses ==\n";
 
    $self->print_ores;
 
    $self->print_crafts;
 
    $self->print_reactions;
 
  }
 
  sub print_ores {
 
    my ($self) = @_;
 
    for my $ore ($self->get('METAL_ORE')) {
 
      my ($metalid, $chance) = (split(':', $ore, 2));
 
      my $metal = $main::objectsbyid{$metalid};
 
      my $metalname = defined($metal) ? $metal->name() : $metalid;
 
      printf "* Ore of %s (%d%%)\n", $metalname, $chance;
 
    }
 
  }
 
  sub print_crafts {
 
    my ($self) = @_;
 
    if ($self->get('IS_STONE')) {
 
      print "* Masonry\n* Stone crafting\n* Construction\n";
 
    }
 
    if ($self->get('IS_METAL')) {
 
      print "* Metal crafting\n* Construction\n";
 
    }
 
    if ($self->get('IS_GEM')) {
 
      print "* Gemcrafting\n* Encrusting\n";
 
    }
 
  }
 
  sub print_reactions {
 
    my ($self) = @_;
 
    for my $reaction (@{$main::reactions->{objects}}) {
 
      my $match = 0;
 
      for my $reagent ($reaction->get('REAGENT')) {
 
        my ($name, $quantity, $itemtoken, $itemsubtype, $materialtoken, $materialsubtype) = split ':', $reagent;
 
        my @values = map {s/:.*//; $_} $self->get($itemtoken);
 
        #print "My values of $itemtoken are '@values', id $self->{id}, type $self->{type}, expecting value $itemsubtype";
 
        #if (defined $materialtoken) {print ", material $materialtoken of type $materialsubtype";}
 
        #print "\n";
 
        if (
 
          # does the reaction require anything?
 
          ($itemsubtype ne 'NONE' and $itemsubtype ne 'NO_SUBTYPE' or defined $materialtoken and $materialtoken ne 'NONE' or defined $materialsubtype and $materialsubtype ne 'NO_SUBTYPE' and $materialsubtype ne 'NONE') and (
 
 
          # it requires something. do we match the item subtype?
 
          (@values ~~ $itemsubtype)
 
 
          # if not, do we match the material?
 
          or defined($materialtoken) and ($materialtoken eq $self->{type} or $self->get("IS_$materialtoken")) and ($materialsubtype eq 'NO_SUBTYPE' or $materialsubtype eq $self->{id}))) {
 
 
          # we're a match!
 
          $match = 1;
 
        }
 
      }
 
      if ($match) {
 
        printf "* %s\n", ucfirst scalar($reaction->get('NAME'));
 
      }
 
    }
 
  }
 
  sub print_raw {
 
    my ($self) = @_;
 
    printf "[%s]\n", $_ for @{$self->{tokens}};
 
  }
 
}
 
 
sub parsefiles {
 
  my ($expecttype, @filenames) = @_;
 
  my @objects;
 
  my %objectsbyid;
 
  for my $filename (@filenames) {
 
    my $parsed = parsefile($filename);
 
    if ($parsed->{object} ne $expecttype) {
 
      die "Expected objects of type $expecttype in $filename, got $parsed->{object}";
 
    }
 
    push @objects, @{$parsed->{objects}};
 
    %objectsbyid = (%objectsbyid, %{$parsed->{objectsbyid}});
 
  }
 
  return {objects => \@objects, objectsbyid => \%objectsbyid};
 
 
  }
 
  }
 
   
 
   
Line 291: Line 31:
 
   my $fp;
 
   my $fp;
 
   unless (open $fp, '<', $filename) {
 
   unless (open $fp, '<', $filename) {
     print STDERR "Couldn't open $filename for reading. Are you in the right directory?";
+
     die "Couldn't open $filename for reading";
    exit 1;
 
 
   }
 
   }
 +
  my $res = parsefile_ $fp, $filename;
 +
  close $fp;
 +
  $res;
 +
}
 +
 +
sub parsefile_ {
 +
  my ($fp, $filename) = @_;
 
   my $expectfilename = $filename;
 
   my $expectfilename = $filename;
 
   $expectfilename =~ s/^.*\/|\.txt$//g;
 
   $expectfilename =~ s/^.*\/|\.txt$//g;
Line 299: Line 45:
 
   $gotfilename =~ s/\r?\n?$//s;
 
   $gotfilename =~ s/\r?\n?$//s;
 
   if ($expectfilename ne $gotfilename) {
 
   if ($expectfilename ne $gotfilename) {
     print STDERR "Expected filename '$expectfilename' in $filename, got '$gotfilename' (ignoring)\n";
+
     print STDERR "Expected filename '$expectfilename' in $filename, got '$gotfilename'\n";
 
   }
 
   }
 
   local $/ = ']';
 
   local $/ = ']';
 
   my $firsttok = gettoken $fp, 1;
 
   my $firsttok = gettoken $fp, 1;
   unless ($firsttok =~ /^OBJECT:(.*)/) {
+
   if ($firsttok->[0] ne 'OBJECT') {
 
     print STDERR "Expected first token to be an OBJECT-token, got $firsttok->[0]\n";
 
     print STDERR "Expected first token to be an OBJECT-token, got $firsttok->[0]\n";
 
   }
 
   }
   my $objecttype = $1;
+
  if (!defined $firsttok->[1]) {
 +
    print STDERR "In OBJECT-token, 1st arg is undef\n";
 +
    return;
 +
  }
 +
   my $objecttype = $firsttok->[1];
 
   my $objects = [];
 
   my $objects = [];
 
   my $objectsbyid = {};
 
   my $objectsbyid = {};
 +
  my $object = {};
 
   my $res = {object => $objecttype, objects => $objects, objectsbyid => $objectsbyid};
 
   my $res = {object => $objecttype, objects => $objects, objectsbyid => $objectsbyid};
  my $objectid;
 
  my @object;
 
 
   my $pushobject = sub {
 
   my $pushobject = sub {
     if (defined $objectid) {
+
     push @$objects, $object if keys %$object;
      my $object = Object->new($objecttype, $objectid, @object);
+
    $objectsbyid->{$object->{id}} = $object if exists $object->{id};
      push @$objects, $object;
+
     $object = {};
      $objectsbyid->{$object->id()} = $object;
 
    }
 
    @object = ();
 
     $objectid = undef;
 
 
   };
 
   };
 
   my $token;
 
   my $token;
 
   while ($token = gettoken $fp and keys %$token) {
 
   while ($token = gettoken $fp and keys %$token) {
 
     last unless keys %$token;
 
     last unless keys %$token;
     next unless defined $token->{token};
+
     next unless defined $token->{key};
     $token = $token->{token};
+
     if ($token->{key} eq $objecttype) {
    if (substr($token, 0, length($objecttype)) eq $objecttype) {
 
 
       $pushobject->();
 
       $pushobject->();
       $token =~ s/[^:]*://;
+
       $object->{'id'} = $token->{value};
      $objectid = $token;
 
 
     } else {
 
     } else {
       push @object, $token;
+
       $object->{$token->{key}} = $token->{value};
 
     }
 
     }
 
   }
 
   }
 
   $pushobject->();
 
   $pushobject->();
  close $fp;
 
 
   $res;
 
   $res;
 
  }
 
  }
Line 360: Line 102:
 
   $comment =~ s/^\s+|\s+$//g;
 
   $comment =~ s/^\s+|\s+$//g;
 
   $comment = undef unless length $comment;
 
   $comment = undef unless length $comment;
   return $token if $asserttoken;
+
  my ($key, $value) = ($token);
   return {comment => $comment, token => $token};
+
  if ($token =~ /^(STATE_[^:]+:[^:]+|[^:]+)(?::(.*))/) {
 +
    ($key, $value) = ($1, $2);
 +
  }
 +
   return [$key, $value] if $asserttoken;
 +
   return {comment => $comment, key => $key, value => $value};
 
  }
 
  }
 
   
 
   
Line 369: Line 115:
 
  }
 
  }
 
   
 
   
  # at the moment only inorganics are supported
+
  my $type = 'INORGANIC';
our $type = 'INORGANIC';
+
  my $templatetype = 'MATERIAL_TEMPLATE';
  our $templatetype = 'MATERIAL_TEMPLATE';
+
  my $templateincludekey = "USE_$templatetype";
  our $templateincludekey = "USE_$templatetype";
 
 
  my $templates = parsefile 'material_template_default.txt';
 
  my $templates = parsefile 'material_template_default.txt';
 
  if ($templates->{object} ne $templatetype) {
 
  if ($templates->{object} ne $templatetype) {
 
   die "Template file contains objects of type $templates->{object}, expected $templatetype";
 
   die "Template file contains objects of type $templates->{object}, expected $templatetype";
 
  }
 
  }
  our %templates = %{$templates->{objectsbyid}};
+
  my %templates = %{$templates->{objectsbyid}};
 
   
 
   
  my $parsed = parsefiles($type, <inorganic_*.txt>);
+
  my @objects;
our @objects = @{$parsed->{objects}};
+
for my $filename (<inorganic_*.txt>) {
  our %objectsbyid = %{$parsed->{objectsbyid}};
+
  my $parsed = parsefile $filename;
   
+
  if ($parsed->{object} ne $type) {
  our $reactions = parsefiles('REACTION', <reaction_*.txt>);
+
    die "Expected objects of type $type in $filename, got $parsed->{object}";
 +
  }
 +
  push @objects, @{$parsed->{objects}};
 +
  }
 +
fetchtemplates for @objects;
 +
sub fetchtemplates (_) {
 +
  my ($obj) = @_;
 +
  my $id = $obj->{id};
 +
  return unless defined $obj->{$templateincludekey};
 +
  my $templatename = $obj->{$templateincludekey};
 +
  my $template = $templates{$templatename};
 +
  unless (defined $template) {
 +
    print STDERR "Object $id references a template called $templatename, but it doesn't exist!\n";
 +
    return;
 +
  }
 +
  delete $obj->{$templateincludekey};
 +
  for my $key (keys %$template) {
 +
    $obj->{$key} //= $template->{$key};
 +
  }
 +
  }
 +
  fixstatenames for @objects;
 +
sub fixstatenames (_) {
 +
  my ($obj) = @_;
 +
  if (($obj->{IS_GEM} // '') =~ /^([^:]+):[^:]+:OVERWRITE_SOLID/) {
 +
    my $name = $1;
 +
    $obj->{'STATE_NAME_ADJ:ALL_SOLID'} = $name;
 +
  }
 +
  for my $key (keys %$obj) {
 +
    next unless $key =~ /^STATE_([^:]+_[^:]+):(.*)/;
 +
    my $states = $1;
 +
    my $subkey = $2;
 +
    my $value = $obj->{$key};
 +
    while ($states =~ /([^_]+)/g) {
 +
      $obj->{"STATE_${1}:$subkey"} = $value;
 +
    }
 +
  }
 +
  for my $key (keys %$obj) {
 +
    next unless $key =~ /^(STATE_[^:]+:)ALL_SOLID/;
 +
    my $prefix = $1;
 +
    my $value = $obj->{$key};
 +
    $obj->{$prefix.'SOLID'} = $value;
 +
    $obj->{$prefix.'SOLID_POWDER'} = $value;
 +
  }
 +
}
 
   
 
   
 +
my %objectsbytype;
 +
for my $obj (@objects) {
 +
  my @keys = grep {/^IS_/ or !defined $obj->{$_}} keys %$obj;
 +
  for my $key (@keys) {
 +
    $objectsbytype{$key} //= [];
 +
    push @{$objectsbytype{$key}}, $obj;
 +
  }
 +
}
 
  sub tabstops {
 
  sub tabstops {
 
   my ($line) = @_;
 
   my ($line) = @_;
Line 393: Line 189:
 
   $line.$suffix;
 
   $line.$suffix;
 
  }
 
  }
  sub find_object {
+
  if (@ARGV == 0) {
   my ($name) = @_;
+
   for my $key (sort {@{$objectsbytype{$b}}-@{$objectsbytype{$a}}} keys %objectsbytype) {
  if (exists $objectsbyid{$name}) {
+
     print tabstops(sprintf "%-30s %3d\n", $key, scalar @{$objectsbytype{$key}});
    $objectsbyid{$name}->print;
 
  } elsif (exists $objectsbyid{uc $name}) {
 
     $objectsbyid{uc $name}->print;
 
  } else {
 
    for my $obj (@objects) {
 
      if (lc($obj->name) eq lc($name)) {
 
        $obj->print;
 
        return 1;
 
      }
 
    }
 
 
   }
 
   }
  0;
+
  } else {
  }
+
   for my $key (@ARGV) {
 
sub find_by_key {
 
  my @keys = @_;
 
  my %objectsbytype;
 
   for my $obj (@objects) {
 
    for my $key (@keys) {
 
      my @vals = $obj->get($key);
 
      next unless @vals;
 
      $objectsbytype{$key} //= [];
 
      push @{$objectsbytype{$key}}, $obj;
 
    }
 
  }
 
  return 0 unless keys %objectsbytype;
 
  for my $key (keys %objectsbytype) {
 
 
     print "$key\n";
 
     print "$key\n";
 
     my @rows;
 
     my @rows;
    my $boolean = 0;
 
    my $numeric = 1;
 
 
     for my $obj (@{$objectsbytype{$key}}) {
 
     for my $obj (@{$objectsbytype{$key}}) {
       my @row = ($obj->name);
+
       my @row = ($obj->{'STATE_NAME:SOLID'} // $obj->{'id'});
 
       for (qw(MATERIAL_VALUE MOLAR_MASS)) {
 
       for (qw(MATERIAL_VALUE MOLAR_MASS)) {
         push @row, scalar($obj->get($_)) // 0;
+
         push @row, $obj->{$_} // 0;
      }
 
      my $val = $obj->get($key);
 
      if (defined $val) {
 
        push @row, $val;
 
        $numeric = 0 if $numeric and $val =~ /\D/;
 
      } else {
 
        push @row, '';
 
        $boolean = 1;
 
 
       }
 
       }
 
       push @rows, \@row;
 
       push @rows, \@row;
 
     }
 
     }
     if ($boolean) {
+
     for my $row (sort {$a->[0] cmp $b->[0]} @rows) {
      @rows = sort {$a->[0] cmp $b->[0]} @rows;
+
       print tabstops(sprintf "  %-26s %6d %10d\n", @$row);
    } elsif ($numeric) {
 
      @rows = sort {$a->[3] <=> $b->[3]} @rows;
 
    } else {
 
      @rows = sort {$a->[3] cmp $b->[3]} @rows;
 
    }
 
    for my $row (@rows) {
 
       print tabstops(sprintf "  %-26s %6d %10d %s\n", @$row);
 
    }
 
  }
 
  1;
 
}
 
if (@ARGV == 0) {
 
  my %booleankeys;
 
  for my $obj (@objects) {
 
    my @keys = grep {/^IS_|^[^:]+$/} @{$obj->{tokens}};
 
    for my $key (@keys) {
 
      $key =~ s/:.*//g;
 
      $booleankeys{$key} //= 0;
 
      ++$booleankeys{$key};
 
 
     }
 
     }
 
   }
 
   }
  for my $key (sort {$booleankeys{$b}-$booleankeys{$a}} keys %booleankeys) {
 
    print tabstops(sprintf "%-30s %3d\n", $key, $booleankeys{$key});
 
  }
 
} elsif (@ARGV == 1 and $ARGV[0] eq '--all') {
 
  my %keys = ();
 
  for my $obj (@objects) {
 
    for my $token (@{$obj->{tokens}}) {
 
      while ($token =~ /:/g) {
 
        my $key = substr($token, 0, $-[0]);
 
        $keys{$key} //= 0;
 
        ++$keys{$key};
 
      }
 
      $keys{$token} //= 0;
 
      ++$keys{$token};
 
    }
 
  }
 
  my @keys = grep {/:[^:]*[^:\d][^:]*$/ and ($keys{$_} > 1 or !/:/)} keys %keys;
 
  {
 
    local $, = ', ';
 
    local $\ = "\n";
 
    print map {"$_ ($keys{$_})"} sort {$keys{$b}-$keys{$a}} @keys;
 
  }
 
} else {
 
  exit if find_object "@ARGV";
 
  exit if map {find_object($_) ? (1) : ()} @ARGV;
 
  exit if find_by_key @ARGV;
 
  print STDERR "I couldn't understand that.\n";
 
  usage;
 
  exit 1;
 
 
  }
 
  }

Please note that all contributions to Dwarf Fortress Wiki are considered to be released under the GFDL & MIT (see Dwarf Fortress Wiki:Copyrights for details). If you do not want your writing to be edited mercilessly and redistributed at will, then do not submit it here.
You are also promising us that you wrote this yourself, or copied it from a public domain or similar free resource. Do not submit copyrighted work without permission!

To protect the wiki against automated edit spam, we kindly ask you to solve the following CAPTCHA:

Cancel Editing help (opens in new window)