<?php
/* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
*        _   _                     _
*       | | | |                   | |
*       | |_| | ___ _ __ ___ _   _| | ___  ___
*       |  _  |/ _ \ '__/ __| | | | |/ _ \/ __|
*       | | | |  __/ | | (__| |_| | |  __/\__ \
*       \_| |_/\___|_|  \___|\__,_|_|\___||___/
*
* * * * * * * * * * * * * * License * * * * * * * * * * * * * * * * * * * * * *
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
* Copyright (C) 2016-  Smokexyz/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/>.
* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
* 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  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-2018  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";
}
