changeset 187:18b142c83761 misc

Some major refactoring, added code for parsing 'identify' spell output (and other related data) to produce Item/Weapon/Armour templates.
author Matti Hamalainen <ccr@tnsp.org>
date Mon, 24 Jan 2011 18:45:09 +0200
parents e23ea99e7aa8
children 31ac75a88dee
files log2npctemplate.pl
diffstat 1 files changed, 396 insertions(+), 94 deletions(-) [+]
line wrap: on
line diff
--- a/log2npctemplate.pl	Mon Jan 17 21:14:36 2011 +0200
+++ b/log2npctemplate.pl	Mon Jan 24 18:45:09 2011 +0200
@@ -15,6 +15,8 @@
 # 5) Fight and kill monster.
 # 6) run log2npctemplate.pl < logfile.log > output.txt
 #
+# 7) command id 
+#
 # Notes
 # =====
 # - You must have spellname translator, preferably one with format:
@@ -31,6 +33,8 @@
 my $opt_debug = 0;	# 1 = enable debug output
 my $opt_pkills_crop = 60;
 my $opt_outfile;
+my $opt_identify = 1;
+my $opt_npc = 1;
 
 
 # Define the regular expression to match any outputs of "say"
@@ -65,11 +69,26 @@
 );
 
 
+# Stat name translations
+my @statTransTable = (
+  sub { return $_[0] =~ s/^ability at the (skill|spell) (.+)$/$2/ },
+  sub { return $_[0] =~ s/^mental regeneration$/spr/g },
+  sub { return $_[0] =~ s/^physical regeneration$/hpr/g },
+#  sub { return $_[0] =~ s///g },
+);
+
+
 ### Options
 while (defined(my $arg = shift)) {
   if ($arg eq "-d") {
     $opt_debug++;
   }
+  elsif ($arg eq "-i") {
+    $opt_identify = 0;
+  }
+  elsif ($arg eq "-n") {
+    $opt_npc = 0;
+  }
   elsif ($arg eq "-o") {
     $opt_outfile = shift or die("Output file option -o requires an argument.\n");
   }
@@ -79,6 +98,8 @@
 
     -o <filename>         Output filename.
     -d                    Enable debug mode.
+    -i                    Disable identify parser.
+    -n                    Disable NPC parser.
 
 ");
   }
@@ -91,25 +112,42 @@
 }
 
 
+### Translate stats
+sub trans_stat($)
+{
+  my ($s) = @_;
+  foreach my $pat (@statTransTable) {
+    return $s if ($pat->($s));
+  }  
+  return $s;
+}
+
+
 ### Globals
 my %monsters = ();
 my %aligns = ();
 my %spells = ();
 my %races = ();
 my %areas = ();
+my %ids = ();
 
 my $line = 0;
-my ($mob_sname, $mob_sdesc, $mob_ldesc, $mob_area, $mob_cont, $mob_line);
-my $mob_eqs = { };
+
+my $mob_sdesc;
+my $mob = { };
 my $state = 0;
 
+my $id_tale;
+my $id_tale2;
+my $id = {};
 
-### Convert spellchants array
+
+### Convert spellchants array to regexp
 my $spellregexps = join("|", map { s/ (his|its|her) / ... /g; $_ } @spellchants);
 
 
 ### Change parsing state
-sub setstate($$)
+sub set_state($$)
 {
   return unless ($_[0] != $state);
   print STDERR "STATE = $_[0], old = $state\n" if ($opt_debug > 1);
@@ -121,6 +159,250 @@
 }
 
 
