<?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-2016 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"; }