malufett's post in Associated DB Tables Upon Character Creation was marked as the answer
//-----------------------------------
// Function to create a new character
//-----------------------------------
#if PACKETVER >= 20120307
int make_new_char_sql(struct char_session_data* sd, char* name_, int slot, int hair_color, int hair_style) {
int str = 1, agi = 1, vit = 1, int_ = 1, dex = 1, luk = 1;
#else
int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int agi, int vit, int int_, int dex, int luk, int slot, int hair_color, int hair_style) {
#endif
char name[NAME_LENGTH];
char esc_name[NAME_LENGTH*2+1];
int char_id, flag;
safestrncpy(name, name_, NAME_LENGTH);
normalize_name(name,TRIM_CHARS);
Sql_EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
flag = check_char_name(name,esc_name);
if( flag < 0 )
return flag;
//check other inputs
#if PACKETVER >= 20120307
if(slot >= MAX_CHARS)
#else
if((slot >= MAX_CHARS) // slots
|| (str + agi + vit + int_ + dex + luk != 6*5 ) // stats
|| (str < 1 || str > 9 || agi < 1 || agi > 9 || vit < 1 || vit > 9 || int_ < 1 || int_ > 9 || dex < 1 || dex > 9 || luk < 1 || luk > 9) // individual stat values
|| (str + int_ != 10 || agi + luk != 10 || vit + dex != 10) ) // pairs
#endif
return -2; // invalid input
// check the number of already existing chars in this account
if( char_per_account != 0 ) {
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d'", char_db, sd->account_id) )
Sql_ShowDebug(sql_handle);
if( Sql_NumRows(sql_handle) >= char_per_account )
return -2; // character account limit exceeded
}
// check char slot
if( SQL_ERROR == Sql_Query(sql_handle, "SELECT 1 FROM `%s` WHERE `account_id` = '%d' AND `char_num` = '%d' LIMIT 1", char_db, sd->account_id, slot) )
Sql_ShowDebug(sql_handle);
if( Sql_NumRows(sql_handle) > 0 )
return -2; // slot already in use
// validation success, log result
if (log_char) {
if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)"
"VALUES (NOW(), '%s', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
charlog_db, "make new char", sd->account_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) )
Sql_ShowDebug(sql_handle);
}
#if PACKETVER >= 20120307
//Insert the new char entry to the database
if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `status_point`,`str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
"'%d', '%d', '%s', '%d', '%d','%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
char_db, sd->account_id , slot, esc_name, start_zeny, 48, str, agi, vit, int_, dex, luk,
(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) )
{
Sql_ShowDebug(sql_handle);
return -2; //No, stop the procedure!
}
#else
//Insert the new char entry to the database
if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`account_id`, `char_num`, `name`, `zeny`, `str`, `agi`, `vit`, `int`, `dex`, `luk`, `max_hp`, `hp`,"
"`max_sp`, `sp`, `hair`, `hair_color`, `last_map`, `last_x`, `last_y`, `save_map`, `save_x`, `save_y`) VALUES ("
"'%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d','%d', '%d','%d', '%d', '%s', '%d', '%d', '%s', '%d', '%d')",
char_db, sd->account_id , slot, esc_name, start_zeny, str, agi, vit, int_, dex, luk,
(40 * (100 + vit)/100) , (40 * (100 + vit)/100 ), (11 * (100 + int_)/100), (11 * (100 + int_)/100), hair_style, hair_color,
mapindex_id2name(start_point.map), start_point.x, start_point.y, mapindex_id2name(start_point.map), start_point.x, start_point.y) )
{
Sql_ShowDebug(sql_handle);
return -2; //No, stop the procedure!
}
#endif
//Retrieve the newly auto-generated char id
char_id = (int)Sql_LastInsertId(sql_handle);
//Give the char the default items
if (start_weapon > 0) { //add Start Weapon (Knife?)
if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_weapon, 1, 1) )
Sql_ShowDebug(sql_handle);
}
if (start_armor > 0) { //Add default armor (cotton shirt?)
if( SQL_ERROR == Sql_Query(sql_handle, "INSERT INTO `%s` (`char_id`,`nameid`, `amount`, `identify`) VALUES ('%d', '%d', '%d', '%d')", inventory_db, char_id, start_armor, 1, 1) )
Sql_ShowDebug(sql_handle);
}
ShowInfo("Created char: account: %d, char: %d, slot: %d, name: %s\n", sd->account_id, char_id, slot, name);
return char_id;
}