+sub parse_npc($)
+{
+  my ($s) = @_;
+  
+  if ($state == 1) {
+    if ($s =~ /^You prod (.+?) like a stray cow\.$/o) {
+      # Get 'short name'
+      $$mob{"sname"} = $1;
+    } elsif ($s =~ /^You are in '.*?' in (.+?) on the continent of ([A-Z][a-z]+). \(Coordinates: (\d+)x, (\d+)y\)$/o) {
+      # Area, continent
+      $$mob{"area"} = $1;
+      $$mob{"cont"} = $2;
+
+      $areas{$1}{"cont"} = $2;
+      $areas{$1}{"x"} = $3;
+      $areas{$1}{"y"} = $4;
+    } elsif ($s =~ /^You are in '.*?', which is on the continent of ([A-Z][a-z]+). \(Coordinates: (\d)+x, (\d)+y\)$/o) {
+      # Area, continent
+      $$mob{"area"} = $1;
+      $$mob{"cont"} = $1;
+
+      $areas{$1}{"cont"} = $1;
+      $areas{$1}{"x"} = $2;
+      $areas{$1}{"y"} = $3;
+    } elsif ($s =~ /^You $sayregex '(-\?\?-|--\?\?--\?\?--\?\?--\?\?--)\.'$/o) {
+      set_state(2, $s);
+    } else {
+      set_state(-1, $s);
+    }
+  }
+  elsif ($state == 2) {
+    # Mostly just grab shortdesc here
+    if ($s =~ /^You $sayregex '(-==-|-=-=-=-=-=-=-=-=-)\.'$/o) {
+      set_state(3, $s);
+    } elsif ($s =~ /^(He|She|It) +\[[a-z]+\] \([0-9-]+\%\)/o) {
+      set_state(-1, $s);
+    } elsif ($s =~ /^You $sayregex /o) {
+      set_state(-1, $s);
+    } else {
+      $mob_sdesc = $s;
+    }
+  }
+  elsif ($state == 3) {
+    if ($s =~ /^ +([a-zA-Z ,-]+?)'s equipment:$/o) {
+      # End of long desc
+      set_state(4, $s);
+    } elsif ($s =~ /^(He|She|It) +\[[a-z]+\] \([0-9-]+\%\)$/o ||
+      $s =~ /^(He|She|It) is (in (a )?)?(excellent shape|good shape|slightly hurt|noticeably hurt|not in a good shape|bad shape|very bad shape|near death)/o) {
+      # End of long desc
+      set_state(4, $s);
+    } elsif ($s =~ /^You $sayregex /o) {
+      set_state(-1, $s);
+    } else {
+      # Collect long desc
+      $$mob{"ldesc"} .= $s." ";
+    }
+  }
+  elsif ($state == 4) {
+    if ($s =~ /^You $sayregex '====*'?\.'$/o) {
+      # Finished, submit information to hash
+      $monsters{$mob_sdesc} = $mob;
+      set_state(0, $s);
+    } elsif ($s =~ /^([A-Z][a-z, ]+): (.*)$/o) {
+      # Collect EQ and slot information
+      $$mob{"eqs"}{$1} = $2;
+    } elsif ($s =~ /^([A-Z][a-z, ]+)\s+\(partially hidden\)\s*: (.*)$/o) {
+      # Collect EQ and slot information
+      $$mob{"eqs"}{$1} = $2;
+    } elsif ($s =~ /^ +([a-zA-Z -]+?)'s equipment:$/o) {
+      # Ignore this line
+    } elsif ($s =~ /^((It|She|He) has a blueish black kiss on ... cheek\.|(It|She|He) suffers from scourge\.|Some glittering red mist is surrounding this creature.|Nothing\.|(It|He|She) has a faint ring of .+ magic mist around ... neck\.)$/o) {
+      # Ignore various useless lines such as holz markings
+    } else {
+      # Error.
+      set_state(-1, $s);
+    }
+  }
+}
+
+
+sub parse_identify($)
+{
+  my ($s) = @_;
+  
+  if ($state == 10) {
+    if ($s =~ /^You $sayregex '-#-\.'$/o) {
+      set_state(11, $s);
+    }
+    elsif ($s =~ /^:\s*(\d+\.\d+)\s+(.+)$/) {
+      # Weigh in kgs, and sdesc. Will have to match these later.
+      $$id{"kg"}{$2} = $1;
+      $$id{"full"} = $2;
+    }
+  }
+  elsif ($state == 11) {
+    if ($s =~ /^It is surrounded by .+? glow\.$|^It is labeled as|^This item is a present from santa to /) {
+      # Just skip these
+    }
+    elsif ($s =~ /You $sayregex '-!-\.'$/o) {
+      set_state(12, $s);
+    }
+    elsif ($s =~ /^It contains a tale;$/) {
+      $id_tale = 1;
+    }
+    elsif ($s =~ /^This (.+?) is in .+? condition\.$/) {
+      $$id{"type"} = $1;
+    }
+    elsif ($s =~ /^These (.+?) are in .+? condition\.$/) {
+      $$id{"type"} = $1;
+    }
+    elsif ($s =~ /^It looks (light weight|a bit heavy|heavy|very very heavy|very light weight|very heavy|ridiculously heavy)\.$/) {
+      $$id{"weight"} = $1;
+    }
+    else {
+      if ($id_tale) {
+        $$id{"tale"} .= $s." ";
+      } else {
+        my $len = length($s);
+        $$id{"ldesc"} .= $s;
+        if (defined($$id{"len"}) && $len + $$id{"len"} < 79) {
+          $$id{"ldesc"} .= "\n";
+        } else  {
+          $$id{"ldesc"} .= " ";
+        }
+        $$id{"len"} = $len;
+      }
+    }
+  }
+  elsif ($state == 12) {
+    if ($s =~ /^The following messages seem to vibrate from (.+?):$/o) {
+      $$id{"sdesc"} = $1;
+      set_state(13, $s);
+    }
+  }
+  elsif ($state == 13) {
+    if ($s =~ /^It is called (.+)\.$/) {
+      $$id{"handles"} = $1;
+      $id_tale2 = 0;
+    }
+    elsif ($s =~ /^It takes the following slots: (.+)\.$/) {
+      $$id{"slots"} = $1;
+      $id_tale2 = 0;
+    }
+    elsif ($s =~ /^A halo of purity surrounds it\.$/) {
+      push(@{$$id{"stats"}}, "[[:category:halo of purity|good wear only]]");
+      $$id{"cat"}{"halo of purity"} = 1;
+      $id_tale2 = 0;
+    }
+    elsif ($s =~ /^An aura of blackness surrounds it\.$/) {
+      push(@{$$id{"stats"}}, "[[:category:aura of darkness|evil wear only]]");
+      $$id{"cat"}{"aura of darkness"} = 1;
+      $id_tale2 = 0;
+    }
+    elsif ($s =~ /^It will (.+?) (improve|reduce) your (.+?)\.$/) {
+      my ($amt, $imp, $stat) = ($1, $2, $3);
+      push(@{$$id{"stats"}}, ($imp eq "improve" ? "+" : "-").$amt." ".trans_stat($stat));
+      $$id{"cat"}{trans_stat($stat)} = 1 if ($imp eq "improve");
+      $id_tale2 = 0;
+    }
+    elsif ($s =~ /^It will (raise|lower) your (.+?)\.$/) {
+      my $imp = $1;
+      my $stat = substr($2, 0, 3);
+      push(@{$$id{"stats"}}, ($imp eq "raise" ? "+" : "-").$stat);
+      $$id{"cat"}{$stat} = 1 if ($imp eq "raise");
+      $id_tale2 = 0;
+    }
+    elsif ($s =~ /^It contains a tale;$/) {
+      $id_tale2 = 1;
+    }
+    elsif ($s =~ /^(.+?) did the heroic deed to bring this piece of equipment before you (.+)$/) {
+      my $info = $2;
+      $$id{""} = "";
+      
+      # Parse the big data blob
+      if ($info =~ /It is ([A-Za-z -]+), ([A-Za-z -]+),/) {
+        $$id{"weight2"} = $1;
+        $$id{"size"} = $2;
+      }
+      
+      if ($info =~ /of ([A-Za-z ]+) quality/) {
+        $$id{"quality"} = $1;
+      }
+      
+      if ($info =~ /(emits darkness|emits light)/) {
+        push(@{$$id{"stats"}}, $1);
+        $$id{"cat"}{$1} = 1;
+      }
+      
+      if ($info =~ /made of,? ?(.+?), (feather|worth)/) {
+        @{$$id{"materials"}} = split(/\s*,\s*/, $1);
+        my $qmat = $$id{"materials"}[0];
+        my $qmax = -1;
+        foreach my $mat (@{$$id{"materials"}}) {
+          if ($mat =~ /^(\d+)% (.+)$/) {
+            if ($1 >= $qmax) {
+              $qmax = $1;
+              $qmat = $2;
+            }
+          }
+        }
+        $$id{"material"} = $qmat;
+        $$id{"cat"}{$qmat} = 1;
+      }
+      
+      # Check for nun relics
+      if ($$id{"full"} =~ / \(holy\)/) {
+        $$id{"cat"}{"relic"} = 1;
+      }
+      
+      # Set item class
+      $$id{"class"} = "Item";
+      if ($info =~ /The weapon skill to best use this in combat/) {
+        $$id{"class"} = "Weapon";
+      } elsif (defined($$id{"type"}) && $$id{"type"} ne "") {
+        $$id{"class"} = "Armour";
+      }
+      
+      # Check if the weight data is for FW'd item
+      if ($$id{"full"} =~ / <(yellow|green|white) glow>$/) {
+        $$id{"kg"} = "";
+        $$id{"weight"} = "";
+      } else {
+        if (defined($$id{"kg"}{$$id{"full"}})) {
+          $$id{"kg"} = $$id{"kg"}{$$id{"full"}};
+        } else {
+          $$id{"kg"} = "";
+        }
+      }
+      
+      # Submit data
+      $ids{$$id{"full"}} = $id;
+      set_state(0, $s);
+    }
+    else {
+      if ($id_tale2) {
+        $$id{"tale"} .= $s." ";
+      } else {
+        push(@{$$id{"other"}}, $s);
+      }
+    }
+  }
+}
+
+
 ###
 ### Main parsing loop
 ###
@@ -136,7 +418,8 @@
   {
     # Grab cast spells
     $spells{$1}{$line} = lc($3);
-  } elsif ($s =~ /\| \d\d:\d\d +(\d+): (.+?) +\|$/) {
+  }
+  elsif ($s =~ /\| \d\d:\d\d +(\d+): (.+?) +\|$/) {
     # Grab exp worth
     my $exp = $1;
     my $tmp = $2;
@@ -150,105 +433,124 @@
         $monsters{$sdesc}{"exp"} = $exp;
       }
     }
-  } elsif ($s =~ /^\[\d\d:\d\d:\d\d\] hp/ || $s =~ /^You laugh out loud\.$/) {
-    # Ignore
-  } elsif ($s =~ /^You see nothing special\.$/o) {
-    setstate(0, $s);
-  } elsif ($state == 0 && $s =~ /^You $sayregex '-+ .+? -+\.'$/o) {
-    setstate(1, $s);
-    $mob_sname = "";
+  }
+  elsif ($s =~ /^\[\d\d:\d\d:\d\d\] hp|^You laugh out loud\.$|^Dunk dunk$/) {
+    # Ignore these lines
+  }
+  elsif ($s =~ /^You see nothing special\.$/o) {
+    # Reset parsing state if the target obviously didn't exist
+    set_state(0, $s);
+  }
+  elsif ($state == 0 && $s =~ /^You $sayregex '-+ .+? -+\.'$/o) {
+    next unless ($opt_npc);
+    # Beginning of NPC info block
+    set_state(1, $s);
+    undef($mob);
     $mob_sdesc = "";
-    $mob_ldesc = "";
-    $mob_area = "";
-    $mob_cont = "";
-    $mob_line = $line;
-    undef($mob_eqs);
-  } elsif ($state == 1) {
-    if ($s =~ /^You prod (.+?) like a stray cow\.$/o) {
-      # Get 'short name'
-      $mob_sname = $1;
-    } elsif ($s =~ /^You are in '.*?' in (.+?) on the continent of ([A-Z][a-z]+). \(Coordinates: (\d+)x, (\d+)y\)$/o) {
-      # Area, continent
-      $mob_area = $1;
-      $mob_cont = $2;
-
-      $areas{$1}{"cont"} = $2;
-      $areas{$1}{"x"} = $3;
-      $areas{$1}{"y"} = $4;
-    } elsif ($s =~ /^You are in '.*?', which is on the continent of ([A-Z][a-z]+). \(Coordinates: (\d)+x, (\d)+y\)$/o) {
-      # Area, continent
-      $mob_area = $1;
-      $mob_cont = $1;
-
-      $areas{$1}{"cont"} = $1;
-      $areas{$1}{"x"} = $2;
-      $areas{$1}{"y"} = $3;
-    } elsif ($s =~ /^You $sayregex '(-\?\?-|--\?\?--\?\?--\?\?--\?\?--)\.'$/o) {
-      setstate(2, $s);
-    } else {
-      setstate(-1, $s);
-    }
-  } elsif ($state == 2) {
-    if ($s =~ /^You $sayregex '(-==-|-=-=-=-=-=-=-=-=-)\.'$/o) {
-      setstate(3, $s);
-    } elsif ($s =~ /^(He|She|It) +\[[a-z]+\] \([0-9-]+\%\)/o) {
-      setstate(-1, $s);
-    } elsif ($s =~ /^You $sayregex /o) {
-      setstate(-1, $s);
-    } else {
-      $mob_sdesc = $s;
-    }
-  } elsif ($state == 3) {
-    if ($s =~ /^ +([a-zA-Z ,-]+?)'s equipment:$/o) {
-      # End of long desc
-      setstate(4, $s);
-    } elsif ($s =~ /^(He|She|It) +\[[a-z]+\] \([0-9-]+\%\)$/o ||
-      $s =~ /^(He|She|It) is (in (a )?)?(excellent shape|good shape|slightly hurt|noticeably hurt|not in a good shape|bad shape|very bad shape|near death)/o) {
-      # End of long desc
-      setstate(4, $s);
-    } elsif ($s =~ /^You $sayregex /o) {
-      setstate(-1, $s);
-    } else {
-      # Collect long desc
-      $mob_ldesc .= $s." ";
-    }
-  } elsif ($state == 4) {
-    if ($s =~ /^You $sayregex '====*'?\.'$/o) {
-      # Finished, submit information to hash
-      $monsters{$mob_sdesc}{"line"} = $mob_line;
-      $monsters{$mob_sdesc}{"eqs"} = $mob_eqs;
-      $monsters{$mob_sdesc}{"sname"} = $mob_sname;
-      $monsters{$mob_sdesc}{"ldesc"} = $mob_ldesc;
-      $monsters{$mob_sdesc}{"area"} = $mob_area;
-      $monsters{$mob_sdesc}{"cont"} = $mob_cont;
-      setstate(0, $s);
-    } elsif ($s =~ /^([A-Z][a-z, ]+): (.*)$/o) {
-      # Collect EQ and slot information
-      $mob_eqs->{$1} = $2;
-    } elsif ($s =~ /^([A-Z][a-z, ]+)\s+\(partially hidden\)\s*: (.*)$/o) {
-      # Collect EQ and slot information
-      $mob_eqs->{$1} = $2;
-    } elsif ($s =~ /^ +([a-zA-Z -]+?)'s equipment:$/o) {
-      # Ignore this line
-    } elsif ($s =~ /^((It|She|He) has a blueish black kiss on ... cheek\.|(It|She|He) suffers from scourge\.|Some glittering red mist is surrounding this creature.|Nothing\.|(It|He|She) has a faint ring of .+ magic mist around ... neck\.)$/o) {
-      # Ignore various useless lines such as holz markings
-    } else {
-      setstate(-1, $s);
-    }
-  } elsif ($s =~ /^(.+?) is (a bit good|a bit evil|evil|good|neutral)\.$/o) {
+    $$mob{"line"} = $line;
+  }
+  elsif ($state == 0 && $s =~ /^You $sayregex '-ID-\.'$/o) {
+    next unless ($opt_identify);
+    # Beginning of identify info block
+    set_state(10, $s);
+    $id = {};
+    undef($id);
+    $id_tale = 0;
+    $id_tale2 = 0;
+    $$id{"line"} = $line;
+  }
+  elsif ($state > 0 && $state < 10) {
+    # States for NPC parsing
+    parse_npc($s);
+  }
+  elsif ($state >= 10) {
+    parse_identify($s);
+  }
+  elsif ($s =~ /^(.+?) is (a bit good|a bit evil|evil|good|neutral)\.$/o) {
     # Grab detect alignment
     $aligns{$1}{$line} = $2;
-  } elsif ($s =~ /^([A-Za-z][A-Za-z\ .-]+?)\ is an? ([a-z-]+)\.$/o) {
+  }
+  elsif ($s =~ /^([A-Za-z][A-Za-z\ .-]+?)\ is an? ([a-z-]+)\.$/o) {
     # Grab detect race
     $races{$1}{$line} = $2;
-  } elsif ($s =~ /^You $sayregex /o) {
-    setstate(0, $s);
+  }
+  elsif ($s =~ /^You $sayregex /o) {
+    # Error, reset parsing state
+    set_state(0, $s);
   }
 }
 
 
 ###
