Advertisement
Kylroi

15th wowhead NPC to TDB 4.3.4 - 2015-08-11

Nov 19th, 2013
262
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
Perl 9.84 KB | None | 0 0
  1. #!/usr/bin/perl
  2. # adjust path to fit your host
  3.  
  4. # NOT INTENDED FOR UNEDITED IMPORTING TO DATABASE
  5.  
  6. # This script does NOT import NPC location data or create NPC entries
  7. # Only vendor, training, and skinning/mining loot are extracted
  8.  
  9. # Fourteenth generation NPC scanner
  10. # Designed for use with Trinity DB 4.3.4
  11. # Other DB formats should be easily implemented
  12.  
  13. # Output sorted in ascending order (lowest value first)
  14. # Output is NOT sent to a file. Redirect output as desired.
  15.  
  16. # usage:
  17. #        npc.pl                       (takes input from STDIN, aka piped stream)
  18. #        npc.pl npc#                  (reads the specified NPC from www.wowhead.com)
  19. #        npc.pl startnpc endnpc       (reads the given range of NPCs from www.wowhead.com)
  20. #        npc.pl startnpc endnpc delay (reads the given range of NPCs from www.wowhead.com and
  21. #                                      pauses for "delay" seconds between each read)
  22.  
  23. # Generation history:
  24. #      First: basic npc_vendor query generation
  25. #     Second: added sorting of items by ilvl
  26. #      Third: add npc_trainer query generation
  27. #      Forth: minor code changes, added ExtendedCost gathering for vendors
  28. #      Fifth: added item ID as secondary sort criteria for item sorting
  29. #      Sixth: updated filter to remove "sourcemore" sub-field which broke vendlist() operation
  30. #             previous filter was only filtering the tail end of this sub-field
  31. #    Seventh: added conditional for header display so only 1 header printed
  32. #             also changed header format
  33. #     Eighth: changed to an updated "sourcemore" (sub-group in the wowhead item entry) filter
  34. #      Ninth: changed filter from "sourcemore" to "sourcemore"|"modelviewer" to strip both sub-groups
  35. #             replaced split function with a regex method for splitting the items up
  36. #             altered comment header format
  37. #      Tenth: streamlined code for item data output
  38. #             added notice to check for extended cost value (from ItemExtendedCost.dbc)
  39. #             added additional output to help identify the `ExtendedCost` value
  40. #   Eleventh: added mining/skinning loot processing
  41. #    Twelfth: relocated ExtendedCost comments
  42. #             added `reqlevel` support for trainer lists
  43. #             tweaked a few print statements
  44. # Thirteenth: added support for user specified sleep period (in seconds) between Wowhead reads
  45. # Fourteenth: removed spacing between values in generated SQL output (Trinity preferred format)
  46. #  Fifteenth: updated regex for current (for August 11 of 2015) wowhead page structure
  47.  
  48. use warnings;
  49. use strict;
  50. use LWP::Simple;
  51. use constant { true => 1, false => 0 };
  52.  
  53. my $currentNPC;
  54. my $page;
  55. my $line;
  56. my @lines;
  57. my $NPCname;
  58. my $NPCid;
  59. my $head = false;
  60.  
  61. # item level then id sort order
  62. sub itemcmp {
  63.   $a =~ /^.*\,\"level\":(\d+)\,/;
  64.   my $x = $1;
  65.   $a =~ /^.*\"id\":(.+?)\,/;
  66.   my $xx = $1;
  67.   $b =~ /^.*\,\"level\":(\d+)\,/;
  68.   my $y = $1;
  69.   $b =~ /^.*\"id\":(.+?)\,/;
  70.   my $yy = $1;
  71.   if ($x eq $y) {
  72.     return ($xx <=> $yy);
  73.   } else {
  74.     return ($x <=> $y);
  75.   }
  76. }
  77.  
  78. # build MySQL queries
  79. sub vendlist {
  80.   my ($npc, $items) = @_;
  81.   my $slot = 1;
  82.   my $extcost;
  83.   my $extcostamt;
  84.   my $extcosttype;
  85.   $items =~ s/\,\"sourcemore\":\[.+?\]\,|\,\"modelviewer\":\{.+?\}\,/\,/g;
  86.   my @itemlist = ($items =~ m/\"classs\".+?\}/g);
  87.   @itemlist = sort itemcmp @itemlist;
  88.   print "-- CHECK FOR ItemExtendedCost.dbc LOOKUP REQUIREMENT\n" x 4, "\n";
  89.   print "DELETE FROM `npc_vendor` WHERE `entry`=$npc;\n";
  90.   print "INSERT INTO `npc_vendor` (`entry`,`slot`,`item`,`maxcount`,`incrtime`,`ExtendedCost`,`type`) VALUES\n";
  91.   foreach my $itemdata (@itemlist) {
  92.     $extcost = 0;
  93. # extended cost match pattern for currency and/or item: \,cost:\[0\,\[(\[(.+?)\,(.+?)\])?\]\,\[(\[(.+?)\,(.+?)\])?\]\]
  94.     if ($itemdata =~ /\,cost:\[0\,\[\[(.+?)\,(.+?)\]\]\,\[\]\]/) {
  95. # extended cost is the specified amount of a given points id
  96.       $extcost = $1;
  97.       $extcostamt = $2;
  98.       $extcosttype = "points id";
  99.     } elsif ($itemdata =~ /\,cost:\[0\,\[\]\,\[\[(.+?)\,(.+?)\]\]\]/) {
  100. # extended cost is the specified number of a given item id
  101.       $extcost = $1;
  102.       $extcostamt = $2;
  103.       $extcosttype = "item id";
  104.     }
  105.     $itemdata =~ /^.*id\":(.+?)\,\"level\":(.+?)\,\"name\":\"(.+?)\".*\,avail:(.+?)\,/;    
  106.     my $itemid = $1;
  107.     my $itemlvl = $2;
  108.     my $itemname = $3;
  109.     my $itemavail = $4;
  110.     if ($itemname =~ /^[+-]?\d/) {
  111.       $itemname =~ s/^.//;
  112.     }
  113.     print "\t($npc,$slot,$itemid,";
  114. # `incrtime` = how often to restock vendor, timer based on seconds (900 = 15 minutes)
  115.     print $itemavail > 0 ? "$itemavail,900" : "0,0";
  116.     print $extcost > 0 ? ", ItemExtendedCost [$extcosttype:$extcost / amount:$extcostamt]" : ",0";
  117.     print ",1)", ($slot < scalar(@itemlist)) ? "," : ";", " -- $itemname (ilvl $itemlvl)\n";
  118.     $slot++;
  119.   }
  120.   print "\n";
  121. }
  122.  
  123. # required skill sort
  124. sub skcmp {
  125.   $a =~ /^.*\,\"learnedat\":(\d+)\,/;
  126.   my $x = $1;
  127.   $b =~ /^.*\,\"learnedat\":(\d+)\,/;
  128.   my $y = $1;
  129.   return ($x <=> $y);
  130. }
  131.  
  132. # build MySQL queries
  133. sub trainlist {
  134.   my ($npc, $spells) = @_;
  135.   my $slot = 1;
  136. # shouldn't need the filter here, but we'll have it as a precaution
  137.   $spells =~ s/\,\"sourcemore\":\[.+?\]\,|\,\"modelviewer\":\{.+?\}\,/\,/g;
  138.   my @spellarr = ($spells =~ m/\{.+?\}/g);
  139.   @spellarr = sort skcmp @spellarr;
  140.   print "DELETE FROM `npc_trainer` WHERE `entry`=$npc;\n";
  141.   print "INSERT INTO `npc_trainer` (`entry`,`spell`,`spellcost`,`reqskill`,`reqskillvalue`,`reqlevel`) VALUES\n";
  142.   foreach my $data (@spellarr) {
  143.     $data =~ /^.*id\":(.+?)\,\"learnedat\":(\d+)\,\"level\":(\d+),\"name\":\"(.+?)\".*\,\"skill\":\[(\d+)\].*\,\"trainingcost\":(\d+)/;
  144.     my $spell = $1;
  145.     my $learned = $2;
  146.     my $reqlevel = $3;
  147.     my $name = $4;
  148.     my $skill = $5;
  149.     my $cost = $6;
  150.     if (($name =~ /^[+-]?\d/) || ($name =~ /^@?/)) {
  151.       $name =~ s/^.//;
  152.     }
  153.     print "\t($npc,$spell,$cost,$skill,$learned,$reqlevel)", ($slot < scalar(@spellarr)) ? "," : ";", " -- $name\n";
  154.     $slot++;
  155.   }
  156.   print "\n";
  157. }
  158.  
  159. # build MySQL queries
  160. sub skinloot {
  161.   my ($npc, $opened, $items) = @_;
  162.   my $slot = 1;
  163.   $items =~ s/\,\"sourcemore\":\[.+?\]\,|\,\"modelviewer\":\{.+?\}\,/\,/g;
  164.   my @itemlist = ($items =~ m/\{.+?\}/g);
  165.   @itemlist = sort itemcmp @itemlist;
  166.   print "-- verify that UNIT_FLAG_SKINNABLE is enabled and point to loot template\n";
  167.   print "UPDATE `creature_template` SET `skinloot`=$npc,`unit_flags`=`unit_flags` | 67108864 WHERE `entry`=$npc;\n\n";
  168.   print "-- (re)build skinning_loot_template\n";
  169.   print "-- CHECK/VERIFY/CORRECT `ChanceOrQuestChance` AND `groupid` VALUES\n";
  170.   print "DELETE FROM `skinning_loot_template` WHERE `entry`=$npc;\n";
  171.   print "INSERT INTO `skinning_loot_template` (`entry`,`item`,`ChanceOrQuestChance`,`lootmode`,`groupid`,`mincountOrRef`,`maxcount`)VALUES\n";
  172.   foreach my $itemdata (@itemlist) {
  173.     $itemdata =~ /^.*\"id\":(.+?)\,\"level\":(.+?)\,\"name\":\"(.+?)\".*\,count:(.+?)\,stack:\[(.+?)\,(.+?)\]/;    
  174.     my $id = $1;
  175.     my $ilvl = $2;
  176.     my $name = $3;
  177.     my $count = $4;
  178.     my $minval = $5;
  179.     my $maxval = $6;
  180.     my $pct = sprintf("%.2f", (($count / $opened) * 100));
  181.     if ($name =~ /^[+-]?\d/) {
  182.       $name =~ s/^.//;
  183.     }
  184.     print "\t($npc,$id,$pct,1,0,$minval,$maxval)", ($slot < scalar(@itemlist)) ? "," : ";";
  185.     print " -- $name (ilvl $ilvl) / $count time", ($count > 1) ? "s" : " ", "\n";
  186.     $slot++;
  187.   }
  188.   print "\n";
  189. }
  190.  
  191. # print name & ID as a comment header
  192. sub header {
  193.   if ($head == false) {
  194.     foreach $line (@lines) {
  195.       if (defined $line && length $line > 0) {
  196.         chop($line);
  197.         if ($line =~ /\$\.extend\(g_npcs/) {
  198.           $line =~ /\$\.extend\(g_npcs\[(.+?)\].*\,\"name\":\"(.+?)\"/;
  199.           $NPCid = $1;
  200.           $NPCname = $2;
  201.           my $dashes = length($1) + length($2) + 3;
  202.           print "-- ---", "-" x $dashes, "---\n";
  203.           print "-- -- $2 \($1\) --\n";
  204.           print "-- ---", "-" x $dashes, "---\n\n";
  205.         }
  206.       }
  207.     }
  208.     $head = true;
  209.   }
  210. }
  211.  
  212. # scan the page, obviously
  213. sub parsepage {
  214.   my $data;
  215.   my $totalcount;
  216.   foreach $line (@lines) {
  217.     if (defined $line && length $line > 0) {
  218.       if ($line =~ /^new.Listview.*id:..sells/) {
  219.          $line =~ /^new.Listview.*id:..sells.*data: \[(.+?)\]\}\)/;
  220.          $data = $1;
  221.          header();
  222.          vendlist($NPCid, $data);
  223.       } elsif ($line =~ /^new.Listview.*id:..teaches-recipe/) {
  224.          $line =~ /^new.Listview.*id:..teaches-recipe.*data: \[(.+?)\]\}\)/;
  225.          $data = $1;
  226.          header();
  227.          trainlist($NPCid, $data);
  228.       } elsif ($line =~ /^new.Listview.*id:..(mining|skinning)/) {
  229.          $line =~ /^.*_totalCount:.(.+?)\,/;
  230.          $totalcount = $1;
  231.          $line =~ /^new.Listview.*data: \[(.+?)\]\}\)\;/;
  232.          $data = $1;
  233.          header();
  234.          skinloot($NPCid, $totalcount, $data);
  235.       }
  236.     }
  237.   }
  238. }
  239.  
  240. # generate a URL and get the HTML source
  241. sub getpage {
  242.   my ($NPC) = @_;
  243.   my $URL = "http://www.wowhead.com/npc=$NPC";
  244.   $page = get($URL);
  245.   if (defined $page) {
  246.     $page =~ s/(\r\n)|(\r)/\n/g;
  247.     if ($page =~ /\<title\>Error.-.Wowhead\<\/title\>/) {
  248.       print "\nNPC #$NPC not on Wowhead!\n\n";
  249.       exit;
  250.     }
  251.   } else {
  252.     print "\nUnable to load $URL\n\n";
  253.     exit;
  254.   }
  255. }
  256.  
  257. if ($#ARGV == -1) {
  258.   while ($_ = <>) {
  259.     push (@lines, $_);
  260.   }
  261.   parsepage();
  262.   exit;
  263. } elsif ($#ARGV == 0) {
  264.   $currentNPC = $ARGV[0];
  265.   getpage($currentNPC);
  266.   @lines = split(/(\r)|(\n)|(\r\n)/, $page);
  267.   parsepage();
  268.   exit;
  269. } elsif ($#ARGV == 1 || $#ARGV == 2) {
  270.   for ($currentNPC = $ARGV[0]; $currentNPC <= $ARGV[1]; $currentNPC++) {
  271.     getpage($currentNPC);
  272.     @lines = split(/(\r)|(\n)|(\r\n)/, $page);
  273.     parsepage();
  274.     if ($currentNPC < $ARGV[1]) {
  275.       if ($#ARGV == 1) {
  276.         sleep(5);
  277.       } else {
  278.         sleep($ARGV[2]) if ($ARGV[2] != 0);
  279.       }
  280.     }
  281.   }
  282. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement