/**
* This file is part of Hercules.
* http://herc.ws - http://github.com/HerculesWS/Hercules
*
* Copyright (C) 2013-2020 Hercules Dev Team
*
* Hercules is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* 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 .
*/
#include "config/core.h"
#include "common/hercules.h"
#include "common/cbasetypes.h"
#include "common/conf.h"
#include "common/memmgr.h"
#include "common/mmo.h"
#include "common/nullpo.h"
#include "common/sql.h"
#include "common/strlib.h"
#include "map/battle.h"
#include "map/itemdb.h"
#include "map/mob.h"
#include "map/map.h"
#include "map/pc.h"
#include "common/HPMDataCheck.h"
#include
#include
HPExport struct hplugin_info pinfo = {
"DB2SQL", // Plugin name
SERVER_TYPE_MAP, // Which server types this plugin works with?
"0.5", // Plugin version
HPM_VERSION, // HPM Version (don't change, macro is automatically updated)
};
#ifdef RENEWAL
#define DBSUFFIX "_re"
#else // not RENEWAL
#define DBSUFFIX ""
#endif
/// Conversion state tracking.
struct {
FILE *fp; ///< Currently open file pointer
struct {
char *p; ///< Buffer pointer
size_t len; ///< Buffer length
} buf[4]; ///< Output buffer
const char *db_name; ///< Database table name
} tosql;
/// Whether the item_db converter will automatically run.
bool itemdb2sql_torun = false;
/// Whether the mob_db converter will automatically run.
bool mobdb2sql_torun = false;
/// Backup of the original item_db parser function pointer.
int (*itemdb_readdb_libconfig_sub) (struct config_setting_t *it, int n, const char *source);
/// Backup of the original mob_db parser function pointer.
int (*mob_read_db_sub) (struct config_setting_t *it, int n, const char *source);
bool (*mob_skill_db_libconfig_sub_skill) (struct config_setting_t *it, int n, int mob_id);
//
void do_mobskilldb2sql(void);
/**
* Normalizes and appends a string to the output buffer.
*
* @param str The string to append.
*/
void hstr(const char *str)
{
nullpo_retv(str);
if (strlen(str) > tosql.buf[3].len) {
tosql.buf[3].len = tosql.buf[3].len + strlen(str) + 1000;
RECREATE(tosql.buf[3].p,char,tosql.buf[3].len);
}
safestrncpy(tosql.buf[3].p,str,strlen(str));
normalize_name(tosql.buf[3].p,"\t\n ");
}
/**
* Prints a SQL file header for the current item_db file.
*/
void db2sql_fileheader(void)
{
time_t t = time(NULL);
struct tm *lt = localtime(&t);
int year = lt->tm_year+1900;
fprintf(tosql.fp,
"-- This file is part of Hercules.\n"
"-- http://herc.ws - http://github.com/HerculesWS/Hercules\n"
"--\n"
"-- Copyright (C) 2013-%d Hercules Dev Team\n"
"--\n"
"-- Hercules is free software: you can redistribute it and/or modify\n"
"-- it under the terms of the GNU General Public License as published by\n"
"-- the Free Software Foundation, either version 3 of the License, or\n"
"-- (at your option) any later version.\n"
"--\n"
"-- This program is distributed in the hope that it will be useful,\n"
"-- but WITHOUT ANY WARRANTY; without even the implied warranty of\n"
"-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the\n"
"-- GNU General Public License for more details.\n"
"--\n"
"-- You should have received a copy of the GNU General Public License\n"
"-- along with this program. If not, see .\n\n"
"-- NOTE: This file was auto-generated and should never be manually edited,\n"
"-- as it will get overwritten. If you need to modify this file,\n"
"-- please consider modifying the corresponding .conf file inside\n"
"-- the db folder, and then re-run the db2sql plugin.\n\n"
"-- GENERATED FILE DO NOT EDIT --\n"
"\n", year);
}
/**
* Converts the Job field of an Item DB entry to the numeric format used in the SQL table.
*/
uint64 itemdb2sql_readdb_job_sub(struct config_setting_t *t)
{
uint64 jobmask = 0;
int idx = 0;
struct config_setting_t *it = NULL;
bool enable_all = false;
if (libconfig->setting_lookup_bool_real(t, "All", &enable_all) && enable_all) {
jobmask |= UINT64_MAX;
}
while ((it = libconfig->setting_get_elem(t, idx++)) != NULL) {
const char *job_name = config_setting_name(it);
int job_id;
if (strcmp(job_name, "All") == 0)
continue;
if ((job_id = pc->check_job_name(job_name)) != -1) {
uint64 newmask = 0;
switch (job_id) {
// Base Classes
case JOB_NOVICE:
case JOB_SUPER_NOVICE:
newmask = 1ULL << JOB_NOVICE;
break;
case JOB_SWORDMAN:
case JOB_MAGE:
case JOB_ARCHER:
case JOB_ACOLYTE:
case JOB_MERCHANT:
case JOB_THIEF:
// 2-1 Classes
case JOB_KNIGHT:
case JOB_PRIEST:
case JOB_WIZARD:
case JOB_BLACKSMITH:
case JOB_HUNTER:
case JOB_ASSASSIN:
// 2-2 Classes
case JOB_CRUSADER:
case JOB_MONK:
case JOB_SAGE:
case JOB_ALCHEMIST:
case JOB_BARD:
case JOB_DANCER:
case JOB_ROGUE:
// Extended Classes
case JOB_GUNSLINGER:
case JOB_NINJA:
newmask = 1ULL << job_id;
break;
// Extended Classes (special handling)
case JOB_TAEKWON:
newmask = 1ULL << 21;
break;
case JOB_STAR_GLADIATOR:
newmask = 1ULL << 22;
break;
case JOB_SOUL_LINKER:
newmask = 1ULL << 23;
break;
// Other Classes
case JOB_GANGSI: //Bongun/Munak
newmask = 1ULL << 26;
break;
case JOB_DEATH_KNIGHT:
newmask = 1ULL << 27;
break;
case JOB_DARK_COLLECTOR:
newmask = 1ULL << 28;
break;
case JOB_KAGEROU:
case JOB_OBORO:
newmask = 1ULL << 29;
break;
case JOB_REBELLION:
newmask = 1ULL << 30;
break;
}
if (libconfig->setting_get_bool(it)) {
jobmask |= newmask;
} else {
jobmask &= ~newmask;
}
}
}
return jobmask;
}
/**
* Converts an Item DB entry to SQL.
*
* @see itemdb_readdb_libconfig_sub.
*/
int itemdb2sql_sub(struct config_setting_t *entry, int n, const char *source)
{
struct item_data *it = NULL;
if ((it = itemdb->exists(itemdb_readdb_libconfig_sub(entry,n,source)))) {
char e_name[ITEM_NAME_LENGTH*2+1];
const char *bonus = NULL;
char *str;
int i32;
uint32 ui32;
uint64 ui64;
struct config_setting_t *t = NULL;
StringBuf buf;
nullpo_ret(entry);
StrBuf->Init(&buf);
// id
StrBuf->Printf(&buf, "'%u',", (uint32)it->nameid);
// name_english
SQL->EscapeString(NULL, e_name, it->name);
StrBuf->Printf(&buf, "'%s',", e_name);
// name_japanese
SQL->EscapeString(NULL, e_name, it->jname);
StrBuf->Printf(&buf, "'%s',", e_name);
// type
StrBuf->Printf(&buf, "'%d',", it->flag.delay_consume ? IT_DELAYCONSUME : it->type);
// subtype
StrBuf->Printf(&buf, "'%d',", it->subtype);
// price_buy
StrBuf->Printf(&buf, "'%d',", it->value_buy);
// price_sell
StrBuf->Printf(&buf, "'%d',", it->value_sell);
// weight
StrBuf->Printf(&buf, "'%d',", it->weight);
// atk
StrBuf->Printf(&buf, "'%d',", it->atk);
// matk
StrBuf->Printf(&buf, "'%d',", it->matk);
// defence
StrBuf->Printf(&buf, "'%d',", it->def);
// range
StrBuf->Printf(&buf, "'%d',", it->range);
// slots
StrBuf->Printf(&buf, "'%d',", it->slot);
// equip_jobs
if ((t = libconfig->setting_get_member(entry, "Job")) != NULL) {
if (config_setting_is_group(t)) {
ui64 = itemdb2sql_readdb_job_sub(t);
} else if (itemdb->lookup_const(entry, "Job", &i32)) { // This is an unsigned value, do not check for >= 0
ui64 = (uint64)i32;
} else {
ui64 = UINT64_MAX;
}
} else {
ui64 = UINT64_MAX;
}
StrBuf->Printf(&buf, "'%"PRIu64"',", ui64);
// equip_upper
if (itemdb->lookup_const_mask(entry, "Upper", &i32) && i32 >= 0)
ui32 = (uint32)i32;
else
ui32 = ITEMUPPER_ALL;
StrBuf->Printf(&buf, "'%u',", ui32);
// equip_genders
StrBuf->Printf(&buf, "'%d',", it->sex);
// equip_locations
StrBuf->Printf(&buf, "'%d',", it->equip);
// weapon_level
StrBuf->Printf(&buf, "'%d',", it->wlv);
// equip_level_min
StrBuf->Printf(&buf, "'%d',", it->elv);
// equip_level_max
if ((t = libconfig->setting_get_member(entry, "EquipLv")) && config_setting_is_aggregate(t) && libconfig->setting_length(t) >= 2)
StrBuf->Printf(&buf, "'%d',", it->elvmax);
else
StrBuf->AppendStr(&buf, "NULL,");
// refineable
StrBuf->Printf(&buf, "'%d',", it->flag.no_refine?0:1);
// disable_options
StrBuf->Printf(&buf, "'%d',", it->flag.no_options?1:0);
// view_sprite
StrBuf->Printf(&buf, "'%d',", it->view_sprite);
// bindonequip
StrBuf->Printf(&buf, "'%d',", it->flag.bindonequip?1:0);
// forceserial
StrBuf->Printf(&buf, "'%d',", it->flag.force_serial?1:0);
// buyingstore
StrBuf->Printf(&buf, "'%d',", it->flag.buyingstore?1:0);
// delay
StrBuf->Printf(&buf, "'%d',", it->delay);
// trade_flag
StrBuf->Printf(&buf, "'%d',", it->flag.trade_restriction);
// trade_group
if (it->flag.trade_restriction != ITR_NONE && it->gm_lv_trade_override > 0 && it->gm_lv_trade_override < 100) {
StrBuf->Printf(&buf, "'%d',", it->gm_lv_trade_override);
} else {
StrBuf->AppendStr(&buf, "NULL,");
}
// nouse_flag
StrBuf->Printf(&buf, "'%u',", it->item_usage.flag);
// nouse_group
if (it->item_usage.flag != INR_NONE && it->item_usage.override > 0 && it->item_usage.override < 100) {
StrBuf->Printf(&buf, "'%u',", it->item_usage.override);
} else {
StrBuf->AppendStr(&buf, "NULL,");
}
// stack_amount
StrBuf->Printf(&buf, "'%u',", it->stack.amount);
// stack_flag
if (it->stack.amount) {
uint32 value = 0; // FIXME: Use an enum
value |= it->stack.inventory ? 1 : 0;
value |= it->stack.cart ? 2 : 0;
value |= it->stack.storage ? 4 : 0;
value |= it->stack.guildstorage ? 8 : 0;
StrBuf->Printf(&buf, "'%u',", value);
} else {
StrBuf->AppendStr(&buf, "NULL,");
}
// sprite
if (it->flag.available) {
StrBuf->Printf(&buf, "'%d',", it->view_id);
} else {
StrBuf->AppendStr(&buf, "NULL,");
}
// script
if (it->script && libconfig->setting_lookup_string(entry, "Script", &bonus)) {
hstr(bonus);
str = tosql.buf[3].p;
if (strlen(str) > tosql.buf[0].len) {
tosql.buf[0].len = tosql.buf[0].len + strlen(str) + 1000;
RECREATE(tosql.buf[0].p,char,tosql.buf[0].len);
}
SQL->EscapeString(NULL, tosql.buf[0].p, str);
StrBuf->Printf(&buf, "'%s',", tosql.buf[0].p);
} else {
StrBuf->AppendStr(&buf, "'',");
}
// equip_script
if (it->equip_script && libconfig->setting_lookup_string(entry, "OnEquipScript", &bonus)) {
hstr(bonus);
str = tosql.buf[3].p;
if (strlen(str) > tosql.buf[1].len) {
tosql.buf[1].len = tosql.buf[1].len + strlen(str) + 1000;
RECREATE(tosql.buf[1].p,char,tosql.buf[1].len);
}
SQL->EscapeString(NULL, tosql.buf[1].p, str);
StrBuf->Printf(&buf, "'%s',", tosql.buf[1].p);
} else {
StrBuf->AppendStr(&buf, "'',");
}
// unequip_script
if (it->unequip_script && libconfig->setting_lookup_string(entry, "OnUnequipScript", &bonus)) {
hstr(bonus);
str = tosql.buf[3].p;
if (strlen(str) > tosql.buf[2].len) {
tosql.buf[2].len = tosql.buf[2].len + strlen(str) + 1000;
RECREATE(tosql.buf[2].p,char,tosql.buf[2].len);
}
SQL->EscapeString(NULL, tosql.buf[2].p, str);
StrBuf->Printf(&buf, "'%s'", tosql.buf[2].p);
} else {
StrBuf->AppendStr(&buf, "''");
}
fprintf(tosql.fp, "REPLACE INTO `%s` VALUES (%s);\n", tosql.db_name, StrBuf->Value(&buf));
StrBuf->Destroy(&buf);
}
return it?it->nameid:0;
}
/**
* Prints a SQL table header for the current item_db table.
*/
void itemdb2sql_tableheader(void)
{
db2sql_fileheader();
fprintf(tosql.fp,
"--\n"
"-- Table structure for table `%s`\n"
"--\n"
"\n"
"DROP TABLE IF EXISTS `%s`;\n"
"CREATE TABLE `%s` (\n"
" `id` int(11) UNSIGNED NOT NULL DEFAULT '0',\n"
" `name_english` varchar(50) NOT NULL DEFAULT '',\n"
" `name_japanese` varchar(50) NOT NULL DEFAULT '',\n"
" `type` tinyint(2) UNSIGNED NOT NULL DEFAULT '0',\n"
" `subtype` tinyint(2) UNSIGNED DEFAULT NULL,\n"
" `price_buy` mediumint(10) DEFAULT NULL,\n"
" `price_sell` mediumint(10) DEFAULT NULL,\n"
" `weight` smallint(5) UNSIGNED DEFAULT NULL,\n"
" `atk` smallint(5) UNSIGNED DEFAULT NULL,\n"
" `matk` smallint(5) UNSIGNED DEFAULT NULL,\n"
" `defence` smallint(5) UNSIGNED DEFAULT NULL,\n"
" `range` tinyint(2) UNSIGNED DEFAULT NULL,\n"
" `slots` tinyint(2) UNSIGNED DEFAULT NULL,\n"
" `equip_jobs` bigint(20) UNSIGNED DEFAULT NULL,\n"
" `equip_upper` tinyint(8) UNSIGNED DEFAULT NULL,\n"
" `equip_genders` tinyint(2) UNSIGNED DEFAULT NULL,\n"
" `equip_locations` mediumint(8) UNSIGNED DEFAULT NULL,\n"
" `weapon_level` tinyint(2) UNSIGNED DEFAULT NULL,\n"
" `equip_level_min` smallint(5) UNSIGNED DEFAULT NULL,\n"
" `equip_level_max` smallint(5) UNSIGNED DEFAULT NULL,\n"
" `refineable` tinyint(1) UNSIGNED DEFAULT NULL,\n"
" `disable_options` tinyint(1) UNSIGNED DEFAULT NULL,\n"
" `view_sprite` smallint(3) UNSIGNED DEFAULT NULL,\n"
" `bindonequip` tinyint(1) UNSIGNED DEFAULT NULL,\n"
" `forceserial` tinyint(1) UNSIGNED DEFAULT NULL,\n"
" `buyingstore` tinyint(1) UNSIGNED DEFAULT NULL,\n"
" `delay` mediumint(9) UNSIGNED DEFAULT NULL,\n"
" `trade_flag` smallint(4) UNSIGNED DEFAULT NULL,\n"
" `trade_group` smallint(3) UNSIGNED DEFAULT NULL,\n"
" `nouse_flag` smallint(4) UNSIGNED DEFAULT NULL,\n"
" `nouse_group` smallint(4) UNSIGNED DEFAULT NULL,\n"
" `stack_amount` mediumint(6) UNSIGNED DEFAULT NULL,\n"
" `stack_flag` tinyint(2) UNSIGNED DEFAULT NULL,\n"
" `sprite` mediumint(6) UNSIGNED DEFAULT NULL,\n"
" `script` text,\n"
" `equip_script` text,\n"
" `unequip_script` text,\n"
" PRIMARY KEY (`id`)\n"
") ENGINE=MyISAM;\n"
"\n", tosql.db_name,tosql.db_name,tosql.db_name);
}
/**
* Item DB Conversion.
*
* Converts Item DB and Item DB2 to SQL scripts.
*/
void do_itemdb2sql(void)
{
int i;
struct convert_db_files {
const char *name;
const char *source;
const char *destination;
} files[] = {
{"item_db", DBPATH"item_db.conf", "sql-files/item_db" DBSUFFIX ".sql"},
{"item_db2", "item_db2.conf", "sql-files/item_db2.sql"},
};
/* link */
itemdb_readdb_libconfig_sub = itemdb->readdb_libconfig_sub;
itemdb->readdb_libconfig_sub = itemdb2sql_sub;
memset(&tosql.buf, 0, sizeof(tosql.buf));
itemdb->clear(false);
for (i = 0; i < ARRAYLENGTH(files); i++) {
if ((tosql.fp = fopen(files[i].destination, "wt+")) == NULL) {
ShowError("itemdb_tosql: File not found \"%s\".\n", files[i].destination);
return;
}
tosql.db_name = files[i].name;
itemdb2sql_tableheader();
itemdb->readdb_libconfig(files[i].source);
fclose(tosql.fp);
}
/* unlink */
itemdb->readdb_libconfig_sub = itemdb_readdb_libconfig_sub;
for (i = 0; i < ARRAYLENGTH(tosql.buf); i++) {
if (tosql.buf[i].p)
aFree(tosql.buf[i].p);
}
}
/**
* Converts a Mob DB entry to SQL.
*
* @see mobdb_readdb_libconfig_sub.
*/
int mobdb2sql_sub(struct config_setting_t *mobt, int n, const char *source)
{
struct mob_db *md = NULL;
nullpo_ret(mobt);
if ((md = mob->db(mob_read_db_sub(mobt, n, source))) != mob->dummy) {
char e_name[NAME_LENGTH*2+1];
StringBuf buf;
int card_idx = 9, i;
StrBuf->Init(&buf);
// id
StrBuf->Printf(&buf, "%d,", md->mob_id);
// Sprite
SQL->EscapeString(NULL, e_name, md->sprite);
StrBuf->Printf(&buf, "'%s',", e_name);
// kName
SQL->EscapeString(NULL, e_name, md->name);
StrBuf->Printf(&buf, "'%s',", e_name);
// iName
SQL->EscapeString(NULL, e_name, md->jname);
StrBuf->Printf(&buf, "'%s',", e_name);
// LV
StrBuf->Printf(&buf, "%u,", md->lv);
// HP
StrBuf->Printf(&buf, "%u,", md->status.max_hp);
// SP
StrBuf->Printf(&buf, "%u,", md->status.max_sp);
// EXP
StrBuf->Printf(&buf, "%u,", md->base_exp);
// JEXP
StrBuf->Printf(&buf, "%u,", md->job_exp);
// Range1
StrBuf->Printf(&buf, "%u,", md->status.rhw.range);
// ATK1
StrBuf->Printf(&buf, "%u,", md->status.rhw.atk);
// ATK2
StrBuf->Printf(&buf, "%u,", md->status.rhw.atk2);
// DEF
StrBuf->Printf(&buf, "%d,", md->status.def);
// MDEF
StrBuf->Printf(&buf, "%d,", md->status.mdef);
// STR
StrBuf->Printf(&buf, "%u,", md->status.str);
// AGI
StrBuf->Printf(&buf, "%u,", md->status.agi);
// VIT
StrBuf->Printf(&buf, "%u,", md->status.vit);
// INT
StrBuf->Printf(&buf, "%u,", md->status.int_);
// DEX
StrBuf->Printf(&buf, "%u,", md->status.dex);
// LUK
StrBuf->Printf(&buf, "%u,", md->status.luk);
// Range2
StrBuf->Printf(&buf, "%d,", md->range2);
// Range3
StrBuf->Printf(&buf, "%d,", md->range3);
// Scale
StrBuf->Printf(&buf, "%u,", md->status.size);
// Race
StrBuf->Printf(&buf, "%u,", md->status.race);
// Element
StrBuf->Printf(&buf, "%d,", md->status.def_ele + 20 * md->status.ele_lv);
// Mode
StrBuf->Printf(&buf, "%u,", md->status.mode);
// Speed
StrBuf->Printf(&buf, "%u,", md->status.speed);
// aDelay
StrBuf->Printf(&buf, "%u,", md->status.adelay);
// aMotion
StrBuf->Printf(&buf, "%u,", md->status.amotion);
// dMotion
StrBuf->Printf(&buf, "%u,", md->status.dmotion);
// MEXP
StrBuf->Printf(&buf, "%u,", md->mexp);
for (i = 0; i < 3; i++) {
// MVP{i}id
StrBuf->Printf(&buf, "%d,", md->mvpitem[i].nameid);
// MVP{i}per
StrBuf->Printf(&buf, "%d,", md->mvpitem[i].p);
}
// Scan for cards
for (i = 0; i < 10; i++) {
struct item_data *it = NULL;
if (md->dropitem[i].nameid != 0 && (it = itemdb->exists(md->dropitem[i].nameid)) != NULL && it->type == IT_CARD)
card_idx = i;
}
for (i = 0; i < 10; i++) {
if (card_idx == i)
continue;
// Drop{i}id
StrBuf->Printf(&buf, "%d,", md->dropitem[i].nameid);
// Drop{i}per
StrBuf->Printf(&buf, "%d,", md->dropitem[i].p);
}
// DropCardid
StrBuf->Printf(&buf, "%d,", md->dropitem[card_idx].nameid);
// DropCardper
StrBuf->Printf(&buf, "%d", md->dropitem[card_idx].p);
fprintf(tosql.fp, "REPLACE INTO `%s` VALUES (%s);\n", tosql.db_name, StrBuf->Value(&buf));
StrBuf->Destroy(&buf);
}
return md ? md->mob_id : 0;
}
/**
* Prints a SQL table header for the current mob_db table.
*/
void mobdb2sql_tableheader(void)
{
db2sql_fileheader();
fprintf(tosql.fp,
"--\n"
"-- Table structure for table `%s`\n"
"--\n"
"\n"
"DROP TABLE IF EXISTS `%s`;\n"
"CREATE TABLE `%s` (\n"
" `ID` MEDIUMINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Sprite` TEXT NOT NULL,\n"
" `kName` TEXT NOT NULL,\n"
" `iName` TEXT NOT NULL,\n"
" `LV` TINYINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `HP` INT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `SP` MEDIUMINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `EXP` MEDIUMINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `JEXP` MEDIUMINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Range1` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',\n"
" `ATK1` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `ATK2` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `DEF` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `MDEF` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `STR` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `AGI` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `VIT` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `INT` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `DEX` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `LUK` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Range2` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Range3` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Scale` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Race` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Element` TINYINT(4) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Mode` INT(11) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Speed` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `aDelay` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `aMotion` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `dMotion` SMALLINT(6) UNSIGNED NOT NULL DEFAULT '0',\n"
" `MEXP` MEDIUMINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `MVP1id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `MVP1per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `MVP2id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `MVP2per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `MVP3id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `MVP3per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop1id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop1per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop2id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop2per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop3id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop3per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop4id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop4per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop5id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop5per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop6id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop6per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop7id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop7per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop8id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop8per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop9id` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `Drop9per` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `DropCardid` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" `DropCardper` SMALLINT(9) UNSIGNED NOT NULL DEFAULT '0',\n"
" PRIMARY KEY (`ID`)\n"
") ENGINE=MyISAM;\n"
"\n", tosql.db_name, tosql.db_name, tosql.db_name);
}
/**
* Mob DB Conversion.
*
* Converts Mob DB and Mob DB2 to SQL scripts.
*/
void do_mobdb2sql(void)
{
int i;
struct convert_db_files {
const char *name;
const char *source;
const char *destination;
} files[] = {
{"mob_db", DBPATH"mob_db.conf", "sql-files/mob_db" DBSUFFIX ".sql"},
{"mob_db2", "mob_db2.conf", "sql-files/mob_db2.sql"},
};
/* link */
mob_read_db_sub = mob->read_db_sub;
mob->read_db_sub = mobdb2sql_sub;
if (map->minimal) {
// Set up modifiers
battle->config_set_defaults();
}
memset(&tosql.buf, 0, sizeof(tosql.buf));
for (i = 0; i < ARRAYLENGTH(files); i++) {
if ((tosql.fp = fopen(files[i].destination, "wt+")) == NULL) {
ShowError("mobdb_tosql: File not found \"%s\".\n", files[i].destination);
return;
}
tosql.db_name = files[i].name;
mobdb2sql_tableheader();
mob->read_libconfig(files[i].source, false);
fclose(tosql.fp);
}
/* unlink */
mob->read_db_sub = mob_read_db_sub;
for (i = 0; i < ARRAYLENGTH(tosql.buf); i++) {
if (tosql.buf[i].p)
aFree(tosql.buf[i].p);
}
// Run mob_skill_db converter
do_mobskilldb2sql();
}
/**
* Converts Mob Skill State constant to string
*/
const char* mob_skill_state_tostring(enum MobSkillState mss)
{
switch(mss) {
case MSS_ANY:
return "any";
case MSS_IDLE:
return "idle";
case MSS_WALK:
return "walk";
case MSS_LOOT:
return "loot";
case MSS_DEAD:
return "dead";
case MSS_BERSERK:
return "attack";
case MSS_ANGRY:
return "angry";
case MSS_RUSH:
return "chase";
case MSS_FOLLOW:
return "follow";
case MSS_ANYTARGET:
return "anytarget";
}
return "unknown";
}
/**
* Converts Mob Skill Target constant to string
*/
const char* mob_skill_target_tostring(int target)
{
switch(target) {
case MST_TARGET:
return "target";
case MST_RANDOM:
return "randomtarget";
case MST_SELF:
return "self";
case MST_FRIEND:
return "friend";
case MST_MASTER:
return "master";
case MST_AROUND1:
return "around1";
case MST_AROUND2:
return "around2";
case MST_AROUND3:
return "around3";
//case MST_AROUND: // same value as MST_AROUND4
case MST_AROUND4:
return "around4";
case MST_AROUND5:
return "around5";
case MST_AROUND6:
return "around6";
case MST_AROUND7:
return "around7";
case MST_AROUND8:
return "around8";
}
return "unknown";
}
/**
* Converts Mob Skill Condition constant to string
*/
const char* mob_skill_condition_tostring(int condition)
{
switch(condition) {
case MSC_ALWAYS:
return "always";
case MSC_MYHPLTMAXRATE:
return "myhpltmaxrate";
case MSC_MYHPINRATE:
return "myhpinrate";
case MSC_FRIENDHPLTMAXRATE:
return "friendhpltmaxrate";
case MSC_FRIENDHPINRATE:
return "friendhpinrate";
case MSC_MYSTATUSON:
return "mystatuson";
case MSC_MYSTATUSOFF:
return "mystatusoff";
case MSC_FRIENDSTATUSON:
return "friendstatuson";
case MSC_FRIENDSTATUSOFF:
return "friendstatusoff";
case MSC_ATTACKPCGT:
return "attackpcgt";
case MSC_ATTACKPCGE:
return "attackpcge";
case MSC_SLAVELT:
return "slavelt";
case MSC_SLAVELE:
return "slavele";
case MSC_CLOSEDATTACKED:
return "closedattacked";
case MSC_LONGRANGEATTACKED:
return "longrangeattacked";
case MSC_AFTERSKILL:
return "afterskill";
case MSC_SKILLUSED:
return "skillused";
case MSC_CASTTARGETED:
return "casttargeted";
case MSC_RUDEATTACKED:
return "rudeattacked";
case MSC_MASTERHPLTMAXRATE:
return "masterhpltmaxrate";
case MSC_MASTERATTACKED:
return "masterattacked";
case MSC_ALCHEMIST:
return "alchemist";
case MSC_SPAWN:
return "onspawn";
}
return "unknown";
}
/**
* Converts a Mob Skill DB entry to SQL.
*
* @see mob_skill_db_libconfig_sub_skill.
*/
bool mobskilldb2sql_sub(struct config_setting_t *it, int n, int mob_id)
{
int i32 = 0, i;
StringBuf buf;
struct mob_db *md = mob->db(mob_id);
char valname[15];
const char *name = config_setting_name(it);
char e_name[NAME_LENGTH*2+1];
nullpo_retr(false, it);
Assert_retr(false, mob_id <= 0 || md != mob->dummy);
StrBuf->Init(&buf);
// MonsterID
StrBuf->Printf(&buf, "%d,", mob_id);
// Info
SQL->EscapeString(NULL, e_name, md->name);
StrBuf->Printf(&buf, "'%s@%s',", e_name, name);
if (mob->lookup_const(it, "SkillState", &i32) && (i32 < MSS_ANY || i32 > MSS_ANYTARGET)) {
ShowWarning("mob_skill_db_libconfig_sub_skill: Invalid skill state %d for skill '%s' in monster %d, defaulting to MSS_ANY.\n", i32, name, mob_id);
i32 = MSS_ANY;
}
// State
StrBuf->Printf(&buf, "'%s',", mob_skill_state_tostring(i32));
// SkillID
if (!(i32 = skill->name2id(name))) {
ShowWarning("mob_skill_db_libconfig_sub_skill: Non existant skill id %d in monster %d, skipping.\n", i32, mob_id);
return false;
}
StrBuf->Printf(&buf, "%d,", i32);
// SkillLv
if (!libconfig->setting_lookup_int(it, "SkillLevel", &i32) || i32 <= 0)
i32 = 1;
StrBuf->Printf(&buf, "%d,", i32);
// Rate
i32 = 0;
libconfig->setting_lookup_int(it, "Rate", &i32);
StrBuf->Printf(&buf, "%d,", i32);
// CastTime
i32 = 0;
libconfig->setting_lookup_int(it, "CastTime", &i32);
StrBuf->Printf(&buf, "%d,", i32);
// Delay
i32 = 0;
libconfig->setting_lookup_int(it, "Delay", &i32);
StrBuf->Printf(&buf, "%d,", i32);
// Cancelable
if (libconfig->setting_lookup_bool(it, "Cancelable", &i32)) {
StrBuf->Printf(&buf, "'%s',", ((i32 == 0) ? "no" : "yes"));
} else {
StrBuf->Printf(&buf, "'no',");
}
// Target
if (mob->lookup_const(it, "SkillTarget", &i32) && (i32 < MST_TARGET || i32 > MST_AROUND)) {
i32 = MST_TARGET;
}
StrBuf->Printf(&buf, "'%s',", mob_skill_target_tostring(i32));
// Condition
if (mob->lookup_const(it, "CastCondition", &i32) && (i32 < MSC_ALWAYS || i32 > MSC_SPAWN)) {
i32 = MSC_ALWAYS;
}
StrBuf->Printf(&buf, "'%s',", mob_skill_condition_tostring(i32));
// ConditionValue
i32 = 0;
if (mob->lookup_const(it, "ConditionData", &i32)) {
StrBuf->Printf(&buf, "'%d',", i32);
} else {
StrBuf->Printf(&buf, "NULL,");
}
// Val1-Val5
for (i = 0; i < 5; i++) {
sprintf(valname, "val%1d", i);
if (libconfig->setting_lookup_int(it, valname, &i32)) {
StrBuf->Printf(&buf, "%d,", i32);
} else {
StrBuf->Printf(&buf, "NULL,");
}
}
// Emotion
if (libconfig->setting_lookup_int(it, "Emotion", &i32)) {
StrBuf->Printf(&buf, "'%d',", i32);
} else {
StrBuf->Printf(&buf, "NULL,");
}
if (libconfig->setting_lookup_int(it, "ChatMsgID", &i32) && i32 > 0 && i32 <= MAX_MOB_CHAT) {
StrBuf->Printf(&buf, "'%d'", i32);
} else {
StrBuf->Printf(&buf, "NULL");
}
fprintf(tosql.fp, "REPLACE INTO `%s` VALUES (%s);\n", tosql.db_name, StrBuf->Value(&buf));
StrBuf->Destroy(&buf);
return true;
}
/**
* Prints a SQL table header for the current mob_skill_db table.
*/
void mobskilldb2sql_tableheader(void)
{
db2sql_fileheader();
fprintf(tosql.fp,
"--\n"
"-- Table structure for table `%s`\n"
"--\n"
"\n"
"DROP TABLE IF EXISTS `%s`;\n"
"CREATE TABLE `%s` (\n"
" `MOB_ID` SMALLINT(6) NOT NULL,\n"
" `INFO` TEXT NOT NULL,\n"
" `STATE` TEXT NOT NULL,\n"
" `SKILL_ID` SMALLINT(6) NOT NULL,\n"
" `SKILL_LV` TINYINT(4) NOT NULL,\n"
" `RATE` SMALLINT(4) NOT NULL,\n"
" `CASTTIME` MEDIUMINT(9) NOT NULL,\n"
" `DELAY` INT(9) NOT NULL,\n"
" `CANCELABLE` TEXT NOT NULL,\n"
" `TARGET` TEXT NOT NULL,\n"
" `CONDITION` TEXT NOT NULL,\n"
" `CONDITION_VALUE` TEXT,\n"
" `VAL1` INT(11) DEFAULT NULL,\n"
" `VAL2` INT(11) DEFAULT NULL,\n"
" `VAL3` INT(11) DEFAULT NULL,\n"
" `VAL4` INT(11) DEFAULT NULL,\n"
" `VAL5` INT(11) DEFAULT NULL,\n"
" `EMOTION` TEXT,\n"
" `CHAT` TEXT\n"
") ENGINE=MyISAM;\n"
"\n", tosql.db_name, tosql.db_name, tosql.db_name);
}
/**
* Mob Skill DB Conversion
*/
void do_mobskilldb2sql(void)
{
int i;
struct convert_db_files {
const char *name;
const char *source;
const char *destination;
} files[] = {
{"mob_skill_db", DBPATH"mob_skill_db.conf", "sql-files/mob_skill_db" DBSUFFIX ".sql"},
{"mob_skill_db2", "mob_skill_db2.conf", "sql-files/mob_skill_db2.sql"},
};
/* link */
mob_skill_db_libconfig_sub_skill = mob->skill_db_libconfig_sub_skill;
mob->skill_db_libconfig_sub_skill = mobskilldb2sql_sub;
memset(&tosql.buf, 0, sizeof(tosql.buf));
for (i = 0; i < ARRAYLENGTH(files); i++) {
if ((tosql.fp = fopen(files[i].destination, "wt+")) == NULL) {
ShowError("do_mobskilldb2sql: File not found \"%s\".\n", files[i].destination);
return;
}
tosql.db_name = files[i].name;
mobskilldb2sql_tableheader();
mob->skill_db_libconfig(files[i].source, false);
fclose(tosql.fp);
}
/* unlink */
mob->skill_db_libconfig_sub_skill = mob_skill_db_libconfig_sub_skill;
for (i = 0; i < ARRAYLENGTH(tosql.buf); i++) {
if (tosql.buf[i].p)
aFree(tosql.buf[i].p);
}
}
/**
* Console command db2sql.
*/
CPCMD(db2sql)
{
do_itemdb2sql();
do_mobdb2sql();
}
/**
* Console command itemdb2sql.
*/
CPCMD(itemdb2sql)
{
do_itemdb2sql();
}
/**
* Console command mobdb2sql.
*/
CPCMD(mobdb2sql)
{
do_mobdb2sql();
}
/**
* Command line argument handler for --db2sql
*/
CMDLINEARG(db2sql)
{
map->minimal = true;
itemdb2sql_torun = true;
mobdb2sql_torun = true;
return true;
}
/**
* Command line argument handler for --itemdb2sql
*/
CMDLINEARG(itemdb2sql)
{
map->minimal = true;
itemdb2sql_torun = true;
return true;
}
/**
* Command line argument handler for --mobdb2sql
*/
CMDLINEARG(mobdb2sql)
{
map->minimal = true;
mobdb2sql_torun = true;
return true;
}
HPExport void server_preinit(void)
{
addArg("--db2sql", false, db2sql, NULL);
addArg("--itemdb2sql", false, itemdb2sql, NULL);
addArg("--mobdb2sql", false, mobdb2sql, NULL);
}
HPExport void plugin_init(void)
{
addCPCommand("server:tools:db2sql", db2sql);
addCPCommand("server:tools:itemdb2sql", itemdb2sql);
addCPCommand("server:tools:mobdb2sql", mobdb2sql);
}
HPExport void server_online(void)
{
if (itemdb2sql_torun)
do_itemdb2sql();
if (mobdb2sql_torun)
do_mobdb2sql();
}