-### Print out the NPO information
+### Print out item/identify information
+###
+foreach my $sdesc (sort { $a cmp $b } keys %ids) {
+  my $item = $ids{$sdesc};
+  my $name = $$item{"sdesc"};
+  $name =~ s/ labeled as .*$//;
+  my $qdesc = $name;
+  if ($$item{"full"} =~ / <(red|purple|white) glow>$/) {
+    $name .= " <red glow>";
+  }
+
+  print "---------------------------\n".
+  $qdesc."\n\n".
+  "{{ Infobox ".$$item{"class"}."\n".
+  "| name = ".$name."\n".
+  "| description = ".$$item{"ldesc"}."\n";
+
+  if (defined($$item{"tale"}) && $$item{"tale"} ne "") {
+    print "| tale = ".$$item{"tale"}."\n";
+  }
+
+  if (defined($$item{"type"})) {
+    print "| type = ".$$item{"type"}."\n";
+  }
+
+  if (defined($$item{"stats"})) {
+    print "| stats = ".join(", ", @{$$item{"stats"}})."\n";
+  } else {
+    print "| stats = \n";
+  }
+
+  print
+  "| weight = ".$$item{"weight"}."\n".
+  "| kg = ".$$item{"kg"}."\n".
+  "| sacvalue = \n".
+  "| handles = ".$$item{"handles"}."\n";
+  
+  if (defined($$item{"materials"})) {
+    print "| material = ".join(", ", @{$$item{"materials"}})."\n";
+  }
+
+  print
+  "| size = ".$$item{"size"}."\n".
+  "| quality = ".$$item{"quality"}."\n".
+  "| from = \n";
+
+  if ($$item{"class"} eq "Weapon") {
+    print
+    "| wep1 = \n".
+    "| wep2 = \n";
+  }
+
+  if (defined($$item{"other"})) {
+    print "| other = ".join("\n", @{$$item{"other"}})."\n";
+  }
+
+  print
+  "}}\n";
+
+  foreach my $cat (keys %{$$item{"cat"}}) {
+    print "[[Category:$cat]]\n";
+  }
+
+  print "---------------------\n";
+}
+
+
+###
+### Print out the NPC information
 ###
 foreach my $sdesc (sort { $a cmp $b } keys %monsters) {
   my $mob = $monsters{$sdesc};