summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/HPMHookGen/HPMDataCheckGen.pl14
-rwxr-xr-xtools/HPMHookGen/HPMHookGen.pl285
-rw-r--r--tools/HPMHookGen/Makefile.in4
-rw-r--r--tools/HPMHookGen/doxygen.conf6
-rw-r--r--tools/Script-Checker.applescript2
-rwxr-xr-xtools/check-doc2
-rwxr-xr-xtools/checksql.sh13
-rwxr-xr-xtools/ci/retry.sh33
-rwxr-xr-xtools/ci/travis.sh244
-rwxr-xr-xtools/configconverter.pl967
-rwxr-xr-xtools/constdbconverter.pl4
-rw-r--r--tools/doxygen/Hercules128.pngbin0 -> 19237 bytes
-rw-r--r--tools/doxygen/Hercules48.pngbin0 -> 4954 bytes
-rw-r--r--tools/doxygen/Makefile.in70
-rw-r--r--tools/doxygen/doxygen.conf2490
-rw-r--r--tools/doxygen/footer.html21
-rw-r--r--tools/doxygen/header.html55
-rw-r--r--tools/doxygen/layoutFile.xml194
-rw-r--r--tools/doxygen/pages_index.html39
-rw-r--r--tools/doxygen/style.css1440
-rw-r--r--tools/install_mariadb.bat7
-rw-r--r--tools/item_merge.lua4
-rw-r--r--tools/itemcombodbconverter.py112
-rw-r--r--tools/itemdb_jobmask_converter.pl2
-rwxr-xr-xtools/itemdbconverter.pl8
-rw-r--r--tools/mobavailconverter.py94
-rwxr-xr-xtools/mobdbconvall.sh4
-rwxr-xr-xtools/mobdbconverter.py38
-rwxr-xr-xtools/mobskilldbconverter.py264
-rw-r--r--tools/petdbconverter.py214
-rw-r--r--tools/petevolutionconverter.py248
-rwxr-xr-xtools/php-sqllint/bin/php-sqllint31
-rw-r--r--tools/php-sqllint/build.xml103
-rw-r--r--tools/php-sqllint/composer.json22
-rw-r--r--tools/php-sqllint/composer.lock186
-rw-r--r--tools/php-sqllint/src/phpsqllint/Autoloader.php57
-rw-r--r--tools/php-sqllint/src/phpsqllint/Cli.php280
-rw-r--r--tools/php-sqllint/src/phpsqllint/Renderer.php54
-rw-r--r--tools/php-sqllint/src/phpsqllint/Renderer/Emacs.php70
-rw-r--r--tools/php-sqllint/src/phpsqllint/Renderer/Text.php102
-rw-r--r--tools/php-sqllint/src/stub-phar.php18
-rwxr-xr-xtools/questdbconverter.pl2
-rw-r--r--tools/scconfigconverter.py105
-rw-r--r--tools/setup_mariadb.ps190
-rw-r--r--tools/skilldbconverter.php1202
-rwxr-xr-xtools/stackdump2
-rw-r--r--tools/utils/__init__.py0
-rw-r--r--tools/utils/common.py68
-rw-r--r--tools/utils/libconf.py700
-rwxr-xr-xtools/validateinterfaces.py4
50 files changed, 9778 insertions, 196 deletions
diff --git a/tools/HPMHookGen/HPMDataCheckGen.pl b/tools/HPMHookGen/HPMDataCheckGen.pl
index 3965668d9..538068f80 100644
--- a/tools/HPMHookGen/HPMDataCheckGen.pl
+++ b/tools/HPMHookGen/HPMDataCheckGen.pl
@@ -3,7 +3,7 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2014-2015 Hercules Dev Team
+# Copyright (C) 2014-2020 Hercules Dev Team
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -42,11 +42,13 @@ foreach my $file (@files) {
my @filepath = split(/[\/\\]/, $data->{compounddef}->{$filekey}->{location}->[0]->{file});
my $foldername = uc($filepath[-2]);
next if $filepath[-1] eq "HPM.h"; # Skip the HPM core, plugins don't need it
- my $filename = uc($filepath[-1]); $filename =~ s/-/_/g; $filename =~ s/\.[^.]*$//;
+ my $filename = uc($filepath[-1]); $filename =~ s/[.-]/_/g; $filename =~ s/\.[^.]*$//;
my $plugintypes = 'SERVER_TYPE_UNKNOWN';
if ($foldername eq 'COMMON') {
- if ($filename eq 'MAPINDEX') {
+ if ($filename eq 'MAPINDEX_H') {
$plugintypes = 'SERVER_TYPE_CHAR|SERVER_TYPE_MAP';
+ } elsif ($filename eq 'GRFIO_H') {
+ $plugintypes = 'SERVER_TYPE_MAP';
} else {
$plugintypes = 'SERVER_TYPE_ALL';
}
@@ -57,7 +59,7 @@ foreach my $file (@files) {
name => $data->{compounddef}->{$filekey}->{compoundname}->[0],
type => $plugintypes,
};
- my $name = "${foldername}_${filename}_H";
+ my $name = "${foldername}_${filename}";
push @{ $out{$name} }, $symboldata;
}
@@ -70,7 +72,7 @@ print FH <<"EOF";
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2014-$year Hercules Dev Team
+ * Copyright (C) 2014-$year Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -91,6 +93,8 @@ print FH <<"EOF";
* as it will get overwritten.
*/
+/* GENERATED FILE DO NOT EDIT */
+
#ifndef HPM_DATA_CHECK_H
#define HPM_DATA_CHECK_H
diff --git a/tools/HPMHookGen/HPMHookGen.pl b/tools/HPMHookGen/HPMHookGen.pl
index d471b874d..cd4f10e2a 100755
--- a/tools/HPMHookGen/HPMHookGen.pl
+++ b/tools/HPMHookGen/HPMHookGen.pl
@@ -3,7 +3,7 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2013-2015 Hercules Dev Team
+# Copyright (C) 2013-2020 Hercules Dev Team
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -40,7 +40,7 @@ sub parse($$) {
$p =~ s/^.*?\)\((.*)\).*$/$1/; # Clean up extra parentheses )(around the arglist)
# Retrieve return type
- unless ($d =~ /^(.+)\(\*\s*[a-zA-Z0-9_]+_interface::([^\)]+)\s*\)\s*\(.*\)$/) {
+ unless ($d =~ /^(.+)\(\*\s*[a-zA-Z0-9_]+_interface(?:_private)?::([^\)]+)\s*\)\s*\(.*\)$/) {
print "Error: unable to parse '$d'\n";
return {};
}
@@ -187,28 +187,29 @@ sub parse($$) {
$post_code = "va_end(${callvar});";
$var = '';
$variadic = 1;
- } elsif (!$indirectionlvl) { # Increase indirection level when necessary
+ } else { # Increase indirection level when necessary
$dereference = '*';
$addressof = '&';
}
$indirectionlvl++ if ($array); # Arrays are pointer, no matter how cute you write them
push(@args, {
- var => $var,
- callvar => $callvar,
- type => $type1.$array.$type2,
- orig => $type1 eq '...' ? '...' : trim("$type1 $indir$var$array $type2"),
- indir => $indirectionlvl,
- hookf => $type1 eq '...' ? "va_list ${var}" : trim("$type1 $dereference$indir$var$array $type2"),
- hookc => trim("$addressof$callvar"),
- origc => trim($callvar),
- pre => $pre_code,
- post => $post_code,
+ var => $var,
+ callvar => $callvar,
+ type => $type1.$array.$type2,
+ orig => $type1 eq '...' ? '...' : trim("$type1 $indir$var$array $type2"),
+ indir => $indirectionlvl,
+ hookpref => $type1 eq '...' ? "va_list ${var}" : trim("$type1 $dereference$indir$var$array $type2"),
+ hookpostf => $type1 eq '...' ? "va_list ${var}" : trim("$type1 $indir$var$array $type2"),
+ hookprec => trim("$addressof$callvar"),
+ hookpostc => trim("$callvar"),
+ origc => trim($callvar),
+ pre => $pre_code,
+ post => $post_code,
});
$lastvar = $var;
}
- my $rtmemset = 0;
my $rtinit = '';
foreach ($rt) { # Decide initialization for the return value
my $x = $_;
@@ -237,13 +238,20 @@ sub parse($$) {
$rtinit = ' = HCS_STATUS_FAIL';
} elsif ($x =~ /^enum\s+bg_queue_types$/) { # Known enum bg_queue_types
$rtinit = ' = BGQT_INVALID';
- } elsif ($x =~ /^(?:enum\s+)?DBOptions$/) { # Known enum DBOptions
+ } elsif ($x =~ /^enum\s+parsefunc_rcode$/) { # Known enum parsefunc_rcode
+ $rtinit = ' = PACKET_UNKNOWN';
+ } elsif ($x =~ /^enum\s+DBOptions$/) { # Known enum DBOptions
$rtinit = ' = DB_OPT_BASE';
+ } elsif ($x =~ /^enum\s+thread_priority$/) { # Known enum thread_priority
+ $rtinit = ' = THREADPRIO_NORMAL';
+ } elsif ($x =~ /^enum\s+market_buy_result$/) { # Known enum market_buy_result
+ $rtinit = ' = MARKET_BUY_RESULT_ERROR';
+ } elsif ($x =~ /^enum\s+unit_dir$/) { # Known enum unit_dir
+ $rtinit = ' = UNIT_DIR_UNDEFINED';
} elsif ($x eq 'DBComparator' or $x eq 'DBHasher' or $x eq 'DBReleaser') { # DB function pointers
$rtinit = ' = NULL';
} elsif ($x =~ /^(?:struct|union)\s+.*$/) { # Structs and unions
- $rtinit = '';
- $rtmemset = 1;
+ $rtinit = ' = { 0 }';
} elsif ($x =~ /^float|double$/) { # Floating point variables
$rtinit = ' = 0.';
} elsif ($x =~ /^(?:(?:un)?signed\s+)?(?:char|int|long|short)$/
@@ -251,6 +259,7 @@ sub parse($$) {
or $x =~ /^u?int(?:8|16|32|64)$/
or $x eq 'defType'
or $x eq 'size_t'
+ or $x eq 'time_t'
) { # Numeric variables
$rtinit = ' = 0';
} else { # Anything else
@@ -265,7 +274,6 @@ sub parse($$) {
vname => $variadic ? "v$name" : $name,
type => $rt,
typeinit => $rtinit,
- memset => $rtmemset,
variadic => $variadic,
args => \@args,
notes => $notes,
@@ -273,6 +281,7 @@ sub parse($$) {
}
my %key2original;
+my %key2pointer;
my @files = grep { -f } glob 'doxyoutput/xml/*interface*.xml';
my %ifs;
my %keys = (
@@ -291,6 +300,7 @@ foreach my $file (@files) { # Loop through the xml files
my $loc = $data->{compounddef}->{$filekey}->{location}->[0];
next unless $loc->{file} =~ /src\/(map|char|login|common)\//;
next if $loc->{file} =~ /\/HPM.*\.h/; # Don't allow hooking into the HPM itself
+ next if $loc->{file} =~ /\/memmgr\.h/; # Don't allow hooking into the memory manager
my $servertype = $1;
my $key = $data->{compounddef}->{$filekey}->{compoundname}->[0];
my $original = $key;
@@ -302,14 +312,18 @@ foreach my $file (@files) { # Loop through the xml files
} elsif ($key eq "mapindex_interface") {
push @servertypes, ("map", "char"); # Currently not used by the login server
$servermask = 'SERVER_TYPE_MAP|SERVER_TYPE_CHAR';
+ } elsif ($key eq "grfio_interface") {
+ push @servertypes, ("map"); # Currently not used by the login and char servers
+ $servermask = 'SERVER_TYPE_MAP';
} else {
push @servertypes, ("map", "char", "login");
$servermask = 'SERVER_TYPE_ALL';
}
my @filepath = split(/[\/\\]/, $loc->{file});
my $foldername = uc($filepath[-2]);
- my $filename = uc($filepath[-1]); $filename =~ s/-/_/g; $filename =~ s/\.[^.]*$//;
- my $guardname = "${foldername}_${filename}_H";
+ my $filename = uc($filepath[-1]); $filename =~ s/[.-]/_/g; $filename =~ s/\.[^.]*$//;
+ my $guardname = "${foldername}_${filename}";
+ my $private = $key =~ /_interface_private$/ ? 1 : 0;
# Some known interfaces with different names
if ($key =~ /battleground/) {
@@ -330,8 +344,6 @@ foreach my $file (@files) { # Loop through the xml files
$key = "chr";
} elsif ($key eq "db_interface") {
$key = "DB";
- } elsif ($key eq "malloc_interface") {
- $key = "iMalloc";
} elsif ($key eq "socket_interface") {
$key = "sockt";
} elsif ($key eq "sql_interface") {
@@ -344,6 +356,9 @@ foreach my $file (@files) { # Loop through the xml files
} else {
$key =~ s/_interface//;
}
+ $key =~ s/^(.*)_private$/PRIV__$1/ if $private;
+ my $pointername = $key;
+ $pointername =~ s/^PRIV__(.*)$/$1->p/ if $private;
my $sectiondef = $data->{compounddef}->{$filekey}->{sectiondef};
foreach my $v (@$sectiondef) { # Loop through the sections
@@ -353,10 +368,17 @@ foreach my $file (@files) { # Loop through the xml files
my $bstart = $b->{location}->[0]->{bodystart} || $b->{location}->[0]->{line};
$astart <=> $bstart
} @$memberdef) { # Loop through the members
+ next unless $f->{kind} eq 'variable'; # Skip macros
my $t = $f->{argsstring}->[0];
- next unless ref $t ne 'HASH' and $t =~ /^[^\[]/; # If it's not a string, or if it starts with an array subscript, we can skip it
+ my $def = $f->{definition}->[0];
+ if ($f->{type}->[0] =~ /^\s*LoginParseFunc\s*\*\s*$/) {
+ $t = ')(int fd, struct login_session_data *sd)'; # typedef LoginParseFunc
+ $def =~ s/^LoginParseFunc\s*\*\s*(.*)$/enum parsefunc_rcode(* $1) (int fd, struct login_session_data *sd)/;
+ }
+ next if ref $t eq 'HASH'; # Skip if it's not a string
+ next if $t =~ /^\)?\[.*\]$/; # Skip arrays or pointers to array
- my $if = parse($t, $f->{definition}->[0]);
+ my $if = parse($t, $def);
next unless scalar keys %$if; # If it returns an empty hash reference, an error must've occurred
# Skip variadic functions, we only allow hooks on their arglist equivalents.
@@ -407,10 +429,10 @@ foreach my $file (@files) { # Loop through the xml files
$if->{postcall} .= ', ';
}
$if->{handlerdef} .= $arg->{orig};
- $if->{predef} .= $arg->{hookf};
- $if->{precall} .= $arg->{hookc};
- $if->{postdef} .= $arg->{hookf};
- $if->{postcall} .= $arg->{hookc};
+ $if->{predef} .= $arg->{hookpref};
+ $if->{precall} .= $arg->{hookprec};
+ $if->{postdef} .= $arg->{hookpostf};
+ $if->{postcall} .= $arg->{hookpostc};
$if->{origcall} .= $arg->{origc};
$i++; $j++;
}
@@ -431,6 +453,7 @@ foreach my $file (@files) { # Loop through the xml files
$if->{origcall} .= ");";
$key2original{$key} = $original;
+ $key2pointer{$key} = $pointername;
$ifs{$key} = [] unless $ifs{$key};
push(@{ $ifs{$key} }, $if);
}
@@ -442,35 +465,18 @@ foreach my $file (@files) { # Loop through the xml files
$fileguards{$key} = {
guard => $guardname,
type => $servermask,
+ private => $private,
};
}
my $year = (localtime)[5] + 1900;
-foreach my $servertype (keys %keys) {
- my $keysref = $keys{$servertype};
- # Some interfaces use different names
- my %exportsymbols = map {
- $_ => &{ sub ($) {
- return 'battlegrounds' if $_ =~ /^bg$/;
- return 'pc_groups' if $_ =~ /^pcg$/;
- return $_;
- }}($_);
- } @$keysref;
-
- my ($maxlen, $idx) = (0, 0);
- my $fname;
-
- if ($servertype eq 'all') {
- $fname = "../../src/common/HPMSymbols.inc.h";
- open(FH, ">", $fname)
- or die "cannot open > $fname: $!";
- print FH <<"EOF";
+my $fileheader = <<"EOF";
/**
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
- * Copyright (C) 2015-$year Hercules Dev Team
+ * Copyright (C) 2013-$year Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
@@ -491,10 +497,35 @@ foreach my $servertype (keys %keys) {
* as it will get overwritten.
*/
+/* GENERATED FILE DO NOT EDIT */
+EOF
+
+foreach my $servertype (keys %keys) {
+ my $keysref = $keys{$servertype};
+ # Some interfaces use different names
+ my %exportsymbols = map {
+ $_ => &{ sub ($) {
+ return 'battlegrounds' if $_ =~ /^bg$/;
+ return 'pc_groups' if $_ =~ /^pcg$/;
+ return $_;
+ }}($_);
+ } @$keysref;
+
+ my ($maxlen, $idx) = (0, 0);
+ my $fname;
+
+ if ($servertype eq 'all') {
+ $fname = "../../src/common/HPMSymbols.inc.h";
+ open(FH, ">", $fname)
+ or die "cannot open > $fname: $!";
+
+ print FH <<"EOF";
+$fileheader
#if !defined(HERCULES_CORE)
EOF
foreach my $key (@$keysref) {
+ next if $fileguards{$key}->{private};
print FH <<"EOF";
#ifdef $fileguards{$key}->{guard} /* $key */
struct $key2original{$key} *$key;
@@ -510,9 +541,11 @@ HPExport const char *HPM_shared_symbols(int server_type)
EOF
foreach my $key (@$keysref) {
+ next if $fileguards{$key}->{private};
print FH <<"EOF";
#ifdef $fileguards{$key}->{guard} /* $key */
-if ((server_type&($fileguards{$key}->{type})) && !HPM_SYMBOL("$exportsymbols{$key}", $key)) return "$exportsymbols{$key}";
+ if ((server_type&($fileguards{$key}->{type})) != 0 && !HPM_SYMBOL("$exportsymbols{$key}", $key))
+ return "$exportsymbols{$key}";
#endif // $fileguards{$key}->{guard}
EOF
}
@@ -522,6 +555,36 @@ EOF
}
EOF
close FH;
+
+ $fname = "../../src/plugins/HPMHooking/HPMHooking.Defs.inc";
+ open(FH, ">", $fname)
+ or die "cannot open > $fname: $!";
+
+ print FH <<"EOF";
+$fileheader
+EOF
+
+ foreach my $key (@$keysref) {
+ print FH <<"EOF";
+#ifdef $fileguards{$key}->{guard} /* $key */
+EOF
+
+ foreach my $if (@{ $ifs{$key} }) {
+ my ($predef, $postdef) = ($if->{predef}, $if->{postdef});
+ $predef =~ s/preHookFunc/HPMHOOK_pre_${key}_$if->{name}/;
+ $postdef =~ s/postHookFunc/HPMHOOK_post_${key}_$if->{name}/;
+
+ print FH <<"EOF";
+typedef $predef
+typedef $postdef
+EOF
+ }
+ print FH <<"EOF";
+#endif // $fileguards{$key}->{guard}
+EOF
+ }
+ close FH;
+
next;
}
@@ -530,43 +593,20 @@ EOF
or die "cannot open > $fname: $!";
print FH <<"EOF";
-/**
- * This file is part of Hercules.
- *
- * Copyright (C) 2013-$year Hercules Dev Team
- *
- * Hercules is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * NOTE: This file was auto-generated and should never be manually edited,
- * as it will get overwritten.
- */
-
+$fileheader
struct HookingPointData HookingPoints[] = {
EOF
foreach my $key (@$keysref) {
- print FH "/* ".$key." */\n";
+ print FH "/* $key2original{$key} */\n";
foreach my $if (@{ $ifs{$key} }) {
print FH <<"EOF";
- { HP_POP($key\->$if->{name}, $if->{hname}) },
+ { HP_POP($key2pointer{$key}\->$if->{name}, $if->{hname}) },
EOF
$idx += 2;
- $maxlen = length($key."->".$if->{name}) if( length($key."->".$if->{name}) > $maxlen );
+ $maxlen = length($key."->".$if->{name}) if (length($key."->".$if->{name}) > $maxlen);
}
}
print FH <<"EOF";
@@ -581,36 +621,12 @@ EOF
or die "cannot open > $fname: $!";
print FH <<"EOF";
-/**
- * This file is part of Hercules.
- * http://herc.ws - http://github.com/HerculesWS/Hercules
- *
- * Copyright (C) 2013-$year Hercules Dev Team
- *
- * Hercules is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * NOTE: This file was auto-generated and should never be manually edited,
- * as it will get overwritten.
- */
-
+$fileheader
EOF
foreach my $key (@$keysref) {
print FH <<"EOF";
-memcpy(&HPMHooks.source.$key, $key, sizeof(struct $key2original{$key}));
+HPMHooks.source.$key = *$key2pointer{$key};
EOF
}
close FH;
@@ -620,31 +636,7 @@ EOF
or die "cannot open > $fname: $!";
print FH <<"EOF";
-/**
- * This file is part of Hercules.
- * http://herc.ws - http://github.com/HerculesWS/Hercules
- *
- * Copyright (C) 2013-$year Hercules Dev Team
- *
- * Hercules is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * NOTE: This file was auto-generated and should never be manually edited,
- * as it will get overwritten.
- */
-
+$fileheader
struct {
EOF
@@ -695,36 +687,12 @@ EOF
or die "cannot open > $fname: $!";
print FH <<"EOF";
-/**
- * This file is part of Hercules.
- * http://herc.ws - http://github.com/HerculesWS/Hercules
- *
- * Copyright (C) 2013-$year Hercules Dev Team
- *
- * Hercules is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- */
-
-/*
- * NOTE: This file was auto-generated and should never be manually edited,
- * as it will get overwritten.
- */
-
+$fileheader
EOF
foreach my $key (@$keysref) {
print FH <<"EOF";
-/* $key */
+/* $key2original{$key} */
EOF
foreach my $if (@{ $ifs{$key} }) {
@@ -732,7 +700,6 @@ EOF
unless ($if->{type} eq 'void') {
$initialization = "\n\t$if->{type} retVal___$if->{typeinit};";
- $initialization .= "\n\tmemset(&retVal___, '\\0', sizeof($if->{type}));" if $if->{memset};
}
$beforeblock3 .= "\n\t\t\t$_" foreach (@{ $if->{before} });
@@ -744,14 +711,14 @@ EOF
print FH <<"EOF";
$if->{handlerdef} {$if->{notes}
int hIndex = 0;${initialization}
- if( HPMHooks.count.$if->{hname}_pre ) {
+ if (HPMHooks.count.$if->{hname}_pre > 0) {
$if->{predef}
*HPMforce_return = false;
- for(hIndex = 0; hIndex < HPMHooks.count.$if->{hname}_pre; hIndex++ ) {$beforeblock3
+ for (hIndex = 0; hIndex < HPMHooks.count.$if->{hname}_pre; hIndex++) {$beforeblock3
preHookFunc = HPMHooks.list.$if->{hname}_pre[hIndex].func;
$if->{precall}$afterblock3
}
- if( *HPMforce_return ) {
+ if (*HPMforce_return) {
*HPMforce_return = false;
return$retval;
}
@@ -759,9 +726,9 @@ $if->{handlerdef} {$if->{notes}
{$beforeblock2
$if->{origcall}$afterblock2
}
- if( HPMHooks.count.$if->{hname}_post ) {
+ if (HPMHooks.count.$if->{hname}_post > 0) {
$if->{postdef}
- for(hIndex = 0; hIndex < HPMHooks.count.$if->{hname}_post; hIndex++ ) {$beforeblock3
+ for (hIndex = 0; hIndex < HPMHooks.count.$if->{hname}_post; hIndex++) {$beforeblock3
postHookFunc = HPMHooks.list.$if->{hname}_post[hIndex].func;
$if->{postcall}$afterblock3
}
diff --git a/tools/HPMHookGen/Makefile.in b/tools/HPMHookGen/Makefile.in
index d2fe379d8..43c6efff3 100644
--- a/tools/HPMHookGen/Makefile.in
+++ b/tools/HPMHookGen/Makefile.in
@@ -1,8 +1,8 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2012-2015 Hercules Dev Team
-# Copyright (C) Athena Dev Teams
+# Copyright (C) 2012-2020 Hercules Dev Team
+# Copyright (C) Athena Dev Teams
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/HPMHookGen/doxygen.conf b/tools/HPMHookGen/doxygen.conf
index ec55967b1..ead1deeca 100644
--- a/tools/HPMHookGen/doxygen.conf
+++ b/tools/HPMHookGen/doxygen.conf
@@ -269,7 +269,9 @@ INCLUDE_PATH = ../../src \
../../3rdparty
INCLUDE_FILE_PATTERNS =
PREDEFINED = __attribute__(x)= \
- HPMHOOKGEN
+ HPMHOOKGEN \
+ PACKETVER=20031028 \
+ PACKETVER_MAIN_NUM=20031028
EXPAND_AS_DEFINED =
SKIP_FUNCTION_MACROS = NO
#---------------------------------------------------------------------------
@@ -280,12 +282,10 @@ GENERATE_TAGFILE =
ALLEXTERNALS = NO
EXTERNAL_GROUPS = NO
EXTERNAL_PAGES = YES
-PERL_PATH = /usr/bin/perl
#---------------------------------------------------------------------------
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
CLASS_DIAGRAMS = NO
-MSCGEN_PATH =
DIA_PATH =
HIDE_UNDOC_RELATIONS = YES
HAVE_DOT = NO
diff --git a/tools/Script-Checker.applescript b/tools/Script-Checker.applescript
index 0b7207569..202e19800 100644
--- a/tools/Script-Checker.applescript
+++ b/tools/Script-Checker.applescript
@@ -2,7 +2,7 @@
This file is part of Hercules.
http://herc.ws - http://github.com/HerculesWS/Hercules
- Copyright (C) 2014-2015 Hercules Dev Team
+ Copyright (C) 2014-2020 Hercules Dev Team
Hercules is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
diff --git a/tools/check-doc b/tools/check-doc
index 8ac9a87ad..267968470 100755
--- a/tools/check-doc
+++ b/tools/check-doc
@@ -3,7 +3,7 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2012-2015 Hercules Dev Team
+# Copyright (C) 2012-2020 Hercules Dev Team
# checking-doc script by trojal
# modified by lighta
#
diff --git a/tools/checksql.sh b/tools/checksql.sh
new file mode 100755
index 000000000..f7fb23700
--- /dev/null
+++ b/tools/checksql.sh
@@ -0,0 +1,13 @@
+#!/bin/bash
+
+function checkdir {
+ for sql in $1/*.sql
+ do
+ echo "checking ${sql}"
+ php -d memory_limit=4G ./tools/php-sqllint/bin/php-sqllint "${sql}" || exit 1
+ done
+}
+
+checkdir "sql-files"
+checkdir "sql-files/upgrades"
+checkdir "sql-files/tools"
diff --git a/tools/ci/retry.sh b/tools/ci/retry.sh
new file mode 100755
index 000000000..584e78f13
--- /dev/null
+++ b/tools/ci/retry.sh
@@ -0,0 +1,33 @@
+#!/usr/bin/env bash
+
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2016-2020 Hercules Dev Team
+# Copyright (C) 2016 Haru <haru@herc.ws>
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+n=0
+
+while true; do
+ $@ && break
+ if [[ $n -ge 5 ]]; then
+ exit -1
+ fi
+ WAITTIME=$((2**n))
+ echo "Execution of $@ failed. Retrying in $WAITTIME seconds..."
+ sleep $WAITTIME
+ n=$((n+1))
+done
diff --git a/tools/ci/travis.sh b/tools/ci/travis.sh
new file mode 100755
index 000000000..10c653925
--- /dev/null
+++ b/tools/ci/travis.sh
@@ -0,0 +1,244 @@
+#!/usr/bin/env bash
+
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2014-2020 Hercules Dev Team
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# Base Author: Haru @ http://herc.ws
+
+MODE="$1"
+shift
+
+function foo {
+ for i in "$@"; do
+ echo "> $i"
+ done
+}
+
+function usage {
+ echo "usage:"
+ echo " $0 createdb <dbname> [dbuser] [dbpassword] [dbhost]"
+ echo " $0 importdb <dbname> [dbuser] [dbpassword] [dbhost]"
+ echo " $0 adduser <dbname> <new_user> <new_user_password> [dbuser] [dbpassword] [dbhost]"
+ echo " $0 build [configure args]"
+ echo " $0 test <dbname> [dbuser] [dbpassword] [dbhost]"
+ echo " $0 getplugins"
+ exit 1
+}
+
+function aborterror {
+ echo $@
+ exit 1
+}
+
+function run_server {
+ echo "Running: $1 --run-once $2"
+ rm -rf core* || true
+ CRASH_PLEASE=1 $1 --run-once $2 2>runlog.txt
+ export errcode=$?
+ export teststr=$(head -c 10000 runlog.txt)
+ if [[ -n "${teststr}" ]]; then
+ echo "Errors found in running server $1."
+ head -c 10000 runlog.txt
+ aborterror "Errors found in running server $1."
+ else
+ echo "No errors found for server $1."
+ fi
+ if [ ${errcode} -ne 0 ]; then
+ echo "server $1 terminated with exit code ${errcode}"
+ COREFILE=$(find . -maxdepth 1 -name "core*" | head -n 1)
+ if [[ -f "$COREFILE" ]]; then
+ gdb -c "$COREFILE" $1 -ex "thread apply all bt" -ex "set pagination 0" -batch
+ fi
+ aborterror "Test failed"
+ fi
+}
+
+function run_test {
+ echo "Running: test_$1"
+ sysctl -w kernel.core_pattern=core || true
+ ./test_$1 2>runlog.txt
+ export errcode=$?
+ export teststr=$(head -c 10000 runlog.txt)
+ if [[ -n "${teststr}" ]]; then
+ echo "Errors found in running test $1."
+ head -c 10000 runlog.txt
+ aborterror "Errors found in running test $1."
+ else
+ echo "No errors found for test $1."
+ fi
+ if [ ${errcode} -ne 0 ]; then
+ echo "test $1 terminated with exit code ${errcode}"
+ aborterror "Test failed"
+ fi
+}
+
+# Defaults
+DBNAME=ragnarok
+DBUSER=ragnarok
+DBPASS=ragnarok
+DBHOST=localhost
+
+case "$MODE" in
+ createdb|importdb|test)
+ if [ -z "$1" ]; then
+ usage
+ fi
+ DBNAME="$1"
+ if [ -n "$2" ]; then
+ DBUSER_ARG="--user=$2"
+ DBUSER="$2"
+ fi
+ if [ -n "$3" ]; then
+ DBPASS_ARG="--password=$3"
+ DBPASS="$3"
+ fi
+ if [ -n "$4" ]; then
+ DBHOST_ARG="--host=$4"
+ DBHOST="$4"
+ fi
+ ;;
+ adduser)
+ if [ -z "$3" ]; then
+ usage
+ fi
+ DBNAME="$1"
+ NEWUSER="$2"
+ NEWPASS="$3"
+ if [ -n "$4" ]; then
+ DBUSER_ARG="--user=$4"
+ DBUSER="$4"
+ fi
+ if [ -n "$5" ]; then
+ DBPASS_ARG="--password=$5"
+ DBPASS="$5"
+ fi
+ if [ -n "$6" ]; then
+ DBHOST_ARG="--host=$6"
+ DBHOST="$6"
+ fi
+ ;;
+esac
+
+case "$MODE" in
+ createdb)
+ echo "Creating database $DBNAME as $DBUSER..."
+ mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --execute="CREATE DATABASE $DBNAME;" || aborterror "Unable to create database."
+ ;;
+ importdb)
+ echo "Importing tables into $DBNAME as $DBUSER..."
+ mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --database=$DBNAME < sql-files/main.sql || aborterror "Unable to import main database."
+ mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --database=$DBNAME < sql-files/logs.sql || aborterror "Unable to import logs database."
+ ;;
+ adduser)
+ echo "Adding user $NEWUSER as $DBUSER, with access to database $DBNAME..."
+ mysql $DBUSER_ARG $DBPASS_ARG $DBHOST_ARG --execute="GRANT SELECT,INSERT,UPDATE,DELETE ON $DBNAME.* TO '$NEWUSER'@'$DBHOST' IDENTIFIED BY '$NEWPASS';"
+ ;;
+ build)
+ (cd tools && ./validateinterfaces.py silent) || aborterror "Interface validation error."
+ ./configure $@ || (cat config.log && aborterror "Configure error, aborting build.")
+ make -j3 || aborterror "Build failed."
+ make plugins -j3 || aborterror "Build failed."
+ make plugin.script_mapquit -j3 || aborterror "Build failed."
+ make test || aborterror "Build failed."
+ ;;
+ buildhpm)
+ ./configure $@ || (cat config.log && aborterror "Configure error, aborting build.")
+ cd tools/HPMHookGen
+ make
+ ;;
+ test)
+ cat > conf/travis_sql_connection.conf << EOF
+sql_connection: {
+ //default_codepage: ""
+ //case_sensitive: false
+ db_hostname: "$DBHOST"
+ db_username: "$DBUSER"
+ db_password: "$DBPASS"
+ db_database: "$DBNAME"
+ //codepage:""
+}
+EOF
+ [ $? -eq 0 ] || aborterror "Unable to write database configuration, aborting tests."
+ cat > conf/import/login-server.conf << EOF
+login_configuration: {
+ account: {
+ @include "conf/travis_sql_connection.conf"
+ ipban: {
+ @include "conf/travis_sql_connection.conf"
+ }
+ }
+}
+EOF
+ [ $? -eq 0 ] || aborterror "Unable to override login-server configuration, aborting tests."
+ cat > conf/import/char-server.conf << EOF
+char_configuration: {
+ @include "conf/travis_sql_connection.conf"
+}
+EOF
+ [ $? -eq 0 ] || aborterror "Unable to override char-server configuration, aborting tests."
+ cat > conf/import/map-server.conf << EOF
+map_configuration: {
+ @include "conf/travis_sql_connection.conf"
+}
+EOF
+ [ $? -eq 0 ] || aborterror "Unable to override map-server configuration, aborting tests."
+ cat > conf/import/inter-server.conf << EOF
+inter_configuration: {
+ log: {
+ @include "conf/travis_sql_connection.conf"
+ }
+}
+EOF
+ [ $? -eq 0 ] || aborterror "Unable to override inter-server configuration, aborting tests."
+ ARGS="--load-script npc/dev/test.txt "
+ ARGS="--load-plugin script_mapquit $ARGS --load-script npc/dev/ci_test.txt"
+ PLUGINS="--load-plugin HPMHooking --load-plugin sample"
+ echo "run tests"
+ if [[ $DBUSER == "travis" ]]; then
+ echo "Disable leak dection on travis"
+ export ASAN_OPTIONS=detect_leaks=0:detect_stack_use_after_return=true:strict_init_order=true
+ else
+ export ASAN_OPTIONS=detect_stack_use_after_return=true:strict_init_order=true
+ fi
+ # run_test spinlock # Not running the spinlock test for the time being (too time consuming)
+ run_test libconfig
+ echo "run all servers without HPM"
+ run_server ./login-server
+ run_server ./char-server
+ run_server ./map-server "$ARGS"
+ echo "run all servers wit HPM"
+ run_server ./login-server "$PLUGINS"
+ run_server ./char-server "$PLUGINS"
+ run_server ./map-server "$ARGS $PLUGINS"
+ ;;
+ getplugins)
+ echo "Cloning plugins repository..."
+ # Nothing to clone right now, all relevant plugins are part of the repository.
+ #git clone http://github.com/HerculesWS/StaffPlugins.git || aborterror "Unable to fetch plugin repository"
+ #if [ -f StaffPlugins/Haru/script_mapquit/script_mapquit.c -a -f StaffPlugins/Haru/script_mapquit/examples/ci_test.txt ]; then
+ # pushd src/plugins || aborterror "Unable to enter plugins directory."
+ # ln -s ../../StaffPlugins/Haru/script_mapquit/script_mapquit.c ./
+ # popd
+ #else
+ # echo "Plugin not found, skipping advanced tests."
+ #fi
+ ;;
+ *)
+ usage
+ ;;
+esac
diff --git a/tools/configconverter.pl b/tools/configconverter.pl
new file mode 100755
index 000000000..385278963
--- /dev/null
+++ b/tools/configconverter.pl
@@ -0,0 +1,967 @@
+#!/usr/bin/perl
+#
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2016-2020 Hercules Dev Team
+# Copyright (C) 2016 Haru
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+use strict;
+use warnings;
+
+my $silent = 0;
+my $confpath = 'conf';
+
+sub parse_config($$) {
+ my ($input, $defaults) = @_;
+
+ my %output = ();
+
+ for my $line (<$input>) {
+ chomp $line;
+ $line =~ s/^\s*//; $line =~ s/\s*$//;
+ if ($line =~ /^([a-z0-9A-Z_.]+)\s*:\s*(.*)$/) {
+ my ($variable, $value) = ($1, $2);
+ if ($defaults->{$variable}) {
+ next if $defaults->{$variable}->{parse}->($variable, $value, $defaults->{$variable}, \%output);
+ print "Error: Invalid value for setting '$variable: $value'\n";
+ next;
+ } else {
+ print "Found unhandled configuration setting: '$variable: $value'\n";
+ next;
+ }
+ } elsif ($line =~ m{^\s*(?://.*)?$}) {
+ next;
+ } else {
+ print "Error: Unable to parse line '$line'\n";
+ }
+ }
+ return \%output;
+}
+
+sub cfg_add($$$$) {
+ my ($variable, $value, $default, $output) = @_;
+ $output->{$variable} = {value => $value, print => $default->{print}, path => $default->{path}} unless $value eq $default->{default};
+}
+
+sub cfg_append($$$$) {
+ my ($variable, $value, $default, $output) = @_;
+ for my $default_value (@{$default->{default}}) {
+ return if $value eq $default_value;
+ }
+ $output->{$variable} = {value => [], print => $default->{print}, path => $default->{path}} unless $output->{$variable};
+ push(@{$output->{$variable}->{value}}, $value);
+}
+
+sub parsecfg_string_sub($$$$$) {
+ my ($variable, $value, $default, $output, $func) = @_;
+ if ($value =~ m{\s*"((?:\\"|.)*)"\s*(?://.*)?$}i) {
+ $func->($variable, $1, $default, $output);
+ return 1;
+ } elsif ($value =~ m{\s*((?:\\"|.)*)\s*(?://.*)?$}i) {
+ $func->($variable, $1, $default, $output);
+ return 1;
+ }
+ return 0;
+}
+
+sub parsecfg_string($$$$) {
+ my ($variable, $value, $default, $output) = @_;
+ return parsecfg_string_sub($variable, $value, $default, $output, \&cfg_add);
+}
+
+sub parsecfg_stringarr($$$$) {
+ my ($variable, $value, $default, $output) = @_;
+ return parsecfg_string_sub($variable, $value, $default, $output, \&cfg_append);
+}
+
+sub parsecfg_int($$$$) {
+ my ($variable, $value, $default, $output) = @_;
+ if ($value =~ m{\s*(-?[0-9]+)\s*(?://.*)?$}) {
+ cfg_add($variable, int $1, $default, $output);
+ return 1;
+ } elsif ($value =~ m{\s*(0x[0-9A-F]+)\s*(?://.*)?$}) {
+ cfg_add($variable, hex $1, $default, $output);
+ return 1;
+ } elsif ($value =~ m{\s*(no|false|off)\s*(?://.*)?$}) {
+ cfg_add($variable, 0, $default, $output);
+ return 1;
+ }
+ return 0;
+}
+
+sub parsecfg_bool($$$$) {
+ my ($variable, $value, $default, $output) = @_;
+ if ($value =~ m{\s*(yes|true|1|on)\s*(?://.*)?$}i) {
+ cfg_add($variable, "true", $default, $output);
+ return 1;
+ } elsif ($value =~ m{\s*(no|false|0|off)\s*(?://.*)?$}i) {
+ cfg_add($variable, "false", $default, $output);
+ return 1;
+ }
+ return 0;
+}
+
+sub print_config($) {
+ my ($config) = @_;
+
+ for my $variable (keys %$config) {
+ my $fullpath = $config->{$variable}->{path};
+ $fullpath .= $variable if $fullpath =~ m{[:/]$};
+ my ($filename, $configpath) = split(/:/, $fullpath, 2);
+ next unless $filename and $configpath;
+ my @path = split(/\//, $configpath);
+ next unless @path;
+
+ my %output = ();
+
+ my $setting = \%output;
+ while (scalar @path > 1) {
+ my $nodename = shift @path;
+ $setting->{$nodename} = {print => \&printcfg_tree, value => {}} unless $setting->{$nodename};
+ $setting = $setting->{$nodename}->{value};
+ }
+ $setting->{$path[0]} = {print => $config->{$variable}->{print}, value => $config->{$variable}->{value}};
+ verbose("- Found setting: '$variable'.\n Please manually move the setting to '$filename.conf' as in the following example:\n",
+ "- '$filename.conf': (from $variable)\n");
+ $output{$_}->{print}->($_, $output{$_}->{value}, 0) for keys %output;
+ }
+}
+
+sub indent($$) {
+ my ($message, $nestlevel) = @_;
+ return print "\t" x ($nestlevel + 1) . $message;
+}
+
+sub printcfg_tree($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: {\n", $nestlevel);
+ $value->{$_}{print}->($_, $value->{$_}{value}, $nestlevel + 1) for keys %$value;
+ indent("}\n", $nestlevel);
+}
+
+sub printcfg_nil($$$) {
+}
+
+sub printcfg_string($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: \"$value\"\n", $nestlevel);
+}
+
+sub printcfg_int($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: $value\n", $nestlevel);
+}
+
+sub printcfg_hexint($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent(sprintf("%s: 0x%x\n", $variable, $value), $nestlevel);
+}
+
+sub printcfg_bool($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: $value\n", $nestlevel);
+}
+
+sub printcfg_point($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: {\n", $nestlevel);
+
+ my @point = split(/,/, $value, 3);
+ indent("map: \"$point[0]\"\n", $nestlevel + 1);
+ indent("x: $point[1]\n", $nestlevel + 1);
+ indent("y: $point[2]\n", $nestlevel + 1);
+
+ indent("}\n", $nestlevel);
+}
+
+sub printcfg_items($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: (\n", $nestlevel);
+
+ my @items = split(/,/, $value);
+ while (scalar @items >= 3) {
+ my $id = shift @items;
+ my $amount = shift @items;
+ my $stackable = (shift @items) ? "true" : "false";
+ indent("{\n", $nestlevel);
+ indent("id: $id\n", $nestlevel + 1);
+ indent("amount: $amount\n", $nestlevel + 1);
+ indent("stackable: $stackable\n", $nestlevel + 1);
+ indent("},\n", $nestlevel);
+ }
+
+ indent(")\n", $nestlevel);
+}
+
+sub printcfg_md5hash($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: (\n", $nestlevel);
+
+ for (@$value) {
+ my ($group_id, $hash) = split(/,/, $_, 2);
+ $group_id =~ s/\s*$//; $group_id =~ s/^\s*//;
+ $hash =~ s/\s*$//; $hash =~ s/^\s*//;
+
+ indent("{\n", $nestlevel);
+ indent("group_id: $group_id\n", $nestlevel + 1);
+ indent("hash: \"$hash\"\n", $nestlevel + 1);
+ indent("},\n", $nestlevel);
+ }
+
+ indent(")\n", $nestlevel);
+}
+
+sub printcfg_strlist($$$) {
+ my ($variable, $value, $nestlevel) = @_;
+
+ indent("$variable: (\n", $nestlevel);
+
+ for my $string (split(/,/, $value)) {
+ $string =~ s/\s*$//; $string =~ s/^\s*//;
+
+ indent("\"$string\",\n", $nestlevel + 1);
+ }
+
+ indent(")\n", $nestlevel);
+}
+
+sub process_conf($$) {
+ my ($files, $defaults) = @_;
+ my $found = 0;
+ for my $file (@$files) {
+ print "\nChecking $file...";
+ print " Ok\n" and next unless open my $FH, '<', $file; # File not found or already converted
+ print " Old file is still present\n";
+ my $output = parse_config($FH, $defaults);
+ close($FH);
+ my $count = scalar keys %$output;
+ print "$count non-default settings found.";
+ verbose(" The file '$file' is no longer used by Hercules and can be deleted.\n", "\n") and next unless $count;
+ verbose(" Please review and migrate the settings as described, then delete the file '$file', as it is no longer used by Hercules.\n", "\n");
+ print_config($output);
+ $found = 1;
+ }
+ return $found;
+}
+
+sub verbose($;$) {
+ my ($verbose_message, $silent_message) = @_;
+ return print $verbose_message unless $silent;
+ return print $silent_message if defined $silent_message;
+ return 1;
+}
+
+my @defaults = (
+ {
+ files => ['char-server.conf', 'import/char_conf.txt'],
+ settings => {
+ autosave_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/database/", default => 60},
+ bind_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/inter/", default => "127.0.0.1"},
+ char_aegis_delete => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "char-server:char_configuration/player/deletion/use_aegis_delete", default => "false"},
+ char_del_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/player/deletion/delay", default => 86400},
+ char_del_level => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/player/deletion/level", default => 0},
+ char_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/inter/", default => "127.0.0.1"},
+ char_maintenance_min_group_id => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/permission/maintenance_min_group_id", default => 99},
+ char_name_letters => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/player/name/name_letters", default => "abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"},
+ char_name_option => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/player/name/name_option", default => 1},
+ char_new => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "char-server:char_configuration/permission/enable_char_creation", default => "true"},
+ char_new_display => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "char-server:char_configuration/permission/display_new", default => "false"},
+ char_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/inter/", default => 6121},
+ char_server_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/permission/server_type", default => 0},
+ console_silent => {parse => \&parsecfg_int, print => \&printcfg_int, path => "console:console/", default => 0},
+ db_path => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/database/", default => "db"},
+ fame_list_alchemist => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/fame/alchemist", default => 10},
+ fame_list_blacksmith => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/fame/blacksmith", default => 10},
+ fame_list_taekwon => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/fame/taekwon", default => 10},
+ gm_allow_group => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/permission/", default => -1},
+ guild_exp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/", default => 100},
+ log_char => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "char-server:char_configuration/database/", default => "true"},
+ login_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/inter/", default => "127.0.0.1"},
+ login_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/inter/", default => 6900},
+ max_connect_user => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/permission/", default => -1},
+ name_ignoring_case => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "char-server:char_configuration/player/name/", default => "false"},
+ passwd => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/inter/", default => "p1"},
+ pincode_changetime => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/pincode/change_time", default => 0},
+ pincode_charselect => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/pincode/request", default => 0},
+ pincode_enabled => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "char-server:char_configuration/pincode/enabled", default => "true"},
+ pincode_maxtry => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/pincode/max_tries", default => 3},
+ save_log => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "console:console/", default => "true"},
+ server_name => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/", default => "Hercules"},
+ start_items => {parse => \&parsecfg_string, print => \&printcfg_items, path => "char-server:char_configuration/player/new/", default => "1201,1,0,2301,1,0"},
+ start_point_pre => {parse => \&parsecfg_string, print => \&printcfg_point, path => "char-server:char_configuration/player/new/", default => "new_1-1,53,111"},
+ start_point_re => {parse => \&parsecfg_string, print => \&printcfg_point, path => "char-server:char_configuration/player/new/", default => "iz_int,97,90"},
+ start_zeny => {parse => \&parsecfg_int, print => \&printcfg_int, path => "char-server:char_configuration/player/new/zeny", default => 0},
+ stdout_with_ansisequence => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "console:console/", default => "false"},
+ timestamp_format => {parse => \&parsecfg_string, print => \&printcfg_string, path => "console:console/", default => "[%d/%b %H:%M]"},
+ unknown_char_name => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/player/name/", default => "Unknown"},
+ userid => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/inter/", default => "s1"},
+ wisp_server_name => {parse => \&parsecfg_string, print => \&printcfg_string, path => "char-server:char_configuration/", default => "Server"},
+ import => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "conf/import/char_conf.txt"},
+ }
+ },
+ {
+ files => ['inter-server.conf', 'import/inter_conf.txt'],
+ settings => {
+ party_share_level => {parse => \&parsecfg_int, print => \&printcfg_int, path => "inter-server:inter_configuration/", default => 15},
+ log_inter => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "inter-server:inter_configuration/log/", default => "true"},
+ inter_log_filename => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/log/", default => "log/inter.log"},
+ mysql_reconnect_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "inter-server:inter_configuration/mysql_reconnect/type", default => 2},
+ mysql_reconnect_count => {parse => \&parsecfg_int, print => \&printcfg_int, path => "inter-server:inter_configuration/mysql_reconnect/count", default => 1},
+ log_login_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/login_db", default => "loginlog"},
+ char_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "char"},
+ interlog_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "interlog"},
+ ragsrvinfo_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "ragsrvinfo"},
+ acc_reg_num_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/registry/", default => "acc_reg_num_db"},
+ acc_reg_str_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/registry/", default => "acc_reg_str_db"},
+ char_reg_num_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/registry/", default => "char_reg_num_db"},
+ char_reg_str_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/registry/", default => "char_reg_str_db"},
+ global_acc_reg_num_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/registry/", default => "global_acc_reg_num_db"},
+ global_acc_reg_str_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/registry/", default => "global_acc_reg_str_db"},
+ hotkey_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "hotkey"},
+ scdata_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "sc_data"},
+ cart_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "cart_inventory"},
+ inventory_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "inventory"},
+ charlog_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "charlog"},
+ storage_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "storage"},
+ skill_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "skill"},
+ memo_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "memo"},
+ party_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "party"},
+ pet_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "pet"},
+ friend_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "friends"},
+ mail_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "mail"},
+ auction_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "auction"},
+ quest_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "quest"},
+ homunculus_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "homunculus"},
+ skill_homunculus_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "skill_homunculus"},
+ mercenary_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "mercenary"},
+ mercenary_owner_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "mercenary_owner"},
+ elemental_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "elemental"},
+ account_data_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/pc/", default => "account_data"},
+ guild_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/guild/main_db", default => "guild"},
+ guild_alliance_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/guild/alliance_db", default => "guild_alliance"},
+ guild_castle_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/guild/castle_db", default => "guild_castle"},
+ guild_expulsion_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/guild/expulsion_db", default => "guild_expulsion"},
+ guild_member_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/guild/member_db", default => "guild_member"},
+ guild_skill_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/guild/skill_db", default => "guild_skill"},
+ guild_position_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/guild/position_db", default => "guild_position"},
+ guild_storage_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/guild/storage_db", default => "guild_storage"},
+ mapreg_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "mapreg"},
+ autotrade_merchants_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "autotrade_merchants"},
+ autotrade_data_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "autotrade_data"},
+ npc_market_data_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/", default => "npc_market_data"},
+ default_codepage => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/", default => ""},
+ 'sql.db_hostname' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_hostname", default => "127.0.0.1"},
+ char_server_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_hostname", default => "127.0.0.1"},
+ map_server_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_hostname", default => "127.0.0.1"},
+ log_db_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_hostname", default => "127.0.0.1"},
+ 'sql.db_port' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "sql_connection:sql_connection/db_port", default => 3306},
+ char_server_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "sql_connection:sql_connection/db_port", default => 3306},
+ map_server_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "sql_connection:sql_connection/db_port", default => 3306},
+ log_db_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "sql_connection:sql_connection/db_port", default => 3306},
+ 'sql.db_username' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_username", default => "ragnarok"},
+ char_server_id => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_username", default => "ragnarok"},
+ map_server_id => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_username", default => "ragnarok"},
+ log_db_id => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_username", default => "ragnarok"},
+ 'sql.db_password' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_password", default => "ragnarok"},
+ char_server_pw => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_password", default => "ragnarok"},
+ map_server_pw => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_password", default => "ragnarok"},
+ log_db_pw => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_password", default => "ragnarok"},
+ 'sql.db_database' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_database", default => "ragnarok"},
+ char_server_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_database", default => "ragnarok"},
+ map_server_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_database", default => "ragnarok"},
+ log_db_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_database", default => "ragnarok"},
+ 'sql.codepage' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/codepage", default => ""},
+ log_codepage => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/codepage", default => ""},
+ interreg_db => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "interreg"},
+ import => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "conf/import/inter_conf.txt"},
+ }
+ },
+ {
+ files => ['login-server.conf', 'import/login_conf.txt'],
+ settings => {
+ bind_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "login-server:login_configuration/inter/", default => "127.0.0.1"},
+ login_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/inter/", default => 6900},
+ timestamp_format => {parse => \&parsecfg_string, print => \&printcfg_string, path => "console:console/", default => "[%d/%b %H:%M]"},
+ stdout_with_ansisequence => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "console:console/", default => "false"},
+ console_silent => {parse => \&parsecfg_int, print => \&printcfg_int, path => "console:console/", default => 0},
+ new_account => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/", default => "true"},
+ new_acc_length_limit => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/", default => "true"},
+ allowed_regs => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/", default => 1},
+ time_allowed => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/", default => 10},
+ log_login => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/log/", default => "true"},
+ date_format => {parse => \&parsecfg_string, print => \&printcfg_string, path => "login-server:login_configuration/log/", default => "%Y-%m-%d %H:%M:%S"},
+ group_id_to_connect => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/permission/", default => -1},
+ min_group_id_to_connect => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/permission/", default => -1},
+ start_limited_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/", default => -1},
+ check_client_version => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/permission/", default => "false"},
+ client_version_to_connect => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/permission/", default => 20},
+ use_MD5_passwords => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/", default => "false"},
+ 'ipban.enable' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/ipban/enabled", default => "true"},
+ 'ipban.sql.db_hostname' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_hostname", default => "127.0.0.1"},
+ 'ipban.sql.db_port' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "sql_connection:sql_connection/db_port", default => 3306},
+ 'ipban.sql.db_username' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_username", default => "ragnarok"},
+ 'ipban.sql.db_password' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_password", default => "ragnarok"},
+ 'ipban.sql.db_database' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_database", default => "ragnarok"},
+ 'ipban.sql.codepage' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/codepage", default => ""},
+ 'ipban.sql.ipban_table' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/ipban_table", default => "ipbanlist"},
+ 'ipban.dynamic_pass_failure_ban' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/account/ipban/dynamic_pass_failure/enabled", default => "true"},
+ 'ipban.dynamic_pass_failure_ban_interval' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/ipban/dynamic_pass_failure/ban_interval", default => 5},
+ 'ipban.dynamic_pass_failure_ban_limit' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/ipban/dynamic_pass_failure/ban_limit", default => 7},
+ 'ipban.dynamic_pass_failure_ban_duration' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/ipban/dynamic_pass_failure/ban_duration", default => 5},
+ ipban_cleanup_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/account/ipban/cleanup_interval", default => 60},
+ ip_sync_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "login-server:login_configuration/inter/ip_sync_interval", default => 10},
+ use_dnsbl => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/permission/DNS_blacklist/enabled", default => "false"},
+ dnsbl_servers => {parse => \&parsecfg_string, print => \&printcfg_strlist, path => "login-server:login_configuration/permission/DNS_blacklist/dnsbl_servers", default => "bl.blocklist.de, socks.dnsbl.sorbs.net"},
+ 'account.sql.db_hostname' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_hostname", default => "127.0.0.1"},
+ 'account.sql.db_port' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "sql_connection:sql_connection/db_port", default => 3306},
+ 'account.sql.db_username' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_username", default => "ragnarok"},
+ 'account.sql.db_password' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_password", default => "ragnarok"},
+ 'account.sql.db_database' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/db_database", default => "ragnarok"},
+ 'account.sql.codepage' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "sql_connection:sql_connection/codepage", default => ""},
+ 'account.sql.case_sensitive' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "sql_connection:sql_connection/case_sensitive", default => "false"},
+ 'account.sql.account_db' => {parse => \&parsecfg_string, print => \&printcfg_string, path => "inter-server:inter_configuration/database_names/account_db", default => "login"},
+ client_hash_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "login-server:login_configuration/permission/hash/enabled", default => "false"},
+ client_hash => {parse => \&parsecfg_stringarr, print => \&printcfg_md5hash, path => "login-server:login_configuration/permission/hash/MD5_hashes", default => []},
+ 'account.sql.accreg_db' => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "global_reg_value"},
+ import => {parse => \&parsecfg_stringarr, print => \&printcfg_nil, path => "", default => ["conf/inter-server.conf", "conf/import/login_conf.txt"]},
+ }
+ },
+ {
+ files => ['map-server.conf', 'import/map_conf.txt'],
+ settings => {
+ userid => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/inter/", default => "s1"},
+ passwd => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/inter/", default => "p1"},
+ char_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/inter/", default => "127.0.0.1"},
+ bind_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/inter/", default => "127.0.0.1"},
+ char_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "map-server:map_configuration/inter/", default => 6121},
+ map_ip => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/inter/", default => "127.0.0.1"},
+ map_port => {parse => \&parsecfg_int, print => \&printcfg_int, path => "map-server:map_configuration/inter/", default => 5121},
+ timestamp_format => {parse => \&parsecfg_string, print => \&printcfg_string, path => "console:console/", default => "[%d/%b %H:%M]"},
+ stdout_with_ansisequence => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "console:console/", default => "false"},
+ console_msg_log => {parse => \&parsecfg_int, print => \&printcfg_int, path => "console:console/", default => 0},
+ console_silent => {parse => \&parsecfg_int, print => \&printcfg_int, path => "console:console/", default => 0},
+ db_path => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/database/", default => "db"},
+ enable_spy => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "map-server:map_configuration/", default => "false"},
+ use_grf => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "map-server:map_configuration/", default => "false"},
+ autosave_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "map-server:map_configuration/database/", default => 300},
+ minsave_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "map-server:map_configuration/database/", default => 100},
+ save_settings => {parse => \&parsecfg_int, print => \&printcfg_hexint, path => "map-server:map_configuration/database/", default => 511},
+ default_language => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/", default => "English"},
+ help_txt => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/", default => "conf/help.txt"},
+ charhelp_txt => {parse => \&parsecfg_string, print => \&printcfg_string, path => "map-server:map_configuration/", default => "conf/charhelp.txt"},
+ help2_txt => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "conf/help2.txt"},
+ import => {parse => \&parsecfg_stringarr, print => \&printcfg_nil, path => "", default => ["conf/maps.conf", "conf/import/map_conf.txt"]},
+ }
+ },
+ {
+ files => ['logs.conf', 'import/log_conf.txt'],
+ settings => {
+ enable_logs => {parse => \&parsecfg_int, print => \&printcfg_hexint, path => "logs:map_log/enable", default => 0xFFFFF},
+ sql_logs => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "logs:map_log/database/use_sql", default => "true"},
+ log_filter => {parse => \&parsecfg_int, print => \&printcfg_int, path => "logs:map_log/filter/item/", default => 1},
+ refine_items_log => {parse => \&parsecfg_int, print => \&printcfg_int, path => "logs:map_log/filter/item/", default => 5},
+ rare_items_log => {parse => \&parsecfg_int, print => \&printcfg_int, path => "logs:map_log/filter/item/", default => 100},
+ price_items_log => {parse => \&parsecfg_int, print => \&printcfg_int, path => "logs:map_log/filter/item/", default => 1000},
+ amount_items_log => {parse => \&parsecfg_int, print => \&printcfg_int, path => "logs:map_log/filter/item/", default => 100},
+ log_branch => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "logs:map_log/", default => "false"},
+ log_zeny => {parse => \&parsecfg_int, print => \&printcfg_int, path => "logs:map_log/", default => 0},
+ log_mvpdrop => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "logs:map_log/", default => "false"},
+ log_commands => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "logs:map_log/", default => "true"},
+ log_npc => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "logs:map_log/", default => "false"},
+ log_chat => {parse => \&parsecfg_int, print => \&printcfg_int, path => "logs:map_log/filter/chat/", default => 0},
+ log_chat_woe_disable => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "logs:map_log/filter/chat/", default => "false"},
+ log_gm_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "logs:map_log/database/", default => "atcommandlog"},
+ log_branch_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "logs:map_log/database/", default => "branchlog"},
+ log_chat_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "logs:map_log/database/", default => "chatlog"},
+ log_mvpdrop_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "logs:map_log/database/", default => "mvplog"},
+ log_npc_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "logs:map_log/database/", default => "npclog"},
+ log_pick_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "logs:map_log/database/", default => "picklog"},
+ log_zeny_db => {parse => \&parsecfg_string, print => \&printcfg_string, path => "logs:map_log/database/", default => "zenylog"},
+ import => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "conf/import/log_conf.txt"},
+ }
+ },
+ {
+ files => ['script.conf', 'import/script_conf.txt'],
+ settings => {
+ warn_func_mismatch_paramnum => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "script:script_configuration/", default => "true"},
+ check_cmdcount => {parse => \&parsecfg_int, print => \&printcfg_int, path => "script:script_configuration/", default => 655360},
+ check_gotocount => {parse => \&parsecfg_int, print => \&printcfg_int, path => "script:script_configuration/", default => 2048},
+ input_min_value => {parse => \&parsecfg_int, print => \&printcfg_int, path => "script:script_configuration/", default => 0},
+ input_max_value => {parse => \&parsecfg_int, print => \&printcfg_int, path => "script:script_configuration/", default => 10000000},
+ warn_func_mismatch_argtypes => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "script:script_configuration/", default => "true"},
+ import => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "conf/import/script_conf.txt"},
+ }
+ },
+ {
+ files => ['packet.conf', 'import/packet_conf.txt'],
+ settings => {
+ debug => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "socket:socket_configuration/", default => "false"},
+ stall_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "socket:socket_configuration/", default => 60},
+ epoll_maxevents => {parse => \&parsecfg_int, print => \&printcfg_int, path => "socket:socket_configuration/", default => 1024},
+ socket_max_client_packet => {parse => \&parsecfg_int, print => \&printcfg_int, path => "socket:socket_configuration/", default => 65535},
+ enable_ip_rules => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "socket:socket_configuration/ip_rules/enable", default => "true"},
+ order => {parse => \&parsecfg_string, print => \&printcfg_string, path => "socket:socket_configuration/ip_rules/", default => "deny,allow"},
+ allow => {parse => \&parsecfg_stringarr, print => \&printcfg_strlist, path => "socket:socket_configuration/ip_rules/allow_list", default => []},
+ deny => {parse => \&parsecfg_stringarr, print => \&printcfg_strlist, path => "socket:socket_configuration/ip_rules/deny_list", default => []},
+ ddos_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "socket:socket_configuration/ddos/interval", default => 3000},
+ ddos_count => {parse => \&parsecfg_int, print => \&printcfg_int, path => "socket:socket_configuration/ddos/count", default => 5},
+ ddos_autoreset => {parse => \&parsecfg_int, print => \&printcfg_int, path => "socket:socket_configuration/ddos/autoreset", default => 600000},
+ import => {parse => \&parsecfg_string, print => \&printcfg_nil, path => "", default => "conf/import/packet_conf.txt"},
+ }
+ },
+ {
+ files => ['battle.conf', 'battle/battle.conf', 'battle/client.conf', 'battle/drops.conf', 'battle/exp.conf', 'battle/gm.conf', 'battle/guild.conf', 'battle/battleground.conf', 'battle/items.conf', 'battle/monster.conf', 'battle/party.conf', 'battle/pet.conf', 'battle/homunc.conf', 'battle/player.conf', 'battle/skill.conf', 'battle/status.conf', 'battle/feature.conf', 'battle/misc.conf', 'import/battle_conf.txt'],
+ settings => {
+ bg_flee_penalty => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battleground:", default => 20},
+ bg_update_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battleground:", default => 1000},
+ 'feature.buying_store' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "feature:features/buying_store", default => "true"},
+ 'feature.search_stores' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "feature:features/search_stores", default => "true"},
+ 'feature.atcommand_suggestions' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "feature:features/atcommand_suggestions", default => "false"},
+ 'feature.banking' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "feature:features/banking", default => "true"},
+ 'feature.auction' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "feature:features/auction", default => "false"},
+ 'feature.roulette' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "feature:features/roulette", default => "false"},
+ atcommand_spawn_quantity_limit => {parse => \&parsecfg_int, print => \&printcfg_int, path => "gm:", default => 100},
+ atcommand_slave_clone_limit => {parse => \&parsecfg_int, print => \&printcfg_int, path => "gm:", default => 25},
+ partial_name_scan => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "gm:", default => "true"},
+ atcommand_max_stat_bypass => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "gm:", default => "false"},
+ ban_hack_trade => {parse => \&parsecfg_int, print => \&printcfg_int, path => "gm:", default => 5},
+ atcommand_mobinfo_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "gm:", default => 0},
+ gm_ignore_warpable_area => {parse => \&parsecfg_int, print => \&printcfg_int, path => "gm:", default => 2},
+ atcommand_levelup_events => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "gm:", default => "false"},
+ guild_emperium_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "guild:", default => "true"},
+ guild_exp_limit => {parse => \&parsecfg_int, print => \&printcfg_int, path => "guild:", default => 50},
+ guild_max_castles => {parse => \&parsecfg_int, print => \&printcfg_int, path => "guild:", default => 0},
+ guild_skill_relog_delay => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "guild:", default => "false"},
+ gvg_flee_penalty => {parse => \&parsecfg_int, print => \&printcfg_int, path => "guild:", default => 20},
+ require_glory_guild => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "guild:", default => "false"},
+ max_guild_alliance => {parse => \&parsecfg_int, print => \&printcfg_int, path => "guild:", default => 3},
+ guild_notice_changemap => {parse => \&parsecfg_int, print => \&printcfg_int, path => "guild:", default => 2},
+ guild_castle_invite => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "guild:", default => "false"},
+ guild_castle_expulsion => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "guild:", default => "false"},
+ hom_setting => {parse => \&parsecfg_int, print => \&printcfg_hexint, path => "homunc:", default => 0x1D},
+ homunculus_friendly_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "homunc:", default => 100},
+ hom_rename => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "homunc:", default => "false"},
+ hvan_explosion_intimate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "homunc:", default => 45000},
+ homunculus_show_growth => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "homunc:", default => "true"},
+ homunculus_autoloot => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "homunc:", default => "true"},
+ homunculus_auto_vapor => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "homunc:", default => "true"},
+ homunculus_max_level => {parse => \&parsecfg_int, print => \&printcfg_int, path => "homunc:", default => 99},
+ homunculus_S_max_level => {parse => \&parsecfg_int, print => \&printcfg_int, path => "homunc:", default => 150},
+ enable_baseatk => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 9},
+ enable_perfect_flee => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 1},
+ enable_critical => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 17},
+ mob_critical_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 100},
+ critical_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 100},
+ attack_walk_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 15},
+ pc_damage_walk_delay_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 20},
+ damage_walk_delay_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 100},
+ multihit_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 80},
+ player_damage_delay_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 100},
+ undead_detect_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 0},
+ attribute_recover => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "battle:", default => "false"},
+ min_hitrate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 5},
+ max_hitrate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 100},
+ agi_penalty_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 1},
+ agi_penalty_target => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 1},
+ agi_penalty_count => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 3},
+ agi_penalty_num => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 10},
+ vit_penalty_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 1},
+ vit_penalty_target => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 1},
+ vit_penalty_count => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 3},
+ vit_penalty_num => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 5},
+ weapon_defense_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 0},
+ magic_defense_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 0},
+ attack_direction_change => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 0},
+ attack_attr_none => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 14},
+ equip_natural_break_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 0},
+ equip_self_break_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 100},
+ equip_skill_break_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 100},
+ delay_battle_damage => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "battle:", default => "true"},
+ arrow_decrement => {parse => \&parsecfg_int, print => \&printcfg_int, path => "battle:", default => 1},
+ autospell_check_range => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "battle:", default => "false"},
+ knockback_left => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "battle:", default => "true"},
+ snap_dodge => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "battle:", default => "false"},
+ packet_obfuscation => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 1},
+ min_chat_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 0},
+ min_hair_style => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 0},
+ max_hair_style => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 29},
+ min_hair_color => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 0},
+ max_hair_color => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 8},
+ min_cloth_color => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 0},
+ max_cloth_color => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 4},
+ min_body_style => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 0},
+ max_body_style => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 4},
+ hide_woe_damage => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "true"},
+ pet_hair_style => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 100},
+ area_size => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 14},
+ max_walk_path => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 17},
+ max_lv => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 99},
+ aura_lv => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 99},
+ client_limit_unit_lv => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 0},
+ wedding_modifydisplay => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "false"},
+ save_clothcolor => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "true"},
+ save_body_style => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "false"},
+ wedding_ignorepalette => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "false"},
+ xmas_ignorepalette => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "false"},
+ summer_ignorepalette => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "false"},
+ hanbok_ignorepalette => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "false"},
+ display_version => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "false"},
+ display_hallucination => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "true"},
+ display_status_timers => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "true"},
+ client_reshuffle_dice => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "true"},
+ client_sort_storage => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "client:", default => "false"},
+ client_accept_chatdori => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 0},
+ client_emblem_max_blank_percent => {parse => \&parsecfg_int, print => \&printcfg_int, path => "client:", default => 100},
+ item_auto_get => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "drops:", default => "false"},
+ flooritem_lifetime => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 60000},
+ item_first_get_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 3000},
+ item_second_get_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1000},
+ item_third_get_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1000},
+ mvp_item_first_get_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ mvp_item_second_get_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ mvp_item_third_get_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 2000},
+ item_rate_common => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_rate_common_boss => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_drop_common_min => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ item_drop_common_max => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ item_rate_heal => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_rate_heal_boss => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_drop_heal_min => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ item_drop_heal_max => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ item_rate_use => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_rate_use_boss => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_drop_use_min => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ item_drop_use_max => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ item_rate_equip => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_rate_equip_boss => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_drop_equip_min => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ item_drop_equip_max => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ item_rate_card => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_rate_card_boss => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_drop_card_min => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ item_drop_card_max => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ item_rate_mvp => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_drop_mvp_min => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ item_drop_mvp_max => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ item_rate_adddrop => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_drop_add_min => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ item_drop_add_max => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ item_rate_treasure => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 100},
+ item_drop_treasure_min => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ item_drop_treasure_max => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 10000},
+ item_logarithmic_drops => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "drops:", default => "false"},
+ drop_rate0item => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "drops:", default => "false"},
+ drops_by_luk => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 0},
+ drops_by_luk2 => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 0},
+ alchemist_summon_reward => {parse => \&parsecfg_int, print => \&printcfg_int, path => "drops:", default => 1},
+ base_exp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 100},
+ job_exp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 100},
+ multi_level_up => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "exp:", default => "false"},
+ max_exp_gain_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 0},
+ exp_calc_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 0},
+ exp_bonus_attacker => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 25},
+ exp_bonus_max_attacker => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 12},
+ mvp_exp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 100},
+ quest_exp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 100},
+ heal_exp => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 0},
+ resurrection_exp => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 0},
+ shop_exp => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 0},
+ pvp_exp => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "exp:", default => "true"},
+ death_penalty_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 1},
+ death_penalty_base => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 100},
+ death_penalty_job => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 100},
+ zeny_penalty => {parse => \&parsecfg_int, print => \&printcfg_int, path => "exp:", default => 0},
+ disp_experience => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "exp:", default => "false"},
+ disp_zeny => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "exp:", default => "false"},
+ use_statpoint_table => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "exp:", default => "true"},
+ vending_max_value => {parse => \&parsecfg_int, print => \&printcfg_int, path => "items:", default => 1000000000},
+ vending_over_max => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "true"},
+ vending_tax => {parse => \&parsecfg_int, print => \&printcfg_int, path => "items:", default => 200},
+ buyer_name => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "true"},
+ weapon_produce_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "items:", default => 100},
+ potion_produce_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "items:", default => 100},
+ produce_item_name_input => {parse => \&parsecfg_int, print => \&printcfg_hexint, path => "items:", default => 0x03},
+ dead_branch_active => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "true"},
+ random_monster_checklv => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "false"},
+ ignore_items_gender => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "true"},
+ item_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "false"},
+ item_use_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "items:", default => 100},
+ cashfood_use_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "items:", default => 60000},
+ gtb_sc_immunity => {parse => \&parsecfg_int, print => \&printcfg_int, path => "items:", default => 50},
+ autospell_stacking => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "false"},
+ item_restricted_consumption_type => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "true"},
+ item_enabled_npc => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "items:", default => "true"},
+ unequip_restricted_equipment => {parse => \&parsecfg_int, print => \&printcfg_int, path => "items:", default => 0},
+ pk_mode => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 0},
+ manner_system => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 31},
+ pk_min_level => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 55},
+ pk_level_range => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 0},
+ skill_log => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ battle_log => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ etc_log => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ warp_point_debug => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ night_at_start => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ day_duration => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 0},
+ night_duration => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 0},
+ duel_allow_pvp => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ duel_allow_gvg => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ duel_allow_teleport => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ duel_autoleave_when_die => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "true"},
+ duel_time_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 60},
+ duel_only_on_same_map => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ official_cell_stack_limit => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 1},
+ custom_cell_stack_limit => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 1},
+ check_occupied_cells => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "true"},
+ at_mapflag => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ at_timeout => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 0},
+ auction_feeperhour => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 12000},
+ auction_maximumprice => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 500000000},
+ searchstore_querydelay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 10},
+ searchstore_maxresults => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 30},
+ cashshop_show_points => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ mail_show_status => {parse => \&parsecfg_int, print => \&printcfg_int, path => "misc:", default => 0},
+ mon_trans_disable_in_gvg => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "false"},
+ case_sensitive_aegisnames => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "misc:", default => "true"},
+ mvp_hp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ monster_hp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ monster_max_aspd => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 199},
+ monster_ai => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ monster_chase_refresh => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 3},
+ mob_warp => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ mob_active_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ boss_active_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ view_range_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ chase_range_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ monster_active_enable => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ override_mob_names => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ monster_damage_delay_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ monster_loot_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ mob_skill_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ mob_skill_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ mob_count_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ mob_spawn_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ plant_spawn_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ boss_spawn_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 100},
+ no_spawn_on_player => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ force_random_spawn => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "false"},
+ slaves_inherit_mode => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 2},
+ slaves_inherit_speed => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 3},
+ summons_trigger_autospells => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ retaliate_to_master => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ mob_changetarget_byskill => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "false"},
+ monster_class_change_full_recover => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ show_mob_info => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ zeny_from_mobs => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "false"},
+ mobs_level_up => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "false"},
+ mobs_level_up_exp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 1},
+ dynamic_mobs => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ mob_remove_damaged => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ mob_remove_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 300000},
+ mob_npc_event_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 1},
+ ksprotection => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 0},
+ mob_slave_keep_target => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ mvp_tomb_enabled => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ show_monster_hp_bar => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "true"},
+ mob_size_influence => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "monster:", default => "false"},
+ mob_icewall_walk_block => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 220},
+ boss_icewall_walk_block => {parse => \&parsecfg_int, print => \&printcfg_int, path => "monster:", default => 1},
+ show_steal_in_same_party => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "party:", default => "false"},
+ party_update_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "party:", default => 1000},
+ party_hp_mode => {parse => \&parsecfg_int, print => \&printcfg_int, path => "party:", default => 0},
+ show_party_share_picker => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "party:", default => "true"},
+ 'show_picker.item_type' => {parse => \&parsecfg_int, print => \&printcfg_int, path => "party:show_picker_item_type", default => 112},
+ party_item_share_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "party:", default => 0},
+ idle_no_share => {parse => \&parsecfg_int, print => \&printcfg_int, path => "party:", default => 0},
+ party_even_share_bonus => {parse => \&parsecfg_int, print => \&printcfg_int, path => "party:", default => 0},
+ display_party_name => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "party:", default => "false"},
+ pet_catch_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 100},
+ pet_rename => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "pet:", default => "false"},
+ pet_friendly_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 100},
+ pet_hungry_delay_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 100},
+ pet_hungry_friendly_decrease => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 5},
+ pet_equip_required => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "pet:", default => "true"},
+ pet_attack_support => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "pet:", default => "false"},
+ pet_damage_support => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "pet:", default => "false"},
+ pet_support_min_friendly => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 900},
+ pet_equip_min_friendly => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 900},
+ pet_status_support => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "pet:", default => "false"},
+ pet_support_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 100},
+ pet_attack_exp_to_master => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "pet:", default => "false"},
+ pet_attack_exp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 100},
+ pet_lv_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 0},
+ pet_max_stats => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 99},
+ pet_max_atk1 => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 500},
+ pet_max_atk2 => {parse => \&parsecfg_int, print => \&printcfg_int, path => "pet:", default => 1000},
+ pet_disable_in_gvg => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "pet:", default => "false"},
+ hp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 100},
+ sp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 100},
+ left_cardfix_to_right => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ restart_hp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 0},
+ restart_sp_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 0},
+ player_skillfree => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "false"},
+ player_skillup_limit => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ quest_skill_learn => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "false"},
+ quest_skill_reset => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "false"},
+ basic_skill_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ player_invincible_time => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 5000},
+ fix_warp_hit_delay_abuse => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "false"},
+ natural_healhp_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 6000},
+ natural_healsp_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 8000},
+ natural_heal_skill_interval => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 10000},
+ natural_heal_weight_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 50},
+ max_aspd => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 190},
+ max_third_aspd => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 193},
+ max_walk_speed => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 300},
+ max_hp => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 1000000},
+ max_sp => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 1000000},
+ max_parameter => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 99},
+ max_third_parameter => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 130},
+ max_extended_parameter => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 125},
+ max_baby_parameter => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 80},
+ max_baby_third_parameter => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 117},
+ max_def => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 99},
+ over_def_bonus => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 0},
+ max_cart_weight => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 8000},
+ prevent_logout => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 10000},
+ show_hp_sp_drain => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "false"},
+ show_hp_sp_gain => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ show_katar_crit_bonus => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "false"},
+ friend_auto_add => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ invite_request_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ bone_drop => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 0},
+ character_size => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 0},
+ idle_no_autoloot => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 0},
+ min_npc_vendchat_distance => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 3},
+ vendchat_near_hiddennpc => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "false"},
+ snovice_call_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "player:", default => 0},
+ idletime_criteria => {parse => \&parsecfg_int, print => \&printcfg_hexint, path => "player:", default => 0x1F},
+ costume_refine_def => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ shadow_refine_def => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ shadow_refine_atk => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ player_warp_keep_direction => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "player:", default => "true"},
+ casting_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 100},
+ delay_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 100},
+ delay_dependon_dex => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ delay_dependon_agi => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ min_skill_delay_limit => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 100},
+ default_walk_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 300},
+ no_skill_delay => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 2},
+ castrate_dex_scale => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 150},
+ vcast_stat_scale => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 530},
+ skill_amotion_leniency => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 90},
+ skill_delay_attack_enable => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "true"},
+ skill_add_range => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ skill_out_range_consume => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ skillrange_by_distance => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 14},
+ skillrange_from_weapon => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ skill_caster_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "true"},
+ clear_skills_on_death => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ clear_skills_on_warp => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 15},
+ defunit_not_enemy => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ skill_min_damage => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 6},
+ combo_delay_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 100},
+ auto_counter_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 15},
+ skill_reiteration => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ skill_nofootset => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 1},
+ gvg_traps_target_all => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 1},
+ traps_setting => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ summon_flora_setting => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 3},
+ song_timer_reset => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ skill_wall_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "true"},
+ player_cloak_check_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 1},
+ monster_cloak_check_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 4},
+ land_skill_limit => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 9},
+ display_skill_fail => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ chat_warpportal => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ sense_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 1},
+ finger_offensive_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ gx_allhit => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ gx_disptype => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 1},
+ devotion_level_difference => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 10},
+ player_skill_partner_check => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "true"},
+ skill_removetrap_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ backstab_bow_penalty => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "true"},
+ skill_steal_max_tries => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ copyskill_restrict => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 2},
+ berserk_cancels_buffs => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ max_heal => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 9999},
+ max_heal_lv => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 11},
+ emergency_call => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 11},
+ guild_aura => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 31},
+ skip_teleport_lv1_menu => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ allow_skill_without_day => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ allow_es_magic_player => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ sg_miracle_skill_ratio => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 2},
+ sg_miracle_skill_duration => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 3600000},
+ sg_angel_skill_ratio => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 10},
+ skill_add_heal_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 7},
+ eq_single_target_reflectable => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "true"},
+ 'invincible.nodamage' => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "false"},
+ dancing_weaponswitch_fix => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "true"},
+ skill_trap_type => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ mob_max_skilllvl => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 100},
+ bowling_bash_area => {parse => \&parsecfg_int, print => \&printcfg_int, path => "skill:", default => 0},
+ stormgust_knockback => {parse => \&parsecfg_bool, print => \&printcfg_bool, path => "skill:", default => "true"},
+ status_cast_cancel => {parse => \&parsecfg_int, print => \&printcfg_int, path => "status:", default => 0},
+ pc_status_def_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "status:", default => 100},
+ mob_status_def_rate => {parse => \&parsecfg_int, print => \&printcfg_int, path => "status:", default => 100},
+ pc_max_status_def => {parse => \&parsecfg_int, print => \&printcfg_int, path => "status:", default => 100},
+ mob_max_status_def => {parse => \&parsecfg_int, print => \&printcfg_int, path => "status:", default => 100},
+ import => {parse => \&parsecfg_stringarr, print => \&printcfg_nil, path => "", default => ['conf/battle/battle.conf', 'conf/battle/client.conf', 'conf/battle/drops.conf', 'conf/battle/exp.conf', 'conf/battle/gm.conf', 'conf/battle/guild.conf', 'conf/battle/battleground.conf', 'conf/battle/items.conf', 'conf/battle/monster.conf', 'conf/battle/party.conf', 'conf/battle/pet.conf', 'conf/battle/homunc.conf', 'conf/battle/player.conf', 'conf/battle/skill.conf', 'conf/battle/status.conf', 'conf/battle/feature.conf', 'conf/battle/misc.conf', 'conf/import/battle_conf.txt']},
+ }
+ },
+);
+
+for (@ARGV) {
+ if (/^-q$/) { $silent = 1; }
+ elsif (/^-v$/) { $silent = 0; }
+ elsif (-d) { $confpath = $_; }
+ else { undef $confpath }
+}
+
+verbose(<<'EOF');
+=============== Hercules Configuration Migration Helper ===============
+= _ _ _ =
+= | | | | | | =
+= | |_| | ___ _ __ ___ _ _| | ___ ___ =
+= | _ |/ _ \ '__/ __| | | | |/ _ \/ __| =
+= | | | | __/ | | (__| |_| | | __/\__ \ =
+= \_| |_/\___|_| \___|\__,_|_|\___||___/ =
+=======================================================================
+This tool will assist you through the migration of the old (txt-based)
+configuration files to the new (libconfig-based) format.
+Please follow the displayed instructions.
+=======================================================================
+
+EOF
+
+die "Usage: ./$0 [-q | -v] [path to the conf directory]\nIf no options are passed, it acts as if called as ./$0 conf\n" unless defined $confpath and -d $confpath;
+
+my $count = 0;
+for (@defaults) {
+ my @files = map { $confpath . '/' . $_ } @{$_->{files}};
+ $count += process_conf(\@files, $_->{settings})
+}
+verbose("\nThere are no files to migrate.\n") unless $count;
diff --git a/tools/constdbconverter.pl b/tools/constdbconverter.pl
index b534eba70..39f594790 100755
--- a/tools/constdbconverter.pl
+++ b/tools/constdbconverter.pl
@@ -3,7 +3,7 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2016 Hercules Dev Team
+# Copyright (C) 2016-2020 Hercules Dev Team
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -73,7 +73,7 @@ print << "EOF";
//= This file is part of Hercules.
//= http://herc.ws - http://github.com/HerculesWS/Hercules
//=
-//= Copyright (C) 2016-$year Hercules Dev Team
+//= Copyright (C) 2016-$year Hercules Dev Team
//=
//= Hercules is free software: you can redistribute it and/or modify
//= it under the terms of the GNU General Public License as published by
diff --git a/tools/doxygen/Hercules128.png b/tools/doxygen/Hercules128.png
new file mode 100644
index 000000000..79919da9b
--- /dev/null
+++ b/tools/doxygen/Hercules128.png
Binary files differ
diff --git a/tools/doxygen/Hercules48.png b/tools/doxygen/Hercules48.png
new file mode 100644
index 000000000..022893953
--- /dev/null
+++ b/tools/doxygen/Hercules48.png
Binary files differ
diff --git a/tools/doxygen/Makefile.in b/tools/doxygen/Makefile.in
new file mode 100644
index 000000000..483e640aa
--- /dev/null
+++ b/tools/doxygen/Makefile.in
@@ -0,0 +1,70 @@
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2016-2020 Hercules Dev Team
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# @configure_input@
+
+@SET_MAKE@
+
+COMMON_D = ../../src/common
+MAP_D = ../../src/map
+CHAR_D = ../../src/char
+LOGIN_D = ../../src/login
+PLUGIN_D = ../../src/plugins
+COMMON_C = $(wildcard $(COMMON_D)/*.c)
+COMMON_H = $(wildcard $(COMMON_D)/*.h)
+MAP_C = $(wildcard $(MAP_D)/*.c)
+MAP_H = $(wildcard $(MAP_D)/*.h)
+CHAR_C = $(wildcard $(CHAR_D)/*.c)
+CHAR_H = $(wildcard $(CHAR_D)/*.h)
+LOGIN_C = $(wildcard $(LOGIN_D)/*.c)
+LOGIN_H = $(wildcard $(LOGIN_D)/*.h)
+ALL_C = $(COMMON_C) $(MAP_C) $(CHAR_C) $(LOGIN_C)
+ALL_H = $(COMMON_H) $(MAP_H) $(CHAR_H) $(LOGIN_H)
+
+HAVE_DOXYGEN=@HAVE_DOXYGEN@
+ifeq ($(HAVE_DOXYGEN),yes)
+ ALL_DEPENDS = docs
+else
+ ALL_DEPENDS = needs_doxygen
+endif
+
+#####################################################################
+.PHONY: clean buildclean
+
+all: $(ALL_DEPENDS)
+
+buildclean:
+
+clean: buildclean
+ @echo " CLEAN docs"
+ @rm -rf docs
+
+Makefile: Makefile.in
+ @$(MAKE) -C ../.. tools/doxygen/Makefile
+
+#####################################################################
+
+docs: $(ALL_C) $(ALL_H) doxygen.conf
+ @echo " Generating Doxygen documentation..."
+ @doxygen doxygen.conf
+
+#####################################################################
+
+needs_doxygen:
+ @echo "doxygen not found or disabled by the configure script"
+ @exit 1
diff --git a/tools/doxygen/doxygen.conf b/tools/doxygen/doxygen.conf
new file mode 100644
index 000000000..95d3b3ebf
--- /dev/null
+++ b/tools/doxygen/doxygen.conf
@@ -0,0 +1,2490 @@
+# Doxyfile 1.8.16
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the configuration
+# file that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# https://www.gnu.org/software/libiconv/ for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "Hercules"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO = Hercules48.png
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = docs
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# The OUTPUT_TEXT_DIRECTION tag is used to specify the direction in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all generated output in the proper direction.
+# Possible values are: None, LTR, RTL and Context.
+# The default value is: None.
+
+OUTPUT_TEXT_DIRECTION = None
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = YES
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH = ../../
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH = ../../
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the JAVADOC_BANNER tag is set to YES then doxygen will interpret a line
+# such as
+# /***************
+# as being the beginning of a Javadoc-style comment "banner". If set to NO, the
+# Javadoc-style will behave just like regular comments and it will not be
+# interpreted by doxygen.
+# The default value is: NO.
+
+JAVADOC_BANNER = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = NO
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines (in the resulting output). You can put ^^ in the value part of an
+# alias to insert a newline as if a physical newline was in the original file.
+# When you need a literal { or } or , in the value part of an alias you have to
+# escape them by means of a backslash (\), this can lead to conflicts with the
+# commands \{ and \} for these it is advised to use the version @{ and @} or use
+# a double escape (\\{ and \\})
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Set the OPTIMIZE_OUTPUT_SLICE tag to YES if your project consists of Slice
+# sources only. Doxygen will then generate output that is more tailored for that
+# language. For instance, namespaces will be presented as modules, types will be
+# separated into more groups, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_SLICE = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# Csharp (C#), C, C++, D, PHP, md (Markdown), Objective-C, Python, Slice,
+# Fortran (fixed format Fortran: FortranFixed, free formatted Fortran:
+# FortranFree, unknown formatted Fortran: Fortran. In the later case the parser
+# tries to guess whether the code is fixed or free formatted code, this is the
+# default for Fortran type files), VHDL, tcl. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is
+# Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING = h=C
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See https://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When the TOC_INCLUDE_HEADINGS tag is set to a non-zero value, all headings up
+# to that level are automatically included in the table of contents, even if
+# they do not have an id attribute.
+# Note: This feature currently applies only to Markdown headings.
+# Minimum value: 0, maximum value: 99, default value: 5.
+# This tag requires that the tag MARKDOWN_SUPPORT is set to YES.
+
+TOC_INCLUDE_HEADINGS = 5
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# https://www.riverbankcomputing.com/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = NO
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = NO
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = YES
+
+# If the EXTRACT_PRIV_VIRTUAL tag is set to YES, documented private virtual
+# methods of a class will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIV_VIRTUAL = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = YES
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# (including Cygwin) ands Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER = "git log -n 1 --pretty=format:%h -- "
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE = layoutFile.xml
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also https://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation. If
+# EXTRACT_ALL is set to YES then this flag will automatically be disabled.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = YES
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = ../../src/map \
+ ../../src/common \
+ ../../src/char \
+ ../../src/login \
+ ../../src/config
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: https://www.gnu.org/software/libiconv/) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f95, *.f03, *.f08,
+# *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf, *.qsf and *.ice.
+
+FILE_PATTERNS = *.c \
+ *.h
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = YES
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = YES
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# entity all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see https://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the configuration file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# https://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 30
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 100
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = YES
+
+# If the HTML_DYNAMIC_MENUS tag is set to YES then the generated HTML
+# documentation will contain a main index with vertical navigation menus that
+# are dynamically created via Javascript. If disabled, the navigation index will
+# consists of multiple levels of tabs that are statically embedded in every HTML
+# page. Disable this option to support browsers that do not have Javascript,
+# like the Qt help browser.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_MENUS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: https://developer.apple.com/xcode/), introduced with OSX
+# 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See https://developer.apple.com/library/archive/featuredarticles/Doxy
+# genXcode/_index.html for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: https://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: https://doc.qt.io/archives/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# https://doc.qt.io/archives/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANSPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# https://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from https://www.mathjax.org before deployment.
+# The default value is: https://cdnjs.cloudflare.com/ajax/libs/mathjax/2.7.5/.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: https://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when not enabling USE_PDFLATEX the default is latex when enabling
+# USE_PDFLATEX the default is pdflatex and when in the later case latex is
+# chosen this is overwritten by pdflatex. For specific output languages the
+# default can have been set differently, this depends on the implementation of
+# the output language.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# Note: This tag is used in the Makefile / make.bat.
+# See also: LATEX_MAKEINDEX_CMD for the part in the generated output file
+# (.tex).
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# The LATEX_MAKEINDEX_CMD tag can be used to specify the command name to
+# generate index for LaTeX. In case there is no backslash (\) as first character
+# it will be automatically added in the LaTeX code.
+# Note: This tag is used in the generated output file (.tex).
+# See also: MAKEINDEX_CMD_NAME for the part in the Makefile / make.bat.
+# The default value is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_MAKEINDEX_CMD = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# https://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+# The LATEX_EMOJI_DIRECTORY tag is used to specify the (relative or absolute)
+# path from which the emoji images will be read. If a relative path is entered,
+# it will be relative to the LATEX_OUTPUT directory. If left blank the
+# LATEX_OUTPUT directory will be used.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EMOJI_DIRECTORY =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# configuration file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's configuration file. A template extensions file can be
+# generated using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+# If the XML_NS_MEMB_FILE_SCOPE tag is set to YES, doxygen will include
+# namespace members in file scope as well, matching the HTML output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_NS_MEMB_FILE_SCOPE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sourceforge.net/) file that captures
+# the structure of the code including all documentation. Note that this feature
+# is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = YES
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH = ../../src \
+ ../../3rdparty
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = YES
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = NO
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: NO.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = YES
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = YES
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, jpg, gif, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the PLANTUML_CFG_FILE tag can be used to specify a
+# configuration file for plantuml.
+
+PLANTUML_CFG_FILE =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 100
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = YES
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = YES
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/tools/doxygen/footer.html b/tools/doxygen/footer.html
new file mode 100644
index 000000000..aecaafcc4
--- /dev/null
+++ b/tools/doxygen/footer.html
@@ -0,0 +1,21 @@
+<!-- HTML footer for doxygen 1.8.8-->
+<!-- start footer part -->
+<!--BEGIN GENERATE_TREEVIEW-->
+<div id="nav-path" class="navpath"><!-- id is needed for treeview function! -->
+ <ul>
+ $navpath
+ <li class="footer">$generatedby
+ <a href="http://www.doxygen.org/index.html">
+ <img class="footer" src="$relpath^doxygen.png" alt="doxygen"/></a> $doxygenversion </li>
+ </ul>
+</div>
+<!--END GENERATE_TREEVIEW-->
+<!--BEGIN !GENERATE_TREEVIEW-->
+<hr class="footer"/><address class="footer"><small>
+$generatedby &#160;<a href="http://www.doxygen.org/index.html">
+<img class="footer" src="$relpath^doxygen.png" alt="doxygen"/>
+</a> $doxygenversion
+</small></address>
+<!--END !GENERATE_TREEVIEW-->
+</body>
+</html>
diff --git a/tools/doxygen/header.html b/tools/doxygen/header.html
new file mode 100644
index 000000000..31aae0ea2
--- /dev/null
+++ b/tools/doxygen/header.html
@@ -0,0 +1,55 @@
+<!-- HTML header for doxygen 1.8.8-->
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+<head>
+<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+<meta http-equiv="X-UA-Compatible" content="IE=9"/>
+<meta name="generator" content="Doxygen $doxygenversion"/>
+<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
+<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
+<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
+<script type="text/javascript" src="$relpath^jquery.js"></script>
+<script type="text/javascript" src="$relpath^dynsections.js"></script>
+$treeview
+$search
+$mathjax
+<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css" />
+$extrastylesheet
+</head>
+<body>
+<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
+
+<!--BEGIN TITLEAREA-->
+<div id="titlearea">
+<table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+ <!--BEGIN PROJECT_LOGO-->
+ <td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
+ <!--END PROJECT_LOGO-->
+ <!--BEGIN PROJECT_NAME-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectname">$projectname
+ <!--BEGIN PROJECT_NUMBER-->&#160;<span id="projectnumber">$projectnumber</span><!--END PROJECT_NUMBER-->
+ </div>
+ <!--BEGIN PROJECT_BRIEF--><div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
+ </td>
+ <!--END PROJECT_NAME-->
+ <!--BEGIN !PROJECT_NAME-->
+ <!--BEGIN PROJECT_BRIEF-->
+ <td style="padding-left: 0.5em;">
+ <div id="projectbrief">$projectbrief</div>
+ </td>
+ <!--END PROJECT_BRIEF-->
+ <!--END !PROJECT_NAME-->
+ <!--BEGIN DISABLE_INDEX-->
+ <!--BEGIN SEARCHENGINE-->
+ <td>$searchbox</td>
+ <!--END SEARCHENGINE-->
+ <!--END DISABLE_INDEX-->
+ </tr>
+ </tbody>
+</table>
+</div>
+<!--END TITLEAREA-->
+<!-- end header part -->
diff --git a/tools/doxygen/layoutFile.xml b/tools/doxygen/layoutFile.xml
new file mode 100644
index 000000000..740548619
--- /dev/null
+++ b/tools/doxygen/layoutFile.xml
@@ -0,0 +1,194 @@
+<doxygenlayout version="1.0">
+ <!-- Generated by doxygen 1.8.8 -->
+ <!-- Navigation index tabs for HTML output -->
+ <navindex>
+ <tab type="mainpage" visible="yes" title=""/>
+ <tab type="pages" visible="yes" title="" intro=""/>
+ <tab type="modules" visible="yes" title="" intro=""/>
+ <tab type="namespaces" visible="yes" title="">
+ <tab type="namespacelist" visible="yes" title="" intro=""/>
+ <tab type="namespacemembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="classes" visible="yes" title="">
+ <tab type="classlist" visible="yes" title="" intro=""/>
+ <tab type="classindex" visible="$ALPHABETICAL_INDEX" title=""/>
+ <tab type="hierarchy" visible="yes" title="" intro=""/>
+ <tab type="classmembers" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="files" visible="yes" title="">
+ <tab type="filelist" visible="yes" title="" intro=""/>
+ <tab type="globals" visible="yes" title="" intro=""/>
+ </tab>
+ <tab type="examples" visible="yes" title="" intro=""/>
+ </navindex>
+
+ <!-- Layout definition for a class page -->
+ <class>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <inheritancegraph visible="$CLASS_GRAPH"/>
+ <collaborationgraph visible="$COLLABORATION_GRAPH"/>
+ <memberdecl>
+ <nestedclasses visible="yes" title=""/>
+ <publictypes title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <publicslots title=""/>
+ <signals title=""/>
+ <publicmethods title=""/>
+ <publicstaticmethods title=""/>
+ <publicattributes title=""/>
+ <publicstaticattributes title=""/>
+ <protectedtypes title=""/>
+ <protectedslots title=""/>
+ <protectedmethods title=""/>
+ <protectedstaticmethods title=""/>
+ <protectedattributes title=""/>
+ <protectedstaticattributes title=""/>
+ <packagetypes title=""/>
+ <packagemethods title=""/>
+ <packagestaticmethods title=""/>
+ <packageattributes title=""/>
+ <packagestaticattributes title=""/>
+ <properties title=""/>
+ <events title=""/>
+ <privatetypes title=""/>
+ <privateslots title=""/>
+ <privatemethods title=""/>
+ <privatestaticmethods title=""/>
+ <privateattributes title=""/>
+ <privatestaticattributes title=""/>
+ <friends title=""/>
+ <related title="" subtitle=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <services title=""/>
+ <interfaces title=""/>
+ <constructors title=""/>
+ <functions title=""/>
+ <related title=""/>
+ <variables title=""/>
+ <properties title=""/>
+ <events title=""/>
+ </memberdef>
+ <allmemberslink visible="yes"/>
+ <usedfiles visible="$SHOW_USED_FILES"/>
+ <authorsection visible="yes"/>
+ </class>
+
+ <!-- Layout definition for a namespace page -->
+ <namespace>
+ <briefdescription visible="yes"/>
+ <memberdecl>
+ <nestednamespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </namespace>
+
+ <!-- Layout definition for a file page -->
+ <file>
+ <briefdescription visible="yes"/>
+ <includes visible="$SHOW_INCLUDE_FILES"/>
+ <includegraph visible="$INCLUDE_GRAPH"/>
+ <includedbygraph visible="$INCLUDED_BY_GRAPH"/>
+ <sourcelink visible="yes"/>
+ <memberdecl>
+ <classes visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <constantgroups visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ </memberdef>
+ <authorsection/>
+ </file>
+
+ <!-- Layout definition for a group page -->
+ <group>
+ <briefdescription visible="yes"/>
+ <groupgraph visible="$GROUP_GRAPHS"/>
+ <memberdecl>
+ <nestedgroups visible="yes" title=""/>
+ <dirs visible="yes" title=""/>
+ <files visible="yes" title=""/>
+ <namespaces visible="yes" title=""/>
+ <classes visible="yes" title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ <membergroups visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ <memberdef>
+ <pagedocs/>
+ <inlineclasses title=""/>
+ <defines title=""/>
+ <typedefs title=""/>
+ <enums title=""/>
+ <enumvalues title=""/>
+ <functions title=""/>
+ <variables title=""/>
+ <signals title=""/>
+ <publicslots title=""/>
+ <protectedslots title=""/>
+ <privateslots title=""/>
+ <events title=""/>
+ <properties title=""/>
+ <friends title=""/>
+ </memberdef>
+ <authorsection visible="yes"/>
+ </group>
+
+ <!-- Layout definition for a directory page -->
+ <directory>
+ <briefdescription visible="yes"/>
+ <directorygraph visible="yes"/>
+ <memberdecl>
+ <dirs visible="yes"/>
+ <files visible="yes"/>
+ </memberdecl>
+ <detaileddescription title=""/>
+ </directory>
+</doxygenlayout>
diff --git a/tools/doxygen/pages_index.html b/tools/doxygen/pages_index.html
new file mode 100644
index 000000000..c9ca5b58c
--- /dev/null
+++ b/tools/doxygen/pages_index.html
@@ -0,0 +1,39 @@
+<!DOCTYPE html>
+<html>
+<head>
+ <meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
+ <meta http-equiv="X-UA-Compatible" content="IE=9"/>
+ <title>Hercules documentation</title>
+ <link href="docs/doxygen.css" rel="stylesheet" type="text/css" />
+</head>
+<body>
+ <div id="top">
+ <div id="titlearea">
+ <table cellspacing="0" cellpadding="0">
+ <tbody>
+ <tr style="height: 56px;">
+ <td id="projectlogo"><img alt="Logo" src="docs/Hercules48.png"/></td>
+ <td id="projectalign" style="padding-left: 0.5em;">
+ <div id="projectname">Hercules</div>
+ </td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div>
+ <div class="header">
+ <div class="headertitle">
+ <div class="title">Hercules Documentation</div>
+ </div>
+ </div><!--header-->
+ <div class="contents">
+ <ul>
+ <li><a href="docs/">Doxygen</a></li>
+ <li><a href="gcov_pre.html">Coverage Report: pre-renewal build</a> <a href="gcov_pre.txt">(raw data)</a></li>
+ <li><a href="gcov_re.html">Coverage Report: renewal build</a> <a href="gcov_re.txt">(raw data)</a></li>
+ <li><a href="https://github.com/HerculesWS/Hercules">GitHub</a></li>
+ <li><a href="https://gitlab.com/HerculesWS/Hercules">GitLab</a></li>
+ </ul>
+ </div><!-- contents -->
+ <hr class="footer">
+</body></html>
diff --git a/tools/doxygen/style.css b/tools/doxygen/style.css
new file mode 100644
index 000000000..02e8b0152
--- /dev/null
+++ b/tools/doxygen/style.css
@@ -0,0 +1,1440 @@
+/* The standard CSS for doxygen 1.8.8 */
+
+body, table, div, p, dl {
+ font: 400 14px/22px Roboto,sans-serif;
+}
+
+/* @group Heading Levels */
+
+h1.groupheader {
+ font-size: 150%;
+}
+
+.title {
+ font: 400 14px/28px Roboto,sans-serif;
+ font-size: 150%;
+ font-weight: bold;
+ margin: 10px 2px;
+}
+
+h2.groupheader {
+ border-bottom: 1px solid #879ECB;
+ color: #354C7B;
+ font-size: 150%;
+ font-weight: normal;
+ margin-top: 1.75em;
+ padding-top: 8px;
+ padding-bottom: 4px;
+ width: 100%;
+}
+
+h3.groupheader {
+ font-size: 100%;
+}
+
+h1, h2, h3, h4, h5, h6 {
+ -webkit-transition: text-shadow 0.5s linear;
+ -moz-transition: text-shadow 0.5s linear;
+ -ms-transition: text-shadow 0.5s linear;
+ -o-transition: text-shadow 0.5s linear;
+ transition: text-shadow 0.5s linear;
+ margin-right: 15px;
+}
+
+h1.glow, h2.glow, h3.glow, h4.glow, h5.glow, h6.glow {
+ text-shadow: 0 0 15px cyan;
+}
+
+dt {
+ font-weight: bold;
+}
+
+div.multicol {
+ -moz-column-gap: 1em;
+ -webkit-column-gap: 1em;
+ -moz-column-count: 3;
+ -webkit-column-count: 3;
+}
+
+p.startli, p.startdd {
+ margin-top: 2px;
+}
+
+p.starttd {
+ margin-top: 0px;
+}
+
+p.endli {
+ margin-bottom: 0px;
+}
+
+p.enddd {
+ margin-bottom: 4px;
+}
+
+p.endtd {
+ margin-bottom: 2px;
+}
+
+/* @end */
+
+caption {
+ font-weight: bold;
+}
+
+span.legend {
+ font-size: 70%;
+ text-align: center;
+}
+
+h3.version {
+ font-size: 90%;
+ text-align: center;
+}
+
+div.qindex, div.navtab{
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+}
+
+div.qindex, div.navpath {
+ width: 100%;
+ line-height: 140%;
+}
+
+div.navtab {
+ margin-right: 15px;
+}
+
+/* @group Link Styling */
+
+a {
+ color: #3D578C;
+ font-weight: normal;
+ text-decoration: none;
+}
+
+.contents a:visited {
+ color: #4665A2;
+}
+
+a:hover {
+ text-decoration: underline;
+}
+
+a.qindex {
+ font-weight: bold;
+}
+
+a.qindexHL {
+ font-weight: bold;
+ background-color: #9CAFD4;
+ color: #ffffff;
+ border: 1px double #869DCA;
+}
+
+.contents a.qindexHL:visited {
+ color: #ffffff;
+}
+
+a.el {
+ font-weight: bold;
+}
+
+a.elRef {
+}
+
+a.code, a.code:visited, a.line, a.line:visited {
+ color: #4665A2;
+}
+
+a.codeRef, a.codeRef:visited, a.lineRef, a.lineRef:visited {
+ color: #4665A2;
+}
+
+/* @end */
+
+dl.el {
+ margin-left: -1cm;
+}
+
+pre.fragment {
+ border: 1px solid #C4CFE5;
+ background-color: #FBFCFD;
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ overflow: auto;
+ word-wrap: break-word;
+ font-size: 9pt;
+ line-height: 125%;
+ font-family: monospace, fixed;
+ font-size: 105%;
+}
+
+div.fragment {
+ padding: 4px 6px;
+ margin: 4px 8px 4px 2px;
+ background-color: #FBFCFD;
+ border: 1px solid #C4CFE5;
+}
+
+div.line {
+ font-family: monospace, fixed;
+ font-size: 13px;
+ min-height: 13px;
+ line-height: 1.0;
+ text-wrap: unrestricted;
+ white-space: -moz-pre-wrap; /* Moz */
+ white-space: -pre-wrap; /* Opera 4-6 */
+ white-space: -o-pre-wrap; /* Opera 7 */
+ white-space: pre-wrap; /* CSS3 */
+ word-wrap: break-word; /* IE 5.5+ */
+ text-indent: -53px;
+ padding-left: 53px;
+ padding-bottom: 0px;
+ margin: 0px;
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+div.line.glow {
+ background-color: cyan;
+ box-shadow: 0 0 10px cyan;
+}
+
+
+span.lineno {
+ padding-right: 4px;
+ text-align: right;
+ border-right: 2px solid #0F0;
+ background-color: #E8E8E8;
+ white-space: pre;
+}
+span.lineno a {
+ background-color: #D8D8D8;
+}
+
+span.lineno a:hover {
+ background-color: #C8C8C8;
+}
+
+div.ah {
+ background-color: black;
+ font-weight: bold;
+ color: #ffffff;
+ margin-bottom: 3px;
+ margin-top: 3px;
+ padding: 0.2em;
+ border: solid thin #333;
+ border-radius: 0.5em;
+ -webkit-border-radius: .5em;
+ -moz-border-radius: .5em;
+ box-shadow: 2px 2px 3px #999;
+ -webkit-box-shadow: 2px 2px 3px #999;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ background-image: -webkit-gradient(linear, left top, left bottom, from(#eee), to(#000),color-stop(0.3, #444));
+ background-image: -moz-linear-gradient(center top, #eee 0%, #444 40%, #000);
+}
+
+div.groupHeader {
+ margin-left: 16px;
+ margin-top: 12px;
+ font-weight: bold;
+}
+
+div.groupText {
+ margin-left: 16px;
+ font-style: italic;
+}
+
+body {
+ background-color: white;
+ color: black;
+ margin: 0;
+}
+
+div.contents {
+ margin-top: 10px;
+ margin-left: 12px;
+ margin-right: 8px;
+}
+
+td.indexkey {
+ background-color: #EBEFF6;
+ font-weight: bold;
+ border: 1px solid #C4CFE5;
+ margin: 2px 0px 2px 0;
+ padding: 2px 10px;
+ white-space: nowrap;
+ vertical-align: top;
+}
+
+td.indexvalue {
+ background-color: #EBEFF6;
+ border: 1px solid #C4CFE5;
+ padding: 2px 10px;
+ margin: 2px 0px;
+}
+
+tr.memlist {
+ background-color: #EEF1F7;
+}
+
+p.formulaDsp {
+ text-align: center;
+}
+
+img.formulaDsp {
+
+}
+
+img.formulaInl {
+ vertical-align: middle;
+}
+
+div.center {
+ text-align: center;
+ margin-top: 0px;
+ margin-bottom: 0px;
+ padding: 0px;
+}
+
+div.center img {
+ border: 0px;
+}
+
+address.footer {
+ text-align: right;
+ padding-right: 12px;
+}
+
+img.footer {
+ border: 0px;
+ vertical-align: middle;
+}
+
+/* @group Code Colorization */
+
+span.keyword {
+ color: #008000
+}
+
+span.keywordtype {
+ color: #604020
+}
+
+span.keywordflow {
+ color: #e08000
+}
+
+span.comment {
+ color: #800000
+}
+
+span.preprocessor {
+ color: #806020
+}
+
+span.stringliteral {
+ color: #002080
+}
+
+span.charliteral {
+ color: #008080
+}
+
+span.vhdldigit {
+ color: #ff00ff
+}
+
+span.vhdlchar {
+ color: #000000
+}
+
+span.vhdlkeyword {
+ color: #700070
+}
+
+span.vhdllogic {
+ color: #ff0000
+}
+
+blockquote {
+ background-color: #F7F8FB;
+ border-left: 2px solid #9CAFD4;
+ margin: 0 24px 0 4px;
+ padding: 0 12px 0 16px;
+}
+
+/* @end */
+
+/*
+.search {
+ color: #003399;
+ font-weight: bold;
+}
+
+form.search {
+ margin-bottom: 0px;
+ margin-top: 0px;
+}
+
+input.search {
+ font-size: 75%;
+ color: #000080;
+ font-weight: normal;
+ background-color: #e8eef2;
+}
+*/
+
+td.tiny {
+ font-size: 75%;
+}
+
+.dirtab {
+ padding: 4px;
+ border-collapse: collapse;
+ border: 1px solid #A3B4D7;
+}
+
+th.dirtab {
+ background: #EBEFF6;
+ font-weight: bold;
+}
+
+hr {
+ height: 0px;
+ border: none;
+ border-top: 1px solid #4A6AAA;
+}
+
+hr.footer {
+ height: 1px;
+}
+
+/* @group Member Descriptions */
+
+table.memberdecls {
+ border-spacing: 0px;
+ padding: 0px;
+}
+
+.memberdecls td, .fieldtable tr {
+ -webkit-transition-property: background-color, box-shadow;
+ -webkit-transition-duration: 0.5s;
+ -moz-transition-property: background-color, box-shadow;
+ -moz-transition-duration: 0.5s;
+ -ms-transition-property: background-color, box-shadow;
+ -ms-transition-duration: 0.5s;
+ -o-transition-property: background-color, box-shadow;
+ -o-transition-duration: 0.5s;
+ transition-property: background-color, box-shadow;
+ transition-duration: 0.5s;
+}
+
+.memberdecls td.glow, .fieldtable tr.glow {
+ background-color: cyan;
+ box-shadow: 0 0 15px cyan;
+}
+
+.mdescLeft, .mdescRight,
+.memItemLeft, .memItemRight,
+.memTemplItemLeft, .memTemplItemRight, .memTemplParams {
+ background-color: #F9FAFC;
+ border: none;
+ margin: 4px;
+ padding: 1px 0 0 8px;
+}
+
+.mdescLeft, .mdescRight {
+ padding: 0px 8px 4px 8px;
+ color: #555;
+}
+
+.memSeparator {
+ border-bottom: 1px solid #DEE4F0;
+ line-height: 1px;
+ margin: 0px;
+ padding: 0px;
+}
+
+.memItemLeft, .memTemplItemLeft {
+ white-space: nowrap;
+}
+
+.memItemRight {
+ width: 100%;
+}
+
+.memTemplParams {
+ color: #4665A2;
+ white-space: nowrap;
+ font-size: 80%;
+}
+
+/* @end */
+
+/* @group Member Details */
+
+/* Styles for detailed member documentation */
+
+.memtemplate {
+ font-size: 80%;
+ color: #4665A2;
+ font-weight: normal;
+ margin-left: 9px;
+}
+
+.memnav {
+ background-color: #EBEFF6;
+ border: 1px solid #A3B4D7;
+ text-align: center;
+ margin: 2px;
+ margin-right: 15px;
+ padding: 2px;
+}
+
+.mempage {
+ width: 100%;
+}
+
+.memitem {
+ padding: 0;
+ margin-bottom: 10px;
+ margin-right: 5px;
+ -webkit-transition: box-shadow 0.5s linear;
+ -moz-transition: box-shadow 0.5s linear;
+ -ms-transition: box-shadow 0.5s linear;
+ -o-transition: box-shadow 0.5s linear;
+ transition: box-shadow 0.5s linear;
+ display: table !important;
+ width: 100%;
+}
+
+.memitem.glow {
+ box-shadow: 0 0 15px cyan;
+}
+
+.memname {
+ font-weight: bold;
+ margin-left: 6px;
+}
+
+.memname td {
+ vertical-align: bottom;
+}
+
+.memproto, dl.reflist dt {
+ border-top: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 6px 0px 6px 0px;
+ color: #253555;
+ font-weight: bold;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E2E8F2;
+ /* opera specific markup */
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ /* firefox specific markup */
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ -moz-border-radius-topright: 4px;
+ -moz-border-radius-topleft: 4px;
+ /* webkit specific markup */
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ -webkit-border-top-right-radius: 4px;
+ -webkit-border-top-left-radius: 4px;
+
+}
+
+.memdoc, dl.reflist dd {
+ border-bottom: 1px solid #A8B8D9;
+ border-left: 1px solid #A8B8D9;
+ border-right: 1px solid #A8B8D9;
+ padding: 6px 10px 2px 10px;
+ background-color: #FBFCFD;
+ border-top-width: 0;
+ background-image:url('nav_g.png');
+ background-repeat:repeat-x;
+ background-color: #FFFFFF;
+ /* opera specific markup */
+ border-bottom-left-radius: 4px;
+ border-bottom-right-radius: 4px;
+ box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+ /* firefox specific markup */
+ -moz-border-radius-bottomleft: 4px;
+ -moz-border-radius-bottomright: 4px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 5px 5px 5px;
+ /* webkit specific markup */
+ -webkit-border-bottom-left-radius: 4px;
+ -webkit-border-bottom-right-radius: 4px;
+ -webkit-box-shadow: 5px 5px 5px rgba(0, 0, 0, 0.15);
+}
+
+dl.reflist dt {
+ padding: 5px;
+}
+
+dl.reflist dd {
+ margin: 0px 0px 10px 0px;
+ padding: 5px;
+}
+
+.paramkey {
+ text-align: right;
+}
+
+.paramtype {
+ white-space: nowrap;
+}
+
+.paramname {
+ color: #602020;
+ white-space: nowrap;
+}
+.paramname em {
+ font-style: normal;
+}
+.paramname code {
+ line-height: 14px;
+}
+
+.params, .retval, .exception, .tparams {
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+.params .paramname, .retval .paramname {
+ font-weight: bold;
+ vertical-align: top;
+}
+
+.params .paramtype {
+ font-style: italic;
+ vertical-align: top;
+}
+
+.params .paramdir {
+ font-family: "courier new",courier,monospace;
+ vertical-align: top;
+}
+
+table.mlabels {
+ border-spacing: 0px;
+}
+
+td.mlabels-left {
+ width: 100%;
+ padding: 0px;
+}
+
+td.mlabels-right {
+ vertical-align: bottom;
+ padding: 0px;
+ white-space: nowrap;
+}
+
+span.mlabels {
+ margin-left: 8px;
+}
+
+span.mlabel {
+ background-color: #728DC1;
+ border-top:1px solid #5373B4;
+ border-left:1px solid #5373B4;
+ border-right:1px solid #C4CFE5;
+ border-bottom:1px solid #C4CFE5;
+ text-shadow: none;
+ color: white;
+ margin-right: 4px;
+ padding: 2px 3px;
+ border-radius: 3px;
+ font-size: 7pt;
+ white-space: nowrap;
+ vertical-align: middle;
+}
+
+
+
+/* @end */
+
+/* these are for tree view inside a (index) page */
+
+div.directory {
+ margin: 10px 0px;
+ border-top: 1px solid #9CAFD4;
+ border-bottom: 1px solid #9CAFD4;
+ width: 100%;
+}
+
+.directory table {
+ border-collapse:collapse;
+}
+
+.directory td {
+ margin: 0px;
+ padding: 0px;
+ vertical-align: top;
+}
+
+.directory td.entry {
+ white-space: nowrap;
+ padding-right: 6px;
+ padding-top: 3px;
+}
+
+.directory td.entry a {
+ outline:none;
+}
+
+.directory td.entry a img {
+ border: none;
+}
+
+.directory td.desc {
+ width: 100%;
+ padding-left: 6px;
+ padding-right: 6px;
+ padding-top: 3px;
+ border-left: 1px solid rgba(0,0,0,0.05);
+}
+
+.directory tr.even {
+ padding-left: 6px;
+ background-color: #F7F8FB;
+}
+
+.directory img {
+ vertical-align: -30%;
+}
+
+.directory .levels {
+ white-space: nowrap;
+ width: 100%;
+ text-align: right;
+ font-size: 9pt;
+}
+
+.directory .levels span {
+ cursor: pointer;
+ padding-left: 2px;
+ padding-right: 2px;
+ color: #3D578C;
+}
+
+.arrow {
+ color: #9CAFD4;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ cursor: pointer;
+ font-size: 80%;
+ display: inline-block;
+ width: 16px;
+ height: 22px;
+}
+
+.icon {
+ font-family: Arial, Helvetica;
+ font-weight: bold;
+ font-size: 12px;
+ height: 14px;
+ width: 16px;
+ display: inline-block;
+ background-color: #728DC1;
+ color: white;
+ text-align: center;
+ border-radius: 4px;
+ margin-left: 2px;
+ margin-right: 2px;
+}
+
+.icona {
+ width: 24px;
+ height: 22px;
+ display: inline-block;
+}
+
+.iconfopen {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('ftv2folderopen.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+.iconfclosed {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('ftv2folderclosed.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+.icondoc {
+ width: 24px;
+ height: 18px;
+ margin-bottom: 4px;
+ background-image:url('ftv2doc.png');
+ background-position: 0px -4px;
+ background-repeat: repeat-y;
+ vertical-align:top;
+ display: inline-block;
+}
+
+table.directory {
+ font: 400 14px Roboto,sans-serif;
+}
+
+/* @end */
+
+div.dynheader {
+ margin-top: 8px;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+address {
+ font-style: normal;
+ color: #2A3D61;
+}
+
+table.doxtable {
+ border-collapse:collapse;
+ margin-top: 4px;
+ margin-bottom: 4px;
+}
+
+table.doxtable td, table.doxtable th {
+ border: 1px solid #2D4068;
+ padding: 3px 7px 2px;
+}
+
+table.doxtable th {
+ background-color: #374F7F;
+ color: #FFFFFF;
+ font-size: 110%;
+ padding-bottom: 4px;
+ padding-top: 5px;
+}
+
+table.fieldtable {
+ /*width: 100%;*/
+ margin-bottom: 10px;
+ border: 1px solid #A8B8D9;
+ border-spacing: 0px;
+ -moz-border-radius: 4px;
+ -webkit-border-radius: 4px;
+ border-radius: 4px;
+ -moz-box-shadow: rgba(0, 0, 0, 0.15) 2px 2px 2px;
+ -webkit-box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+ box-shadow: 2px 2px 2px rgba(0, 0, 0, 0.15);
+}
+
+.fieldtable td, .fieldtable th {
+ padding: 3px 7px 2px;
+}
+
+.fieldtable td.fieldtype, .fieldtable td.fieldname {
+ white-space: nowrap;
+ border-right: 1px solid #A8B8D9;
+ border-bottom: 1px solid #A8B8D9;
+ vertical-align: top;
+}
+
+.fieldtable td.fieldname {
+ padding-top: 3px;
+}
+
+.fieldtable td.fielddoc {
+ border-bottom: 1px solid #A8B8D9;
+ /*width: 100%;*/
+}
+
+.fieldtable td.fielddoc p:first-child {
+ margin-top: 0px;
+}
+
+.fieldtable td.fielddoc p:last-child {
+ margin-bottom: 2px;
+}
+
+.fieldtable tr:last-child td {
+ border-bottom: none;
+}
+
+.fieldtable th {
+ background-image:url('nav_f.png');
+ background-repeat:repeat-x;
+ background-color: #E2E8F2;
+ font-size: 90%;
+ color: #253555;
+ padding-bottom: 4px;
+ padding-top: 5px;
+ text-align:left;
+ -moz-border-radius-topleft: 4px;
+ -moz-border-radius-topright: 4px;
+ -webkit-border-top-left-radius: 4px;
+ -webkit-border-top-right-radius: 4px;
+ border-top-left-radius: 4px;
+ border-top-right-radius: 4px;
+ border-bottom: 1px solid #A8B8D9;
+}
+
+
+.tabsearch {
+ top: 0px;
+ left: 10px;
+ height: 36px;
+ background-image: url('tab_b.png');
+ z-index: 101;
+ overflow: hidden;
+ font-size: 13px;
+}
+
+.navpath ul
+{
+ font-size: 11px;
+ background-image:url('tab_b.png');
+ background-repeat:repeat-x;
+ background-position: 0 -5px;
+ height:30px;
+ line-height:30px;
+ color:#8AA0CC;
+ border:solid 1px #C2CDE4;
+ overflow:hidden;
+ margin:0px;
+ padding:0px;
+}
+
+.navpath li
+{
+ list-style-type:none;
+ float:left;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:url('bc_s.png');
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+}
+
+.navpath li.navelem a
+{
+ height:32px;
+ display:block;
+ text-decoration: none;
+ outline: none;
+ color: #283A5D;
+ font-family: 'Lucida Grande',Geneva,Helvetica,Arial,sans-serif;
+ text-shadow: 0px 1px 1px rgba(255, 255, 255, 0.9);
+ text-decoration: none;
+}
+
+.navpath li.navelem a:hover
+{
+ color:#6884BD;
+}
+
+.navpath li.footer
+{
+ list-style-type:none;
+ float:right;
+ padding-left:10px;
+ padding-right:15px;
+ background-image:none;
+ background-repeat:no-repeat;
+ background-position:right;
+ color:#364D7C;
+ font-size: 8pt;
+}
+
+
+div.summary
+{
+ float: right;
+ font-size: 8pt;
+ padding-right: 5px;
+ width: 50%;
+ text-align: right;
+}
+
+div.summary a
+{
+ white-space: nowrap;
+}
+
+div.ingroups
+{
+ font-size: 8pt;
+ width: 50%;
+ text-align: left;
+}
+
+div.ingroups a
+{
+ white-space: nowrap;
+}
+
+div.header
+{
+ background-image:url('nav_h.png');
+ background-repeat:repeat-x;
+ background-color: #F9FAFC;
+ margin: 0px;
+ border-bottom: 1px solid #C4CFE5;
+}
+
+div.headertitle
+{
+ padding: 5px 5px 5px 10px;
+}
+
+dl
+{
+ padding: 0 0 0 10px;
+}
+
+/* dl.note, dl.warning, dl.attention, dl.pre, dl.post, dl.invariant, dl.deprecated, dl.todo, dl.test, dl.bug */
+dl.section
+{
+ margin-left: 0px;
+ padding-left: 0px;
+}
+
+dl.note
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #D0C000;
+}
+
+dl.warning, dl.attention
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #FF0000;
+}
+
+dl.pre, dl.post, dl.invariant
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00D000;
+}
+
+dl.deprecated
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #505050;
+}
+
+dl.todo
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #00C0E0;
+}
+
+dl.test
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #3030E0;
+}
+
+dl.bug
+{
+ margin-left:-7px;
+ padding-left: 3px;
+ border-left:4px solid;
+ border-color: #C08050;
+}
+
+dl.section dd {
+ margin-bottom: 6px;
+}
+
+
+#projectlogo
+{
+ text-align: center;
+ vertical-align: bottom;
+ border-collapse: separate;
+}
+
+#projectlogo img
+{
+ border: 0px none;
+}
+
+#projectname
+{
+ font: 300% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 2px 0px;
+}
+
+#projectbrief
+{
+ font: 120% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#projectnumber
+{
+ font: 50% Tahoma, Arial,sans-serif;
+ margin: 0px;
+ padding: 0px;
+}
+
+#titlearea
+{
+ padding: 0px;
+ margin: 0px;
+ width: 100%;
+ border-bottom: 1px solid #5373B4;
+}
+
+.image
+{
+ text-align: center;
+}
+
+.dotgraph
+{
+ text-align: center;
+}
+
+.mscgraph
+{
+ text-align: center;
+}
+
+.diagraph
+{
+ text-align: center;
+}
+
+.caption
+{
+ font-weight: bold;
+}
+
+div.zoom
+{
+ border: 1px solid #90A5CE;
+}
+
+dl.citelist {
+ margin-bottom:50px;
+}
+
+dl.citelist dt {
+ color:#334975;
+ float:left;
+ font-weight:bold;
+ margin-right:10px;
+ padding:5px;
+}
+
+dl.citelist dd {
+ margin:2px 0;
+ padding:5px 0;
+}
+
+div.toc {
+ padding: 14px 25px;
+ background-color: #F4F6FA;
+ border: 1px solid #D8DFEE;
+ border-radius: 7px 7px 7px 7px;
+ float: right;
+ height: auto;
+ margin: 0 20px 10px 10px;
+ width: 200px;
+}
+
+div.toc li {
+ background: url("bdwn.png") no-repeat scroll 0 5px transparent;
+ font: 10px/1.2 Verdana,DejaVu Sans,Geneva,sans-serif;
+ margin-top: 5px;
+ padding-left: 10px;
+ padding-top: 2px;
+}
+
+div.toc h3 {
+ font: bold 12px/1.2 Arial,FreeSans,sans-serif;
+ color: #4665A2;
+ border-bottom: 0 none;
+ margin: 0;
+}
+
+div.toc ul {
+ list-style: none outside none;
+ border: medium none;
+ padding: 0px;
+}
+
+div.toc li.level1 {
+ margin-left: 0px;
+}
+
+div.toc li.level2 {
+ margin-left: 15px;
+}
+
+div.toc li.level3 {
+ margin-left: 30px;
+}
+
+div.toc li.level4 {
+ margin-left: 45px;
+}
+
+.inherit_header {
+ font-weight: bold;
+ color: gray;
+ cursor: pointer;
+ -webkit-touch-callout: none;
+ -webkit-user-select: none;
+ -khtml-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+}
+
+.inherit_header td {
+ padding: 6px 0px 2px 5px;
+}
+
+.inherit {
+ display: none;
+}
+
+tr.heading h2 {
+ margin-top: 12px;
+ margin-bottom: 4px;
+}
+
+/* tooltip related style info */
+
+.ttc {
+ position: absolute;
+ display: none;
+}
+
+#powerTip {
+ cursor: default;
+ white-space: nowrap;
+ background-color: white;
+ border: 1px solid gray;
+ border-radius: 4px 4px 4px 4px;
+ box-shadow: 1px 1px 7px gray;
+ display: none;
+ font-size: smaller;
+ max-width: 80%;
+ opacity: 0.9;
+ padding: 1ex 1em 1em;
+ position: absolute;
+ z-index: 2147483647;
+}
+
+#powerTip div.ttdoc {
+ color: grey;
+ font-style: italic;
+}
+
+#powerTip div.ttname a {
+ font-weight: bold;
+}
+
+#powerTip div.ttname {
+ font-weight: bold;
+}
+
+#powerTip div.ttdeci {
+ color: #006318;
+}
+
+#powerTip div {
+ margin: 0px;
+ padding: 0px;
+ font: 12px/16px Roboto,sans-serif;
+}
+
+#powerTip:before, #powerTip:after {
+ content: "";
+ position: absolute;
+ margin: 0px;
+}
+
+#powerTip.n:after, #powerTip.n:before,
+#powerTip.s:after, #powerTip.s:before,
+#powerTip.w:after, #powerTip.w:before,
+#powerTip.e:after, #powerTip.e:before,
+#powerTip.ne:after, #powerTip.ne:before,
+#powerTip.se:after, #powerTip.se:before,
+#powerTip.nw:after, #powerTip.nw:before,
+#powerTip.sw:after, #powerTip.sw:before {
+ border: solid transparent;
+ content: " ";
+ height: 0;
+ width: 0;
+ position: absolute;
+}
+
+#powerTip.n:after, #powerTip.s:after,
+#powerTip.w:after, #powerTip.e:after,
+#powerTip.nw:after, #powerTip.ne:after,
+#powerTip.sw:after, #powerTip.se:after {
+ border-color: rgba(255, 255, 255, 0);
+}
+
+#powerTip.n:before, #powerTip.s:before,
+#powerTip.w:before, #powerTip.e:before,
+#powerTip.nw:before, #powerTip.ne:before,
+#powerTip.sw:before, #powerTip.se:before {
+ border-color: rgba(128, 128, 128, 0);
+}
+
+#powerTip.n:after, #powerTip.n:before,
+#powerTip.ne:after, #powerTip.ne:before,
+#powerTip.nw:after, #powerTip.nw:before {
+ top: 100%;
+}
+
+#powerTip.n:after, #powerTip.ne:after, #powerTip.nw:after {
+ border-top-color: #ffffff;
+ border-width: 10px;
+ margin: 0px -10px;
+}
+#powerTip.n:before {
+ border-top-color: #808080;
+ border-width: 11px;
+ margin: 0px -11px;
+}
+#powerTip.n:after, #powerTip.n:before {
+ left: 50%;
+}
+
+#powerTip.nw:after, #powerTip.nw:before {
+ right: 14px;
+}
+
+#powerTip.ne:after, #powerTip.ne:before {
+ left: 14px;
+}
+
+#powerTip.s:after, #powerTip.s:before,
+#powerTip.se:after, #powerTip.se:before,
+#powerTip.sw:after, #powerTip.sw:before {
+ bottom: 100%;
+}
+
+#powerTip.s:after, #powerTip.se:after, #powerTip.sw:after {
+ border-bottom-color: #ffffff;
+ border-width: 10px;
+ margin: 0px -10px;
+}
+
+#powerTip.s:before, #powerTip.se:before, #powerTip.sw:before {
+ border-bottom-color: #808080;
+ border-width: 11px;
+ margin: 0px -11px;
+}
+
+#powerTip.s:after, #powerTip.s:before {
+ left: 50%;
+}
+
+#powerTip.sw:after, #powerTip.sw:before {
+ right: 14px;
+}
+
+#powerTip.se:after, #powerTip.se:before {
+ left: 14px;
+}
+
+#powerTip.e:after, #powerTip.e:before {
+ left: 100%;
+}
+#powerTip.e:after {
+ border-left-color: #ffffff;
+ border-width: 10px;
+ top: 50%;
+ margin-top: -10px;
+}
+#powerTip.e:before {
+ border-left-color: #808080;
+ border-width: 11px;
+ top: 50%;
+ margin-top: -11px;
+}
+
+#powerTip.w:after, #powerTip.w:before {
+ right: 100%;
+}
+#powerTip.w:after {
+ border-right-color: #ffffff;
+ border-width: 10px;
+ top: 50%;
+ margin-top: -10px;
+}
+#powerTip.w:before {
+ border-right-color: #808080;
+ border-width: 11px;
+ top: 50%;
+ margin-top: -11px;
+}
+
+@media print
+{
+ #top { display: none; }
+ #side-nav { display: none; }
+ #nav-path { display: none; }
+ body { overflow:visible; }
+ h1, h2, h3, h4, h5, h6 { page-break-after: avoid; }
+ .summary { display: none; }
+ .memitem { page-break-inside: avoid; }
+ #doc-content
+ {
+ margin-left:0 !important;
+ height:auto !important;
+ width:auto !important;
+ overflow:inherit;
+ display:inline;
+ }
+}
+
diff --git a/tools/install_mariadb.bat b/tools/install_mariadb.bat
new file mode 100644
index 000000000..cfe2ce3b7
--- /dev/null
+++ b/tools/install_mariadb.bat
@@ -0,0 +1,7 @@
+@echo off
+
+:: this file installs the mariadb service
+
+if not "%1"=="am_admin" (powershell start -verb runas '%0' am_admin & exit /b)
+mysqld.exe --install "MySQL"
+net start MySQL
diff --git a/tools/item_merge.lua b/tools/item_merge.lua
index 38708f452..ba2e4b9b9 100644
--- a/tools/item_merge.lua
+++ b/tools/item_merge.lua
@@ -1,7 +1,7 @@
-- This file is part of Hercules.
-- http://herc.ws - http://github.com/HerculesWS/Hercules
--
--- Copyright (C) 2014-2015 Hercules Dev Team
+-- Copyright (C) 2014-2020 Hercules Dev Team
--
-- Hercules is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
@@ -16,7 +16,7 @@
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
--- Base Author: Dastgir @ http://hercules.ws
+-- Base Author: Dastgir @ http://herc.ws
--
-- This script requires lua 5.1 to run.
diff --git a/tools/itemcombodbconverter.py b/tools/itemcombodbconverter.py
new file mode 100644
index 000000000..33519646a
--- /dev/null
+++ b/tools/itemcombodbconverter.py
@@ -0,0 +1,112 @@
+#!/usr/bin/env python3
+# -*- coding: utf8 -*-
+#
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2019-2020 Hercules Dev Team
+# Copyright (C) 2019 Asheraf
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import argparse
+import json
+import re
+from utils import libconf
+import utils.common as Tools
+
+
+def ConvertFile(args):
+ print(r'''//================= Hercules Database =====================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2019-2020 Hercules Dev Team
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//================= Description ===========================================
+// Configurations file for status effects
+//=========================================================================
+
+combo_db: (
+/**************************************************************************
+ ************* Entry structure ********************************************
+ **************************************************************************
+{
+ // ================ Mandatory fields ===============================
+ Items: ["item_list"] (string, array) list of items
+ Script: <"
+ Script
+ (it can be multi-line)
+ ">
+}
+**************************************************************************/''')
+ ItemDB = Tools.LoadDBConsts('item_db', f'{args.mode}', '../')
+ with open (f'../db/{args.mode}/item_combo_db.txt') as dbfile:
+ line = 0
+ for entry in dbfile:
+ line = line + 1
+ if not entry.strip() or entry.startswith('//'):
+ continue
+ m = re.search(r'(^[0-9:]+),\{(.*)\}$', entry)
+ if not m:
+ print(f'Error: Invalid pattern in entry {entry}, line {line}, aborting..')
+ exit()
+
+ items_list = m.group(1).split(':')
+ script = m.group(2)
+ for item in range(len(items_list)):
+ if int(items_list[item]) not in ItemDB:
+ print(f'Error: invalid item {item} found in line {line}, aborting..')
+ exit()
+ items_list[item] = ItemDB[int(items_list[item])]
+
+ if args.enable_jsbeautifier:
+ import jsbeautifier
+ opts = jsbeautifier.default_options()
+ opts.indent_with_tabs = True
+ opts.indent_level = 2
+ script = jsbeautifier.beautify(script, opts)
+ print(
+f'''{{
+ Items: {json.dumps(items_list)}
+ Script: <"\n{script}\n\t">
+}},''')
+ print(')')
+
+if __name__ == '__main__':
+ parser = argparse.ArgumentParser(description='Convert item combo db to new format')
+ parser.add_argument('--mode', type=str, dest='mode', help='Define usage mode re/pre-re.')
+ parser.add_argument('--enable-jsbeautifier', type=bool, dest='enable_jsbeautifier', help='Use jsbeautifier to auto format script fields.')
+ parsed_args = parser.parse_args()
+ ConvertFile(parsed_args)
diff --git a/tools/itemdb_jobmask_converter.pl b/tools/itemdb_jobmask_converter.pl
index 11a5e7a5f..e9295c217 100644
--- a/tools/itemdb_jobmask_converter.pl
+++ b/tools/itemdb_jobmask_converter.pl
@@ -3,7 +3,7 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2016 Hercules Dev Team
+# Copyright (C) 2016-2020 Hercules Dev Team
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/itemdbconverter.pl b/tools/itemdbconverter.pl
index 58cb08bc1..913af0486 100755
--- a/tools/itemdbconverter.pl
+++ b/tools/itemdbconverter.pl
@@ -3,7 +3,7 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2013-2015 Hercules Dev Team
+# Copyright (C) 2013-2020 Hercules Dev Team
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -109,9 +109,9 @@ sub parsedb (@) {
(?<eLV>[0-9]*)[^,:]*(?<hasmaxlv>:[\s\t]*(?<eLVmax>[0-9]*))?[^,]*,[\s\t]*
(?<Refineable>[0-9]*)[^,]*,[\s\t]*
(?<View>[0-9]*)[^,]*,[\s\t]*
- {(?<Script>.*)},
- {(?<OnEquip>.*)},
- {(?<OnUnequip>.*)}
+ \{(?<Script>.*)},
+ \{(?<OnEquip>.*)},
+ \{(?<OnUnequip>.*)}
/x ) {
my %cols = map { $_ => $+{$_} } keys %+;
print "/*\n" if $cols{prefix};
diff --git a/tools/mobavailconverter.py b/tools/mobavailconverter.py
new file mode 100644
index 000000000..377557710
--- /dev/null
+++ b/tools/mobavailconverter.py
@@ -0,0 +1,94 @@
+#!/usr/bin/env python
+# -*- coding: utf8 -*-
+#
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2019-2020 Hercules Dev Team
+# Copyright (C) 2019 Asheraf
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import re
+import csv
+
+f = open('../db/re/mob_db.conf')
+mob_db = f.read()
+
+with open('../db/mob_avail.txt') as dbfile:
+ mob_avail = csv.reader(dbfile, delimiter=',')
+
+ for mob in mob_avail:
+ if len(mob) == 0 or mob[0].startswith('//'):
+ continue
+
+ mob = [re.sub(r'//.*', '', i).strip() for i in mob]
+
+ mob_id = int(mob[0])
+ sprite_id = int(mob[1])
+ weapon = 0
+ shield = 0
+ head_top = 0
+ head_mid = 0
+ head_bottom = 0
+ hair_style = 0
+ hair_color = 0
+ cloth_color = 0
+ gender = 0
+ option = 0
+ if len(mob) == 3:
+ head_bottom = int(mob[2])
+ elif len(mob) == 12:
+ gender = int(mob[2])
+ hair_style = int(mob[3])
+ hair_color = int(mob[4])
+ weapon = int(mob[5])
+ shield = int(mob[6])
+ head_top = int(mob[7])
+ head_mid = int(mob[8])
+ head_bottom = int(mob[9])
+ option = int(mob[10])
+ cloth_color = int(mob[11])
+
+ s = ''
+ s += '\tViewData: {\n'
+ s += '\t\tSpriteId: {}\n'.format(sprite_id)
+ if weapon != 0:
+ s += '\t\tWeaponId: {}\n'.format(weapon)
+ if shield != 0:
+ s += '\t\tShieldId: {}\n'.format(shield)
+ if head_top != 0:
+ s += '\t\tHeadTopId: {}\n'.format(head_top)
+ if head_mid != 0:
+ s += '\t\tHeadMidId: {}\n'.format(head_mid)
+ if head_bottom != 0:
+ s += '\t\tHeadLowId: {}\n'.format(head_bottom)
+ if hair_style != 0:
+ s += '\t\tHairStyleId: {}\n'.format(hair_style)
+ if hair_color != 0:
+ s += '\t\tHairColorId: {}\n'.format(hair_color)
+ if cloth_color != 0:
+ s += '\t\tBodyColorId: {}\n'.format(cloth_color)
+ if gender != 0:
+ s += '\t\tGender: SEX_MALE\n'
+ if option != 0:
+ s += '\t\tOptions: {}\n'.format(option)
+ s += '\t}'
+
+ mob_db = re.sub(
+ r'(\tId: ' + str(mob_id) + r'\n([\S\s]*?)(?=},))},',
+ r'\1' + str(s) + r'\n},',
+ mob_db)
+ print(mob_db)
diff --git a/tools/mobdbconvall.sh b/tools/mobdbconvall.sh
index a6f421329..4cbd21a56 100755
--- a/tools/mobdbconvall.sh
+++ b/tools/mobdbconvall.sh
@@ -1,9 +1,9 @@
-#!/bin/bash
+#!/usr/bin/env bash
#
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2015-2015 Hercules Dev Team
+# Copyright (C) 2015-2020 Hercules Dev Team
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/mobdbconverter.py b/tools/mobdbconverter.py
index 78047aed9..8a220b08d 100755
--- a/tools/mobdbconverter.py
+++ b/tools/mobdbconverter.py
@@ -1,11 +1,11 @@
-#! /usr/bin/env python
+#! /usr/bin/env python3
# -*- coding: utf8 -*-
#
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2015 Hercules Dev Team
-# Copyright (C) 2015 Andrei Karas (4144)
+# Copyright (C) 2015-2020 Hercules Dev Team
+# Copyright (C) 2015 Andrei Karas (4144)
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
@@ -141,6 +141,24 @@ def isHaveData(fields, start, cnt):
return True
return False
+def convertToSize(size):
+ sizes = ["Size_Small", "Size_Medium", "Size_Large"]
+ if (size >= len(sizes)):
+ return size
+ return f'"{sizes[size]}"'
+
+def convertToRace(race):
+ races = ["RC_Formless", "RC_Undead", "RC_Brute", "RC_Plant", "RC_Insect", "RC_Fish", "RC_Demon", "RC_DemiHuman", "RC_Angel", "RC_Dragon"]
+ if (race >= len(races)):
+ return race
+ return f'"{races[race]}"'
+
+def convertToElement(element):
+ elements = ["Ele_Neutral", "Ele_Water", "Ele_Earth", "Ele_Fire", "Ele_Wind", "Ele_Poison", "Ele_Holy", "Ele_Dark", "Ele_Ghost", "Ele_Undead"]
+ if (element >= len(elements)):
+ return element
+ return f'"{elements[element]}"'
+
def convertFile(inFile, itemDb):
if inFile != "" and not os.path.exists(inFile):
return
@@ -186,9 +204,9 @@ def convertFile(inFile, itemDb):
endGroup()
printField("ViewRange", fields[20])
printField("ChaseRange", fields[21])
- printField("Size", fields[22])
- printField("Race", fields[23])
- print("\tElement: ({0}, {1})".format(int(fields[24]) % 10, int(fields[24]) / 20));
+ printField("Size", convertToSize(int(fields[22])))
+ printField("Race", convertToRace(int(fields[23])))
+ print("\tElement: ({0}, {1})".format(convertToElement(int(fields[24]) % 10), int(int(fields[24]) / 20)));
mode = int(fields[25], 0)
if mode != 0:
startGroup("Mode")
@@ -260,7 +278,7 @@ def readItemDB(inFile, itemDb):
elif line[:3] == "Id:":
try:
itemId = int(line[4:])
- except:
+ except ValueError:
started = False
if itemId != 0 and itemName != "":
# was need for remove wrong characters
@@ -277,13 +295,13 @@ def readItemDB(inFile, itemDb):
return itemDb
if len(sys.argv) != 4 and len(sys.argv) != 3:
- printHelp();
+ printHelp()
exit(1)
startPath = sys.argv[2]
if len(sys.argv) == 4:
sourceFile = sys.argv[3]
else:
- sourceFile = "";
+ sourceFile = ""
itemDb = dict()
if sys.argv[1] == "re":
@@ -293,7 +311,7 @@ elif sys.argv[1] == "pre-re":
itemDb = readItemDB(startPath + "/db/pre-re/item_db.conf", itemDb)
itemDb = readItemDB(startPath + "/db/item_db2.conf", itemDb)
else:
- printHelp();
+ printHelp()
exit(1)
convertFile(sourceFile, itemDb)
diff --git a/tools/mobskilldbconverter.py b/tools/mobskilldbconverter.py
new file mode 100755
index 000000000..ac73b1f7b
--- /dev/null
+++ b/tools/mobskilldbconverter.py
@@ -0,0 +1,264 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+#
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2018-2020 Hercules Dev Team
+# Copyright (C) 2018 Asheraf
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import re
+import sys
+import utils.common as Tools
+
+SKILL_STATES = {
+ "any": "MSS_ANY",
+ "idle": "MSS_IDLE",
+ "walk": "MSS_WALK",
+ "loot": "MSS_LOOT",
+ "dead": "MSS_DEAD",
+ "attack": "MSS_BERSERK",
+ "angry": "MSS_ANGRY",
+ "chase": "MSS_RUSH",
+ "follow": "MSS_FOLLOW",
+ "anytarget": "MSS_ANYTARGET"
+}
+SKILL_COND1 = {
+ "always": "MSC_ALWAYS",
+ "myhpltmaxrate": "MSC_MYHPLTMAXRATE",
+ "myhpinrate": "MSC_MYHPINRATE",
+ "friendhpltmaxrate": "MSC_FRIENDHPLTMAXRATE",
+ "friendhpinrate": "MSC_FRIENDHPINRATE",
+ "mystatuson": "MSC_MYSTATUSON",
+ "mystatusoff": "MSC_MYSTATUSOFF",
+ "friendstatuson": "MSC_FRIENDSTATUSON",
+ "friendstatusoff": "MSC_FRIENDSTATUSOFF",
+ "attackpcgt": "MSC_ATTACKPCGT",
+ "attackpcge": "MSC_ATTACKPCGE",
+ "slavelt": "MSC_SLAVELT",
+ "slavele": "MSC_SLAVELE",
+ "closedattacked": "MSC_CLOSEDATTACKED",
+ "longrangeattacked": "MSC_LONGRANGEATTACKED",
+ "skillused": "MSC_SKILLUSED",
+ "afterskill": "MSC_AFTERSKILL",
+ "casttargeted": "MSC_CASTTARGETED",
+ "rudeattacked": "MSC_RUDEATTACKED",
+ "masterhpltmaxrate": "MSC_MASTERHPLTMAXRATE",
+ "masterattacked": "MSC_MASTERATTACKED",
+ "alchemist": "MSC_ALCHEMIST",
+ "onspawn": "MSC_SPAWN"
+}
+SKILL_COND2 = {
+ "anybad": "MSC_ANY",
+ "stone": "SC_STONE",
+ "freeze": "SC_FREEZE",
+ "stun": "SC_STUN",
+ "sleep": "SC_SLEEP",
+ "poison": "SC_POISON",
+ "curse": "SC_CURSE",
+ "silence": "SC_SILENCE",
+ "confusion": "SC_CONFUSION",
+ "blind": "SC_BLIND",
+ "hiding": "SC_HIDING",
+ "sight": "SC_SIGHT"
+}
+SKILL_TARGET = {
+ "target": "MST_TARGET",
+ "randomtarget": "MST_RANDOM",
+ "self": "MST_SELF",
+ "friend": "MST_FRIEND",
+ "master": "MST_MASTER",
+ "around5": "MST_AROUND5",
+ "around6": "MST_AROUND6",
+ "around7": "MST_AROUND7",
+ "around8": "MST_AROUND8",
+ "around1": "MST_AROUND1",
+ "around2": "MST_AROUND2",
+ "around3": "MST_AROUND3",
+ "around4": "MST_AROUND4",
+ "around": "MST_AROUND"
+}
+
+def printHeader():
+ print("""
+mob_skill_db:(
+{
+/**************************************************************************
+ ************* Entry structure ********************************************
+ **************************************************************************
+ <Monster_Constant>: {
+ <Skill_Constant>: {
+ ClearSkills: (boolean, defaults to false) allows cleaning all previous defined skills for the mob.
+ SkillLevel: (int, defaults to 1)
+ SkillState: (int, defaults to 0)
+ SkillTarget: (int, defaults to 0)
+ Rate: (int, defaults to 1)
+ CastTime: (int, defaults to 0)
+ Delay: (int, defaults to 0)
+ Cancelable: (boolean, defaults to false)
+ CastCondition: (int, defaults to 0)
+ ConditionData: (int, defaults to 0)
+ val0: (int, defaults to 0)
+ val1: (int, defaults to 0)
+ val2: (int, defaults to 0)
+ val3: (int, defaults to 0)
+ val4: (int, defaults to 0)
+ Emotion: (int, defaults to 0)
+ ChatMsgID: (int, defaults to 0)
+ }
+ }
+**************************************************************************/""")
+
+def printFooter():
+ print('}\n)\n')
+
+def isValidEntry(line):
+ if re.match('^[0-9]+,.*', line):
+ return True
+ return False
+
+def commaSplit(line):
+ return line.split(',')
+
+def stripLinebreak(line):
+ return line.replace('\r', '').replace('\n', '')
+
+def printInt(key, value):
+ if key in value:
+ if int(value[key]) is not 0:
+ print('\t\t\t{}: {}'.format(key, value[key]))
+
+def printStrToInt(key, value):
+ if value[key] is not '':
+ if int(value[key]) is not 0:
+ print('\t\t\t{}: {}'.format(key, value[key]))
+
+def printBool(key, value):
+ if value[key] == 'yes':
+ print('\t\t\t{}: true'.format(key))
+
+def printClearSkills(key, value):
+ if value[key] == 'clear':
+ print('\t\t\t{}: true'.format(key))
+
+def printSkillState(key, value):
+ if value[key]:
+ print('\t\t\t{}: "{}"'.format(key, SKILL_STATES[value[key]]))
+
+def printSkillTarget(key, value):
+ if value[key]:
+ print('\t\t\t{}: "{}"'.format(key, SKILL_TARGET[value[key]]))
+
+def printCastCondition(key, value):
+ if value[key]:
+ print('\t\t\t{}: "{}"'.format(key, SKILL_COND1[value[key]]))
+
+def printConditionData(key, value):
+ if value[key] in SKILL_COND2:
+ print('\t\t\t{}: "{}"'.format(key, SKILL_COND2[value[key]]))
+ elif value[key] is not '':
+ if int(value[key]) is not 0:
+ print('\t\t\t{}: {}'.format(key, value[key]))
+
+def printEmotion(key, value):
+ if value[key] is not '':
+ print('\t\t\t{}: {}'.format(key, value[key]))
+
+def LoadOldDB(mode, serverpath):
+
+ r = open('{}db/{}/mob_skill_db.txt'.format(serverpath, mode), "r")
+
+ Db = dict()
+ for line in r:
+ if isValidEntry(line) == True:
+ entry = commaSplit(stripLinebreak(line))
+ MonsterId = entry[0]
+ if MonsterId not in Db:
+ Db[MonsterId] = dict()
+ skillidx = len(Db[MonsterId])
+ Db[MonsterId][skillidx] = dict()
+ Db[MonsterId][skillidx]['ClearSkills'] = entry[1]
+ Db[MonsterId][skillidx]['SkillState'] = entry[2]
+ Db[MonsterId][skillidx]['SkillId'] = entry[3]
+ Db[MonsterId][skillidx]['SkillLevel'] = entry[4]
+ Db[MonsterId][skillidx]['Rate'] = entry[5]
+ Db[MonsterId][skillidx]['CastTime'] = entry[6]
+ Db[MonsterId][skillidx]['Delay'] = entry[7]
+ Db[MonsterId][skillidx]['Cancelable'] = entry[8]
+ Db[MonsterId][skillidx]['SkillTarget'] = entry[9]
+ Db[MonsterId][skillidx]['CastCondition'] = entry[10]
+ Db[MonsterId][skillidx]['ConditionData'] = entry[11]
+ for i in range(5):
+ if entry[12 + i] is '':
+ continue
+ try:
+ Db[MonsterId][skillidx]['val{}'.format(i)] = int(entry[12 + i])
+ except ValueError:
+ Db[MonsterId][skillidx]['val{}'.format(i)] = int(entry[12 + i], 16)
+ Db[MonsterId][skillidx]['Emotion'] = entry[17]
+ Db[MonsterId][skillidx]['ChatMsgID'] = entry[18]
+ return Db
+
+def ConvertDB(mode, serverpath):
+ db = LoadOldDB(mode, serverpath)
+ MobDB = Tools.LoadDBConsts('mob_db', mode, serverpath)
+ SkillDB = Tools.LoadDBConsts('skill_db', mode, serverpath)
+
+ printHeader()
+ for mobid in sorted(db.iterkeys()):
+ print('\t{}: {{'.format(MobDB[int(mobid)]))
+ for skillidx in sorted(db[mobid].iterkeys()):
+ valid = True
+ if int(db[mobid][skillidx]['SkillId']) not in SkillDB:
+ valid = False
+ print('/*')
+ print('// Can\'t find skill with id {} in skill_db'.format(db[mobid][skillidx]['SkillId']))
+ print('\t\t{}: {{'.format(db[mobid][skillidx]['SkillId']))
+ else:
+ print('\t\t{}: {{'.format(SkillDB[int(db[mobid][skillidx]['SkillId'])]))
+ printClearSkills('ClearSkills', db[mobid][skillidx])
+ printSkillState('SkillState', db[mobid][skillidx])
+ printStrToInt('SkillLevel', db[mobid][skillidx])
+ printStrToInt('Rate', db[mobid][skillidx])
+ printStrToInt('CastTime', db[mobid][skillidx])
+ printStrToInt('Delay', db[mobid][skillidx])
+ printBool('Cancelable', db[mobid][skillidx])
+ printSkillTarget('SkillTarget', db[mobid][skillidx])
+ printCastCondition('CastCondition', db[mobid][skillidx])
+ printConditionData('ConditionData', db[mobid][skillidx])
+ for i in range(5):
+ printInt('val{}'.format(i), db[mobid][skillidx])
+ printEmotion('Emotion', db[mobid][skillidx])
+ printStrToInt('ChatMsgID', db[mobid][skillidx])
+ print('\t\t}')
+ if valid is False:
+ print('*/')
+ print('\t}')
+ printFooter()
+
+if len(sys.argv) != 3:
+ print('Monster Skill db converter from txt to conf format')
+ print('Usage:')
+ print(' mobskilldbconverter.py mode serverpath')
+ print("example:")
+ print(' mobskilldbconverter.py pre-re ../')
+ exit(1)
+
+if sys.argv[1] != 're' and sys.argv[1] != 'pre-re':
+ print('you have entred an invalid server mode')
+ exit(1)
+
+ConvertDB(sys.argv[1], sys.argv[2])
diff --git a/tools/petdbconverter.py b/tools/petdbconverter.py
new file mode 100644
index 000000000..220d54531
--- /dev/null
+++ b/tools/petdbconverter.py
@@ -0,0 +1,214 @@
+#! /usr/bin/env python
+# -*- coding: utf8 -*-
+#
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2018-2020 Hercules Dev Team
+# Copyright (C) 2018 Asheraf
+# Copyright (C) 2015 Andrei Karas (4144)
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import os
+import re
+import sys
+
+def isValidEntry(line):
+ if re.match('^[0-9]+,.*', line):
+ return True
+ return False
+
+def curlSplit(line):
+ return re.split('[{}]|},', line)
+
+def commaSplit(line):
+ return line.split(',')
+
+def printIntField(name, value):
+ if int(value) != 0:
+ print('\t{0}: {1}'.format(name, value))
+
+def printIntField2(name, value):
+ if int(value) != 0:
+ print('\t\t{0}: {1}'.format(name, value))
+
+def printStrField(name, value):
+ if value != '':
+ print('\t{0}: \"{1}\"'.format(name, value))
+
+def printBool(name, value):
+ if int(value) != 0:
+ print('\t{0}: true'.format(name))
+
+def printIntimacy(arr):
+ if int(arr[9]) == 0 or int(arr[10]) == 0 or int(arr[11]) == 0 or int(arr[12]) == 0:
+ return
+ print('\tIntimacy: {')
+ printIntField2('Initial', arr[11])
+ printIntField2('FeedIncrement', arr[9])
+ printIntField2('OverFeedDecrement', arr[10])
+ printIntField2('OwnerDeathDecrement', arr[12])
+ print('\t}')
+
+def printScript(name, value):
+ if re.match('.*[a-zA-Z0-9,]+.*', value):
+ print('\t{0}: <\"{1}\">'.format(name, value))
+
+def printItemName(fieldname, itemid, itemDb):
+ value = int(itemid)
+ if value != 0:
+ if value not in itemDb:
+ print("// Error: pet item with id {0} not found in item_db.conf".format(value))
+ else:
+ printStrField(fieldname, itemDb[value])
+
+
+def printHeader():
+ print("""
+pet_db:(
+/**************************************************************************
+ ************* Entry structure ********************************************
+ **************************************************************************
+{
+ // ================ Mandatory fields ==============================
+ Id: ID (int)
+ SpriteName: "Sprite_Name" (string)
+ Name: "Pet Name" (string)
+ // ================ Optional fields ===============================
+ TamingItem: Taming Item (string, defaults to 0)
+ EggItem: Egg Id (string, defaults to 0)
+ AccessoryItem: Equipment Id (string, defaults to 0)
+ FoodItem: Food Id (string, defaults to 0)
+ FoodEffectiveness: hunger points (int, defaults to 0)
+ HungerDelay: hunger time (int, defaults to 0)
+ Intimacy: {
+ Initial: start intimacy (int, defaults to 0)
+ FeedIncrement: feeding intimacy (int, defaults to 0)
+ OverFeedDecrement: overfeeding intimacy (int, defaults to 0)
+ OwnerDeathDecrement: owner die intimacy (int, defaults to 0)
+ }
+ CaptureRate: capture rate (int, defaults to 0)
+ Speed: speed (int, defaults to 0)
+ SpecialPerformance: true/false (boolean, defaults to false)
+ TalkWithEmotes: convert talk (boolean, defaults to false)
+ AttackRate: attack rate (int, defaults to 0)
+ DefendRate: Defence attack (int, defaults to 0)
+ ChangeTargetRate: change target (int, defaults to 0)
+ PetScript: <" Pet Script (can also be multi-line) ">
+ EquipScript: <" Equip Script (can also be multi-line) ">
+},
+**************************************************************************/
+ """)
+
+def printFooter():
+ print(')\n')
+
+def convertFile(inFile, itemDb):
+ if inFile != "" and not os.path.exists(inFile):
+ return
+
+ if inFile == "":
+ r = sys.stdin
+ else:
+ r = open(inFile, "r")
+
+ printHeader()
+ for line in r:
+ if isValidEntry(line) == True:
+ print('{')
+ firstsplit = curlSplit(line)
+ secondsplit = commaSplit(firstsplit[0])
+ printIntField('Id', secondsplit[0])
+ printStrField('SpriteName', secondsplit[1])
+ printStrField('Name', secondsplit[2])
+ printItemName('TamingItem', secondsplit[3], itemDb)
+ printItemName('EggItem', secondsplit[4], itemDb)
+ printItemName('AccessoryItem', secondsplit[5], itemDb)
+ printItemName('FoodItem', secondsplit[6], itemDb)
+ printIntField('FoodEffectiveness', secondsplit[7])
+ printIntField('HungerDelay', secondsplit[8])
+ printIntimacy(secondsplit)
+ printIntField('CaptureRate', secondsplit[13])
+ printIntField('Speed', secondsplit[14])
+ printBool('SpecialPerformance', secondsplit[15])
+ printBool('TalkWithEmotes', secondsplit[16])
+ printIntField('AttackRate', secondsplit[17])
+ printIntField('DefendRate', secondsplit[18])
+ printIntField('ChangeTargetRate', secondsplit[19])
+ printScript('PetScript', firstsplit[1])
+ printScript('EquipScript', firstsplit[3])
+ print('},')
+ printFooter()
+
+def printHelp():
+ print("PetDB converter from txt to conf format")
+ print("Usage:")
+ print(" petdbconverter.py re serverpath dbfilepath")
+ print(" petdbconverter.py pre-re serverpath dbfilepath")
+ print("Usage for read from stdin:")
+ print(" petdbconverter.py re dbfilepath")
+
+def readItemDB(inFile, itemDb):
+ itemId = 0
+ itemName = ""
+ started = False
+ with open(inFile, "r") as r:
+ for line in r:
+ line = line.strip()
+ if started == True:
+ if line == "},":
+ started = False
+ elif line[:10] == "AegisName:":
+ itemName = line[12:-1]
+ elif line[:3] == "Id:":
+ try:
+ itemId = int(line[4:])
+ except ValueError:
+ started = False
+ if itemId != 0 and itemName != "":
+# was need for remove wrong characters
+# itemName = itemName.replace(".", "")
+# if itemName[0] >= "0" and itemName[0] <= "9":
+# itemName = "Num" + itemName
+ itemDb[itemId] = itemName
+ started = False
+ else:
+ if line == "{":
+ started = True
+ itemId = 0
+ itemName = ""
+ return itemDb
+
+if len(sys.argv) != 4 and len(sys.argv) != 3:
+ printHelp();
+ exit(1)
+startPath = sys.argv[2]
+if len(sys.argv) == 4:
+ sourceFile = sys.argv[3]
+else:
+ sourceFile = "";
+
+itemDb = dict()
+if sys.argv[1] == "re":
+ itemDb = readItemDB(startPath + "/db/re/item_db.conf", itemDb)
+ itemDb = readItemDB(startPath + "/db/item_db2.conf", itemDb)
+elif sys.argv[1] == "pre-re":
+ itemDb = readItemDB(startPath + "/db/pre-re/item_db.conf", itemDb)
+ itemDb = readItemDB(startPath + "/db/item_db2.conf", itemDb)
+else:
+ printHelp();
+ exit(1)
+
+convertFile(sourceFile, itemDb)
diff --git a/tools/petevolutionconverter.py b/tools/petevolutionconverter.py
new file mode 100644
index 000000000..5428ff6eb
--- /dev/null
+++ b/tools/petevolutionconverter.py
@@ -0,0 +1,248 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+#
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2018-2020 Hercules Dev Team
+# Copyright (C) 2018 Dastgir
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+# Usage:
+# python petevolutionconverter.py PetEvolutionCln.lub re ../ > pet_evolve_db.conf
+
+import re
+import sys
+import utils.common as Tools
+
+def printHeader():
+ print('''//================= Hercules Database =====================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2018-2020 Hercules Dev Team
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//=========================================================================
+//= Pets Database
+//=========================================================================
+
+pet_db:(
+/**************************************************************************
+ ************* Entry structure ********************************************
+ **************************************************************************
+{
+ // ================ Mandatory fields ==============================
+ Id: ID (int)
+ SpriteName: "Sprite_Name" (string)
+ Name: "Pet Name" (string)
+ // ================ Optional fields ===============================
+ TamingItem: Taming Item (string, defaults to 0)
+ EggItem: Egg Id (string, defaults to 0)
+ AccessoryItem: Equipment Id (string, defaults to 0)
+ FoodItem: Food Id (string, defaults to 0)
+ FoodEffectiveness: hunger points (int, defaults to 0)
+ HungerDelay: hunger time (int, defaults to 0)
+ Intimacy: {
+ Initial: start intimacy (int, defaults to 0)
+ FeedIncrement: feeding intimacy (int, defaults to 0)
+ OverFeedDecrement: overfeeding intimacy (int, defaults to 0)
+ OwnerDeathDecrement: owner die intimacy (int, defaults to 0)
+ }
+ CaptureRate: capture rate (int, defaults to 0)
+ Speed: speed (int, defaults to 0)
+ SpecialPerformance: true/false (boolean, defaults to false)
+ TalkWithEmotes: convert talk (boolean, defaults to false)
+ AttackRate: attack rate (int, defaults to 0)
+ DefendRate: Defence attack (int, defaults to 0)
+ ChangeTargetRate: change target (int, defaults to 0)
+ Evolve: {
+ EggID: { (string, Evolved Pet EggID)
+ Name: Amount (items required to perform evolution)
+ ...
+ }
+ }
+ AutoFeed: true/false (boolean, defaults to false)
+ PetScript: <" Pet Script (can also be multi-line) ">
+ EquipScript: <" Equip Script (can also be multi-line) ">
+},
+**************************************************************************/''')
+
+def printID(db, name, tabSize = 1):
+ if (name not in db or int(db[name]) == 0):
+ return
+ print('{}{}: {}'.format('\t'*tabSize, name, db[name]))
+
+def printString(db, name, tabSize = 1):
+ if (name not in db or db[name].strip() == ""):
+ return
+ print('{}{}: "{}"'.format('\t'*tabSize, name, db[name]))
+
+def printBool(db, name):
+ if (name not in db or db[name] == '0'):
+ return
+ print('\t{}: true'.format(name))
+
+def printScript(db, name):
+ if (name not in db or db[name].strip() == ""):
+ return
+ print('\t{}: <{}>'.format(name, db[name]))
+
+def printEntry(ItemDB, EvolveDB, autoFeedDB, entry, mode, serverpath):
+ PetDB = Tools.LoadDB('pet_db', mode, serverpath)
+
+ for i, db in enumerate(PetDB):
+ print('{')
+ printID(db, 'Id')
+ printString(db, 'SpriteName')
+ printString(db, 'Name')
+
+ printString(db, 'TamingItem')
+ printString(db, 'EggItem')
+ printString(db, 'AccessoryItem')
+ printString(db, 'FoodItem')
+ printID(db, 'FoodEffectiveness')
+ printID(db, 'HungerDelay')
+
+ if ('Intimacy' in db and (db['Intimacy']['Initial'] != 0 or db['Intimacy']['FeedIncrement'] != 0 or
+ db['Intimacy']['OverFeedDecrement'] != 0 or db['Intimacy']['OwnerDeathDecrement'] != 0)):
+ print('\tIntimacy: {')
+ printID(db['Intimacy'], 'Initial', 2)
+ printID(db['Intimacy'], 'FeedIncrement', 2)
+ printID(db['Intimacy'], 'OverFeedDecrement', 2)
+ printID(db['Intimacy'], 'OwnerDeathDecrement', 2)
+ print('\t}')
+ #
+ printID(db, 'CaptureRate')
+ printID(db, 'Speed')
+ printBool(db, 'SpecialPerformance')
+ printBool(db, 'TalkWithEmotes')
+ printID(db, 'AttackRate')
+ printID(db, 'DefendRate')
+ printID(db, 'ChangeTargetRate')
+ if (str(db['Id']) in autoFeedDB):
+ print('\tAutoFeed: true')
+ else:
+ print('\tAutoFeed: false')
+ printScript(db, 'PetScript')
+ printScript(db, 'EquipScript')
+
+ if (db['EggItem'] in EvolveDB):
+ entry = EvolveDB[db['EggItem']]
+ print('\tEvolve: {')
+
+ for evolve in entry:
+ if ('comment' in evolve):
+ print('/*')
+ print('\t\t{}: {'.format(evolve['Id']))
+
+ for items in evolve['items']:
+ print('\t\t\t{}: {}'.format(items[0], items[1]))
+
+ print('\t\t}')
+ if ('comment' in evolve):
+ print('*/')
+
+ print('\t}')
+ print('},')
+
+def saveEntry(EvolveDB, entry):
+ if (entry['from'] not in EvolveDB):
+ EvolveDB[entry['from']] = list()
+ EvolveDB[entry['from']].append(entry)
+ return EvolveDB
+
+def getItemConstant(entry, ItemDB, itemID):
+ if (itemID in ItemDB):
+ return ItemDB[itemID]
+ print(itemID, "not found", entry)
+ entry['comment'] = 1
+ return itemID
+
+def ConvertDB(luaName, mode, serverpath):
+ ItemDB = Tools.LoadDBConsts('item_db', mode, serverpath)
+ f = open(luaName)
+ content = f.read()
+ f.close()
+
+ recipeDB = re.findall(r'InsertEvolutionRecipeLGU\((\d+),\s*(\d+),\s*(\d+),\s*(\d+)\)', content)
+ autoFeedDB = re.findall(r'InsertPetAutoFeeding\((\d+)\)', content)
+
+ current = 0
+
+ entry = dict()
+ EvolveDB = dict()
+
+ printHeader()
+ for recipe in recipeDB:
+ fromEgg = getItemConstant(entry, ItemDB, int(recipe[0]))
+ petEgg = getItemConstant(entry, ItemDB, int(recipe[1]))
+
+ if (current == 0):
+ entry = {
+ 'Id': petEgg,
+ 'from': fromEgg,
+ 'items': list()
+ }
+ current = petEgg
+
+ if (current != petEgg):
+ EvolveDB = saveEntry(EvolveDB, entry)
+ entry = {
+ 'Id': petEgg,
+ 'from': fromEgg,
+ 'items': list()
+ }
+ entry['id'] = petEgg
+ entry['items'] = list()
+ current = petEgg
+
+ itemConst = getItemConstant(entry, ItemDB, int(recipe[2]))
+ quantity = int(recipe[3])
+
+ entry['items'].append((itemConst, quantity))
+ saveEntry(EvolveDB, entry)
+
+ printEntry(ItemDB, EvolveDB, autoFeedDB, entry, mode, serverpath)
+ print(')')
+
+
+if len(sys.argv) != 4:
+ print('Pet Evolution Lua to DB')
+ print('Usage:')
+ print(' petevolutionconverter.py lua mode serverpath')
+ print("example:")
+ print(' petevolutionconverter.py PetEvolutionCln.lua pre-re ../')
+ exit(1)
+
+ConvertDB(sys.argv[1], sys.argv[2], sys.argv[3])
diff --git a/tools/php-sqllint/bin/php-sqllint b/tools/php-sqllint/bin/php-sqllint
new file mode 100755
index 000000000..fd766bc07
--- /dev/null
+++ b/tools/php-sqllint/bin/php-sqllint
@@ -0,0 +1,31 @@
+#!/usr/bin/env php
+<?php
+/**
+ * SQL linter (syntax checker) written in PHP
+ *
+ * PHP version 5
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://cweiske.de/php-sqllint.htm
+ */
+namespace phpsqllint;
+
+if (file_exists(__DIR__ . '/../vendor/autoload.php')) {
+ //local git checkout
+ include_once __DIR__ . '/../vendor/autoload.php';
+} else if (file_exists('vendor/autoload.php')) {
+ //dependency composer installation
+ include_once 'vendor/autoload.php';
+}
+
+if (file_exists(__DIR__ . '/../src/phpsqllint/Autoloader.php')) {
+ include_once __DIR__ . '/../src/phpsqllint/Autoloader.php';
+ Autoloader::register();
+}
+
+$cli = new Cli();
+$cli->run();
+?> \ No newline at end of file
diff --git a/tools/php-sqllint/build.xml b/tools/php-sqllint/build.xml
new file mode 100644
index 000000000..e1f45f0a4
--- /dev/null
+++ b/tools/php-sqllint/build.xml
@@ -0,0 +1,103 @@
+<?xml version="1.0" encoding="utf-8"?>
+<project name="php-sqllint" default="phar" basedir=".">
+
+ <!--<property name="version" value="dev" />-->
+ <loadfile property="version" file="VERSION">
+ <filterchain>
+ <striplinebreaks />
+ </filterchain>
+ </loadfile>
+
+ <property name="pharfile" value="${phing.dir}/dist/${phing.project.name}-${version}.phar" />
+ <property name="pharfilebz2" value="${phing.dir}/dist/${phing.project.name}-${version}.bz2.phar" />
+ <property name="libdir" value="${phing.dir}/lib"/>
+
+ <fileset id="fs.phar" dir="${phing.dir}">
+ <include name="bin/**"/>
+ <include name="lib/**"/>
+ <include name="src/**"/>
+
+ <include name="README.rst"/>
+ <include name="VERSION"/>
+
+ <include name="vendor/autoload.php"/>
+ <include name="vendor/composer/*.php"/>
+ <include name="vendor/pear/console_commandline/Console/**"/>
+ <include name="vendor/pear/pear_exception/PEAR/**"/>
+ <include name="vendor/phpmyadmin/sql-parser/src/**"/>
+ </fileset>
+
+
+ <typedef name="pearPackageFileSet" classname="phing.types.PearPackageFileSet" />
+
+ <target name="phar" depends="collectdeps"
+ description="Create zip file for release"
+ >
+ <!-- strip the shebang from bin script -->
+ <copy file="${phing.dir}/bin/php-sqllint" tofile="${phing.dir}/bin/phar-php-sqllint.php">
+ <filterchain>
+ <striplinecomments>
+ <comment value="#" />
+ </striplinecomments>
+ </filterchain>
+ </copy>
+
+ <mkdir dir="${phing.dir}/dist"/>
+ <delete file="${pharfile}"/>
+ <pharpackage basedir="${phing.dir}"
+ destfile="${pharfile}"
+ stub="${phing.dir}/src/stub-phar.php"
+ alias="php-sqllint.phar"
+ compression="none"
+ >
+ <fileset refid="fs.phar"/>
+ </pharpackage>
+
+ <pharpackage basedir="${phing.dir}"
+ destfile="${pharfilebz2}"
+ stub="${phing.dir}/src/stub-phar.php"
+ alias="php-sqllint.phar"
+ compression="bzip2"
+ >
+ <fileset refid="fs.phar"/>
+ </pharpackage>
+
+ <exec executable="chmod">
+ <arg value="+x"/>
+ <arg value="${pharfile}"/>
+ <arg value="${pharfilebz2}"/>
+ </exec>
+ </target>
+
+
+ <target name="collectdeps" description="Copy package dependencies to lib/">
+ <exec command="composer install"/>
+ <!--
+ <delete dir="${libdir}"/>
+ <mkdir dir="${libdir}"/>
+
+ <pearPackageFileset id="dep-Console_CommandLine" package="pear.php.net/Console_CommandLine"/>
+ <pearPackageFileset id="dep-PEAR" package="pear.php.net/PEAR">
+ <include name="PEAR/Exception.php"/>
+ </pearPackageFileset>
+
+ <copy todir="${libdir}">
+ <fileset refid="dep-Console_CommandLine"/>
+ <fileset refid="dep-PEAR"/>
+ </copy>
+ -->
+ </target>
+
+
+ <target name="docs" description="render documentation">
+ <rst file="README.rst"/>
+ </target>
+
+ <target name="update-website" depends="docs">
+ <exec command="xmlstarlet sel -t -c '/_:html/_:body/_:div' README.html
+ | xmllint --format -
+ |grep -v '?xml version'
+ > ~/Dev/html/cweiske.de/www/php-sqllint.htm"/>
+ </target>
+
+</project>
diff --git a/tools/php-sqllint/composer.json b/tools/php-sqllint/composer.json
new file mode 100644
index 000000000..bde2da14d
--- /dev/null
+++ b/tools/php-sqllint/composer.json
@@ -0,0 +1,22 @@
+{
+ "name": "cweiske/php-sqllint",
+ "description": "Command line tool to validate (syntax check) SQL files",
+ "type": "project",
+ "bin": ["bin/php-sqllint"],
+ "require": {
+ "phpmyadmin/sql-parser": "^4.1.1",
+ "pear/console_commandline": "^1.2"
+ },
+ "homepage": "http://cweiske.de/php-sqllint.htm",
+ "license": "AGPL-3.0",
+ "authors": [
+ {
+ "name": "Christian Weiske",
+ "email": "cweiske@cweiske.de",
+ "homepage": "http://cweiske.de/"
+ }
+ ],
+ "support": {
+ "issues": "https://github.com/cweiske/php-sqllint/issues"
+ }
+}
diff --git a/tools/php-sqllint/composer.lock b/tools/php-sqllint/composer.lock
new file mode 100644
index 000000000..a30dda3bf
--- /dev/null
+++ b/tools/php-sqllint/composer.lock
@@ -0,0 +1,186 @@
+{
+ "_readme": [
+ "This file locks the dependencies of your project to a known state",
+ "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file",
+ "This file is @generated automatically"
+ ],
+ "hash": "642c0759e68495342f0e4ec0a8b45575",
+ "content-hash": "e52fa298a0c5ce2ff75067ab99b00ce7",
+ "packages": [
+ {
+ "name": "pear/console_commandline",
+ "version": "v1.2.2",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/pear/Console_CommandLine.git",
+ "reference": "7a8afa50bdc8dbfdc0cf394f1101106e8b8f8e67"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/pear/Console_CommandLine/zipball/7a8afa50bdc8dbfdc0cf394f1101106e8b8f8e67",
+ "reference": "7a8afa50bdc8dbfdc0cf394f1101106e8b8f8e67",
+ "shasum": ""
+ },
+ "require": {
+ "ext-dom": "*",
+ "ext-xml": "*",
+ "pear/pear_exception": "^1.0.0",
+ "php": ">=5.3.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "*"
+ },
+ "type": "library",
+ "autoload": {
+ "psr-0": {
+ "Console": "./"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ ""
+ ],
+ "license": [
+ "MIT"
+ ],
+ "authors": [
+ {
+ "name": "Richard Quadling",
+ "email": "rquadling@gmail.com"
+ },
+ {
+ "name": "David Jean Louis",
+ "email": "izimobil@gmail.com"
+ }
+ ],
+ "description": "A full featured command line options and arguments parser.",
+ "homepage": "https://github.com/pear/Console_CommandLine",
+ "keywords": [
+ "console"
+ ],
+ "time": "2016-07-14 06:00:57"
+ },
+ {
+ "name": "pear/pear_exception",
+ "version": "v1.0.0",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/pear/PEAR_Exception.git",
+ "reference": "8c18719fdae000b690e3912be401c76e406dd13b"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/pear/PEAR_Exception/zipball/8c18719fdae000b690e3912be401c76e406dd13b",
+ "reference": "8c18719fdae000b690e3912be401c76e406dd13b",
+ "shasum": ""
+ },
+ "require": {
+ "php": ">=4.4.0"
+ },
+ "require-dev": {
+ "phpunit/phpunit": "*"
+ },
+ "type": "class",
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.0.x-dev"
+ }
+ },
+ "autoload": {
+ "psr-0": {
+ "PEAR": ""
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "include-path": [
+ "."
+ ],
+ "license": [
+ "BSD-2-Clause"
+ ],
+ "authors": [
+ {
+ "name": "Helgi Thormar",
+ "email": "dufuz@php.net"
+ },
+ {
+ "name": "Greg Beaver",
+ "email": "cellog@php.net"
+ }
+ ],
+ "description": "The PEAR Exception base class.",
+ "homepage": "https://github.com/pear/PEAR_Exception",
+ "keywords": [
+ "exception"
+ ],
+ "time": "2015-02-10 20:07:52"
+ },
+ {
+ "name": "phpmyadmin/sql-parser",
+ "version": "v4.1.9",
+ "source": {
+ "type": "git",
+ "url": "https://github.com/phpmyadmin/sql-parser.git",
+ "reference": "deac47217144b21056271674533b289239e1b279"
+ },
+ "dist": {
+ "type": "zip",
+ "url": "https://api.github.com/repos/phpmyadmin/sql-parser/zipball/deac47217144b21056271674533b289239e1b279",
+ "reference": "deac47217144b21056271674533b289239e1b279",
+ "shasum": ""
+ },
+ "require": {
+ "ext-mbstring": "*",
+ "php": ">=5.3.0"
+ },
+ "conflict": {
+ "phpmyadmin/motranslator": "<3.0"
+ },
+ "require-dev": {
+ "phpunit/php-code-coverage": "*",
+ "phpunit/phpunit": "~4.8 || ~5.7"
+ },
+ "suggest": {
+ "phpmyadmin/motranslator": "Translate messages to your favorite locale"
+ },
+ "bin": [
+ "bin/highlight-query",
+ "bin/lint-query"
+ ],
+ "type": "library",
+ "autoload": {
+ "psr-4": {
+ "PhpMyAdmin\\SqlParser\\": "src"
+ }
+ },
+ "notification-url": "https://packagist.org/downloads/",
+ "license": [
+ "GPL-2.0+"
+ ],
+ "authors": [
+ {
+ "name": "The phpMyAdmin Team",
+ "email": "developers@phpmyadmin.net",
+ "homepage": "https://www.phpmyadmin.net/team/"
+ }
+ ],
+ "description": "A validating SQL lexer and parser with a focus on MySQL dialect.",
+ "homepage": "https://github.com/phpmyadmin/sql-parser",
+ "keywords": [
+ "analysis",
+ "lexer",
+ "parser",
+ "sql"
+ ],
+ "time": "2017-07-12 14:54:33"
+ }
+ ],
+ "packages-dev": [],
+ "aliases": [],
+ "minimum-stability": "stable",
+ "stability-flags": [],
+ "prefer-stable": false,
+ "prefer-lowest": false,
+ "platform": [],
+ "platform-dev": []
+}
diff --git a/tools/php-sqllint/src/phpsqllint/Autoloader.php b/tools/php-sqllint/src/phpsqllint/Autoloader.php
new file mode 100644
index 000000000..6811b82f1
--- /dev/null
+++ b/tools/php-sqllint/src/phpsqllint/Autoloader.php
@@ -0,0 +1,57 @@
+<?php
+/**
+ * Part of php-sqllint
+ *
+ * PHP version 5
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2014 Christian Weiske
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://cweiske.de/php-sqllint.htm
+ */
+namespace phpsqllint;
+
+/**
+ * Class autoloader, PSR-0 compliant.
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2014 Christian Weiske
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @version Release: @package_version@
+ * @link http://cweiske.de/php-sqllint.htm
+ */
+class Autoloader
+{
+ /**
+ * Load the given class
+ *
+ * @param string $class Class name
+ *
+ * @return void
+ */
+ public function load($class)
+ {
+ $file = strtr($class, '_\\', '//') . '.php';
+ if (stream_resolve_include_path($file)) {
+ include $file;
+ }
+ }
+
+ /**
+ * Register this autoloader
+ *
+ * @return void
+ */
+ public static function register()
+ {
+ set_include_path(
+ get_include_path() . PATH_SEPARATOR . __DIR__ . '/../'
+ );
+ spl_autoload_register(array(new self(), 'load'));
+ }
+}
+?> \ No newline at end of file
diff --git a/tools/php-sqllint/src/phpsqllint/Cli.php b/tools/php-sqllint/src/phpsqllint/Cli.php
new file mode 100644
index 000000000..1501815eb
--- /dev/null
+++ b/tools/php-sqllint/src/phpsqllint/Cli.php
@@ -0,0 +1,280 @@
+<?php
+/**
+ * Part of php-sqllint
+ *
+ * PHP version 5
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://cweiske.de/php-sqllint.htm
+ */
+namespace phpsqllint;
+use PhpMyAdmin\SqlParser\Parser;
+
+/**
+ * Command line interface
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://www.emacswiki.org/emacs/CreatingYourOwnCompileErrorRegexp
+ */
+class Cli
+{
+ protected $renderer;
+
+ protected $format = false;
+
+ /**
+ * What syntax highlighting mode should be used
+ *
+ * none, ansi, html
+ */
+ protected $highlight = 'none';
+
+
+ /**
+ * Start processing.
+ *
+ * @return void
+ */
+ public function run()
+ {
+ try {
+ $parser = $this->loadOptionParser();
+ $files = $this->parseParameters($parser);
+
+ $allfine = true;
+ foreach ($files as $filename) {
+ if ($this->format) {
+ $allfine &= $this->formatFile($filename);
+ } else {
+ $allfine &= $this->checkFile($filename);
+ }
+ }
+
+ if ($allfine == true) {
+ exit(0);
+ } else {
+ exit(10);
+ }
+ } catch (\Exception $e) {
+ echo 'Error: ' . $e->getMessage() . "\n";
+ exit(1);
+ }
+ }
+
+ /**
+ * Check a .sql file for syntax errors
+ *
+ * @param string $filename File path
+ *
+ * @return boolean True if there were no errors, false if there were some
+ */
+ public function checkFile($filename)
+ {
+ $this->renderer->startRendering($filename);
+ $sql = $this->loadSql($filename);
+ if ($sql === false) {
+ return false;
+ }
+
+ $parser = new \PhpMyAdmin\SqlParser\Parser($sql);
+ if (count($parser->errors) == 0) {
+ $this->renderer->finishOk();
+ return true;
+ }
+
+ $lines = array(1 => 0);
+ $pos = -1;
+ $line = 1;
+ while (false !== $pos = strpos($sql, "\n", ++$pos)) {
+ $lines[++$line] = $pos;
+ }
+
+ foreach ($parser->errors as $error) {
+ /* @var PhpMyAdmin\SqlParser\Exceptions\ParserException $error) */
+ reset($lines);
+ $line = 1;
+ while (next($lines) && $error->token->position >= current($lines)) {
+ ++$line;
+ }
+ $col = $error->token->position - $lines[$line];
+
+ $this->renderer->displayError(
+ $error->getMessage(),
+ //FIXME: ->token or ->value?
+ $error->token->token,
+ $line,
+ $col
+ );
+ }
+
+ return false;
+ }
+
+ /**
+ * Reformat the given file
+ */
+ protected function formatFile($filename)
+ {
+ $this->renderer->startRendering($filename);
+ $sql = $this->loadSql($filename);
+ if ($sql === false) {
+ return false;
+ }
+
+ $typeMap = array(
+ 'none' => 'text',
+ 'ansi' => 'cli',
+ 'html' => 'html',
+ );
+ $options = array(
+ 'type' => $typeMap[$this->highlight],
+ );
+ echo \PhpMyAdmin\SqlParser\Utils\Formatter::format($sql, $options) . "\n";
+ }
+
+ protected function loadSql($filename)
+ {
+ if ($filename == '-') {
+ $sql = file_get_contents('php://stdin');
+ } else {
+ $sql = file_get_contents($filename);
+ }
+ if (trim($sql) == '') {
+ $this->renderer->displayError('SQL file empty', '', 0, 0);
+ return false;
+ }
+ return $sql;
+ }
+
+ /**
+ * Load parameters for the CLI option parser.
+ *
+ * @return \Console_CommandLine CLI option parser
+ */
+ protected function loadOptionParser()
+ {
+ $parser = new \Console_CommandLine();
+ $parser->description = 'php-sqllint';
+ $parser->version = 'dev';
+ $parser->avoid_reading_stdin = true;
+
+ $versionFile = __DIR__ . '/../../VERSION';
+ if (file_exists($versionFile)) {
+ $parser->version = trim(file_get_contents($versionFile));
+ }
+
+ $parser->addOption(
+ 'format',
+ array(
+ 'short_name' => '-f',
+ 'long_name' => '--format',
+ 'description' => 'Reformat SQL instead of checking',
+ 'action' => 'StoreTrue',
+ 'default' => false,
+ )
+ );
+ $parser->addOption(
+ 'highlight',
+ array(
+ 'short_name' => '-h',
+ 'long_name' => '--highlight',
+ 'description' => 'Highlighting mode (when using --format)',
+ 'action' => 'StoreString',
+ 'choices' => array(
+ 'none',
+ 'ansi',
+ 'html',
+ 'auto',
+ ),
+ 'default' => 'auto',
+ 'add_list_option' => true,
+ )
+ );
+ $parser->addOption(
+ 'renderer',
+ array(
+ 'short_name' => '-r',
+ 'long_name' => '--renderer',
+ 'description' => 'Output mode',
+ 'action' => 'StoreString',
+ 'choices' => array(
+ 'emacs',
+ 'text',
+ ),
+ 'default' => 'text',
+ 'add_list_option' => true,
+ )
+ );
+
+ $parser->addArgument(
+ 'sql_files',
+ array(
+ 'description' => 'SQL files, "-" for stdin',
+ 'multiple' => true
+ )
+ );
+
+ return $parser;
+ }
+
+ /**
+ * Let the CLI option parser parse the options.
+ *
+ * @param object $parser Option parser
+ *
+ * @return array Array of file names
+ */
+ protected function parseParameters(\Console_CommandLine $parser)
+ {
+ try {
+ $result = $parser->parse();
+
+ $rendClass = '\\phpsqllint\\Renderer_'
+ . ucfirst($result->options['renderer']);
+ $this->renderer = new $rendClass();
+
+ $this->format = $result->options['format'];
+
+ $this->highlight = $result->options['highlight'];
+ if ($this->highlight == 'auto') {
+ if (php_sapi_name() == 'cli') {
+ //default coloring to enabled, except
+ // when piping | to another tool
+ $this->highlight = 'ansi';
+ if (function_exists('posix_isatty')
+ && !posix_isatty(STDOUT)
+ ) {
+ $this->highlight = 'none';
+ }
+ } else {
+ //no idea where we are, so do not highlight
+ $this->highlight = 'none';
+ }
+ }
+
+ foreach ($result->args['sql_files'] as $filename) {
+ if ($filename == '-') {
+ continue;
+ }
+ if (!file_exists($filename)) {
+ throw new \Exception('File does not exist: ' . $filename);
+ }
+ if (!is_file($filename)) {
+ throw new \Exception('Not a file: ' . $filename);
+ }
+ }
+
+ return $result->args['sql_files'];
+ } catch (\Exception $exc) {
+ $parser->displayError($exc->getMessage());
+ }
+ }
+
+}
+?>
diff --git a/tools/php-sqllint/src/phpsqllint/Renderer.php b/tools/php-sqllint/src/phpsqllint/Renderer.php
new file mode 100644
index 000000000..5b68ee11a
--- /dev/null
+++ b/tools/php-sqllint/src/phpsqllint/Renderer.php
@@ -0,0 +1,54 @@
+<?php
+/**
+ * Part of php-sqllint
+ *
+ * PHP version 5
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://cweiske.de/php-sqllint.htm
+ */
+namespace phpsqllint;
+
+/**
+ * What every renderer has to implement
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://www.emacswiki.org/emacs/CreatingYourOwnCompileErrorRegexp
+ */
+interface Renderer
+{
+ /**
+ * Begin syntax check output rendering
+ *
+ * @param string $filename Path to the SQL file
+ *
+ * @return void
+ */
+ public function startRendering($filename);
+
+ /**
+ * Output errors in GNU style; see emacs compilation.txt
+ *
+ * @param string $msg Error message
+ * @param string $token Character which caused the error
+ * @param integer $line Line at which the error occured
+ * @param integer $col Column at which the error occured
+ *
+ * @return void
+ */
+ public function displayError($msg, $token, $line, $col);
+
+ /**
+ * Finish syntax check output rendering; no syntax errors found
+ *
+ * @return void
+ */
+ public function finishOk();
+}
+?>
diff --git a/tools/php-sqllint/src/phpsqllint/Renderer/Emacs.php b/tools/php-sqllint/src/phpsqllint/Renderer/Emacs.php
new file mode 100644
index 000000000..3a667c7f6
--- /dev/null
+++ b/tools/php-sqllint/src/phpsqllint/Renderer/Emacs.php
@@ -0,0 +1,70 @@
+<?php
+/**
+ * Part of php-sqllint
+ *
+ * PHP version 5
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://cweiske.de/php-sqllint.htm
+ */
+namespace phpsqllint;
+
+/**
+ * Output for emacs' compilation mode
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://www.emacswiki.org/emacs/CreatingYourOwnCompileErrorRegexp
+ */
+class Renderer_Emacs implements Renderer
+{
+ protected $filename;
+
+ /**
+ * Begin syntax check output rendering
+ *
+ * @param string $filename Path to the SQL file
+ *
+ * @return void
+ */
+ public function startRendering($filename)
+ {
+ $this->filename = $filename;
+ }
+
+ /**
+ * Output errors in GNU style; see emacs compilation.txt
+ *
+ * @param string $msg Error message
+ * @param string $token Character which caused the error
+ * @param integer $line Line at which the error occured
+ * @param integer $col Column at which the error occured
+ *
+ * @return void
+ */
+ public function displayError($msg, $token, $line, $col)
+ {
+ echo $this->filename
+ . ':' . $line
+ . '.' . $col
+ . ':Error:'
+ . ' '. $msg
+ . "\n";
+ }
+
+ /**
+ * Finish syntax check output rendering; no syntax errors found
+ *
+ * @return void
+ */
+ public function finishOk()
+ {
+ //do nothing
+ }
+}
+?>
diff --git a/tools/php-sqllint/src/phpsqllint/Renderer/Text.php b/tools/php-sqllint/src/phpsqllint/Renderer/Text.php
new file mode 100644
index 000000000..44e7ecbd4
--- /dev/null
+++ b/tools/php-sqllint/src/phpsqllint/Renderer/Text.php
@@ -0,0 +1,102 @@
+<?php
+/**
+ * Part of php-sqllint
+ *
+ * PHP version 5
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://cweiske.de/php-sqllint.htm
+ */
+namespace phpsqllint;
+
+/**
+ * Textual output, easily readable by humans.
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://www.emacswiki.org/emacs/CreatingYourOwnCompileErrorRegexp
+ */
+class Renderer_Text implements Renderer
+{
+ protected $fileshown = false;
+ protected $filename = null;
+
+ /**
+ * Begin syntax check output rendering
+ *
+ * @param string $filename Path to the SQL file
+ *
+ * @return void
+ */
+ public function startRendering($filename)
+ {
+ $this->filename = $filename;
+ $this->fileshown = false;
+ }
+
+
+ protected function showFile()
+ {
+ if ($this->fileshown) {
+ return;
+ }
+
+ echo "Checking SQL syntax of " . $this->filename . "\n";
+ $this->fileshown = true;
+ }
+
+ /**
+ * Show the error to the user.
+ *
+ * @param string $msg Error message
+ * @param string $token Character which caused the error
+ * @param integer $line Line at which the error occured
+ * @param integer $col Column at which the error occured
+ *
+ * @return void
+ */
+ public function displayError($msg, $token, $line, $col)
+ {
+ $this->showFile();
+ echo ' Line ' . $line
+ . ', col ' . $col
+ . ' at "' . $this->niceToken($token) . '":'
+ . ' ' . $msg
+ . "\n";
+ }
+
+ /**
+ * Finish syntax check output rendering; no syntax errors found
+ *
+ * @return void
+ */
+ public function finishOk()
+ {
+ if ($this->fileshown) {
+ echo " OK\n";
+ }
+ }
+
+ /**
+ * Convert the token string to a readable one, especially special
+ * characters like newline and tabs
+ *
+ * @param string $str String with possibly special characters
+ *
+ * @return string Escaped string
+ */
+ protected function niceToken($str)
+ {
+ return str_replace(
+ ["\n", "\r", "\t"],
+ ['\n', '\r', '\t'],
+ $str
+ );
+ }
+}
+?>
diff --git a/tools/php-sqllint/src/stub-phar.php b/tools/php-sqllint/src/stub-phar.php
new file mode 100644
index 000000000..5c8629e23
--- /dev/null
+++ b/tools/php-sqllint/src/stub-phar.php
@@ -0,0 +1,18 @@
+#!/usr/bin/env php
+<?php
+/**
+ * Phar stub file for php-sqllint. Handles startup of the .phar file.
+ *
+ * PHP version 5
+ *
+ * @category Tools
+ * @package PHP-SQLlint
+ * @author Christian Weiske <cweiske@cweiske.de>
+ * @copyright 2015 Christian Weiske
+ * @license http://www.gnu.org/licenses/agpl.html GNU AGPL v3
+ * @link http://cweiske.de/php-sqllint.htm
+ */
+Phar::mapPhar('php-sqllint.phar');
+require 'phar://php-sqllint.phar/bin/phar-php-sqllint.php';
+__HALT_COMPILER();
+?>
diff --git a/tools/questdbconverter.pl b/tools/questdbconverter.pl
index 42017758a..9bdc650aa 100755
--- a/tools/questdbconverter.pl
+++ b/tools/questdbconverter.pl
@@ -3,7 +3,7 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2015 Hercules Dev Team
+# Copyright (C) 2015-2020 Hercules Dev Team
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
diff --git a/tools/scconfigconverter.py b/tools/scconfigconverter.py
new file mode 100644
index 000000000..e6a82585c
--- /dev/null
+++ b/tools/scconfigconverter.py
@@ -0,0 +1,105 @@
+#!/usr/bin/env python
+# -*- coding: utf8 -*-
+#
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2019-2020 Hercules Dev Team
+# Copyright (C) 2019 Asheraf
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+#
+
+import csv
+
+with open('../db/sc_config.txt') as dbfile:
+ sc_config = csv.reader(dbfile, delimiter=',')
+
+ print(r'''//================= Hercules Database =====================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ===============================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2019-2020 Hercules Dev Team
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//================= Description ===========================================
+// Configurations file for status effects
+//=========================================================================
+''')
+ print('''/**************************************************************************
+ ************* Entry structure ********************************************
+ **************************************************************************
+SC_TYPE: {
+ // ================ Optional fields ===============================
+ Visible: (bool) SC can be visible for all players
+ Flags: {
+ NoDeathReset: (bool) SC cannot be removed by death.
+ NoSave: (bool) SC cannot be saved.
+ NoDispelReset: (bool) SC cannot be reset by dispell.
+ NoClearanceReset: (bool) SC cannot be reset by clearance.
+ Buff: (bool) SC considered as buff and be removed by Hermode and etc.
+ Debuff: (bool) SC considered as debuff and be removed by Gospel and etc.
+ NoMadoReset: (bool) SC cannot be reset when MADO Gear is taken off.
+ NoAllReset: (bool) SC cannot be reset by 'sc_end SC_ALL' and status change clear.
+ }
+}
+**************************************************************************/''')
+ flags = [
+ ('NoDeathReset', 1),
+ ('NoSave', 2),
+ ('NoDispelReset', 4),
+ ('NoClearanceReset', 8),
+ ('Buff', 16),
+ ('Debuff', 32),
+ ('NoMadoReset', 64),
+ ('NoAllReset', 128)
+ ]
+
+ for sc in sc_config:
+ if len(sc) != 2 or sc[0].startswith('//'):
+ continue
+ value = int(sc[1])
+ print('{}: {{'.format(sc[0]))
+ if value & 256:
+ print('\tVisible: true')
+ value &= ~256;
+
+ print('\tFlags: {')
+ for flag in flags:
+ if value & flag[1]:
+ print('\t\t{}: true'.format(flag[0]))
+ value &= ~flag[1];
+ if value != 0:
+ print('Error: invalid value ({}) for status ({}), aborting.'.format(int(sc[1]), sc[0]))
+ exit()
+ print('\t}')
+ print('}')
diff --git a/tools/setup_mariadb.ps1 b/tools/setup_mariadb.ps1
new file mode 100644
index 000000000..709a5cf93
--- /dev/null
+++ b/tools/setup_mariadb.ps1
@@ -0,0 +1,90 @@
+#Requires -Version 5.1
+
+function Ask-Continue { Write-Output ""; pause; Write-Output "" }
+
+Write-Output "This script will automatically install MariaDB and configure it for you."
+Write-Output "You may interrupt the installation by pressing CTRL+C or closing this window."
+Ask-Continue
+
+if (-Not (Select-String -Quiet -SimpleMatch -Pattern "db_password: ""ragnarok""" -LiteralPath "$PSScriptRoot\..\conf\global\sql_connection.conf")) {
+ Write-Output "WARNING: It seems you already configured the sql connection for your server."
+ Write-Output "If you decide to continue, your settings will be overwritten."
+ Ask-Continue
+}
+
+# step 1: install scoop
+if (-Not (Get-Command scoop -errorAction SilentlyContinue)) {
+ Set-ExecutionPolicy RemoteSigned -scope Process -Force # <= this will trigger a yes/no prompt if not already authorized
+ Invoke-Expression (new-object net.webclient).downloadstring('https://get.scoop.sh')
+ scoop update
+}
+
+# step 2: install mariadb
+if (Test-Path $env:USERPROFILE\scoop\apps\mariadb) {
+ # usually we'd want to capture the output of "scoop list mariadb", but it uses
+ # Write-Host, so we can't, hence why we check manually for the folder
+ Write-Output "WARNING: MariaDB is already installed!"
+ Write-Output "If you decide to continue, your hercules user password will be overwritten."
+ Ask-Continue
+} elseif (Get-Command mysqld -errorAction SilentlyContinue) {
+ Write-Output "ERROR: You already have a MySQL provider installed. To avoid conflict, MariaDB will not be installed."
+ Write-Output "If you wish to continue you will have to uninstall your current MySQL provider."
+ exit 1
+} else {
+ scoop install mariadb
+}
+
+# step 3: add the herc user, set up the new database
+$userpw = -join ((48..57) + (97..122) | Get-Random -Count 32 | % {[char]$_})
+$rootpw = -join ((48..57) + (97..122) | Get-Random -Count 32 | % {[char]$_})
+$maria_job = Start-Process -NoNewWindow -FilePath "mysqld.exe" -ArgumentList "--console" -PassThru -RedirectStandardError "$PSScriptRoot\maria.out"
+
+while (-Not $maria_job.HasExited) {
+ if ($lt -Lt 1 -And (Select-String -Quiet -SimpleMatch -Pattern "ready for connections" -LiteralPath "$PSScriptRoot\maria.out")) {
+@"
+CREATE DATABASE IF NOT EXISTS hercules;
+DROP USER IF EXISTS 'hercules'@'localhost';
+DROP USER IF EXISTS 'hercules'@'127.0.0.1';
+CREATE USER 'hercules'@'localhost' IDENTIFIED BY '$userpw';
+CREATE USER 'hercules'@'127.0.0.1' IDENTIFIED BY '$userpw';
+-- ALTER USER 'root'@'localhost' IDENTIFIED BY '$rootpw';
+GRANT ALTER,CREATE,SELECT,INSERT,UPDATE,DELETE,DROP,INDEX ON `hercules`.* TO 'hercules'@'localhost';
+GRANT ALTER,CREATE,SELECT,INSERT,UPDATE,DELETE,DROP,INDEX ON `hercules`.* TO 'hercules'@'127.0.0.1';
+FLUSH PRIVILEGES;
+USE `hercules`;
+\. $PSScriptRoot\..\sql-files\main.sql
+\. $PSScriptRoot\..\sql-files\logs.sql
+shutdown;
+\q
+"@ | mysql.exe -u root
+ $lt++
+ }
+ Start-Sleep 1
+}
+
+if ($lt -Lt 1) {
+ Write-Output "ERROR: MariaDB could not execute the query."
+ Write-Output "This might happen if your root user already has a password, or if the MySQL service is currently running."
+ $maria_job.close()
+ exit 1
+}
+
+# step 4: finish up
+@"
+sql_connection: {
+ db_username: "hercules"
+ db_password: "$userpw"
+ db_database: "hercules"
+}
+"@ | Out-File -Encoding UTF8 -LiteralPath "$PSScriptRoot\..\conf\global\sql_connection.conf"
+Remove-Item -Force -errorAction SilentlyContinue "$PSScriptRoot\maria.out"
+& "$PSScriptRoot\install_mariadb.bat" # <= we need admin permissions, so we use an external script
+Write-Output "========= ALL DONE ========="
+Write-Output ""
+Write-Output "Your hercules installation is now configured to use MariaDB."
+Write-Output "You can find the password in conf\global\sql_connection.conf."
+Write-Output ""
+Write-Output "If you want to start MariaDB on boot, use services.msc and set ""MySQL"" to Automatic."
+Write-Output ""
+Write-Output "Make sure you set a password for the root user. You can do this from the command line or from HeidiSQL."
+Write-Output "You can obtain HeidiSQL at https://www.microsoft.com/store/productId/9NXPRT2T0ZJF"
diff --git a/tools/skilldbconverter.php b/tools/skilldbconverter.php
new file mode 100644
index 000000000..233001e08
--- /dev/null
+++ b/tools/skilldbconverter.php
@@ -0,0 +1,1202 @@
+<?php
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+* _ _ _
+* | | | | | |
+* | |_| | ___ _ __ ___ _ _| | ___ ___
+* | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+* | | | | __/ | | (__| |_| | | __/\__ \
+* \_| |_/\___|_| \___|\__,_|_|\___||___/
+*
+* * * * * * * * * * * * * * License * * * * * * * * * * * * * * * * * * * * * *
+* This file is part of Hercules.
+* http://herc.ws - http://github.com/HerculesWS/Hercules
+*
+* Copyright (C) 2016-2020 Hercules Dev Team
+* Copyright (C) 2016 Smokexyz
+*
+* Hercules is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program is distributed in the hope that it will be useful,
+* but WITHOUT ANY WARRANTY; without even the implied warranty of
+* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+* GNU General Public License for more details.
+*
+* You should have received a copy of the GNU General Public License
+* along with this program. If not, see <http://www.gnu.org/licenses/>.
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
+* Credits : Smokexyz */
+
+// Credits before anything else.
+printcredits();
+
+if(!isset($argv[1]))
+ gethelp();
+
+function issetarg($arg) {
+ global $argv;
+ for($i=1; $i<sizeof($argv); $i++) {
+ if(strncmp($argv[$i],$arg,strlen($arg)) == 0)
+ return $i;
+ }
+ return 0;
+}
+
+$renewal = (issetarg("-re") || issetarg("--renewal"));
+$prere = (issetarg("-pre-re") || issetarg("--pre-renewal"));
+$constants = (!issetarg("-itid") && !issetarg("--use-itemid"));
+$help = (issetarg("-h") || issetarg("--help"));
+$directory = function() use($argv) {
+ $arg = issetarg("--directory")?issetarg("--directory"):(issetarg("-dir")?issetarg("-dir"):0);
+ if ($arg) {
+ $part = explode("=", $argv[$arg]);
+ if(!isset($part[1])) {
+ die("A directory path was not provided!\n");
+ } else if(!is_dir($part[1])) {
+ die("The given directory ".$part[1]." doesn't exist.\n");
+ } else {
+ return $part[1];
+ }
+ }
+};
+
+$dir = $directory();
+
+if ($dir) {
+ print "Read/Write Directory has been set to '".$dir."'\n";
+ print "Please ensure all skill_db TXT files are placed in this path.\n";
+ print "Please also provide the correct version of the database (re/pre-re).\n";
+ define('DIRPATH', $dir);
+}
+
+$debug = (issetarg("-dbg") || issetarg("--with-debug"));
+
+if ($debug) {
+ print "\033[0mDebug Mode Enabled.\n";
+ $t_init = microtime_float();
+}
+
+if($help || (!$renewal && !$prere) || ($renewal && $prere)) {
+ gethelp();
+}
+
+if ($renewal) {
+ print "Renewal enabled.\n";
+ print "skill_db.txt and associated files (cast, nocastdex, require & unit) will be converted.\n";
+ if(!defined('DIRPATH'))
+ define('DIRPATH', '../db/re/');
+ define('RENEWAL', true);
+} else if ($prere) {
+ print "Pre-Renewal enabled.\n";
+ print "skill_db.txt and associated files (cast, nocastdex, require & unit) will be converted.\n";
+ if(!defined('DIRPATH'))
+ define('DIRPATH', '../db/pre-re/');
+}
+
+// check for existence of files.
+
+$file_check = [
+ DIRPATH."skill_require_db.txt",
+ DIRPATH."skill_cast_db.txt",
+ DIRPATH."skill_castnodex_db.txt",
+ DIRPATH."skill_unit_db.txt",
+ DIRPATH."skill_db.txt"
+];
+
+if($constants) array_push($file_check, DIRPATH."item_db.conf");
+
+foreach($file_check as $file) {
+ if(file_exists($file))
+ print $file." - Found\n";
+ else
+ die($file." - Not Found!\n");
+}
+
+if ($constants) {
+ print "Using of Item Constants : enabled\n";
+} else {
+ print "Using of Item Constants : disabled.\n";
+}
+
+/* Begin the Loading of Files */
+
+$i=0;
+$file="skill_require_db.txt";
+$requiredb = fopen(DIRPATH.$file, "r") or die("Unable to open '".DIRPATH.$file."'.\n");
+print "Reading '".DIRPATH.$file."' ...\n";
+while(!feof($requiredb))
+{
+ $line = fgets($requiredb);
+ if(substr($line, 0, 2) == "//" || strlen($line) < 10) continue;
+ $line = strstr(preg_replace('/\s+/','',$line), "//", true);
+ $arr = explode(",", $line);
+ if(!isset($arr[0])) continue;
+ $skreq['ID'][$i] = $arr[0];
+ $skreq['HPCost'][$i] = $arr[1];
+ $skreq['MaxHPTrigger'][$i] = $arr[2];
+ $skreq['SPCost'][$i] = $arr[3];
+ $skreq['HPRateCost'][$i] = $arr[4];
+ $skreq['SPRateCost'][$i] = $arr[5];
+ $skreq['ZenyCost'][$i] = $arr[6];
+ $skreq['Weapons'][$i] = $arr[7];
+ $skreq['AmmoTypes'][$i] = $arr[8];
+ $skreq['AmmoAmount'][$i] = $arr[9];
+ $skreq['State'][$i] = $arr[10];
+ $skreq['SpiritSphere'][$i] = $arr[11];
+ $k=0;
+ for($j=12; $j<=31; $j+=2) {
+ $skreqit['ItemId'][$i][$k] = isset($arr[$j])?$arr[$j]:0;
+ $skreqit['Amount'][$i][$k] = isset($arr[$j+1])?$arr[$j+1]:0;
+ $k++;
+ }
+ $i++;
+}
+if ($debug) {
+ print "[Debug] Read require_db Memory: ".print_mem()."\n";
+}
+fclose($requiredb);
+
+$file="skill_cast_db.txt";
+$skillcastdb = fopen(DIRPATH.$file, "r") or die("Unable to open '".DIRPATH.$file."'.\n");
+print "Reading '".DIRPATH.$file."' ...\n";
+$i=0;
+while(!feof($skillcastdb))
+{
+ $line = fgets($skillcastdb);
+ if (substr($line, 0, 2) == "//" || strlen($line) < 10) continue;
+ $arr = explode(",",$line);
+ if (!isset($arr[0])) continue;
+ $skcast["ID"][$i] = $arr[0]; // SkillCastDBId
+ $skcast["casttime"][$i] = $arr[1];
+ $skcast["actdelay"][$i] = $arr[2];
+ $skcast["walkdelay"][$i] = $arr[3];
+ $skcast["data1"][$i] = $arr[4];
+ $skcast["data2"][$i] = $arr[5];
+ $skcast["cooldown"][$i] = $arr[6];
+ if(defined('RENEWAL')) $skcast["fixedcast"][$i] = $arr[7];
+
+ $i++;
+}
+if($debug) {
+ print "[Debug] Read cast_db Memory: ".print_mem()."\n";
+}
+fclose($skillcastdb);
+
+$file="skill_castnodex_db.txt";
+$castnodex = fopen(DIRPATH.$file, "r") or die("Unable to open '".DIRPATH.$file."'.\n");
+print "Reading '".DIRPATH.$file."' ...\n";
+$i=0;
+while(!feof($castnodex))
+{
+ $line = fgets($castnodex);
+ if(substr($line, 0, 2) == "//" || strlen($line) <= 2) continue;
+ $line = strstr(preg_replace('/\s+/','',$line), "//", true);
+ $arr = explode(",",$line);
+ $sknodex["ID"][$i] = $arr[0];
+ $sknodex["cast"][$i] = isset($arr[1])?$arr[1]:0;
+ $sknodex["delay"][$i] = isset($arr[2])?$arr[2]:0;
+ $i++;
+}
+if($debug) {
+ print "[Debug] Read cast_nodex Memory: ".print_mem()."\n";
+}
+fclose($castnodex);
+
+/***
+* Read item_db.conf to gather aegis item name informations.
+*/
+if ($constants) {
+ $itemdb[] = array();
+
+ $file = "item_db.conf";
+ if(file_exists(DIRPATH.$file)) {
+ $itemconf = fopen(DIRPATH.$file, "r") or die ("Unable to open '".DIRPATH.$file."'.\n");
+ print "Reading '".DIRPATH.$file."' ...\n";
+
+ $started = false;
+ $i=0;
+ while(!feof($itemconf)) {
+ $line = fgets($itemconf);
+ $line = trim($line);
+ if(strcmp($line,"{\n"))
+ $started = true;
+ else if (strcmp($line,"},\n"))
+ $started = false;
+ //echo str_replace(" ","",$line)."\n";
+
+ if($started == true) {
+ $p = explode(":", $line);
+ if(isset($p[0])) {
+ if($p[0] == "Id") {
+ //echo $p[0]." ".(isset($p[1])?$p[1]:NULL)."\n";
+ $itemdb['ID'][$i] = intval($p[1]);
+ }
+ if($p[0] == "AegisName") {
+ //echo $p[0]." ".(isset($p[1])?str_replace("\"","",$p[1]):NULL)."\n";
+ $itemdb['name'][$i] = str_replace("\"","",$p[1]);
+ $i++;
+ }
+ }
+ }
+ }
+ if($debug) {
+ print "[Debug] Read item_db Memory: ".print_mem()."\n";
+ }
+ fclose($itemconf);
+ } else {
+ print "Unable to open '".DIRPATH.$file."'... defaulting to using Item ID's instead of Constants.\n";
+ $constants = false;
+ }
+}
+
+/* * *
+* Bring forth the contents of skill_unit_db.txt and store them.
+*/
+$i=0;
+$file="skill_unit_db.txt";
+$unitdb = fopen(DIRPATH.$file, "r") or die("Unable to open '".DIRPATH.$file."'.\n");
+print "Reading '".DIRPATH.$file."' ...\n";
+while(!feof($unitdb)) {
+ $line = fgets($unitdb);
+ if(substr($line, 0, 2) == "//" || strlen($line) < 10) continue;
+ $line = strstr(preg_replace('/\s+/','',$line), "//", true);
+ $arr = explode(",",$line);
+ $skunit['ID'][$i] = $arr[0];
+ $skunit['UnitID'][$i] = $arr[1];
+ $skunit['UnitID2'][$i] = $arr[2];
+ $skunit['Layout'][$i] = $arr[3];
+ $skunit['Range'][$i] = $arr[4];
+ $skunit['Interval'][$i] = $arr[5];
+ $skunit['Target'][$i] = $arr[6];
+ $skunit['Flag'][$i] = hexdec($arr[7]);
+ $i++;
+}
+if($debug) {
+ print "[Debug] Read unit_db Memory: ".print_mem()."\n";
+}
+fclose($unitdb);
+
+$putsk = ""; // initialize variable for file_put_contents.
+// Publish all comments
+$putsk .= getcomments((defined('RENEWAL')?true:false));
+
+$putsk .= "skill_db: (\n";
+// Get Main Skilldb File
+$file="skill_db.txt";
+$skmain = fopen(DIRPATH.$file, "r") or die("Unable to open '".DIRPATH.$file."'.\n");
+print "Reading '".DIRPATH.$file."' ...\n";
+$linecount = 0;
+
+// Get Number of entries
+while(!feof($skmain)) {
+ $line = fgets($skmain);
+ if(substr($line, 0, 2) == "//" || strlen($line) < 10) continue;
+ $linecount++;
+}
+if($debug) {
+ print "[Debug] Read skill_db Memory: ".print_mem()."\n";
+}
+fclose($skmain);
+print $linecount." entries found in skill_db.txt.\n";
+
+$i=0;
+$skmain = fopen(DIRPATH.$file, "r") or die("Unable to open '".DIRPATH.$file."'.\n");
+// Begin converting process.
+$max_level = 10;
+$max_items = 10;
+while(!feof($skmain)) {
+ $line = fgets($skmain);
+ if(substr($line, 0, 2) == "//" || strlen($line) < 10) continue;
+ $arr = explode(",", $line);
+ // id,range,hit,inf,element,nk,splash,max,list_num,castcancel,cast_defence_rate,inf2,maxcount,skill_type,blow_count,name,description
+ $id = $arr[0];
+ $range = $arr[1];
+ $hit = $arr[2];
+ $inf = $arr[3];
+ $element = $arr[4];
+ $nk = $arr[5];
+ $splash = $arr[6];
+ $max = $arr[7];
+ $max = ($max < 1) ? 1 : $max;
+ $list_num = $arr[8];
+ $castcancel = $arr[9];
+ $cast_defence_rate = $arr[10];
+ $inf2 = $arr[11];
+ $maxcount = $arr[12];
+ $skill_type = $arr[13];
+ $blow_count = $arr[14];
+ $name = $arr[15];
+ if(strlen(substr($arr[16], 0, strpos($arr[16], "//"))))
+ $description = substr($arr[16], 0, strpos($arr[16], "//"));
+ else
+ $description = $arr[16];
+
+ $putsk .= "{\n".
+ "\tId: ".$id."\n".
+ "\tName: \"".trim($name)."\"\n".
+ "\tDescription: \"".trim($description)."\"\n".
+ "\tMaxLevel: ".$max."\n";
+ if($range) $putsk .= "\tRange: ".leveled_guessfill($range, $max_level, $id)."\n";
+ if($hit==8) $putsk .= "\tHit: \"BDT_MULTIHIT\"\n";
+ else if($hit==6) $putsk .= "\tHit: \"BDT_SKILL\"\n";
+ if($inf) $putsk .= "\tSkillType: ".getinf($inf)."\n";
+ if($inf2) $putsk .= "\tSkillInfo: ".getinf2($inf2)."\n";
+ if($skill_type != "none") $putsk .= "\tAttackType: \"".ucfirst($skill_type)."\"\n";
+ if($element) $putsk .= "\tElement: ".leveled_ele($element, $max_level, $id)."\n";
+ if($nk && $nk != "0x0") $putsk .= "\tDamageType: ".getnk($nk)."\n";
+ if($splash) $putsk .= "\tSplashRange: ".leveled_guessfill($splash, $max_level, $id)."\n";
+ if($list_num != "1") $putsk .= "\tNumberOfHits: ".leveled_guessfill($list_num, $max_level, $id)."\n";
+ if($castcancel == "yes") $putsk .= "\tInterruptCast: true\n";
+ if($cast_defence_rate) $putsk .= "\tCastDefRate: ".$cast_defence_rate."\n";
+ if($maxcount) $putsk .= "\tSkillInstances: ".leveled_guessfill($maxcount, $max_level, $id)."\n";
+ if($blow_count) $putsk .= "\tKnockBackTiles: ".leveled_guessfill($blow_count, $max_level, $id)."\n";
+ // Cast Db
+ $key = array_search($id, $skcast['ID']);
+ if($key !== FALSE) {
+ if($skcast['casttime'][$key]) $putsk .= "\tCastTime: ".leveled_guessfill($skcast['casttime'][$key], $max_level, $id)."\n";
+ if($skcast['actdelay'][$key]) $putsk .= "\tAfterCastActDelay: ".leveled_guessfill($skcast['actdelay'][$key], $max_level, $id)."\n";
+ if($skcast['walkdelay'][$key] !== '0') $putsk .= "\tAfterCastWalkDelay: ".leveled_guessfill($skcast['walkdelay'][$key], $max_level, $id)."\n";
+ if($skcast['data1'][$key] !== '0') $putsk .= "\tSkillData1: ".leveled_guessfill($skcast['data1'][$key], $max_level, $id)."\n";
+ if($skcast['data2'][$key] !== '0') $putsk .= "\tSkillData2: ".leveled_guessfill($skcast['data2'][$key], $max_level, $id)."\n";
+ if($skcast['cooldown'][$key] !== '0') $putsk .= "\tCoolDown: ".leveled_guessfill($skcast['cooldown'][$key], $max_level, $id)."\n";
+ if(defined('RENEWAL') && strlen($skcast['fixedcast'][$key]) > 1 && $skcast['fixedcast'][$key] !== '0')
+ $putsk .= "\tFixedCastTime: ".leveled_guessfill($skcast['fixedcast'][$key], $max_level, $id)."\n";
+ }
+ // Cast NoDex
+ unset($key);
+ $key = array_search($id, $sknodex['ID']);
+ if($key !== FALSE) {
+ if (isset($sknodex["cast"][$key]) && $sknodex["cast"][$key] != 0) $putsk .= "\tCastTimeOptions: ".getnocast($sknodex["cast"][$key], $id)."\n";
+ if (isset($sknodex["delay"][$key]) && $sknodex["delay"][$key] != 0) $putsk .= "\tSkillDelayOptions: ".getnocast($sknodex["delay"][$key], $id)."\n";
+ unset($sknodex["ID"][$key]);
+ unset($sknodex["cast"][$key]);
+ unset($sknodex["delay"][$key]);
+ }
+
+ // require DB
+ unset($key);
+ $key = array_search($id, $skreq['ID']);
+ if($key !== FALSE) {
+ $putsk .= "\tRequirements: {\n";
+ if ($skreq['HPCost'][$key]) $putsk .= "\t\tHPCost: ".leveled_guessfill($skreq['HPCost'][$key], $max_level, $id, 1)."\n";
+ if ($skreq['SPCost'][$key]) $putsk .= "\t\tSPCost: ".leveled_guessfill($skreq['SPCost'][$key], $max_level, $id, 1)."\n";
+ if ($skreq['HPRateCost'][$key]) $putsk .= "\t\tHPRateCost: ".leveled_guessfill($skreq['HPRateCost'][$key], $max_level, $id, 1)."\n";
+ if ($skreq['SPRateCost'][$key]) $putsk .= "\t\tSPRateCost: ".leveled_guessfill($skreq['SPRateCost'][$key], $max_level, $id, 1)."\n";
+ if ($skreq['ZenyCost'][$key]) $putsk .= "\t\tZenyCost: ".leveled_guessfill($skreq['ZenyCost'][$key], $max_level, $id, 1)."\n";
+ if ($skreq['Weapons'][$key] != 99) $putsk .= "\t\tWeaponTypes: ".getweapontypes($skreq['Weapons'][$key], $id)."\n";
+ if ($skreq['AmmoTypes'][$key] == 99) $putsk .= "\t\tAmmoTypes: \"All\"\n";
+ else if ($skreq['AmmoTypes'][$key]) $putsk .= "\t\tAmmoTypes: ".getammotypes($skreq['AmmoTypes'][$key], $id)."\n";
+ if ($skreq['AmmoAmount'][$key]) $putsk .= "\t\tAmmoAmount: ".leveled_guessfill($skreq['AmmoAmount'][$key], $max_level, $id, 1)."\n";
+ if ($skreq['State'][$key] != "none" && $skreq['State'][$key]) $putsk .= "\t\tState: \"".getstate($skreq['State'][$key],$id)."\"\n";
+ if ($skreq['SpiritSphere'][$key]) $putsk .= "\t\tSpiritSphereCost: ".leveled_guessfill($skreq['SpiritSphere'][$key], $max_level, $id, 1)."\n";
+ if ($skreqit['ItemId'][$key][0] > 0) {
+ $putsk .= "\t\tItems: {\n";
+ for ($index=0; $index<sizeof($skreqit['ItemId'][$key]); $index++) {
+ $itemID = $skreqit['ItemId'][$key][$index]; // Required Item
+ $itemamt = $skreqit['Amount'][$key][$index]; // Required Amount
+
+ if (strpos($itemID, ':') == true) {
+ $items = explode(":", $itemID);
+ $it = 0;
+ while (isset($items) && isset($items[$it])) {
+ if ($constants && $itemID) {
+ $itkey = array_search($items[$it], $itemdb['ID']);
+ if($itkey === FALSE)
+ $itemname = "ID".$items[$it];
+ else
+ $itemname = $itemdb['name'][$itkey];
+ $putsk .= "\t\t\t".trim($itemname).": ".leveled($itemamt, $max_level, $id, 2)."\n";
+ } else if (intval($itemID)) {
+ $putsk .= "\t\t\tID".$items[$it].": ".leveled($itemamt, $max_level, $id, 2)."\n";
+ }
+ $it++;
+ }
+ } else {
+ if ($constants && $itemID) {
+ $itkey = array_search($skreqit['ItemId'][$key][$index], $itemdb['ID']);
+ if($itkey === FALSE)
+ $itemname = "ID".$itemID;
+ else
+ $itemname = $itemdb['name'][$itkey];
+ $putsk .= "\t\t\t".trim($itemname).": ".leveled($itemamt, $max_items, $id, 2)."\n";
+ } else if ($itemID) {
+ $putsk .= "\t\t\tID".$itemID.": ".leveled($itemamt, $max_items, $id, 2)."\n";
+ }
+ }
+ }
+ $putsk .= "\t\t}\n";
+ }
+ $putsk .= "\t}\n";
+ }
+
+ unset($key);
+ $key = array_search($id, $skunit['ID']);
+ if($key !== FALSE) {
+ $putsk .= "\tUnit: {\n";
+ if(isset($skunit['UnitID'][$key])) {
+ if(isset($skunit['UnitID2'][$key]) && strlen($skunit['UnitID2'][$key])) {
+ $putsk .= "\t\tId: [ ".$skunit['UnitID'][$key].", ".$skunit['UnitID2'][$key]." ]\n";
+ } else $putsk .= "\t\tId: ".$skunit['UnitID'][$key]."\n";
+ }
+ if(isset($skunit['Layout'][$key]) && $skunit['Layout'][$key] != 0) $putsk .= "\t\tLayout: ".leveled_guessfill($skunit['Layout'][$key], $max_level, $id, 1)."\n";
+ if(isset($skunit['Range'][$key]) && $skunit['Range'][$key] != 0) $putsk .= "\t\tRange: ".leveled_guessfill($skunit['Range'][$key], $max_level, $id, 1)."\n";
+# if(isset($skunit['Interval'][$key])) $putsk .= "\t\tInterval: ".leveled_guessfill($skunit['Interval'][$key], $max_level, $id, 1)."\n";
+# in memory present space only for one interval, but in old db intervals present for each level
+ if(isset($skunit['Interval'][$key])) $putsk .= "\t\tInterval: ".intval($skunit['Interval'][$key])."\n";
+ if(isset($skunit['Target'][$key]) && $skunit['Target'][$key] != "noone") $putsk .= "\t\tTarget: \"".trim(ucfirst($skunit['Target'][$key]))."\"\n";
+ if(isset($skunit['Flag'][$key]) && $skunit['Flag'][$key] != "") {
+ $putsk .= "\t\tFlag: ".getunitflag($skunit['Flag'][$key], $id)."\n";
+ }
+ $putsk .= "\t}\n";
+ }
+ // close skill
+ $putsk .= "},\n";
+ // Display progress bar
+ show_status($i++, $linecount);
+}
+show_status($linecount, $linecount);
+/**
+ * Print final messages and exit the script, conversion has completed.
+ */
+print "\n";
+print "The skill database has been successfully converted to Hercules' libconfig\n";
+print "format and has been saved as '".DIRPATH."skill_db.conf'.\n";
+print "The following files are now deprecated and can be deleted -\n";
+print DIRPATH."skill_db.txt\n";
+print DIRPATH."skill_cast_db.txt\n";
+print DIRPATH."skill_castnodex_db.txt\n";
+print DIRPATH."skill_require_db.txt\n";
+print DIRPATH."skill_unit_db.txt\n";
+$putsk .= ")";
+$skconf = "skill_db.conf";
+file_put_contents(DIRPATH.$skconf, $putsk);
+if($debug) {
+ print "[Debug] Memory after converting: ".print_mem()."\n";
+ print "[Debug] Execution Time : ".(microtime_float()-$t_init)."s\n";
+}
+fclose($skmain);
+
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+/* Functions
+/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
+
+function microtime_float()
+{
+ list($usec, $sec) = explode(" ", microtime());
+ return ((float)$usec + (float)$sec);
+}
+
+function show_status($done, $total) {
+ $perc = floor(($done / $total) * 100);
+ $perc = floor($perc/2);
+ $left = 50-$perc;
+ $finalperc = $perc * 2;
+ $write = sprintf("[%'={$perc}s>%-{$left}s] - $finalperc%% - $done/$total\r", "", "");
+ fwrite(STDERR, $write);
+}
+function get_element($ele,$id)
+{
+ switch($ele)
+ {
+ case -1: return "Ele_Weapon";
+ case -2: return "Ele_Endowed";
+ case -3: return "Ele_Random";
+ case 0: return "Ele_Neutral";
+ case 1: return "Ele_Water";
+ case 2: return "Ele_Earth";
+ case 3: return "Ele_Fire";
+ case 4: return "Ele_Wind";
+ case 5: return "Ele_Poison";
+ case 6: return "Ele_Holy";
+ case 7: return "Ele_Dark";
+ case 8: return "Ele_Ghost";
+ case 9: return "Ele_Undead";
+ default: print "\rWarningUnknown Element ".$ele." provided for skill Id ".$id."\n";
+ }
+
+ return NULL;
+}
+function leveled_ele($str, $max, $skill_id)
+{
+ if(strpos($str, ':') == true)
+ {
+ $lvs = explode(":", $str);
+ $retval = "{\n";
+ for($i = 0; $i < $max && isset($lvs[$i]); $i++) {
+ $retval .= "\t\tLv".($i+1).": \"".get_element($lvs[$i],$skill_id)."\"\n";
+ }
+ $retval .= "\t}";
+ } else {
+ $retval = "\"".get_element($str,$skill_id)."\"";
+ }
+
+ return $retval;
+}
+
+function leveled($str, $max, $id, $tab=0)
+{
+ switch($tab) {
+ case 1:
+ $ittab = "\t\t\t";
+ $endtab = "\t\t";
+ break;
+ case 2:
+ $ittab = "\t\t\t\t";
+ $endtab = "\t\t\t";
+ break;
+ default:
+ $ittab = "\t\t";
+ $endtab = "\t";
+ break;
+ }
+
+ $retval = "";
+ if(strpos($str, ':') == true) {
+ $lvs = explode(":", trim($str));
+ $retval = "{\n";
+ for ($i = 0; $i < $max && isset($lvs[$i]); $i++) {
+ $retval .= $ittab."Lv".($i+1).": ".$lvs[$i]."\n";
+ }
+ $retval .= $endtab."}";
+ } else {
+ $retval = intval($str);
+ }
+
+ return $retval;
+}
+
+function leveled_guessfill($str, $max, $id, $tab=0)
+{
+ switch($tab) {
+ case 1:
+ $ittab = "\t\t\t";
+ $endtab = "\t\t";
+ break;
+ case 2:
+ $ittab = "\t\t\t\t";
+ $endtab = "\t\t\t";
+ break;
+ default:
+ $ittab = "\t\t";
+ $endtab = "\t";
+ break;
+ }
+
+ $retval = "";
+ if(strpos($str, ':') == true) {
+ $lvs = explode(":", trim($str));
+ $retval = "{\n";
+ for ($i = 0; $i < $max && isset($lvs[$i]); $i++) {
+ $retval .= $ittab."Lv".($i+1).": ".$lvs[$i]."\n";
+ }
+ if ($i < $max) {
+ /* Algorithm borrowed from skill_split_atoi(), as used by the old parser */
+ for ($step = 1; $step <= $i/2; $step++) {
+ $diff = $lvs[$i - 1] - $lvs[$i - $step - 1];
+ for ($j = $i - 1; $j >= $step; $j--)
+ if ($lvs[$j] - $lvs[$j - $step] != $diff)
+ break;
+
+ if ($j >= $step) //No match, try next step.
+ continue;
+
+ for(; $i < $max; $i++) { //Apply linear increase
+ $lvs[$i] = $lvs[$i - $step] + $diff;
+ if ($lvs[$i] < 1 && $lvs[$i - 1] >= 0) {
+ //Check if we have switched from + to -, cap the decrease to 0 in said cases.
+ $lvs[$i] = 1;
+ $diff = 0;
+ $step = 1;
+ }
+ $retval .= $ittab."Lv".($i+1).": ".$lvs[$i]."\n";
+ }
+ $retval .= $endtab."}";
+ return $retval;
+ }
+ //Okay.. we can't figure this one out, just fill out the stuff with the previous value.
+ for (; $i < $max; $i++) {
+ $lvs[$i] = $lvs[$i - 1];
+ $retval .= $ittab."Lv".($i+1).": ".$lvs[$i]."\n";
+ }
+ }
+ $retval .= $endtab."}";
+ } else {
+ $retval = intval($str);
+ }
+
+ return $retval;
+}
+
+function getstate($state,$id)
+{
+ if( strcmp($state,"hiding") == 0 ) return "Hiding";
+ else if( strcmp($state,"cloaking") == 0 ) return "Cloaking";
+ else if( strcmp($state,"hidden") == 0 ) return "Hidden";
+ else if( strcmp($state,"riding") == 0 ) return "Riding";
+ else if( strcmp($state,"falcon") == 0 ) return "Falcon";
+ else if( strcmp($state,"cart") == 0 ) return "Cart";
+ else if( strcmp($state,"shield") == 0 ) return "Shield";
+ else if( strcmp($state,"sight") == 0 ) return "Sight";
+ else if( strcmp($state,"explosionspirits") == 0 ) return "ExplosionSpirits";
+ else if( strcmp($state,"cartboost") == 0 ) return "CartBoost";
+ else if( strcmp($state,"recover_weight_rate") == 0 ) return "NotOverWeight";
+ else if( strcmp($state,"move_enable") == 0 ) return "Moveable";
+ else if( strcmp($state,"water") == 0 ) return "InWater";
+ else if( strcmp($state,"dragon") == 0 ) return "Dragon";
+ else if( strcmp($state,"warg") == 0 ) return "Warg";
+ else if( strcmp($state,"ridingwarg") == 0 ) return "RidingWarg";
+ else if( strcmp($state,"mado") == 0 ) return "MadoGear";
+ else if( strcmp($state,"elementalspirit") == 0 ) return "ElementalSpirit";
+ else if( strcmp($state,"poisonweapon") == 0 ) return "PoisonWeapon";
+ else if( strcmp($state,"rollingcutter") == 0 ) return "RollingCutter";
+ else if( strcmp($state,"mh_fighting") == 0 ) return "MH_Fighting";
+ else if( strcmp($state,"mh_grappling") == 0 ) return "MH_Grappling";
+ else if( strcmp($state,"peco") == 0 ) return "Peco";
+ else print "\rWarning - Invalid State ".$state." provided for Skill ID ".$id.", please correct this manually.\n";
+}
+
+function getinf($inf)
+{
+ $bitmask = array(
+ "Passive" => 0,
+ "Enemy" => 1,
+ "Place" => 2,
+ "Self" => 4,
+ "Friend" => 16,
+ "Trap" => 32,
+ );
+
+ $retval = "{\n";
+ foreach ($bitmask as $key => $val)
+ {
+ if($inf&$val)
+ $retval .= "\t\t".$key.": true\n";
+ }
+ $retval .= "\t}";
+
+ return $retval;
+}
+
+function getinf2($inf2=0x0000)
+{
+ $bitmask = array(
+ "Quest" => intval(0x0001), // = quest skill
+ "NPC" => intval(0x0002), // = npc skill
+ "Wedding" => intval(0x0004), // = wedding skill
+ "Spirit" => intval(0x0008), // = spirit skill
+ "Guild" => intval(0x0010), // = guild skill
+ "Song" => intval(0x0020), // = song/dance
+ "Ensemble" => intval(0x0040), // = ensemble skill
+ "Trap" => intval(0x0080), // = trap
+ "TargetSelf" => intval(0x0100), // = skill that damages/targets yourself
+ "NoCastSelf" => intval(0x0200), // = cannot be casted on self (if inf = 4, auto-select target skill)
+ "PartyOnly" => intval(0x0400), // = usable only on party-members (and enemies if skill is offensive)
+ "GuildOnly" => intval(0x0800), // = usable only on guild-mates (and enemies if skill is offensive)
+ "NoEnemy" => intval(0x1000), // = disable usage on enemies (for non-offensive skills).
+ "IgnoreLandProtector" => intval(0x2000), // = skill ignores land protector (e.g. arrow shower)
+ "Chorus" => intval(0x4000) // = chorus skill
+ );
+
+ $inf2 = intval(substr($inf2, 2),16);
+
+ $retval = "{\n";
+ foreach($bitmask as $key => $val) {
+ if($inf2&$val) {
+ $retval .= "\t\t".$key.": true\n";
+ }
+ }
+ $retval .= "\t}";
+
+ return $retval;
+}
+
+function getnk($nk)
+{
+ $bitmask = array(
+ "NoDamage" => intval(0x01), //- No damage skill
+ "SplashArea" => intval(0x02), //- Has splash area (requires source modification)
+ "SplitDamage" => intval(0x04), //- Damage should be split among targets (requires 0x02 in order to work)
+ "IgnoreCards" => intval(0x08), //- Skill ignores caster's % damage cards (misc type always ignores)
+ "IgnoreElement" => intval(0x10), //- Skill ignores elemental adjustments
+ "IgnoreDefense" => intval(0x20), //- Skill ignores target's defense (misc type always ignores)
+ "IgnoreFlee" => intval(0x40), //- Skill ignores target's flee (magic type always ignores)
+ "IgnoreDefCards" => intval(0x80) //- Skill ignores target's def cards
+ );
+ $nk = intval($nk,16);
+ $retval = "{\n";
+ foreach($bitmask as $key => $val) {
+ if($nk&$val) {
+ $retval .= "\t\t".$key.": true\n";
+ }
+ }
+ $retval .= "\t}";
+
+ return $retval;
+}
+
+function getnocast($opt, $id)
+{
+ $bitmask = array(
+ 'Default' => 0, //- everything affects the skill's cast time
+ 'IgnoreDex' => 1, //- skill's cast time is not affected by dex
+ 'IgnoreStatusEffect' => 2, //- skill's cast time is not affected by statuses (Suffragium, etc)
+ 'IgnoreItemBonus' => 4 //- skill's cast time is not affected by item bonuses (equip, cards)
+ );
+
+ if($opt > array_sum($bitmask) || $opt < 0)
+ print "\rWarning - a bitmask for CastNoDex entry for skill ID ".$id." is higher than total of masks or lower than 0.";
+
+ $retval = "{\n";
+ foreach($bitmask as $key => $val) {
+ if($opt&$val) {
+ $retval .= "\t\t".$key.": true\n";
+ }
+ }
+ $retval .= "\t}";
+
+ return $retval;
+}
+
+function getweapontypes($list, $id)
+{
+ $bitmask = array(
+ 0 => "NoWeapon",
+ 1 => "Daggers",
+ 2 => "1HSwords",
+ 3 => "2HSwords",
+ 4 => "1HSpears",
+ 5 => "2HSpears",
+ 6 => "1HAxes",
+ 7 => "2HAxes",
+ 8 => "Maces",
+ 9 => "2HMaces",
+ 10 => "Staves",
+ 11 => "Bows",
+ 12 => "Knuckles",
+ 13 => "Instruments",
+ 14 => "Whips",
+ 15 => "Books",
+ 16 => "Katars",
+ 17 => "Revolvers",
+ 18 => "Rifles",
+ 19 => "GatlingGuns",
+ 20 => "Shotguns",
+ 21 => "GrenadeLaunchers",
+ 22 => "FuumaShurikens",
+ 23 => "2HStaves",
+ 24 => "MaxSingleWeaponType",
+ 25 => "DWDaggers",
+ 26 => "DWSwords",
+ 27 => "DWAxes",
+ 28 => "DWDaggerSword",
+ 29 => "DWDaggerAxe",
+ 30 => "DWSwordAxe",
+ );
+ if(strpos($list, ':') == true) {
+ $type = explode(":", $list);
+ $wmask = 0;
+ for($i=0; $i<sizeof($type); $i++) {
+ $wmask |= 1<<$type[$i];
+ if($type[$i] > 30 || $type[$i] < 0)
+ print "\rWarning - Invalid weapon type ".$i." for skill ID ".$id."\n";
+ }
+ $retval = "{\n";
+ for($j=0; $j<sizeof($type); $j++) {
+ if($wmask&1<<$type[$j])
+ $retval .= "\t\t\t".$bitmask[$type[$j]].": true\n";
+ }
+ $retval .= "\t\t}";
+ } else {
+ $retval = "{\n";
+ $retval .= "\t\t\t".$bitmask[$list].": true\n";
+ $retval .= "\t\t}";
+ }
+
+ return $retval;
+}
+
+function getammotypes($list, $id) {
+ $bitmask = array(
+ 1 => "A_ARROW",
+ 2 => "A_DAGGER",
+ 3 => "A_BULLET",
+ 4 => "A_SHELL",
+ 5 => "A_GRENADE",
+ 6 => "A_SHURIKEN",
+ 7 => "A_KUNAI",
+ 8 => "A_CANNONBALL",
+ 9 => "A_THROWWEAPON"
+ );
+
+ if(strpos($list, ':') == true) {
+ $type = explode(":", $list);
+ $wmask = 0;
+ for($i=0; $i<sizeof($type); $i++) {
+ $wmask |= 1<<$type[$i];
+ if($type[$i] > 9 || $type[$i] < 1) {
+ print "\rWarning - Invalid weapon type ".$i." for skill ID ".$id."\n";
+ }
+ }
+ $retval = "{\n";
+ for($j=0; $j<sizeof($type); $j++) {
+ if($wmask&1<<$type[$j]) {
+ $retval .= "\t\t\t".$bitmask[$type[$j]].": true\n";
+ }
+ }
+ $retval .= "\t\t}";
+ } else {
+ $retval = "{\n";
+ $retval .= "\t\t\t".$bitmask[$list].": true\n";
+ $retval .= "\t\t}";
+ }
+
+ return $retval;
+}
+
+function getunitflag($flag, $id)
+{
+ $bitmask = array(
+ 'UF_DEFNOTENEMY' => intval(0x001), //0x001(UF_DEFNOTENEMY)If 'defunit_not_enemy' is set, the target is changed to 'friend'
+ 'UF_NOREITERATION' => intval(0x002), //0x002(UF_NOREITERATION)Spell cannot be stacked
+ 'UF_NOFOOTSET' => intval(0x004), //0x004(UF_NOFOOTSET)Spell cannot be cast near/on targets
+ 'UF_NOOVERLAP' => intval(0x008), //0x008(UF_NOOVERLAP)Spell effects do not overlap
+ 'UF_PATHCHECK' => intval(0x010), //0x010(UF_PATHCHECK)Only cells with a shootable path will be placed
+ 'UF_NOPC' => intval(0x020), //0x020(UF_NOPC)Spell cannot affect players.
+ 'UF_NOMOB' => intval(0x040), //0x040(UF_NOMOB)Spell cannot affect mobs.
+ 'UF_SKILL' => intval(0x080), //0x080(UF_SKILL)Spell CAN affect skills.
+ 'UF_DANCE' => intval(0x100), //0x100(UF_DANCE)Dance skill
+ 'UF_ENSEMBLE' => intval(0x200), //0x200(UF_ENSEMBLE)Ensemble skill
+ 'UF_SONG' => intval(0x400), //0x400(UF_SONG)Song skill
+ 'UF_DUALMODE' => intval(0x800), //0x800(UF_DUALMODE)Spell has effects both at an interval and when you step in/out
+ 'UF_RANGEDSINGLEUNIT' => intval(0x2000) //0x2000(UF_RANGEDSINGLEUNIT)Layout hack, use layout range propriety but only display center.
+ );
+
+ $count = 0;
+ if($flag <= 0) return 0;
+
+ $ret = "{\n";
+ foreach($bitmask as $key => $val) {
+ if($flag&$val) {
+ $ret .= "\t\t\t".$key.": true\n";
+ }
+ }
+
+ if($flag > array_sum($bitmask))
+ print "\rWarning - Invalid Unit Flag ".$flag." provided for skill Id ".$id."\n";
+
+ $ret .= "\t\t}";
+
+ return $ret;
+}
+
+function print_mem()
+{
+ return convert(memory_get_usage(true));
+}
+
+function convert($size)
+{
+ $unit=array('b','kb','mb','gb','tb','pb');
+ return @round($size/pow(1024,($i=floor(log($size,1024)))),2).' '.$unit[$i];
+}
+
+function gethelp()
+{
+ print "Usage: php skilldbconverter.php [option]\n";
+ print "Options:\n";
+ print "\t-re [--renewal] for renewal skill database conversion.\n";
+ print "\t-pre-re [--pre-renewal] for pre-renewal skill database conversion.\n";
+ print "\t-itid [--use-itemid] to use item IDs instead of constants.\n";
+ print "\t-dir [--directory] provide a custom directory.\n";
+ print "\t (Must include the correct -pre-re/-re option)\n";
+ print "\t-dbg [--with-debug] print debug information.\n";
+ print "\t-h [--help] to display this help text.\n\n";
+ print "----------------------- Additional Notes ----------------------\n";
+ print "Important!\n";
+ print "* Please be advised that either and only one of the arguments -re/-pre-re\n";
+ print " must be specified on execution.\n";
+ print "* When using the -dir option, -re/-pre-re options must be specified. \n";
+ print "* This tool isn't designed to convert renewal data to pre-renewal.\n";
+ print "* This tool should ideally be used from the 'tools/' folder, which can be found\n";
+ print " in the root of your Hercules installation. This tool will not delete any files\n";
+ print " from any of the directories that it reads from or prints to.\n\n";
+ print "* Prior to using this tool, please ensure at least 30MB of free RAM.\n";
+ print "----------------------- Usage Example -------------------------\n";
+ print "- Renewal Conversion: php skilldbconverter.php --renewal\n";
+ print "- Pre-renewal Conversion: php skilldbconverter.php --pre-renewal\n";
+ print "----------------------------------------------------------------\n";
+ exit;
+}
+
+function printcredits()
+{
+ print " _ _ _ \n";
+ print " | | | | | | \n";
+ print " | |_| | ___ _ __ ___ _ _| | ___ ___ \n";
+ print " | _ |/ _ \ '__/ __| | | | |/ _ \/ __|\n";
+ print " | | | | __/ | | (__| |_| | | __/\__ \ \n";
+ print " \_| |_/\___|_| \___|\__,_|_|\___||___/\n";
+ print "Hercules Skill Database TXT to Libconfig Converter by Smokexyz\n";
+ print "Copyright (C) 2016-2020 Hercules\n";
+ print "-----------------------------------------------\n\n";
+}
+
+function getcomments($re)
+{
+ return "//================= Hercules Database ==========================================
+//= _ _ _
+//= | | | | | |
+//= | |_| | ___ _ __ ___ _ _| | ___ ___
+//= | _ |/ _ \ '__/ __| | | | |/ _ \/ __|
+//= | | | | __/ | | (__| |_| | | __/\__ \
+//= \_| |_/\___|_| \___|\__,_|_|\___||___/
+//================= License ====================================================
+//= This file is part of Hercules.
+//= http://herc.ws - http://github.com/HerculesWS/Hercules
+//=
+//= Copyright (C) 2014-2020 Hercules Dev Team
+//=
+//= Hercules is free software: you can redistribute it and/or modify
+//= it under the terms of the GNU General Public License as published by
+//= the Free Software Foundation, either version 3 of the License, or
+//= (at your option) any later version.
+//=
+//= This program is distributed in the hope that it will be useful,
+//= but WITHOUT ANY WARRANTY; without even the implied warranty of
+//= MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+//= GNU General Public License for more details.
+//=
+//= You should have received a copy of the GNU General Public License
+//= along with this program. If not, see <http://www.gnu.org/licenses/>.
+//==============================================================================
+//= ".($re?"Renewal":"Pre-Renewal")." Skill Database [Hercules]
+//==============================================================================
+//= @Format Notes:
+//= - All string entries are case-sensitive and must be quoted.
+//= - All setting names are case-sensitive and must be keyed accurately.
+
+
+/******************************************************************************
+********************************* Entry structure *****************************
+*******************************************************************************
+{
+ // ------------------------------ Mandatory Fields ----------------------------
+ Id: ID (int) (Required)
+ Name: \"Skill Name\" (string) (Required)
+ MaxLevel: Skill Level (int) (Required)
+ // ------------------------------ Optional Fields -----------------------------
+ Description: \"Skill Description\" (string) (optional but recommended)
+ Range: Skill Range (int) (optional, defaults to 0) (can be grouped by Levels)
+ Note: Range < 5 is considered Melee range.
+ Hit: Hit Type (int) (optional, default \"BDT_NORMAL\")
+ Types - \"BDT_SKILL\", \"BDT_MULTIHIT\" or \"BDT_NORMAL\"
+ SkillType: { (bool, defaults to \"Passive\")
+ Passive: true/false (boolean, defaults to false)
+ Enemy: true/false (boolean, defaults to false)
+ Place: true/false (boolean, defaults to false)
+ Self: true/false (boolean, defaults to false)
+ Friend: true/false (boolean, defaults to false)
+ Trap: true/false (boolean, defaults to false)
+ }
+ SkillInfo: { (bool, defaults to \"None\")
+ Quest: true/false (boolean, defaults to false)
+ NPC: true/false (boolean, defaults to false)
+ Wedding: true/false (boolean, defaults to false)
+ Spirit: true/false (boolean, defaults to false)
+ Guild: true/false (boolean, defaults to false)
+ Song: true/false (boolean, defaults to false)
+ Ensemble: true/false (boolean, defaults to false)
+ Trap: true/false (boolean, defaults to false)
+ TargetSelf: true/false (boolean, defaults to false)
+ NoCastSelf: true/false (boolean, defaults to false)
+ PartyOnly: true/false (boolean, defaults to false)
+ GuildOnly: true/false (boolean, defaults to false)
+ NoEnemy: true/false (boolean, defaults to false)
+ IgnoreLandProtector: true/false (boolean, defaults to false)
+ Chorus: true/false (boolean, defaults to false)
+ FreeCastReduced: true/false (boolean, defaults to false)
+ Works like skill SA_FREECAST, allow move and attack with reduced speed.
+ FreeCastNormal: true/false (boolean, defaults to false)
+ Works like FreeCastReduced, but not reduce speed.
+ }
+ AttackType: \"Attack Type\" (string, defaults to \"None\")
+ Types: \"None\", \"Weapon\", \"Magic\" or \"Misc\"
+ Element: \"Element Type\" (string) (Optional field - Default \"Ele_Neutral\")
+ (can be grouped by Levels)
+ Types: \"Ele_Neutral\", \"Ele_Water\", \"Ele_Earth\", \"Ele_Fire\", \"Ele_Wind\"
+ \"Ele_Poison\", \"Ele_Holy\", \"Ele_Dark\", \"Ele_Ghost\", \"Ele_Undead\"
+ \"Ele_Weapon\" - Uses weapon's element.
+ \"Ele_Endowed\" - Uses Endowed element.
+ \"Ele_Random\" - Uses random element.
+ DamageType: { (bool, default to \"NoDamage\")
+ NoDamage: true/false No damage skill
+ SplashArea: true/false Has splash area (requires source modification)
+ SplitDamage: true/false Damage should be split among targets (requires 'SplashArea' in order to work)
+ IgnoreCards: true/false Skill ignores caster's % damage cards (misc type always ignores)
+ IgnoreElement: true/false Skill ignores elemental adjustments
+ IgnoreDefense: true/false Skill ignores target's defense (misc type always ignores)
+ IgnoreFlee: true/false Skill ignores target's flee (magic type always ignores)
+ IgnoreDefCards: true/false Skill ignores target's def cards
+ }
+ SplashRange: Damage Splash Area (int, defaults to 0) (can be grouped by Levels)
+ Note: -1 for screen-wide.
+ NumberOfHits: Number of Hits (int, defaults to 1) (can be grouped by Levels)
+ Note: when positive, damage is increased by hits,
+ negative values just show number of hits without
+ increasing total damage.
+ InterruptCast: Cast Interruption (bool, defaults to false)
+ CastDefRate: Cast Defense Reduction (int, defaults to 0)
+ SkillInstances: Skill instances (int, defaults to 0) (can be grouped by Levels)
+ Notes: max amount of skill instances to place on the ground when
+ player_land_skill_limit/monster_land_skill_limit is enabled. For skills
+ that attack using a path, this is the path length to be used.
+ KnockBackTiles: Knock-back by 'n' Tiles (int, defaults to 0) (can be grouped by Levels)
+ CastTime: Skill cast Time (in ms) (int, defaults to 0) (can be grouped by Levels)
+ AfterCastActDelay: Skill Delay (in ms) (int, defaults to 0) (can be grouped by Levels)
+ AfterCastWalkDelay: Walk Delay (in ms) (int, defaults to 0) (can be grouped by Levels)
+ SkillData1: Skill Data/Duration (in ms) (int, defaults to 0) (can be grouped by Levels)
+ SkillData2: Skill Data/Duration (in ms) (int, defaults to 0) (can be grouped by Levels)
+ CoolDown: Skill Cooldown (in ms) (int, defaults to 0) (can be grouped by Levels)
+ ".($re?
+ "FixedCastTime: Fixed Cast Time (in ms) (int, defaults to 0) (can be grouped by Levels)
+ Note: when 0, uses 20% of cast time and less than
+ 0 means no fixed cast time.":"")."
+ CastTimeOptions: {
+ IgnoreDex: true/false (boolean, defaults to false)
+ IgnoreStatusEffect: true/false (boolean, defaults to false)
+ IgnoreItemBonus: true/false (boolean, defaults to false)
+ Note: Delay setting 'IgnoreDex' only makes sense when
+ delay_dependon_dex is enabled.
+ }
+ SkillDelayOptions: {
+ IgnoreDex: true/false (boolean, defaults to false)
+ IgnoreStatusEffect: true/false (boolean, defaults to false)
+ IgnoreItemBonus: true/false (boolean, defaults to false)
+ Note: Delay setting 'IgnoreDex' only makes sense when
+ delay_dependon_dex is enabled.
+ }
+ Requirements: {
+ HPCost: HP Cost (int, defaults to 0) (can be grouped by Levels)
+ SPCost: SP Cost (int, defaults to 0) (can be grouped by Levels)
+ HPRateCost: HP % Cost (int, defaults to 0) (can be grouped by Levels)
+ Note: If positive, it is a percent of your current hp,
+ otherwise it is a percent of your max hp.
+ SPRateCost: SP % Cost (int, defaults to 0) (can be grouped by Levels)
+ Note: If positive, it is a percent of your current sp,
+ otherwise it is a percent of your max sp.
+ ZenyCost: Zeny Cost (int, defaults to 0) (can be grouped by Levels)
+ WeaponTypes: { (bool or string, defaults to \"All\")
+ NoWeapon: true/false (boolean, defaults to false)
+ Daggers: true/false (boolean, defaults to false)
+ 1HSwords: true/false (boolean, defaults to false)
+ 2HSwords: true/false (boolean, defaults to false)
+ 1HSpears: true/false (boolean, defaults to false)
+ 2HSpears: true/false (boolean, defaults to false)
+ 1HAxes: true/false (boolean, defaults to false)
+ 2HAxes: true/false (boolean, defaults to false)
+ Maces: true/false (boolean, defaults to false)
+ 2HMaces: true/false (boolean, defaults to false)
+ Staves: true/false (boolean, defaults to false)
+ Bows: true/false (boolean, defaults to false)
+ Knuckles: true/false (boolean, defaults to false)
+ Instruments: true/false (boolean, defaults to false)
+ Whips: true/false (boolean, defaults to false)
+ Books: true/false (boolean, defaults to false)
+ Katars: true/false (boolean, defaults to false)
+ Revolvers: true/false (boolean, defaults to false)
+ Rifles: true/false (boolean, defaults to false)
+ GatlingGuns: true/false (boolean, defaults to false)
+ Shotguns: true/false (boolean, defaults to false)
+ GrenadeLaunchers: true/false (boolean, defaults to false)
+ FuumaShurikens: true/false (boolean, defaults to false)
+ 2HStaves: true/false (boolean, defaults to false)
+ MaxSingleWeaponType: true/false (boolean, defaults to false)
+ DWDaggers: true/false (boolean, defaults to false)
+ DWSwords: true/false (boolean, defaults to false)
+ DWAxes: true/false (boolean, defaults to false)
+ DWDaggerSword: true/false (boolean, defaults to false)
+ DWDaggerAxe: true/false (boolean, defaults to false)
+ DWSwordAxe: true/false (boolean, defaults to false)
+ }
+ AmmoTypes: { (for all types use string \"All\")
+ A_ARROW: true/false (boolean, defaults to false)
+ A_DAGGER: true/false (boolean, defaults to false)
+ A_BULLET: true/false (boolean, defaults to false)
+ A_SHELL: true/false (boolean, defaults to false)
+ A_GRENADE: true/false (boolean, defaults to false)
+ A_SHURIKEN: true/false (boolean, defaults to false)
+ A_KUNAI: true/false (boolean, defaults to false)
+ A_CANNONBALL: true/false (boolean, defaults to false)
+ A_THROWWEAPON: true/false (boolean, defaults to false)
+ }
+ AmmoAmount: Ammunition Amount (int, defaults to 0) (can be grouped by Levels)
+ State: \"Required State\" (string, defaults to \"None\") (can be grouped by Levels)
+ Types : 'None' = Nothing special
+ 'Moveable' = Requires to be able to move
+ 'NotOverWeight' = Requires to be less than 50% weight
+ 'InWater' = Requires to be standing on a water cell
+ 'Cart' = Requires a Pushcart
+ 'Riding' = Requires to ride either a peco or a dragon
+ 'Falcon' = Requires a Falcon
+ 'Sight' = Requires Sight skill activated
+ 'Hiding' = Requires Hiding skill activated
+ 'Cloaking' = Requires Cloaking skill activated
+ 'ExplosionSpirits' = Requires Fury skill activated
+ 'CartBoost' = Requires a Pushcart and Cart Boost skill activated
+ 'Shield' = Requires a 0,shield equipped
+ 'Warg' = Requires a Warg
+ 'Dragon' = Requires to ride a Dragon
+ 'RidingWarg' = Requires to ride a Warg
+ 'Mado' = Requires to have an active mado
+ 'PoisonWeapon' = Requires to be under Poisoning Weapon.
+ 'RollingCutter' = Requires at least one Rotation Counter from Rolling Cutter.
+ 'ElementalSpirit' = Requires to have an Elemental Spirit summoned.
+ 'MH_Fighting' = Requires Eleanor fighthing mode
+ 'MH_Grappling' = Requires Eleanor grappling mode
+ 'Peco' = Requires riding a peco
+ SpiritSphereCost: Spirit Sphere Cost (int, defaults to 0) (can be grouped by Levels)
+ Items: {
+ ItemID or Aegis_Name : Amount (int, defaults to 0) (can be grouped by Levels)
+ Item example: \"ID717\" or \"Blue_Gemstone\".
+ Notes: Items with amount 0 will not be consumed.
+ Amount can also be grouped by levels.
+ }
+ }
+ Unit: {
+ Id: [ UnitID, UnitID2 ] (int, defaults to 0) (can be grouped by Levels)
+ Layout: Unit Layout (int, defaults to 0) (can be grouped by Levels)
+ Range: Unit Range (int, defaults to 0) (can be grouped by Levels)
+ Interval: Unit Interval (int, defaults to 0) (can be grouped by Levels)
+ Target: \"Unit Target\" (string, defaults to \"None\")
+ Types:
+ All - affects everyone
+ NotEnemy - affects anyone who isn't an enemy
+ Friend - affects party, guildmates and neutral players
+ Party - affects party only
+ Guild - affects guild only
+ Ally - affects party and guildmates only
+ Sameguild - affects guild but not allies
+ Enemy - affects enemies only
+ None - affects nobody
+ Flag: {
+ UF_DEFNOTENEMY: true/false (boolean, defaults to false)
+ UF_NOREITERATION: true/false (boolean, defaults to false)
+ UF_NOFOOTSET: true/false (boolean, defaults to false)
+ UF_NOOVERLAP: true/false (boolean, defaults to false)
+ UF_PATHCHECK: true/false (boolean, defaults to false)
+ UF_NOPC: true/false (boolean, defaults to false)
+ UF_NOMOB: true/false (boolean, defaults to false)
+ UF_SKILL: true/false (boolean, defaults to false)
+ UF_DANCE: true/false (boolean, defaults to false)
+ UF_ENSEMBLE: true/false (boolean, defaults to false)
+ UF_SONG: true/false (boolean, defaults to false)
+ UF_DUALMODE: true/false (boolean, defaults to false)
+ UF_RANGEDSINGLEUNI: true/false (boolean, defaults to false)
+ }
+ }
+}
+* This file has been generated by Smokexyz's skilldbconverter.php tool.
+* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */\n\n";
+}
diff --git a/tools/stackdump b/tools/stackdump
index 25b1fa46a..47cb172ed 100755
--- a/tools/stackdump
+++ b/tools/stackdump
@@ -1,4 +1,4 @@
-#!/bin/bash
+#!/usr/bin/env bash
case "$1" in
map|char|login)
diff --git a/tools/utils/__init__.py b/tools/utils/__init__.py
new file mode 100644
index 000000000..e69de29bb
--- /dev/null
+++ b/tools/utils/__init__.py
diff --git a/tools/utils/common.py b/tools/utils/common.py
new file mode 100644
index 000000000..b4dae0c8c
--- /dev/null
+++ b/tools/utils/common.py
@@ -0,0 +1,68 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+#
+# This file is part of Hercules.
+# http://herc.ws - http://github.com/HerculesWS/Hercules
+#
+# Copyright (C) 2018-2020 Hercules Dev Team
+# Copyright (C) 2018 Asheraf
+#
+# Hercules is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import io
+import sys
+if sys.version_info >= (3, 0):
+ from utils import libconf as libconf
+else:
+ import libconf as libconf
+import os.path
+
+def LoadDBConsts(DBname, mode, serverpath):
+ filenames = [serverpath + 'db/{}/{}.conf'.format(mode, DBname)]
+
+ if os.path.isfile(serverpath + 'db/{}2.conf'.format(DBname)):
+ filenames.append(serverpath + 'db/{}2.conf'.format(DBname))
+
+ consts = dict()
+ for filename in filenames:
+ with io.open(filename) as f:
+ config = libconf.load(f)
+ db = config[DBname]
+ if DBname == 'item_db':
+ for i, v in enumerate(db):
+ consts[db[i].Id] = db[i].AegisName
+ elif DBname == 'mob_db':
+ for i, v in enumerate(db):
+ consts[db[i].Id] = db[i].SpriteName
+ elif DBname == 'skill_db':
+ for i, v in enumerate(db):
+ consts[db[i].Id] = db[i].Name
+ else:
+ print('LoadDBConsts: invalid database name {}'.format(DBname))
+ exit(1)
+ return consts
+
+def LoadDB(DBname, mode, serverpath):
+ filenames = [serverpath + 'db/{}/{}.conf'.format(mode, DBname)]
+
+ if os.path.isfile(serverpath + 'db/{}2.conf'.format(DBname)):
+ filenames.append(serverpath + 'db/{}2.conf'.format(DBname))
+
+ for filename in filenames:
+ with io.open(filename) as f:
+ config = libconf.load(f)
+ db = config[DBname]
+ return db
+ print('LoadDB: invalid database name {}'.format(DBname))
+ exit(1)
diff --git a/tools/utils/libconf.py b/tools/utils/libconf.py
new file mode 100644
index 000000000..3858b93b5
--- /dev/null
+++ b/tools/utils/libconf.py
@@ -0,0 +1,700 @@
+#!/usr/bin/python
+# -*- coding: utf8 -*-
+#
+# Copyright (C) 2018-2020 Hercules Dev Team
+#
+# This library is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+# This file originally licensed under the MIT License
+#
+# Copyright (c) 2016 Christian Aichinger <Greek0@gmx.net>
+# https://github.com/Grk0/python-libconf
+#
+# Permission is hereby granted, free of charge, to any person obtaining a copy of
+# this software and associated documentation files (the "Software"), to deal in
+# the Software without restriction, including without limitation the rights to
+# use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+# of the Software, and to permit persons to whom the Software is furnished to do
+# so, subject to the following conditions:
+#
+# The above copyright notice and this permission notice shall be included in all
+# copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+# IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+# FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+# AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+# LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+from __future__ import absolute_import, division, print_function
+
+import sys
+import os
+import codecs
+import collections
+import io
+import re
+
+# Define an isstr() and isint() that work on both Python2 and Python3.
+# See http://stackoverflow.com/questions/11301138
+try:
+ basestring # attempt to evaluate basestring
+
+ def isstr(s):
+ return isinstance(s, basestring)
+
+ def isint(i):
+ return isinstance(i, (int, long))
+except NameError:
+
+ def isstr(s):
+ return isinstance(s, str)
+
+ def isint(i):
+ return isinstance(i, int)
+
+# Bounds to determine when an "L" suffix should be used during dump().
+SMALL_INT_MIN = -2**31
+SMALL_INT_MAX = 2**31 - 1
+
+ESCAPE_SEQUENCE_RE = re.compile(r'''
+ ( \\x.. # 2-digit hex escapes
+ | \\[\\'"abfnrtv] # Single-character escapes
+ )''', re.UNICODE | re.VERBOSE)
+
+SKIP_RE = re.compile(r'\s+|#.*$|//.*$|/\*(.|\n)*?\*/', re.MULTILINE)
+UNPRINTABLE_CHARACTER_RE = re.compile(r'[\x00-\x1F\x7F]')
+
+
+# load() logic
+##############
+
+def decode_escapes(s):
+ '''Unescape libconfig string literals'''
+ def decode_match(match):
+ return codecs.decode(match.group(0), 'unicode-escape')
+
+ return ESCAPE_SEQUENCE_RE.sub(decode_match, s)
+
+
+class AttrDict(collections.OrderedDict):
+ '''OrderedDict subclass giving access to string keys via attribute access
+
+ This class derives from collections.OrderedDict. Thus, the original
+ order of the config entries in the input stream is maintained.
+ '''
+
+ def __getattr__(self, attr):
+ if attr == '_OrderedDict__root':
+ # Work around Python2's OrderedDict weirdness.
+ raise AttributeError("AttrDict has no attribute %r" % attr)
+ return self.__getitem__(attr)
+
+
+class ConfigParseError(RuntimeError):
+ '''Exception class raised on errors reading the libconfig input'''
+ pass
+
+
+class ConfigSerializeError(TypeError):
+ '''Exception class raised on errors serializing a config object'''
+ pass
+
+
+class Token(object):
+ '''Base class for all tokens produced by the libconf tokenizer'''
+ def __init__(self, type, text, filename, row, column):
+ self.type = type
+ self.text = text
+ self.filename = filename
+ self.row = row
+ self.column = column
+
+ def __str__(self):
+ return "%r in %r, row %d, column %d" % (
+ self.text, self.filename, self.row, self.column)
+
+
+class FltToken(Token):
+ '''Token subclass for floating point values'''
+ def __init__(self, *args, **kwargs):
+ super(FltToken, self).__init__(*args, **kwargs)
+ self.value = float(self.text)
+
+
+class IntToken(Token):
+ '''Token subclass for integral values'''
+ def __init__(self, *args, **kwargs):
+ super(IntToken, self).__init__(*args, **kwargs)
+ self.is_long = self.text.endswith('L')
+ self.is_hex = (self.text[1:2].lower() == 'x')
+ self.value = int(self.text.rstrip('L'), 0)
+
+
+class BoolToken(Token):
+ '''Token subclass for booleans'''
+ def __init__(self, *args, **kwargs):
+ super(BoolToken, self).__init__(*args, **kwargs)
+ self.value = (self.text[0].lower() == 't')
+
+
+class StrToken(Token):
+ '''Token subclass for strings'''
+ def __init__(self, *args, **kwargs):
+ super(StrToken, self).__init__(*args, **kwargs)
+ self.value = decode_escapes(self.text[1:-1])
+
+
+def compile_regexes(token_map):
+ return [(cls, type, re.compile(regex))
+ for cls, type, regex in token_map]
+
+
+class Tokenizer:
+ '''Tokenize an input string
+
+ Typical usage:
+
+ tokens = list(Tokenizer("<memory>").tokenize("""a = 7; b = ();"""))
+
+ The filename argument to the constructor is used only in error messages, no
+ data is loaded from the file. The input data is received as argument to the
+ tokenize function, which yields tokens or throws a ConfigParseError on
+ invalid input.
+
+ Include directives are not supported, they must be handled at a higher
+ level (cf. the TokenStream class).
+ '''
+
+ token_map = compile_regexes([
+ (FltToken, 'float', r'([-+]?(\d+)?\.\d*([eE][-+]?\d+)?)|'
+ r'([-+]?(\d+)(\.\d*)?[eE][-+]?\d+)'),
+ (IntToken, 'hex64', r'0[Xx][0-9A-Fa-f]+(L(L)?)'),
+ (IntToken, 'hex', r'0[Xx][0-9A-Fa-f]+'),
+ (BoolToken, 'boolean', r'(?i)(true|false)\b'),
+ (StrToken, 'string', r'"([^"\\]|\\.)*"'),
+ (StrToken, 'string', r'<"(?<=<")([\S\s]*?)(?=">)">'),
+ (Token, 'name', r'[0-9]*[A-Za-z\*][-A-Za-z0-9_\*]*'),
+ (IntToken, 'integer64', r'[-+]?[0-9]+L(L)?'),
+ (IntToken, 'integer', r'[-+]?[0-9]+'),
+ (Token, '}', r'\}'),
+ (Token, '{', r'\{'),
+ (Token, ')', r'\)'),
+ (Token, '(', r'\('),
+ (Token, ']', r'\]'),
+ (Token, '[', r'\['),
+ (Token, ',', r','),
+ (Token, ';', r';'),
+ (Token, '=', r'='),
+ (Token, ':', r':'),
+ ])
+
+ def __init__(self, filename):
+ self.filename = filename
+ self.row = 1
+ self.column = 1
+
+ def tokenize(self, string):
+ '''Yield tokens from the input string or throw ConfigParseError'''
+ pos = 0
+ while pos < len(string):
+ m = SKIP_RE.match(string, pos=pos)
+ if m:
+ skip_lines = m.group(0).split('\n')
+ if len(skip_lines) > 1:
+ self.row += len(skip_lines) - 1
+ self.column = 1 + len(skip_lines[-1])
+ else:
+ self.column += len(skip_lines[0])
+
+ pos = m.end()
+ continue
+
+ for cls, type, regex in self.token_map:
+ m = regex.match(string, pos=pos)
+ if m:
+ try:
+ yield cls(type, m.group(0),
+ self.filename, self.row, self.column)
+ except ValueError as e:
+ print("Error parsing file "
+ "{0}, in line:\n{1}\n{2}".format(self.filename,
+ m.group(0),
+ self.row))
+ raise
+ self.column += len(m.group(0))
+ pos = m.end()
+ break
+ else:
+ raise ConfigParseError(
+ "Couldn't load config in %r row %d, column %d: %r" %
+ (self.filename, self.row, self.column,
+ string[pos:pos+20]))
+
+
+class TokenStream:
+ '''Offer a parsing-oriented view on tokens
+
+ Provide several methods that are useful to parsers, like ``accept()``,
+ ``expect()``, ...
+
+ The ``from_file()`` method is the preferred way to read input files, as
+ it handles include directives, which the ``Tokenizer`` class does not do.
+ '''
+
+ def __init__(self, tokens):
+ self.position = 0
+ self.tokens = list(tokens)
+
+ @classmethod
+ def from_file(cls, f, filename=None, includedir='', seenfiles=None):
+ '''Create a token stream by reading an input file
+
+ Read tokens from `f`. If an include directive ('@include "file.cfg"')
+ is found, read its contents as well.
+
+ The `filename` argument is used for error messages and to detect
+ circular imports. ``includedir`` sets the lookup directory for included
+ files. ``seenfiles`` is used internally to detect circular includes,
+ and should normally not be supplied by users of is function.
+ '''
+
+ if filename is None:
+ filename = getattr(f, 'name', '<unknown>')
+ if seenfiles is None:
+ seenfiles = set()
+
+ if filename in seenfiles:
+ raise ConfigParseError("Circular include: %r" % (filename,))
+ seenfiles = seenfiles | {filename} # Copy seenfiles, don't alter it.
+
+ tokenizer = Tokenizer(filename=filename)
+ lines = []
+ tokens = []
+ for line in f:
+ m = re.match(r'@include "(.*)"$', line.strip())
+ if m:
+ tokens.extend(tokenizer.tokenize(''.join(lines)))
+ lines = [re.sub(r'\S', ' ', line)]
+
+ includefilename = decode_escapes(m.group(1))
+ includefilename = os.path.join(includedir, includefilename)
+ try:
+ includefile = open(includefilename, "r")
+ except IOError:
+ raise ConfigParseError("Could not open include file %r" %
+ (includefilename,))
+
+ with includefile:
+ includestream = cls.from_file(includefile,
+ filename=includefilename,
+ includedir=includedir,
+ seenfiles=seenfiles)
+ tokens.extend(includestream.tokens)
+
+ else:
+ lines.append(line)
+
+ tokens.extend(tokenizer.tokenize(''.join(lines)))
+ return cls(tokens)
+
+ def peek(self):
+ '''Return (but do not consume) the next token
+
+ At the end of input, ``None`` is returned.
+ '''
+
+ if self.position >= len(self.tokens):
+ return None
+
+ return self.tokens[self.position]
+
+ def accept(self, *args):
+ '''Consume and return the next token if it has the correct type
+
+ Multiple token types (as strings, e.g. 'integer64') can be given
+ as arguments. If the next token is one of them, consume and return it.
+
+ If the token type doesn't match, return None.
+ '''
+
+ token = self.peek()
+ if token is None:
+ return None
+
+ for arg in args:
+ if token.type == arg:
+ self.position += 1
+ return token
+
+ return None
+
+ def expect(self, *args):
+ '''Consume and return the next token if it has the correct type
+
+ Multiple token types (as strings, e.g. 'integer64') can be given
+ as arguments. If the next token is one of them, consume and return it.
+
+ If the token type doesn't match, raise a ConfigParseError.
+ '''
+
+ t = self.accept(*args)
+ if t is not None:
+ return t
+
+ self.error("expected: %r" % (args,))
+
+ def error(self, msg):
+ '''Raise a ConfigParseError at the current input position'''
+ if self.finished():
+ raise ConfigParseError("Unexpected end of input; %s" % (msg,))
+ else:
+ t = self.peek()
+ raise ConfigParseError("Unexpected token %s; %s" % (t, msg))
+
+ def finished(self):
+ '''Return ``True`` if the end of the token stream is reached.'''
+ return self.position >= len(self.tokens)
+
+
+class Parser:
+ '''Recursive descent parser for libconfig files
+
+ Takes a ``TokenStream`` as input, the ``parse()`` method then returns
+ the config file data in a ``json``-module-style format.
+ '''
+
+ def __init__(self, tokenstream):
+ self.tokens = tokenstream
+
+ def parse(self):
+ return self.configuration()
+
+ def configuration(self):
+ result = self.setting_list_or_empty()
+ if not self.tokens.finished():
+ raise ConfigParseError("Expected end of input but found %s" %
+ (self.tokens.peek(),))
+
+ return result
+
+ def setting_list_or_empty(self):
+ result = AttrDict()
+ while True:
+ s = self.setting()
+ if s is None:
+ return result
+
+ result[s[0]] = s[1]
+
+ def setting(self):
+ name = self.tokens.accept('name')
+ if name is None:
+ return None
+
+ self.tokens.expect(':', '=')
+
+ value = self.value()
+ if value is None:
+ self.tokens.error("expected a value")
+
+ self.tokens.accept(';', ',')
+
+ return (name.text, value)
+
+ def value(self):
+ acceptable = [self.scalar_value, self.array, self.list, self.group]
+ return self._parse_any_of(acceptable)
+
+ def scalar_value(self):
+ # This list is ordered so that more common tokens are checked first.
+ acceptable = [self.string, self.boolean, self.integer, self.float,
+ self.hex, self.integer64, self.hex64]
+ return self._parse_any_of(acceptable)
+
+ def value_list_or_empty(self):
+ return tuple(self._comma_separated_list_or_empty(self.value))
+
+ def scalar_value_list_or_empty(self):
+ return self._comma_separated_list_or_empty(self.scalar_value)
+
+ def array(self):
+ return self._enclosed_block('[', self.scalar_value_list_or_empty, ']')
+
+ def list(self):
+ return self._enclosed_block('(', self.value_list_or_empty, ')')
+
+ def group(self):
+ return self._enclosed_block('{', self.setting_list_or_empty, '}')
+
+ def boolean(self):
+ return self._create_value_node('boolean')
+
+ def integer(self):
+ return self._create_value_node('integer')
+
+ def integer64(self):
+ return self._create_value_node('integer64')
+
+ def hex(self):
+ return self._create_value_node('hex')
+
+ def hex64(self):
+ return self._create_value_node('hex64')
+
+ def float(self):
+ return self._create_value_node('float')
+
+ def string(self):
+ t_first = self.tokens.accept('string')
+ if t_first is None:
+ return None
+
+ values = [t_first.value]
+ while True:
+ t = self.tokens.accept('string')
+ if t is None:
+ break
+ values.append(t.value)
+
+ return ''.join(values)
+
+ def _create_value_node(self, tokentype):
+ t = self.tokens.accept(tokentype)
+ if t is None:
+ return None
+
+ return t.value
+
+ def _parse_any_of(self, nonterminals):
+ for fun in nonterminals:
+ result = fun()
+ if result is not None:
+ return result
+
+ return None
+
+ def _comma_separated_list_or_empty(self, nonterminal):
+ values = []
+ first = True
+ while True:
+ v = nonterminal()
+ if v is None:
+ if first:
+ return []
+ else:
+ # This is disabled to enable the last member in a list to have a comma at the end
+ # self.tokens.error("expected value after ','")
+ return values
+
+ values.append(v)
+ if not self.tokens.accept(','):
+ return values
+
+ first = False
+
+ def _enclosed_block(self, start, nonterminal, end):
+ if not self.tokens.accept(start):
+ return None
+ result = nonterminal()
+ self.tokens.expect(end)
+ return result
+
+
+def load(f, filename=None, includedir=''):
+ '''Load the contents of ``f`` (a file-like object) to a Python object
+
+ The returned object is a subclass of ``dict`` that exposes string keys as
+ attributes as well.
+
+ Example:
+
+ >>> with open('test/example.cfg') as f:
+ ... config = libconf.load(f)
+ >>> config['window']['title']
+ 'libconfig example'
+ >>> config.window.title
+ 'libconfig example'
+ '''
+
+ if isinstance(f.read(0), bytes):
+ raise TypeError("libconf.load() input file must by unicode")
+
+ tokenstream = TokenStream.from_file(f,
+ filename=filename,
+ includedir=includedir)
+ return Parser(tokenstream).parse()
+
+
+def loads(string, filename=None, includedir=''):
+ '''Load the contents of ``string`` to a Python object
+
+ The returned object is a subclass of ``dict`` that exposes string keys as
+ attributes as well.
+
+ Example:
+
+ >>> config = libconf.loads('window: { title: "libconfig example"; };')
+ >>> config['window']['title']
+ 'libconfig example'
+ >>> config.window.title
+ 'libconfig example'
+ '''
+
+ try:
+ f = io.StringIO(string)
+ except TypeError:
+ raise TypeError("libconf.loads() input string must by unicode")
+
+ return load(f, filename=filename, includedir=includedir)
+
+
+# dump() logic
+##############
+
+def dump_int(i):
+ '''Stringize ``i``, append 'L' if ``i`` is exceeds the 32-bit int range'''
+ return str(i) + ('' if SMALL_INT_MIN <= i <= SMALL_INT_MAX else 'L')
+
+
+def dump_string(s):
+ '''Stringize ``s``, adding double quotes and escaping as necessary
+
+ Backslash escape backslashes, double quotes, ``\f``, ``\n``, ``\r``, and
+ ``\t``. Escape all remaining unprintable characters in ``\xFF``-style.
+ The returned string will be surrounded by double quotes.
+ '''
+
+ s = (s.replace('\\', '\\\\')
+ .replace('"', '\\"')
+ .replace('\f', r'\f')
+ .replace('\n', r'\n')
+ .replace('\r', r'\r')
+ .replace('\t', r'\t'))
+ s = UNPRINTABLE_CHARACTER_RE.sub(
+ lambda m: r'\x{:02x}'.format(ord(m.group(0))),
+ s)
+ return '"' + s + '"'
+
+
+def dump_value(key, value, f, indent=0):
+ '''Save a value of any libconfig type
+
+ This function serializes takes ``key`` and ``value`` and serializes them
+ into ``f``. If ``key`` is ``None``, a list-style output is produced.
+ Otherwise, output has ``key = value`` format.
+ '''
+
+ spaces = ' ' * indent
+
+ if key is None:
+ key_prefix = ''
+ key_prefix_nl = ''
+ else:
+ key_prefix = key + ' = '
+ key_prefix_nl = key + ' =\n' + spaces
+
+ if isinstance(value, dict):
+ f.write(u'{}{}{{\n'.format(spaces, key_prefix_nl))
+ dump_dict(value, f, indent + 4)
+ f.write(u'{}}}'.format(spaces))
+ elif isinstance(value, tuple):
+ f.write(u'{}{}(\n'.format(spaces, key_prefix_nl))
+ dump_collection(value, f, indent + 4)
+ f.write(u'\n{})'.format(spaces))
+ elif isinstance(value, list):
+ f.write(u'{}{}[\n'.format(spaces, key_prefix_nl))
+ dump_collection(value, f, indent + 4)
+ f.write(u'\n{}]'.format(spaces))
+ elif isstr(value):
+ f.write(u'{}{}{}'.format(spaces, key_prefix, dump_string(value)))
+ elif isint(value):
+ f.write(u'{}{}{}'.format(spaces, key_prefix, dump_int(value)))
+ elif isinstance(value, float):
+ f.write(u'{}{}{}'.format(spaces, key_prefix, value))
+ else:
+ raise ConfigSerializeError("Can not serialize object %r of type %s" %
+ (value, type(value)))
+
+
+def dump_collection(cfg, f, indent=0):
+ '''Save a collection of attributes'''
+
+ for i, value in enumerate(cfg):
+ dump_value(None, value, f, indent)
+ if i < len(cfg) - 1:
+ f.write(u',\n')
+
+
+def dump_dict(cfg, f, indent=0):
+ '''Save a dictionary of attributes'''
+
+ for key in cfg:
+ if not isstr(key):
+ raise ConfigSerializeError("Dict keys must be strings: %r" %
+ (key,))
+ dump_value(key, cfg[key], f, indent)
+ f.write(u';\n')
+
+
+def dumps(cfg):
+ '''Serialize ``cfg`` into a libconfig-formatted ``str``
+
+ ``cfg`` must be a ``dict`` with ``str`` keys and libconf-supported values
+ (numbers, strings, booleans, possibly nested dicts, lists, and tuples).
+
+ Returns the formatted string.
+ '''
+
+ str_file = io.StringIO()
+ dump(cfg, str_file)
+ return str_file.getvalue()
+
+
+def dump(cfg, f):
+ '''Serialize ``cfg`` as a libconfig-formatted stream into ``f``
+
+ ``cfg`` must be a ``dict`` with ``str`` keys and libconf-supported values
+ (numbers, strings, booleans, possibly nested dicts, lists, and tuples).
+
+ ``f`` must be a ``file``-like object with a ``write()`` method.
+ '''
+
+ if not isinstance(cfg, dict):
+ raise ConfigSerializeError(
+ 'dump() requires a dict as input, not %r of type %r' %
+ (cfg, type(cfg)))
+
+ dump_dict(cfg, f, 0)
+
+
+# main(): small example of how to use libconf
+#############################################
+
+def main():
+ '''Open the libconfig file specified by sys.argv[1] and pretty-print it'''
+ global output
+ if len(sys.argv[1:]) == 1:
+ with io.open(sys.argv[1], 'r', encoding='utf-8') as f:
+ output = load(f)
+ else:
+ output = load(sys.stdin)
+
+ dump(output, sys.stdout)
+
+
+if __name__ == '__main__':
+ main()
diff --git a/tools/validateinterfaces.py b/tools/validateinterfaces.py
index 924ea903f..e031c34ab 100755
--- a/tools/validateinterfaces.py
+++ b/tools/validateinterfaces.py
@@ -4,8 +4,8 @@
# This file is part of Hercules.
# http://herc.ws - http://github.com/HerculesWS/Hercules
#
-# Copyright (C) 2014-2015 Hercules Dev Team
-# Copyright (C) 2014 Andrei Karas (4144)
+# Copyright (C) 2014-2020 Hercules Dev Team
+# Copyright (C) 2014 Andrei Karas (4144)
#
# Hercules is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by