summaryrefslogtreecommitdiff
path: root/src/char/char.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/char/char.c')
-rw-r--r--src/char/char.c1410
1 files changed, 945 insertions, 465 deletions
diff --git a/src/char/char.c b/src/char/char.c
index 7dfb6861c..9abb17257 100644
--- a/src/char/char.c
+++ b/src/char/char.c
@@ -2,7 +2,30 @@
// See the LICENSE file
// Portions Copyright (c) Athena Dev Teams
+#define HERCULES_CORE
+
+#include "../config/core.h" // CONSOLE_INPUT
+#include "char.h"
+
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <time.h>
+
+#include "int_elemental.h"
+#include "int_guild.h"
+#include "int_homun.h"
+#include "int_mercenary.h"
+#include "int_party.h"
+#include "int_storage.h"
+#include "inter.h"
+#include "pincode.h"
+#include "../common/HPM.h"
#include "../common/cbasetypes.h"
+#include "../common/console.h"
#include "../common/core.h"
#include "../common/db.h"
#include "../common/malloc.h"
@@ -13,23 +36,6 @@
#include "../common/strlib.h"
#include "../common/timer.h"
#include "../common/utils.h"
-#include "int_guild.h"
-#include "int_homun.h"
-#include "int_mercenary.h"
-#include "int_elemental.h"
-#include "int_party.h"
-#include "int_storage.h"
-#include "char.h"
-#include "inter.h"
-#include "pincode.h"
-
-#include <sys/types.h>
-#include <time.h>
-#include <signal.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdio.h>
-#include <stdlib.h>
// private declarations
#define CHAR_CONF_NAME "conf/char-server.conf"
@@ -43,7 +49,6 @@ char inventory_db[256] = "inventory";
char charlog_db[256] = "charlog";
char storage_db[256] = "storage";
char interlog_db[256] = "interlog";
-char reg_db[256] = "global_reg_value";
char skill_db[256] = "skill";
char memo_db[256] = "memo";
char guild_db[256] = "guild";
@@ -66,7 +71,13 @@ char skill_homunculus_db[256] = "skill_homunculus";
char mercenary_db[256] = "mercenary";
char mercenary_owner_db[256] = "mercenary_owner";
char ragsrvinfo_db[256] = "ragsrvinfo";
+char elemental_db[256] = "elemental";
char interreg_db[32] = "interreg";
+char account_data_db[256] = "account_data";
+char acc_reg_num_db[32] = "acc_reg_num_db";
+char acc_reg_str_db[32] = "acc_reg_str_db";
+char char_reg_str_db[32] = "char_reg_str_db";
+char char_reg_num_db[32] = "char_reg_num_db";
// show loading/saving messages
int save_log = 1;
@@ -75,7 +86,9 @@ static DBMap* char_db_; // int char_id -> struct mmo_charstatus*
char db_path[1024] = "db";
-int db_use_sqldbs;
+int db_use_sql_item_db;
+int db_use_sql_mob_db;
+int db_use_sql_mob_skill_db;
struct mmo_map_server {
int fd;
@@ -99,12 +112,13 @@ uint32 char_ip = 0;
char bind_ip_str[128];
uint32 bind_ip = INADDR_ANY;
uint16 char_port = 6121;
-int char_maintenance = 0;
+int char_server_type = 0;
+int char_maintenance_min_group_id = 0;
bool char_new = true;
int char_new_display = 0;
bool name_ignoring_case = false; // Allow or not identical name for characters but with a different case by [Yor]
-int char_name_option = 0; // Option to know which letters/symbols are authorised in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor]
+int char_name_option = 0; // Option to know which letters/symbols are authorized in the name of a character (0: all, 1: only those in char_name_letters, 2: all EXCEPT those in char_name_letters) by [Yor]
char unknown_char_name[NAME_LENGTH] = "Unknown"; // Name to use when the requested name cannot be determined
#define TRIM_CHARS "\255\xA0\032\t\x0A\x0D " //The following characters are trimmed regardless because they cause confusion and problems on the servers. [Skotlex]
char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) in a character name. by [Yor]
@@ -112,8 +126,10 @@ char char_name_letters[1024] = ""; // list of letters/symbols allowed (or not) i
int char_del_level = 0; //From which level u can delete character [Lupus]
int char_del_delay = 86400;
-int log_char = 1; // loggin char or not [devil]
-int log_inter = 1; // loggin inter or not [devil]
+int log_char = 1; // logging char or not [devil]
+int log_inter = 1; // logging inter or not [devil]
+
+int char_aegis_delete = 0; // Verify if char is in guild/party or char and reacts as Aegis does (doesn't allow deletion), see char_delete2_req for more information
// Advanced subnet check [LuzZza]
struct s_subnet {
@@ -127,12 +143,12 @@ int max_connect_user = -1;
int gm_allow_group = -1;
int autosave_interval = DEFAULT_AUTOSAVE_INTERVAL;
int start_zeny = 0;
-int start_items[MAX_START_ITEMS*2];
+int start_items[MAX_START_ITEMS*3];
int guild_exp_rate = 100;
//Custom limits for the fame lists. [Skotlex]
int fame_list_size_chemist = MAX_FAME_LIST;
-int fame_list_size_smith = MAX_FAME_LIST;
+int fame_list_size_smith = MAX_FAME_LIST;
int fame_list_size_taekwon = MAX_FAME_LIST;
// Char-server-side stored fame lists [DracoRPG]
@@ -173,7 +189,7 @@ static DBMap* auth_db; // int account_id -> struct auth_node*
// Online User Database
//-----------------------------------------------------
-static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data);
+static int chardb_waiting_disconnect(int tid, int64 tick, int id, intptr_t data);
int delete_char_sql(int char_id);
/**
@@ -185,7 +201,7 @@ static DBData create_online_char_data(DBKey key, va_list args)
CREATE(character, struct online_char_data, 1);
character->account_id = key.i;
character->char_id = -1;
- character->server = -1;
+ character->server = -1;
character->pincode_enable = -1;
character->fd = -1;
character->waiting_disconnect = INVALID_TIMER;
@@ -208,7 +224,7 @@ void set_char_charselect(int account_id)
character->pincode_enable = *pincode->charselect + *pincode->enabled;
if(character->waiting_disconnect != INVALID_TIMER) {
- iTimer->delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
+ timer->delete(character->waiting_disconnect, chardb_waiting_disconnect);
character->waiting_disconnect = INVALID_TIMER;
}
@@ -249,7 +265,7 @@ void set_char_online(int map_id, int char_id, int account_id)
//Get rid of disconnect timer
if(character->waiting_disconnect != INVALID_TIMER) {
- iTimer->delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
+ timer->delete(character->waiting_disconnect, chardb_waiting_disconnect);
character->waiting_disconnect = INVALID_TIMER;
}
@@ -294,7 +310,7 @@ void set_char_offline(int char_id, int account_id)
server[character->server].users--;
if(character->waiting_disconnect != INVALID_TIMER){
- iTimer->delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
+ timer->delete(character->waiting_disconnect, chardb_waiting_disconnect);
character->waiting_disconnect = INVALID_TIMER;
}
@@ -324,15 +340,15 @@ void set_char_offline(int char_id, int account_id)
static int char_db_setoffline(DBKey key, DBData *data, va_list ap)
{
struct online_char_data* character = (struct online_char_data*)DB->data2ptr(data);
- int server = va_arg(ap, int);
- if (server == -1) {
+ int server_id = va_arg(ap, int);
+ if (server_id == -1) {
character->char_id = -1;
character->server = -1;
if(character->waiting_disconnect != INVALID_TIMER){
- iTimer->delete_timer(character->waiting_disconnect, chardb_waiting_disconnect);
+ timer->delete(character->waiting_disconnect, chardb_waiting_disconnect);
character->waiting_disconnect = INVALID_TIMER;
}
- } else if (character->server == server)
+ } else if (character->server == server_id)
character->server = -2; //In some map server that we aren't connected to.
return 0;
}
@@ -457,7 +473,8 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
(p->ele_id != cp->ele_id) || (p->shield != cp->shield) || (p->head_top != cp->head_top) ||
(p->head_mid != cp->head_mid) || (p->head_bottom != cp->head_bottom) || (p->delete_date != cp->delete_date) ||
(p->rename != cp->rename) || (p->slotchange != cp->slotchange) || (p->robe != cp->robe) ||
- (p->show_equip != cp->show_equip) || (p->allow_party != cp->allow_party)
+ (p->show_equip != cp->show_equip) || (p->allow_party != cp->allow_party) || (p->font != cp->font) ||
+ (p->uniqueitem_counter != cp->uniqueitem_counter )
) { //Save status
unsigned int opt = 0;
@@ -473,7 +490,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
"`option`='%d',`party_id`='%d',`guild_id`='%d',`pet_id`='%d',`homun_id`='%d',`elemental_id`='%d',"
"`weapon`='%d',`shield`='%d',`head_top`='%d',`head_mid`='%d',`head_bottom`='%d',"
"`last_map`='%s',`last_x`='%d',`last_y`='%d',`save_map`='%s',`save_x`='%d',`save_y`='%d', `rename`='%d',"
- "`delete_date`='%lu',`robe`='%d',`slotchange`='%d', `char_opt`='%u'"
+ "`delete_date`='%lu',`robe`='%d',`slotchange`='%d', `char_opt`='%u', `font`='%u', `uniqueitem_counter` ='%u'"
" WHERE `account_id`='%d' AND `char_id` = '%d'",
char_db, p->base_level, p->job_level,
p->base_exp, p->job_exp, p->zeny,
@@ -484,7 +501,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
mapindex_id2name(p->last_point.map), p->last_point.x, p->last_point.y,
mapindex_id2name(p->save_point.map), p->save_point.x, p->save_point.y, p->rename,
(unsigned long)p->delete_date, // FIXME: platform-dependent size
- p->robe,p->slotchange,opt,
+ p->robe,p->slotchange,opt,p->font,p->uniqueitem_counter,
p->account_id, p->char_id) )
{
Sql_ShowDebug(sql_handle);
@@ -492,6 +509,14 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
} else
strcat(save_status, " status");
}
+
+ if( p->bank_vault != cp->bank_vault || p->mod_exp != cp->mod_exp || p->mod_drop != cp->mod_drop || p->mod_death != cp->mod_death ) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`bank_vault`,`base_exp`,`base_drop`,`base_death`) VALUES ('%d','%d','%d','%d','%d')",account_data_db,p->account_id,p->bank_vault,p->mod_exp,p->mod_drop,p->mod_death) ) {
+ Sql_ShowDebug(sql_handle);
+ errors++;
+ } else
+ strcat(save_status, " accdata");
+ }
//Values that will seldom change (to speed up saving)
if (
@@ -670,6 +695,7 @@ int mmo_char_tosql(int char_id, struct mmo_charstatus* p)
strcat(save_status, " hotkeys");
}
#endif
+
StrBuf->Destroy(&buf);
if (save_status[0]!='\0' && save_log)
ShowInfo("Saved char %d - %s:%s.\n", char_id, p->name, save_status);
@@ -709,8 +735,8 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
// it significantly reduces cpu load on the database server.
StrBuf->Init(&buf);
- StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`");
- for( j = 0; j < MAX_SLOTS; ++j )
+ StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`");
+ for( j = 0; j < MAX_SLOTS; ++j )
StrBuf->Printf(&buf, ", `card%d`", j);
StrBuf->Printf(&buf, " FROM `%s` WHERE `%s`='%d'", tablename, selectoption, id);
@@ -727,13 +753,14 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL);
- SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &item.equip, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL);
- for( j = 0; j < MAX_SLOTS; ++j )
- SQL->StmtBindColumn(stmt, 8+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &item.bound, 0, NULL, NULL);
+ for( j = 0; j < MAX_SLOTS; ++j )
+ SQL->StmtBindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
// bit array indicating which inventory items have already been matched
flag = (bool*) aCalloc(max, sizeof(bool));
@@ -760,17 +787,18 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
items[i].identify == item.identify &&
items[i].refine == item.refine &&
items[i].attribute == item.attribute &&
- items[i].expire_time == item.expire_time )
+ items[i].expire_time == item.expire_time &&
+ items[i].bound == item.bound )
; //Do nothing.
else
{
// update all fields.
StrBuf->Clear(&buf);
- StrBuf->Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u'",
- tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time);
- for( j = 0; j < MAX_SLOTS; ++j )
+ StrBuf->Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `bound`='%d'",
+ tablename, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound);
+ for( j = 0; j < MAX_SLOTS; ++j )for( j = 0; j < MAX_SLOTS; ++j )
StrBuf->Printf(&buf, ", `card%d`=%d", j, items[i].card[j]);
- StrBuf->Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
+ StrBuf->Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
if( SQL_ERROR == SQL->QueryStr(sql_handle, StrBuf->Value(&buf)) )
{
@@ -795,8 +823,8 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
SQL->StmtFree(stmt);
StrBuf->Clear(&buf);
- StrBuf->Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `unique_id`", tablename, selectoption);
- for( j = 0; j < MAX_SLOTS; ++j )
+ StrBuf->Printf(&buf, "INSERT INTO `%s`(`%s`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`", tablename, selectoption);
+ for( j = 0; j < MAX_SLOTS; ++j )
StrBuf->Printf(&buf, ", `card%d`", j);
StrBuf->AppendStr(&buf, ") VALUES ");
@@ -813,15 +841,12 @@ int memitemdata_to_sql(const struct item items[], int max, int id, int tableswit
else
found = true;
- StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%"PRIu64"'",
- id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].unique_id);
- for( j = 0; j < MAX_SLOTS; ++j )
+ StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'",
+ id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].bound, items[i].unique_id);
+ for( j = 0; j < MAX_SLOTS; ++j )
StrBuf->Printf(&buf, ", '%d'", items[i].card[j]);
StrBuf->AppendStr(&buf, ")");
-
- updateLastUid(items[i].unique_id); // Unique Non Stackable Item ID
}
- dbUpdateUid(sql_handle); // Unique Non Stackable Item ID
if( found && SQL_ERROR == SQL->QueryStr(sql_handle, StrBuf->Value(&buf)) )
{
@@ -853,8 +878,8 @@ int inventory_to_sql(const struct item items[], int max, int id) {
// it significantly reduces cpu load on the database server.
StrBuf->Init(&buf);
- StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`");
- for( j = 0; j < MAX_SLOTS; ++j )
+ StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`");
+ for( j = 0; j < MAX_SLOTS; ++j )
StrBuf->Printf(&buf, ", `card%d`", j);
StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`='%d'", inventory_db, id);
@@ -871,14 +896,15 @@ int inventory_to_sql(const struct item items[], int max, int id) {
SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &item.id, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &item.nameid, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &item.amount, 0, NULL, NULL);
- SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &item.equip, 0, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &item.equip, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &item.identify, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &item.refine, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &item.attribute, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &item.expire_time, 0, NULL, NULL);
SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &item.favorite, 0, NULL, NULL);
- for( j = 0; j < MAX_SLOTS; ++j )
- SQL->StmtBindColumn(stmt, 9+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
+ SQL->StmtBindColumn(stmt, 9, SQLDT_UCHAR, &item.bound, 0, NULL, NULL);
+ for( j = 0; j < MAX_SLOTS; ++j )
+ SQL->StmtBindColumn(stmt, 10+j, SQLDT_SHORT, &item.card[j], 0, NULL, NULL);
// bit array indicating which inventory items have already been matched
flag = (bool*) aCalloc(max, sizeof(bool));
@@ -904,15 +930,16 @@ int inventory_to_sql(const struct item items[], int max, int id) {
items[i].refine == item.refine &&
items[i].attribute == item.attribute &&
items[i].expire_time == item.expire_time &&
- items[i].favorite == item.favorite )
+ items[i].favorite == item.favorite &&
+ items[i].bound == item.bound )
; //Do nothing.
else {
// update all fields.
StrBuf->Clear(&buf);
- StrBuf->Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d'",
- inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite);
- for( j = 0; j < MAX_SLOTS; ++j )
- StrBuf->Printf(&buf, ", `card%d`=%d", j, items[i].card[j]);
+ StrBuf->Printf(&buf, "UPDATE `%s` SET `amount`='%d', `equip`='%d', `identify`='%d', `refine`='%d',`attribute`='%d', `expire_time`='%u', `favorite`='%d', `bound`='%d'",
+ inventory_db, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound);
+ for( j = 0; j < MAX_SLOTS; ++j )
+ StrBuf->Printf(&buf, ", `card%d`=%d", j, items[i].card[j]);
StrBuf->Printf(&buf, " WHERE `id`='%d' LIMIT 1", item.id);
if( SQL_ERROR == SQL->QueryStr(sql_handle, StrBuf->Value(&buf)) ) {
@@ -935,8 +962,8 @@ int inventory_to_sql(const struct item items[], int max, int id) {
SQL->StmtFree(stmt);
StrBuf->Clear(&buf);
- StrBuf->Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `unique_id`", inventory_db);
- for( j = 0; j < MAX_SLOTS; ++j )
+ StrBuf->Printf(&buf, "INSERT INTO `%s` (`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`", inventory_db);
+ for( j = 0; j < MAX_SLOTS; ++j )
StrBuf->Printf(&buf, ", `card%d`", j);
StrBuf->AppendStr(&buf, ") VALUES ");
@@ -952,15 +979,12 @@ int inventory_to_sql(const struct item items[], int max, int id) {
else
found = true;
- StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%"PRIu64"'",
- id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].unique_id);
- for( j = 0; j < MAX_SLOTS; ++j )
+ StrBuf->Printf(&buf, "('%d', '%d', '%d', '%d', '%d', '%d', '%d', '%u', '%d', '%d', '%"PRIu64"'",
+ id, items[i].nameid, items[i].amount, items[i].equip, items[i].identify, items[i].refine, items[i].attribute, items[i].expire_time, items[i].favorite, items[i].bound, items[i].unique_id);
+ for( j = 0; j < MAX_SLOTS; ++j )
StrBuf->Printf(&buf, ", '%d'", items[i].card[j]);
StrBuf->AppendStr(&buf, ")");
-
- updateLastUid(items[i].unique_id);// Unique Non Stackable Item ID
}
- dbUpdateUid(sql_handle);
if( found && SQL_ERROR == SQL->QueryStr(sql_handle, StrBuf->Value(&buf)) ) {
Sql_ShowDebug(sql_handle);
@@ -984,6 +1008,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
struct mmo_charstatus p;
int j = 0, i;
char last_map[MAP_NAME_LENGTH_EXT];
+ time_t unban_time = 0;
stmt = SQL->StmtMalloc(sql_handle);
if( stmt == NULL ) {
@@ -992,8 +1017,10 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
}
memset(&p, 0, sizeof(p));
- for(i = 0 ; i < MAX_CHARS; i++ )
+ for(i = 0 ; i < MAX_CHARS; i++ ) {
sd->found_char[i] = -1;
+ sd->unban_time[i] = 0;
+ }
// read char data
if( SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT "
@@ -1001,7 +1028,7 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
"`str`,`agi`,`vit`,`int`,`dex`,`luk`,`max_hp`,`hp`,`max_sp`,`sp`,"
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`hair`,`hair_color`,"
"`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`rename`,`delete_date`,"
- "`robe`,`slotchange`"
+ "`robe`,`slotchange`,`unban_time`"
" FROM `%s` WHERE `account_id`='%d' AND `char_num` < '%d'", char_db, sd->account_id, MAX_CHARS)
|| SQL_ERROR == SQL->StmtExecute(stmt)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &p.char_id, 0, NULL, NULL)
@@ -1037,10 +1064,11 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 30, SQLDT_SHORT, &p.head_mid, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 31, SQLDT_SHORT, &p.head_bottom, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 32, SQLDT_STRING, &last_map, sizeof(last_map), NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 33, SQLDT_USHORT, &p.rename, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 33, SQLDT_USHORT, &p.rename, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 34, SQLDT_UINT32, &p.delete_date, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 35, SQLDT_SHORT, &p.robe, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 36, SQLDT_USHORT, &p.slotchange, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 37, SQLDT_LONG, &unban_time, 0, NULL, NULL)
)
{
SqlStmt_ShowDebug(stmt);
@@ -1049,8 +1077,9 @@ int mmo_chars_fromsql(struct char_session_data* sd, uint8* buf)
}
for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SQL->StmtNextRow(stmt); i++ ) {
- p.last_point.map = mapindex_name2id(last_map);
+ p.last_point.map = mapindex->name2id(last_map);
sd->found_char[p.slot] = p.char_id;
+ sd->unban_time[p.slot] = unban_time;
j += mmo_char_tobuf(WBUFP(buf, j), &p);
}
@@ -1080,6 +1109,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
int hotkey_num;
#endif
unsigned int opt;
+ int account_id;
memset(p, 0, sizeof(struct mmo_charstatus));
@@ -1099,7 +1129,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
"`status_point`,`skill_point`,`option`,`karma`,`manner`,`party_id`,`guild_id`,`pet_id`,`homun_id`,`elemental_id`,`hair`,"
"`hair_color`,`clothes_color`,`weapon`,`shield`,`head_top`,`head_mid`,`head_bottom`,`last_map`,`last_x`,`last_y`,"
"`save_map`,`save_x`,`save_y`,`partner_id`,`father`,`mother`,`child`,`fame`,`rename`,`delete_date`,`robe`,`slotchange`,"
- "`char_opt`"
+ "`char_opt`,`font`,`uniqueitem_counter`"
" FROM `%s` WHERE `char_id`=? LIMIT 1", char_db)
|| SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|| SQL_ERROR == SQL->StmtExecute(stmt)
@@ -1132,7 +1162,7 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 26, SQLDT_INT, &p->guild_id, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 27, SQLDT_INT, &p->pet_id, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 28, SQLDT_INT, &p->hom_id, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 29, SQLDT_INT, &p->ele_id, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 30, SQLDT_SHORT, &p->hair, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 31, SQLDT_SHORT, &p->hair_color, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 32, SQLDT_SHORT, &p->clothes_color, 0, NULL, NULL)
@@ -1152,11 +1182,13 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 46, SQLDT_INT, &p->mother, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 47, SQLDT_INT, &p->child, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 48, SQLDT_INT, &p->fame, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 49, SQLDT_USHORT, &p->rename, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 49, SQLDT_USHORT, &p->rename, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 50, SQLDT_UINT32, &p->delete_date, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 51, SQLDT_SHORT, &p->robe, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 52, SQLDT_USHORT, &p->slotchange, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 53, SQLDT_UINT, &opt, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 53, SQLDT_UINT, &opt, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 54, SQLDT_UCHAR, &p->font, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 55, SQLDT_UINT, &p->uniqueitem_counter, 0, NULL, NULL)
)
{
SqlStmt_ShowDebug(stmt);
@@ -1169,17 +1201,20 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
SQL->StmtFree(stmt);
return 0;
}
- p->last_point.map = mapindex_name2id(last_map);
- p->save_point.map = mapindex_name2id(save_map);
+
+ account_id = p->account_id;
+
+ p->last_point.map = mapindex->name2id(last_map);
+ p->save_point.map = mapindex->name2id(save_map);
if( p->last_point.map == 0 ) {
- p->last_point.map = (unsigned short)strdb_iget(mapindex_db, MAP_DEFAULT);
+ p->last_point.map = (unsigned short)strdb_iget(mapindex->db, MAP_DEFAULT);
p->last_point.x = MAP_DEFAULT_X;
p->last_point.y = MAP_DEFAULT_Y;
}
if( p->save_point.map == 0 ) {
- p->save_point.map = (unsigned short)strdb_iget(mapindex_db, MAP_DEFAULT);
+ p->save_point.map = (unsigned short)strdb_iget(mapindex->db, MAP_DEFAULT);
p->save_point.x = MAP_DEFAULT_X;
p->save_point.y = MAP_DEFAULT_Y;
}
@@ -1203,35 +1238,36 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_MEMOPOINTS && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i ) {
- tmp_point.map = mapindex_name2id(point_map);
+ tmp_point.map = mapindex->name2id(point_map);
memcpy(&p->memo_point[i], &tmp_point, sizeof(tmp_point));
}
strcat(t_msg, " memo");
//read inventory
- //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `unique_id`)
- StrBuf->Init(&buf);
- StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `unique_id`");
- for( i = 0; i < MAX_SLOTS; ++i )
+ //`inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, `expire_time`, `favorite`, `bound`, `unique_id`)
+ StrBuf->Init(&buf);
+ StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `favorite`, `bound`, `unique_id`");
+ for( i = 0; i < MAX_SLOTS; ++i )
StrBuf->Printf(&buf, ", `card%d`", i);
StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", inventory_db, MAX_INVENTORY);
if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
|| SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|| SQL_ERROR == SQL->StmtExecute(stmt)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) )
- SqlStmt_ShowDebug(stmt);
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &tmp_item.equip, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_CHAR, &tmp_item.favorite, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_UCHAR, &tmp_item.bound, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 10, SQLDT_UINT64, &tmp_item.unique_id, 0, NULL, NULL) )
+ SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_SLOTS; ++i )
- if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
+ if( SQL_ERROR == SQL->StmtBindColumn(stmt, 11+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_INVENTORY && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i )
@@ -1240,28 +1276,30 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
strcat(t_msg, " inventory");
//read cart
- //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `unique_id`)
- StrBuf->Clear(&buf);
- StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `unique_id`");
- for( j = 0; j < MAX_SLOTS; ++j )
+ //`cart_inventory` (`id`,`char_id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `card0`, `card1`, `card2`, `card3`, expire_time`, `bound`, `unique_id`)
+ StrBuf->Clear(&buf);
+ StrBuf->AppendStr(&buf, "SELECT `id`, `nameid`, `amount`, `equip`, `identify`, `refine`, `attribute`, `expire_time`, `bound`, `unique_id`");
+ for( j = 0; j < MAX_SLOTS; ++j )
StrBuf->Printf(&buf, ", `card%d`", j);
StrBuf->Printf(&buf, " FROM `%s` WHERE `char_id`=? LIMIT %d", cart_db, MAX_CART);
+ memset(&tmp_item, 0, sizeof(tmp_item));
if( SQL_ERROR == SQL->StmtPrepareStr(stmt, StrBuf->Value(&buf))
|| SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &char_id, 0)
|| SQL_ERROR == SQL->StmtExecute(stmt)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &tmp_item.id, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_SHORT, &tmp_item.nameid, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_SHORT, &tmp_item.amount, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &tmp_item.equip, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_UINT, &tmp_item.equip, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 4, SQLDT_CHAR, &tmp_item.identify, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 5, SQLDT_CHAR, &tmp_item.refine, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 6, SQLDT_CHAR, &tmp_item.attribute, 0, NULL, NULL)
|| SQL_ERROR == SQL->StmtBindColumn(stmt, 7, SQLDT_UINT, &tmp_item.expire_time, 0, NULL, NULL)
- || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_ULONGLONG, &tmp_item.unique_id, 0, NULL, NULL) )
- SqlStmt_ShowDebug(stmt);
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 8, SQLDT_UCHAR, &tmp_item.bound, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 9, SQLDT_UINT64, &tmp_item.unique_id, 0, NULL, NULL) )
+ SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_SLOTS; ++i )
- if( SQL_ERROR == SQL->StmtBindColumn(stmt, 9+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
+ if( SQL_ERROR == SQL->StmtBindColumn(stmt, 10+i, SQLDT_SHORT, &tmp_item.card[i], 0, NULL, NULL) )
SqlStmt_ShowDebug(stmt);
for( i = 0; i < MAX_CART && SQL_SUCCESS == SQL->StmtNextRow(stmt); ++i )
@@ -1333,8 +1371,23 @@ int mmo_char_fromsql(int char_id, struct mmo_charstatus* p, bool load_everything
mercenary_owner_fromsql(char_id, p);
strcat(t_msg, " mercenary");
+ /* default */
+ p->mod_exp = p->mod_drop = p->mod_death = 100;
+
+ //`account_data` (`account_id`,`bank_vault`,`base_exp`,`base_drop`,`base_death`)
+ if( SQL_ERROR == SQL->StmtPrepare(stmt, "SELECT `bank_vault`,`base_exp`,`base_drop`,`base_death` FROM `%s` WHERE `account_id`=? LIMIT 1", account_data_db)
+ || SQL_ERROR == SQL->StmtBindParam(stmt, 0, SQLDT_INT, &account_id, 0)
+ || SQL_ERROR == SQL->StmtExecute(stmt)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 0, SQLDT_INT, &p->bank_vault, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 1, SQLDT_USHORT, &p->mod_exp, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 2, SQLDT_USHORT, &p->mod_drop, 0, NULL, NULL)
+ || SQL_ERROR == SQL->StmtBindColumn(stmt, 3, SQLDT_USHORT, &p->mod_death, 0, NULL, NULL) )
+ SqlStmt_ShowDebug(stmt);
+
+ if( SQL_SUCCESS == SQL->StmtNextRow(stmt) )
+ strcat(t_msg, " accdata");
- if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfuly!
+ if (save_log) ShowInfo("Loaded char (%d - %s): %s\n", char_id, p->name, t_msg); //ok. all data load successfully!
SQL->StmtFree(stmt);
StrBuf->Destroy(&buf);
@@ -1360,7 +1413,7 @@ int mmo_char_sql_init(void)
//and send the loginserver the new state....
// Force all users offline in sql when starting char-server
- // (useful when servers crashs and don't clean the database)
+ // (useful when servers crashes and don't clean the database)
set_all_offline_sql();
return 0;
@@ -1415,7 +1468,7 @@ bool char_slotchange(struct char_session_data *sd, int fd, unsigned short from,
}
//-----------------------------------
-// Function to change chararcter's names
+// Function to change character's names
//-----------------------------------
int rename_char_sql(struct char_session_data *sd, int char_id)
{
@@ -1456,9 +1509,10 @@ int rename_char_sql(struct char_session_data *sd, int char_id)
// log change
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', '0', '0', '0', '0', '0', '0', '0', '0')",
- charlog_db, "change char name", sd->account_id, char_dat.slot, esc_name) )
+ if( SQL_ERROR == SQL->Query(sql_handle,
+ "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)"
+ "VALUES (NOW(), '%s', '%d', '%d', '%d', '%s', '0', '0', '0', '0', '0', '0', '0', '0')",
+ charlog_db, "change char name", sd->account_id, char_dat.char_id, char_dat.slot, esc_name) )
Sql_ShowDebug(sql_handle);
}
@@ -1486,9 +1540,9 @@ int check_char_name(char * name, char * esc_name)
if( strcmpi(name, wisp_server_name) == 0 )
return -1; // nick reserved for internal server messages
- // Check Authorised letters/symbols in the name of the character
+ // Check Authorized letters/symbols in the name of the character
if( char_name_option == 1 )
- { // only letters/symbols in char_name_letters are authorised
+ { // only letters/symbols in char_name_letters are authorized
for( i = 0; i < NAME_LENGTH && name[i]; i++ )
if( strchr(char_name_letters, name[i]) == NULL )
return -2;
@@ -1497,7 +1551,7 @@ int check_char_name(char * name, char * esc_name)
{ // letters/symbols in char_name_letters are forbidden
for( i = 0; i < NAME_LENGTH && name[i]; i++ )
if( strchr(char_name_letters, name[i]) != NULL )
- return -2;
+ return -5;
}
if( name_ignoring_case ) {
if( SQL_ERROR == SQL->Query(sql_handle, "SELECT 1 FROM `%s` WHERE BINARY `name` = '%s' LIMIT 1", char_db, esc_name) ) {
@@ -1516,9 +1570,16 @@ int check_char_name(char * name, char * esc_name)
return 0;
}
-//-----------------------------------
-// Function to create a new character
-//-----------------------------------
+/**
+ * Creates a new character
+ * Return values:
+ * -1: 'Charname already exists'
+ * -2: 'Char creation denied'/ Unknown error
+ * -3: 'You are underaged'
+ * -4: 'You are not eligible to open the Character Slot.'
+ * -5: 'Symbols in Character Names are forbidden'
+ * char_id: Success
+ **/
#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;
@@ -1528,7 +1589,7 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag
char name[NAME_LENGTH];
char esc_name[NAME_LENGTH*2+1];
- int char_id, flag, k;
+ int char_id, flag, k, l;
safestrncpy(name, name_, NAME_LENGTH);
normalize_name(name,TRIM_CHARS);
@@ -1557,13 +1618,6 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag
if( sd->found_char[slot] != -1 )
return -2; /* character account limit exceeded */
- // 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`,"
@@ -1591,11 +1645,40 @@ int make_new_char_sql(struct char_session_data* sd, char* name_, int str, int ag
#endif
//Retrieve the newly auto-generated char id
char_id = (int)SQL->LastInsertId(sql_handle);
+
+ if( !char_id )
+ return -2;
+
+ // Validation success, log result
+ if (log_char) {
+ if( SQL_ERROR == SQL->Query(sql_handle, "INSERT INTO `%s` (`time`, `char_msg`,`account_id`,`char_id`,`char_num`,`name`,`str`,`agi`,`vit`,`int`,`dex`,`luk`,`hair`,`hair_color`)"
+ "VALUES (NOW(), '%s', '%d', '%d', '%d', '%s', '%d', '%d', '%d', '%d', '%d', '%d', '%d', '%d')",
+ charlog_db, "make new char", sd->account_id, char_id, slot, esc_name, str, agi, vit, int_, dex, luk, hair_style, hair_color) )
+ Sql_ShowDebug(sql_handle);
+ }
+
//Give the char the default items
-
- for (k = 0; k < ARRAYLENGTH(start_items) && start_items[k] != 0; k += 2) {
- 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_items[k], start_items[k + 1], 1) )
- Sql_ShowDebug(sql_handle);
+ for (k = 0; k < ARRAYLENGTH(start_items) && start_items[k] != 0; k += 3) {
+ // FIXME: How to define if an item is stackable without having to lookup itemdb? [panikon]
+ if( start_items[k+2] == 1 )
+ {
+ 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_items[k], start_items[k + 1], 1) )
+ Sql_ShowDebug(sql_handle);
+ }
+ else if( start_items[k+2] == 0 )
+ {
+ // Non-stackable items should have their own entries (issue: 7279)
+ for( l = 0; l < start_items[k+1]; l++ )
+ {
+ 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_items[k], 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);
@@ -1655,8 +1738,8 @@ int delete_char_sql(int char_id)
SQL->GetData(sql_handle, 6, &data, NULL); partner_id = atoi(data);
SQL->GetData(sql_handle, 7, &data, NULL); father_id = atoi(data);
SQL->GetData(sql_handle, 8, &data, NULL); mother_id = atoi(data);
- SQL->GetData(sql_handle, 9, &data, NULL);
- elemental_id = atoi(data);
+ SQL->GetData(sql_handle, 9, &data, NULL);
+ elemental_id = atoi(data);
SQL->EscapeStringLen(sql_handle, esc_name, name, min(len, NAME_LENGTH));
SQL->FreeResult(sql_handle);
@@ -1697,7 +1780,7 @@ int delete_char_sql(int char_id)
/* delete char's pet */
//Delete the hatched pet if you have one...
- if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incuvate` = '0'", pet_db, char_id) )
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d' AND `incubate` = '0'", pet_db, char_id) )
Sql_ShowDebug(sql_handle);
//Delete all pets that are stored in eggs (inventory + cart)
@@ -1710,9 +1793,9 @@ int delete_char_sql(int char_id)
if( hom_id )
mapif_homunculus_delete(hom_id);
- /* remove elemental */
- if (elemental_id)
- mapif_elemental_delete(elemental_id);
+ /* remove elemental */
+ if (elemental_id)
+ mapif_elemental_delete(elemental_id);
/* remove mercenary data */
mercenary_owner_delete(char_id);
@@ -1745,7 +1828,9 @@ int delete_char_sql(int char_id)
Sql_ShowDebug(sql_handle);
/* delete character registry */
- if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `type`=3 AND `char_id`='%d'", reg_db, char_id) )
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_reg_str_db, char_id) )
+ Sql_ShowDebug(sql_handle);
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_reg_num_db, char_id) )
Sql_ShowDebug(sql_handle);
/* delete skills */
@@ -1762,15 +1847,16 @@ int delete_char_sql(int char_id)
Sql_ShowDebug(sql_handle);
#endif
- if (log_char) {
- if( SQL_ERROR == SQL->Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`char_msg`,`name`) VALUES (NOW(), '%d', '%d', 'Deleted char (CID %d)', '%s')",
- charlog_db, account_id, 0, char_id, esc_name) )
- Sql_ShowDebug(sql_handle);
- }
-
/* delete character */
if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `char_id`='%d'", char_db, char_id) )
Sql_ShowDebug(sql_handle);
+ else if( log_char ) {
+ if( SQL_ERROR == SQL->Query(sql_handle,
+ "INSERT INTO `%s`(`time`, `account_id`, `char_id`, `char_num`, `char_msg`, `name`)"
+ " VALUES (NOW(), '%d', '%d', '%d', 'Deleted character', '%s')",
+ charlog_db, account_id, char_id, 0, esc_name) )
+ Sql_ShowDebug(sql_handle);
+ }
/* No need as we used inter_guild_leave [Skotlex]
// Also delete info from guildtables.
@@ -1807,8 +1893,7 @@ int count_users(void)
// Used in packets 0x6b (chars info) and 0x6d (new char info)
// Returns the size
#define MAX_CHAR_BUF 144 //Max size (for WFIFOHEAD calls)
-int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
-{
+int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p) {
unsigned short offset = 0;
uint8* buf;
@@ -1827,10 +1912,15 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFL(buf,32) = p->karma;
WBUFL(buf,36) = p->manner;
WBUFW(buf,40) = min(p->status_point, INT16_MAX);
+#if PACKETVER > 20081217
WBUFL(buf,42) = p->hp;
WBUFL(buf,46) = p->max_hp;
offset+=4;
buf = WBUFP(buffer,offset);
+#else
+ WBUFW(buf,42) = min(p->hp, INT16_MAX);
+ WBUFW(buf,44) = min(p->max_hp, INT16_MAX);
+#endif
WBUFW(buf,46) = min(p->sp, INT16_MAX);
WBUFW(buf,48) = min(p->max_sp, INT16_MAX);
WBUFW(buf,50) = DEFAULT_WALK_SPEED; // p->speed;
@@ -1856,14 +1946,16 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
WBUFB(buf,102) = min(p->dex, UINT8_MAX);
WBUFB(buf,103) = min(p->luk, UINT8_MAX);
WBUFW(buf,104) = p->slot;
+#if PACKETVER >= 20061023
WBUFW(buf,106) = ( p->rename > 0 ) ? 0 : 1;
offset += 2;
+#endif
#if (PACKETVER >= 20100720 && PACKETVER <= 20100727) || PACKETVER >= 20100803
- mapindex_getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108));
+ mapindex->getmapname_ext(mapindex_id2name(p->last_point.map), (char*)WBUFP(buf,108));
offset += MAP_NAME_LENGTH_EXT;
#endif
#if PACKETVER >= 20100803
- WBUFL(buf,124) = TOL(p->delete_date);
+ WBUFL(buf,124) = (int)p->delete_date;
offset += 4;
#endif
#if PACKETVER >= 20110111
@@ -1883,6 +1975,7 @@ int mmo_char_tobuf(uint8* buffer, struct mmo_charstatus* p)
return 106+offset;
}
+
/* Made Possible by Yommy~! <3 */
void mmo_char_send099d(int fd, struct char_session_data *sd) {
WFIFOHEAD(fd,4 + (MAX_CHARS*MAX_CHAR_BUF));
@@ -1890,6 +1983,44 @@ void mmo_char_send099d(int fd, struct char_session_data *sd) {
WFIFOW(fd,2) = mmo_chars_fromsql(sd, WFIFOP(fd,4)) + 4;
WFIFOSET(fd,WFIFOW(fd,2));
}
+/* Sends character ban list */
+/* Made Possible by Yommy~! <3 */
+void mmo_char_send020d(int fd, struct char_session_data *sd) {
+ int i;
+ time_t now = time(NULL);
+
+ ARR_FIND(0, MAX_CHARS, i, sd->unban_time[i]);
+
+ if( i != MAX_CHARS ) {
+ int c;
+
+ WFIFOHEAD(fd, 4 + (MAX_CHARS*24));
+
+ WFIFOW(fd, 0) = 0x20d;
+
+ for(i = 0, c = 0; i < MAX_CHARS; i++) {
+ if( sd->unban_time[i] ) {
+ timestamp2string((char*)WFIFOP(fd,8 + (28*c)), 20, sd->unban_time[i], "%Y-%m-%d %H:%M:%S");
+
+ if( sd->unban_time[i] > now )
+ WFIFOL(fd, 4 + (24*c)) = sd->found_char[i];
+ else {
+ /* reset -- client keeps this information even if you logout so we need to clear */
+ WFIFOL(fd, 4 + (24*c)) = 0;
+ /* also update on mysql */
+ sd->unban_time[i] = 0;
+ if( SQL_ERROR == SQL->Query(sql_handle, "UPDATE `%s` SET `unban_time`='0' WHERE `char_id`='%d' LIMIT 1", char_db, sd->found_char[i]) )
+ Sql_ShowDebug(sql_handle);
+ }
+ c++;
+ }
+ }
+
+ WFIFOW(fd, 2) = 4 + (24*c);
+
+ WFIFOSET(fd, WFIFOW(fd, 2));
+ }
+}
int mmo_char_send006b(int fd, struct char_session_data* sd);
//----------------------------------------
// [Ind/Hercules] notify client about charselect window data
@@ -1917,7 +2048,7 @@ int mmo_char_send006b(int fd, struct char_session_data* sd)
int j, offset = 0;
#if PACKETVER >= 20100413
offset += 3;
-#endif
+#endif
if (save_log)
ShowInfo("Loading Char Data ("CL_BOLD"%d"CL_RESET")\n",sd->account_id);
@@ -2011,8 +2142,8 @@ void disconnect_player(int account_id)
struct char_session_data* sd;
// disconnect player if online on char-server
- ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id );
- if( i < fd_max )
+ ARR_FIND( 0, sockt->fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->account_id == account_id );
+ if( i < sockt->fd_max )
set_eof(i);
}
@@ -2026,7 +2157,7 @@ static void char_auth_ok(int fd, struct char_session_data *sd)
{ //Character already online. KICK KICK KICK
mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
if (character->waiting_disconnect == INVALID_TIMER)
- character->waiting_disconnect = iTimer->add_timer(iTimer->gettick()+20000, chardb_waiting_disconnect, character->account_id, 0);
+ character->waiting_disconnect = timer->add(timer->gettick()+20000, chardb_waiting_disconnect, character->account_id, 0);
if (character)
character->pincode_enable = -1;
WFIFOHEAD(fd,3);
@@ -2063,7 +2194,7 @@ static void char_auth_ok(int fd, struct char_session_data *sd)
// continues when account data is received...
}
-int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data);
+int send_accounts_tologin(int tid, int64 tick, int id, intptr_t data);
void mapif_server_reset(int id);
@@ -2071,7 +2202,7 @@ void mapif_server_reset(int id);
void loginif_reset(void)
{
int id;
- // TODO kick everyone out and reset everything or wait for connect and try to reaquire locks [FlavioJS]
+ // TODO kick everyone out and reset everything or wait for connect and try to reacquire locks [FlavioJS]
for( id = 0; id < ARRAYLENGTH(server); ++id )
mapif_server_reset(id);
flush_fifos();
@@ -2105,7 +2236,7 @@ void loginif_on_ready(void)
loginif_check_shutdown();
//Send online accounts to login server.
- send_accounts_tologin(INVALID_TIMER, iTimer->gettick(), 0, 0);
+ send_accounts_tologin(INVALID_TIMER, timer->gettick(), 0, 0);
// if no map-server already connected, display a message...
ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd > 0 && server[i].map[0] );
@@ -2116,7 +2247,6 @@ void loginif_on_ready(void)
int parse_fromlogin(int fd) {
struct char_session_data* sd = NULL;
- int i;
// only process data from the login-server
if( fd != login_fd ) {
@@ -2131,7 +2261,7 @@ int parse_fromlogin(int fd) {
loginif_on_disconnect();
return 0;
} else if ( session[fd]->flag.ping ) {/* we've reached stall time */
- if( DIFF_TICK(last_tick, session[fd]->rdata_tick) > (stall_time * 2) ) {/* we can't wait any longer */
+ if( DIFF_TICK(sockt->last_tick, session[fd]->rdata_tick) > (sockt->stall_time * 2) ) {/* we can't wait any longer */
set_eof(fd);
return 0;
} else if( session[fd]->flag.ping != 2 ) { /* we haven't sent ping out yet */
@@ -2147,9 +2277,16 @@ int parse_fromlogin(int fd) {
while(RFIFOREST(fd) >= 2) {
uint16 command = RFIFOW(fd,0);
+
+ if( HPM->packetsc[hpParse_FromLogin] ) {
+ int success = HPM->parse_packets(fd,hpParse_FromLogin);
+ if( success == 1 ) continue;
+ else if( success == 2 ) return 0;
+ }
+
switch( command ) {
- // acknowledgement of connect-to-loginserver request
+ // acknowledgment of connect-to-loginserver request
case 0x2711:
if (RFIFOREST(fd) < 3)
return 0;
@@ -2169,9 +2306,9 @@ int parse_fromlogin(int fd) {
RFIFOSKIP(fd,3);
break;
- // acknowledgement of account authentication request
+ // acknowledgment of account authentication request
case 0x2713:
- if (RFIFOREST(fd) < 25)
+ if (RFIFOREST(fd) < 33)
return 0;
{
int account_id = RFIFOL(fd,2);
@@ -2182,7 +2319,9 @@ int parse_fromlogin(int fd) {
int request_id = RFIFOL(fd,16);
uint32 version = RFIFOL(fd,20);
uint8 clienttype = RFIFOB(fd,24);
- RFIFOSKIP(fd,25);
+ int group_id = RFIFOL(fd,25);
+ unsigned int expiration_time = RFIFOL(fd, 29);
+ RFIFOSKIP(fd,33);
if( session_isActive(request_id) && (sd=(struct char_session_data*)session[request_id]->session_data) &&
!sd->auth && sd->account_id == account_id && sd->login_id1 == login_id1 && sd->login_id2 == login_id2 && sd->sex == sex )
@@ -2190,30 +2329,46 @@ int parse_fromlogin(int fd) {
int client_fd = request_id;
sd->version = version;
sd->clienttype = clienttype;
- switch( result )
- {
- case 0:// ok
- char_auth_ok(client_fd, sd);
- break;
- case 1:// auth failed
- WFIFOHEAD(client_fd,3);
- WFIFOW(client_fd,0) = 0x6c;
- WFIFOB(client_fd,2) = 0;// rejected from server
- WFIFOSET(client_fd,3);
- break;
+ switch( result ) {
+ case 0:// ok
+ /* restrictions apply */
+ if( char_server_type == CST_MAINTENANCE && group_id < char_maintenance_min_group_id ) {
+ WFIFOHEAD(client_fd,3);
+ WFIFOW(client_fd,0) = 0x6c;
+ WFIFOB(client_fd,2) = 0;// rejected from server
+ WFIFOSET(client_fd,3);
+ break;
+ }
+ /* the client will already deny this request, this check is to avoid someone bypassing. */
+ if( char_server_type == CST_PAYING && (time_t)expiration_time < time(NULL) ) {
+ WFIFOHEAD(client_fd,3);
+ WFIFOW(client_fd,0) = 0x6c;
+ WFIFOB(client_fd,2) = 0;// rejected from server
+ WFIFOSET(client_fd,3);
+ break;
+ }
+ char_auth_ok(client_fd, sd);
+ break;
+ case 1:// auth failed
+ WFIFOHEAD(client_fd,3);
+ WFIFOW(client_fd,0) = 0x6c;
+ WFIFOB(client_fd,2) = 0;// rejected from server
+ WFIFOSET(client_fd,3);
+ break;
}
}
}
break;
case 0x2717: // account data
+ {
+ int i;
if (RFIFOREST(fd) < 72)
return 0;
// find the authenticated session with this account id
- ARR_FIND( 0, fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) );
- if( i < fd_max ) {
- int server_id;
+ ARR_FIND( 0, sockt->fd_max, i, session[i] && (sd = (struct char_session_data*)session[i]->session_data) && sd->auth && sd->account_id == RFIFOL(fd,2) );
+ if( i < sockt->fd_max ) {
memcpy(sd->email, RFIFOP(fd,6), 40);
sd->expiration_time = (time_t)RFIFOL(fd,46);
sd->group_id = RFIFOB(fd,50);
@@ -2226,10 +2381,8 @@ int parse_fromlogin(int fd) {
safestrncpy(sd->birthdate, (const char*)RFIFOP(fd,52), sizeof(sd->birthdate));
safestrncpy(sd->pincode, (const char*)RFIFOP(fd,63), sizeof(sd->pincode));
sd->pincode_change = RFIFOL(fd,68);
- ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
// continued from char_auth_ok...
- if( server_id == ARRAYLENGTH(server) || //server not online, bugreport:2359
- (max_connect_user == 0 && sd->group_id != gm_allow_group) ||
+ if( (max_connect_user == 0 && sd->group_id != gm_allow_group) ||
( max_connect_user > 0 && count_users() >= max_connect_user && sd->group_id != gm_allow_group ) ) {
// refuse connection (over populated)
WFIFOHEAD(i,3);
@@ -2243,12 +2396,16 @@ int parse_fromlogin(int fd) {
#else
mmo_char_send006b(i, sd);
#endif
+ #if PACKETVER >= 20060819
+ mmo_char_send020d(i, sd);
+ #endif
#if PACKETVER >= 20110309
pincode->handle(i, sd);
#endif
}
}
RFIFOSKIP(fd,72);
+ }
break;
// login-server alive packet
@@ -2266,70 +2423,82 @@ int parse_fromlogin(int fd) {
{
unsigned char buf[7];
+ int char_id[MAX_CHARS];
+ int class_[MAX_CHARS];
+ int guild_id[MAX_CHARS];
+ int num;
+ int i;
+ char* data;
+ struct auth_node* node;
+
int acc = RFIFOL(fd,2);
int sex = RFIFOB(fd,6);
+
RFIFOSKIP(fd,7);
- if( acc > 0 )
- {// TODO: Is this even possible?
- int char_id[MAX_CHARS];
- int class_[MAX_CHARS];
- int guild_id[MAX_CHARS];
- int num;
- char* data;
+ // This should _never_ happen
+ if( acc <= 0 ) {
+ ShowError("Received invalid account id from login server! (aid: %d)\n", acc);
+ return 0;
+ }
- struct auth_node* node = (struct auth_node*)idb_get(auth_db, acc);
- if( node != NULL )
- node->sex = sex;
+ node = (struct auth_node*)idb_get(auth_db, acc);
+ if( node != NULL )
+ node->sex = sex;
- // get characters
- if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
- Sql_ShowDebug(sql_handle);
- for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SQL->NextRow(sql_handle); ++i )
+ // get characters
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `char_id`,`class`,`guild_id` FROM `%s` WHERE `account_id` = '%d'", char_db, acc) )
+ Sql_ShowDebug(sql_handle);
+ for( i = 0; i < MAX_CHARS && SQL_SUCCESS == SQL->NextRow(sql_handle); ++i )
+ {
+ SQL->GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
+ SQL->GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
+ SQL->GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
+ }
+ num = i;
+ for( i = 0; i < num; ++i )
+ {
+ if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
+ class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
+ class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
+ class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
+ class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
+ class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
+ class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
{
- SQL->GetData(sql_handle, 0, &data, NULL); char_id[i] = atoi(data);
- SQL->GetData(sql_handle, 1, &data, NULL); class_[i] = atoi(data);
- SQL->GetData(sql_handle, 2, &data, NULL); guild_id[i] = atoi(data);
+ // job modification
+ if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
+ class_[i] = (sex ? JOB_BARD : JOB_DANCER);
+ else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
+ class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
+ else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
+ class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
+ else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
+ class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
+ else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
+ class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
+ else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
+ class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
+ else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
+ class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
}
- num = i;
- for( i = 0; i < num; ++i )
- {
- if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER ||
- class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY ||
- class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER ||
- class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER ||
- class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T ||
- class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER ||
- class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
- {
- // job modification
- if( class_[i] == JOB_BARD || class_[i] == JOB_DANCER )
- class_[i] = (sex ? JOB_BARD : JOB_DANCER);
- else if( class_[i] == JOB_CLOWN || class_[i] == JOB_GYPSY )
- class_[i] = (sex ? JOB_CLOWN : JOB_GYPSY);
- else if( class_[i] == JOB_BABY_BARD || class_[i] == JOB_BABY_DANCER )
- class_[i] = (sex ? JOB_BABY_BARD : JOB_BABY_DANCER);
- else if( class_[i] == JOB_MINSTREL || class_[i] == JOB_WANDERER )
- class_[i] = (sex ? JOB_MINSTREL : JOB_WANDERER);
- else if( class_[i] == JOB_MINSTREL_T || class_[i] == JOB_WANDERER_T )
- class_[i] = (sex ? JOB_MINSTREL_T : JOB_WANDERER_T);
- else if( class_[i] == JOB_BABY_MINSTREL || class_[i] == JOB_BABY_WANDERER )
- class_[i] = (sex ? JOB_BABY_MINSTREL : JOB_BABY_WANDERER);
- else if( class_[i] == JOB_KAGEROU || class_[i] == JOB_OBORO )
- class_[i] = (sex ? JOB_KAGEROU : JOB_OBORO);
- }
- if( SQL_ERROR == SQL->Query(sql_handle, "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', `head_bottom`='0' WHERE `char_id`='%d'", char_db, class_[i], char_id[i]) )
- Sql_ShowDebug(sql_handle);
+ if( SQL_ERROR == SQL->Query(sql_handle, "UPDATE `%s` SET `equip`='0' WHERE `char_id`='%d'", inventory_db, char_id[i]) )
+ Sql_ShowDebug(sql_handle);
- if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
- inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
- }
- SQL->FreeResult(sql_handle);
+ if( SQL_ERROR == SQL->Query(sql_handle,
+ "UPDATE `%s` SET `class`='%d', `weapon`='0', `shield`='0', `head_top`='0', `head_mid`='0', "
+ "`head_bottom`='0' WHERE `char_id`='%d'",
+ char_db, class_[i], char_id[i]) )
+ Sql_ShowDebug(sql_handle);
- // disconnect player if online on char-server
- disconnect_player(acc);
+ if( guild_id[i] )// If there is a guild, update the guild_member data [Skotlex]
+ inter_guild_sex_changed(guild_id[i], acc, char_id[i], sex);
}
+ SQL->FreeResult(sql_handle);
+
+ // disconnect player if online on char-server
+ disconnect_player(acc);
// notify all mapservers about this change
WBUFW(buf,0) = 0x2b0d;
@@ -2340,17 +2509,12 @@ int parse_fromlogin(int fd) {
break;
// reply to an account_reg2 registry request
- case 0x2729:
+ case 0x3804:
if (RFIFOREST(fd) < 4 || RFIFOREST(fd) < RFIFOW(fd,2))
return 0;
-
- { //Receive account_reg2 registry, forward to map servers.
- unsigned char buf[13+ACCOUNT_REG2_NUM*sizeof(struct global_reg)];
- memcpy(buf,RFIFOP(fd,0), RFIFOW(fd,2));
- WBUFW(buf,0) = 0x3804; //Map server can now receive all kinds of reg values with the same packet. [Skotlex]
- mapif_sendall(buf, WBUFW(buf,2));
+ //Receive account_reg2 registry, forward to map servers.
+ mapif_sendall(RFIFOP(fd, 0), RFIFOW(fd,2));
RFIFOSKIP(fd, RFIFOW(fd,2));
- }
break;
// State change of account/ban notification (from login-server)
@@ -2362,7 +2526,7 @@ int parse_fromlogin(int fd) {
unsigned char buf[11];
WBUFW(buf,0) = 0x2b14;
WBUFL(buf,2) = RFIFOL(fd,2);
- WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of statut, 1: ban
+ WBUFB(buf,6) = RFIFOB(fd,6); // 0: change of status, 1: ban
WBUFL(buf,7) = RFIFOL(fd,7); // status or final date of a banishment
mapif_sendall(buf, 11);
}
@@ -2386,14 +2550,14 @@ int parse_fromlogin(int fd) {
{ //Kick it from the map server it is on.
mapif_disconnectplayer(server[character->server].fd, character->account_id, character->char_id, 2);
if (character->waiting_disconnect == INVALID_TIMER)
- character->waiting_disconnect = iTimer->add_timer(iTimer->gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
+ character->waiting_disconnect = timer->add(timer->gettick()+AUTH_TIMEOUT, chardb_waiting_disconnect, character->account_id, 0);
}
else
{// Manual kick from char server.
struct char_session_data *tsd;
int i;
- ARR_FIND( 0, fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
- if( i < fd_max )
+ ARR_FIND( 0, sockt->fd_max, i, session[i] && (tsd = (struct char_session_data*)session[i]->session_data) && tsd->account_id == aid );
+ if( i < sockt->fd_max )
{
WFIFOHEAD(i,3);
WFIFOW(i,0) = 0x81;
@@ -2438,6 +2602,26 @@ int parse_fromlogin(int fd) {
}
break;
+ case 0x2736: // Failed accinfo lookup to forward to mapserver
+ if (RFIFOREST(fd) < 18)
+ return 0;
+
+ mapif_parse_accinfo2(false, RFIFOL(fd,2), RFIFOL(fd,6), RFIFOL(fd,10), RFIFOL(fd,14),
+ NULL, NULL, NULL, NULL, NULL, NULL, NULL, -1, 0, 0);
+ RFIFOSKIP(fd,18);
+ break;
+
+ case 0x2737: // Successful accinfo lookup to forward to mapserver
+ if (RFIFOREST(fd) < 183)
+ return 0;
+
+ mapif_parse_accinfo2(true, RFIFOL(fd,167), RFIFOL(fd,171), RFIFOL(fd,175), RFIFOL(fd,179),
+ (char*)RFIFOP(fd,2), (char*)RFIFOP(fd,26), (char*)RFIFOP(fd,59),
+ (char*)RFIFOP(fd,99), (char*)RFIFOP(fd,119), (char*)RFIFOP(fd,151),
+ (char*)RFIFOP(fd,156), RFIFOL(fd,115), RFIFOL(fd,143), RFIFOL(fd,147));
+ RFIFOSKIP(fd,183);
+ break;
+
default:
ShowError("Unknown packet 0x%04x received from login-server, disconnecting.\n", command);
set_eof(fd);
@@ -2449,18 +2633,17 @@ int parse_fromlogin(int fd) {
return 0;
}
-int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data);
-int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data);
+int check_connect_login_server(int tid, int64 tick, int id, intptr_t data);
void do_init_loginif(void)
{
// establish char-login connection if not present
- iTimer->add_timer_func_list(check_connect_login_server, "check_connect_login_server");
- iTimer->add_timer_interval(iTimer->gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000);
+ timer->add_func_list(check_connect_login_server, "check_connect_login_server");
+ timer->add_interval(timer->gettick() + 1000, check_connect_login_server, 0, 0, 10 * 1000);
// send a list of all online account IDs to login server
- iTimer->add_timer_func_list(send_accounts_tologin, "send_accounts_tologin");
- iTimer->add_timer_interval(iTimer->gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour
+ timer->add_func_list(send_accounts_tologin, "send_accounts_tologin");
+ timer->add_interval(timer->gettick() + 1000, send_accounts_tologin, 0, 0, 3600 * 1000); //Sync online accounts every hour
}
void do_final_loginif(void)
@@ -2484,23 +2667,77 @@ int request_accreg2(int account_id, int char_id)
}
return 0;
}
-
-//Send packet forward to login-server for account saving
-int save_accreg2(unsigned char* buf, int len)
-{
- if (login_fd > 0) {
- WFIFOHEAD(login_fd,len+4);
- memcpy(WFIFOP(login_fd,4), buf, len);
- WFIFOW(login_fd,0) = 0x2728;
- WFIFOW(login_fd,2) = len+4;
- WFIFOSET(login_fd,len+4);
- return 1;
+/**
+ * Handles global account reg saving that continues with global_accreg_to_login_add and global_accreg_to_send
+ **/
+void global_accreg_to_login_start (int account_id, int char_id) {
+ WFIFOHEAD(login_fd, 60000 + 300);
+ WFIFOW(login_fd,0) = 0x2728;
+ WFIFOW(login_fd,2) = 14;
+ WFIFOL(login_fd,4) = account_id;
+ WFIFOL(login_fd,8) = char_id;
+ WFIFOW(login_fd,12) = 0;/* count */
+}
+/**
+ * Completes global account reg saving that starts global_accreg_to_login_start and continues with global_accreg_to_login_add
+ **/
+void global_accreg_to_login_send (void) {
+ WFIFOSET(login_fd, WFIFOW(login_fd,2));
+}
+/**
+ * Handles global account reg saving that starts global_accreg_to_login_start and ends with global_accreg_to_send
+ **/
+void global_accreg_to_login_add (const char *key, unsigned int index, intptr_t val, bool is_string) {
+ int nlen = WFIFOW(login_fd, 2);
+ size_t len;
+
+ len = strlen(key)+1;
+
+ WFIFOB(login_fd, nlen) = (unsigned char)len;/* won't be higher; the column size is 32 */
+ nlen += 1;
+
+ safestrncpy((char*)WFIFOP(login_fd,nlen), key, len);
+ nlen += len;
+
+ WFIFOL(login_fd, nlen) = index;
+ nlen += 4;
+
+ if( is_string ) {
+ WFIFOB(login_fd, nlen) = val ? 2 : 3;
+ nlen += 1;
+
+ if( val ) {
+ char *sval = (char*)val;
+ len = strlen(sval)+1;
+
+ WFIFOB(login_fd, nlen) = (unsigned char)len;/* won't be higher; the column size is 254 */
+ nlen += 1;
+
+ safestrncpy((char*)WFIFOP(login_fd,nlen), sval, len);
+ nlen += len;
+ }
+
+ } else {
+ WFIFOB(login_fd, nlen) = val ? 0 : 1;
+ nlen += 1;
+
+ if( val ) {
+ WFIFOL(login_fd, nlen) = (int)val;
+ nlen += 4;
+ }
+
+ }
+
+ WFIFOW(login_fd,12) += 1;
+
+ WFIFOW(login_fd, 2) = nlen;
+ if( WFIFOW(login_fd, 2) > 60000 ) {
+ int account_id = WFIFOL(login_fd,4), char_id = WFIFOL(login_fd,8);
+ global_accreg_to_login_send();
+ global_accreg_to_login_start(account_id,char_id);/* prepare next */
}
- return 0;
}
-
-void char_read_fame_list(void)
-{
+void char_read_fame_list(void) {
int i;
char* data;
size_t len;
@@ -2558,8 +2795,7 @@ void char_read_fame_list(void)
}
// Send map-servers the fame ranking lists
-int char_send_fame_list(int fd)
-{
+int char_send_fame_list(int fd) {
int i, len = 8;
unsigned char buf[32000];
@@ -2594,8 +2830,7 @@ int char_send_fame_list(int fd)
return 0;
}
-void char_update_fame_list(int type, int index, int fame)
-{
+void char_update_fame_list(int type, int index, int fame) {
unsigned char buf[8];
WBUFW(buf,0) = 0x2b22;
WBUFB(buf,2) = type;
@@ -2681,6 +2916,16 @@ void mapif_on_disconnect(int id)
mapif_server_reset(id);
}
+void mapif_on_parse_accinfo(int account_id, int u_fd, int u_aid, int u_group, int map_fd) {
+ WFIFOHEAD(login_fd,22);
+ WFIFOW(login_fd,0) = 0x2740;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOL(login_fd,6) = u_fd;
+ WFIFOL(login_fd,10) = u_aid;
+ WFIFOL(login_fd,14) = u_group;
+ WFIFOL(login_fd,18) = map_fd;
+ WFIFOSET(login_fd,22);
+}
int parse_frommap(int fd)
{
@@ -2701,12 +2946,20 @@ int parse_frommap(int fd)
}
while(RFIFOREST(fd) >= 2) {
+
+ if( HPM->packetsc[hpParse_FromMap] ) {
+ if( (i = HPM->parse_packets(fd,hpParse_FromMap)) ) {
+ if( i == 1 ) continue;
+ if( i == 2 ) return 0;
+ }
+ }
+
switch(RFIFOW(fd,0)) {
case 0x2b0a:
if( RFIFOREST(fd) < RFIFOW(fd, 2) )
return 0;
- socket_datasync(fd, false);
+ sockt->datasync(fd, false);
RFIFOSKIP(fd,RFIFOW(fd,2));
break;
@@ -2796,14 +3049,14 @@ int parse_frommap(int fd)
int aid, cid;
aid = RFIFOL(fd,2);
cid = RFIFOL(fd,6);
- if( SQL_ERROR == SQL->Query(sql_handle, "SELECT type, tick, val1, val2, val3, val4 from `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `type`, `tick`, `val1`, `val2`, `val3`, `val4` "
+ "FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'",
scdata_db, aid, cid) )
{
Sql_ShowDebug(sql_handle);
break;
}
- if( SQL->NumRows(sql_handle) > 0 )
- {
+ if( SQL->NumRows(sql_handle) > 0 ) {
struct status_change_data scdata;
int count;
char* data;
@@ -2824,8 +3077,7 @@ int parse_frommap(int fd)
}
if (count >= 50)
ShowWarning("Too many status changes for %d:%d, some of them were not loaded.\n", aid, cid);
- if (count > 0)
- {
+ if (count > 0) {
WFIFOW(fd,2) = 14 + count*sizeof(struct status_change_data);
WFIFOW(fd,12) = count;
WFIFOSET(fd,WFIFOW(fd,2));
@@ -2834,6 +3086,14 @@ int parse_frommap(int fd)
if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
Sql_ShowDebug(sql_handle);
}
+ } else { //no sc (needs a response)
+ WFIFOHEAD(fd,14);
+ WFIFOW(fd,0) = 0x2b1d;
+ WFIFOW(fd,2) = 14;
+ WFIFOL(fd,4) = aid;
+ WFIFOL(fd,8) = cid;
+ WFIFOW(fd,12) = 0;
+ WFIFOSET(fd,WFIFOW(fd,2));
}
SQL->FreeResult(sql_handle);
#endif
@@ -2886,9 +3146,8 @@ int parse_frommap(int fd)
int aid = RFIFOL(fd,4), cid = RFIFOL(fd,8), size = RFIFOW(fd,2);
struct online_char_data* character;
- if (size - 13 != sizeof(struct mmo_charstatus))
- {
- ShowError("parse_from_map (save-char): Size mismatch! %d != %d\n", size-13, sizeof(struct mmo_charstatus));
+ if (size - 13 != sizeof(struct mmo_charstatus)) {
+ ShowError("parse_from_map (save-char): Size mismatch! %d != %"PRIuS"\n", size-13, sizeof(struct mmo_charstatus));
RFIFOSKIP(fd,size);
break;
}
@@ -2901,7 +3160,7 @@ int parse_frommap(int fd)
memcpy(&char_dat, RFIFOP(fd,13), sizeof(struct mmo_charstatus));
mmo_char_tosql(cid, &char_dat);
} else { //This may be valid on char-server reconnection, when re-sending characters that already logged off.
- ShowError("parse_from_map (save-char): Received data for non-existant/offline character (%d:%d).\n", aid, cid);
+ ShowError("parse_from_map (save-char): Received data for non-existing/offline character (%d:%d).\n", aid, cid);
set_char_online(id, cid, aid);
}
@@ -2919,14 +3178,15 @@ int parse_frommap(int fd)
break;
case 0x2b02: // req char selection
- if( RFIFOREST(fd) < 18 )
+ if( RFIFOREST(fd) < 22 )
return 0;
{
int account_id = RFIFOL(fd,2);
uint32 login_id1 = RFIFOL(fd,6);
uint32 login_id2 = RFIFOL(fd,10);
uint32 ip = RFIFOL(fd,14);
- RFIFOSKIP(fd,18);
+ int32 group_id = RFIFOL(fd, 18);
+ RFIFOSKIP(fd,22);
if( runflag != CHARSERVER_ST_RUNNING )
{
@@ -2946,8 +3206,10 @@ int parse_frommap(int fd)
node->char_id = 0;
node->login_id1 = login_id1;
node->login_id2 = login_id2;
+ node->group_id = group_id;
//node->sex = 0;
node->ip = ntohl(ip);
+ /* sounds troublesome. */
//node->expiration_time = 0; // unlimited/unknown time by default (not display in map-server)
//node->gmlevel = 0;
idb_put(auth_db, account_id, node);
@@ -3069,7 +3331,7 @@ int parse_frommap(int fd)
RFIFOSKIP(fd, 86);
break;
- case 0x2b0e: // Request from map-server to change an account's status (will just be forwarded to login server)
+ case 0x2b0e: // Request from map-server to change an account's or character's status (accounts will just be forwarded to login server)
if (RFIFOREST(fd) < 44)
return 0;
{
@@ -3078,7 +3340,7 @@ int parse_frommap(int fd)
int acc = RFIFOL(fd,2); // account_id of who ask (-1 if server itself made this request)
const char* name = (char*)RFIFOP(fd,6); // name of the target character
- int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban
+ int type = RFIFOW(fd,30); // type of operation: 1-block, 2-ban, 3-unblock, 4-unban, 5 changesex, 6 charban, 7 charunban
short year = RFIFOW(fd,32);
short month = RFIFOW(fd,34);
short day = RFIFOW(fd,36);
@@ -3088,25 +3350,22 @@ int parse_frommap(int fd)
RFIFOSKIP(fd,44);
SQL->EscapeStringLen(sql_handle, esc_name, name, strnlen(name, NAME_LENGTH));
- if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `account_id`,`name` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
+
+ if( SQL_ERROR == SQL->Query(sql_handle, "SELECT `account_id`,`char_id`,`unban_time` FROM `%s` WHERE `name` = '%s'", char_db, esc_name) )
Sql_ShowDebug(sql_handle);
- else
- if( SQL->NumRows(sql_handle) == 0 )
- {
+ else if( SQL->NumRows(sql_handle) == 0 ) {
result = 1; // 1-player not found
- }
- else
- if( SQL_SUCCESS != SQL->NextRow(sql_handle) )
+ } else if( SQL_SUCCESS != SQL->NextRow(sql_handle) ) {
Sql_ShowDebug(sql_handle);
- //FIXME: set proper result value?
- else
- {
- char name[NAME_LENGTH];
- int account_id;
+ result = 1; // 1-player not found
+ } else {
+ int account_id, char_id;
char* data;
+ time_t unban_time;
SQL->GetData(sql_handle, 0, &data, NULL); account_id = atoi(data);
- SQL->GetData(sql_handle, 1, &data, NULL); safestrncpy(name, data, sizeof(name));
+ SQL->GetData(sql_handle, 1, &data, NULL); char_id = atoi(data);
+ SQL->GetData(sql_handle, 2, &data, NULL); unban_time = atol(data);
if( login_fd <= 0 )
result = 3; // 3-login-server offline
@@ -3114,53 +3373,111 @@ int parse_frommap(int fd)
// else
// if( acc != -1 && isGM(acc) < isGM(account_id) )
// result = 2; // 2-gm level too low
- else
- switch( type ) {
- case 1: // block
- WFIFOHEAD(login_fd,10);
- WFIFOW(login_fd,0) = 0x2724;
- WFIFOL(login_fd,2) = account_id;
- WFIFOL(login_fd,6) = 5; // new account status
- WFIFOSET(login_fd,10);
- break;
- case 2: // ban
- WFIFOHEAD(login_fd,18);
- WFIFOW(login_fd, 0) = 0x2725;
- WFIFOL(login_fd, 2) = account_id;
- WFIFOW(login_fd, 6) = year;
- WFIFOW(login_fd, 8) = month;
- WFIFOW(login_fd,10) = day;
- WFIFOW(login_fd,12) = hour;
- WFIFOW(login_fd,14) = minute;
- WFIFOW(login_fd,16) = second;
- WFIFOSET(login_fd,18);
- break;
- case 3: // unblock
- WFIFOHEAD(login_fd,10);
- WFIFOW(login_fd,0) = 0x2724;
- WFIFOL(login_fd,2) = account_id;
- WFIFOL(login_fd,6) = 0; // new account status
- WFIFOSET(login_fd,10);
- break;
- case 4: // unban
- WFIFOHEAD(login_fd,6);
- WFIFOW(login_fd,0) = 0x272a;
- WFIFOL(login_fd,2) = account_id;
- WFIFOSET(login_fd,6);
- break;
- case 5: // changesex
- WFIFOHEAD(login_fd,6);
- WFIFOW(login_fd,0) = 0x2727;
- WFIFOL(login_fd,2) = account_id;
- WFIFOSET(login_fd,6);
- break;
+ else {
+ switch( type ) {
+ case 1: // block
+ WFIFOHEAD(login_fd,10);
+ WFIFOW(login_fd,0) = 0x2724;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOL(login_fd,6) = 5; // new account status
+ WFIFOSET(login_fd,10);
+ break;
+ case 2: // ban
+ WFIFOHEAD(login_fd,18);
+ WFIFOW(login_fd, 0) = 0x2725;
+ WFIFOL(login_fd, 2) = account_id;
+ WFIFOW(login_fd, 6) = year;
+ WFIFOW(login_fd, 8) = month;
+ WFIFOW(login_fd,10) = day;
+ WFIFOW(login_fd,12) = hour;
+ WFIFOW(login_fd,14) = minute;
+ WFIFOW(login_fd,16) = second;
+ WFIFOSET(login_fd,18);
+ break;
+ case 3: // unblock
+ WFIFOHEAD(login_fd,10);
+ WFIFOW(login_fd,0) = 0x2724;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOL(login_fd,6) = 0; // new account status
+ WFIFOSET(login_fd,10);
+ break;
+ case 4: // unban
+ WFIFOHEAD(login_fd,6);
+ WFIFOW(login_fd,0) = 0x272a;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOSET(login_fd,6);
+ break;
+ case 5: // changesex
+ WFIFOHEAD(login_fd,6);
+ WFIFOW(login_fd,0) = 0x2727;
+ WFIFOL(login_fd,2) = account_id;
+ WFIFOSET(login_fd,6);
+ break;
+ case 6: //char ban
+ /* handled by char server, so no redirection */
+ {
+ time_t timestamp;
+ struct tm *tmtime;
+ SqlStmt* stmt = SQL->StmtMalloc(sql_handle);
+
+ if (unban_time == 0 || unban_time < time(NULL))
+ timestamp = time(NULL); // new ban
+ else
+ timestamp = unban_time; // add to existing ban
+
+ tmtime = localtime(&timestamp);
+ tmtime->tm_year = tmtime->tm_year + year;
+ tmtime->tm_mon = tmtime->tm_mon + month;
+ tmtime->tm_mday = tmtime->tm_mday + day;
+ tmtime->tm_hour = tmtime->tm_hour + hour;
+ tmtime->tm_min = tmtime->tm_min + minute;
+ tmtime->tm_sec = tmtime->tm_sec + second;
+ timestamp = mktime(tmtime);
+
+ if( SQL_SUCCESS != SQL->StmtPrepare(stmt,
+ "UPDATE `%s` SET `unban_time` = ? WHERE `char_id` = ? LIMIT 1",
+ char_db)
+ || SQL_SUCCESS != SQL->StmtBindParam(stmt, 0, SQLDT_LONG, (void*)&timestamp, sizeof(timestamp))
+ || SQL_SUCCESS != SQL->StmtBindParam(stmt, 1, SQLDT_INT, (void*)&char_id, sizeof(char_id))
+ || SQL_SUCCESS != SQL->StmtExecute(stmt)
+
+ ) {
+ SqlStmt_ShowDebug(stmt);
+ }
+
+ SQL->StmtFree(stmt);
+
+ // condition applies; send to all map-servers to disconnect the player
+ if( timestamp > time(NULL) ) {
+ unsigned char buf[11];
+
+ WBUFW(buf,0) = 0x2b14;
+ WBUFL(buf,2) = char_id;
+ WBUFB(buf,6) = 2;
+ WBUFL(buf,7) = (unsigned int)timestamp;
+ mapif_sendall(buf, 11);
+
+ // disconnect player if online on char-server
+ disconnect_player(account_id);
+ }
+ }
+ break;
+ case 7: //char unban
+ /* handled by char server, so no redirection */
+ if( SQL_ERROR == SQL->Query(sql_handle, "UPDATE `%s` SET `unban_time` = '0' WHERE `char_id` = '%d' LIMIT 1", char_db, char_id) ) {
+ Sql_ShowDebug(sql_handle);
+ result = 1;
+ }
+ break;
+
+ }
}
}
SQL->FreeResult(sql_handle);
// send answer if a player ask, not if the server ask
- if( acc != -1 && type != 5) { // Don't send answer for changesex
+ if( acc != -1 && type != 5 ) { // Don't send answer for changesex
WFIFOHEAD(fd,34);
WFIFOW(fd, 0) = 0x2b0f;
WFIFOL(fd, 2) = acc;
@@ -3184,12 +3501,11 @@ int parse_frommap(int fd)
int player_pos;
int fame_pos;
- switch(type)
- {
- case 1: size = fame_list_size_smith; list = smith_fame_list; break;
- case 2: size = fame_list_size_chemist; list = chemist_fame_list; break;
- case 3: size = fame_list_size_taekwon; list = taekwon_fame_list; break;
- default: size = 0; list = NULL; break;
+ switch(type) {
+ case RANKTYPE_BLACKSMITH: size = fame_list_size_smith; list = smith_fame_list; break;
+ case RANKTYPE_ALCHEMIST: size = fame_list_size_chemist; list = chemist_fame_list; break;
+ case RANKTYPE_TAEKWON: size = fame_list_size_taekwon; list = taekwon_fame_list; break;
+ default: size = 0; list = NULL; break;
}
ARR_FIND(0, size, player_pos, list[player_pos].id == cid);// position of the player
@@ -3197,22 +3513,20 @@ int parse_frommap(int fd)
if( player_pos == size && fame_pos == size )
;// not on list and not enough fame to get on it
- else if( fame_pos == player_pos )
- {// same position
+ else if( fame_pos == player_pos ) {
+ // same position
list[player_pos].fame = fame;
char_update_fame_list(type, player_pos, fame);
- }
- else
- {// move in the list
- if( player_pos == size )
- {// new ranker - not in the list
+ } else {
+ // move in the list
+ if( player_pos == size ) {
+ // new ranker - not in the list
ARR_MOVE(size - 1, fame_pos, list, struct fame_list);
list[fame_pos].id = cid;
list[fame_pos].fame = fame;
char_loadName(cid, list[fame_pos].name);
- }
- else
- {// already in the list
+ } else {
+ // already in the list
if( fame_pos == size )
--fame_pos;// move to the end of the list
ARR_MOVE(player_pos, fame_pos, list, struct fame_list);
@@ -3287,11 +3601,14 @@ int parse_frommap(int fd)
cid = RFIFOL(fd, 8);
count = RFIFOW(fd, 12);
+ /* clear; ensure no left overs e.g. permanent */
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id`='%d'", scdata_db, aid, cid) )
+ Sql_ShowDebug(sql_handle);
+
if( count > 0 )
{
struct status_change_data data;
StringBuf buf;
- int i;
StrBuf->Init(&buf);
StrBuf->Printf(&buf, "INSERT INTO `%s` (`account_id`, `char_id`, `type`, `tick`, `val1`, `val2`, `val3`, `val4`) VALUES ", scdata_db);
@@ -3320,14 +3637,14 @@ int parse_frommap(int fd)
break;
case 0x2b26: // auth request from map-server
- if (RFIFOREST(fd) < 19)
+ if (RFIFOREST(fd) < 20)
return 0;
{
int account_id;
int char_id;
int login_id1;
- char sex;
+ char sex, standalone;
uint32 ip;
struct auth_node* node;
struct mmo_charstatus* cd;
@@ -3338,15 +3655,36 @@ int parse_frommap(int fd)
login_id1 = RFIFOL(fd,10);
sex = RFIFOB(fd,14);
ip = ntohl(RFIFOL(fd,15));
- RFIFOSKIP(fd,19);
+ standalone = RFIFOB(fd, 19);
+ RFIFOSKIP(fd,20);
node = (struct auth_node*)idb_get(auth_db, account_id);
cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
- if( cd == NULL )
- { //Really shouldn't happen.
+
+ if( cd == NULL ) { //Really shouldn't happen.
mmo_char_fromsql(char_id, &char_dat, true);
cd = (struct mmo_charstatus*)uidb_get(char_db_,char_id);
}
+
+ if( runflag == CHARSERVER_ST_RUNNING && cd && standalone ) {
+ cd->sex = sex;
+
+ WFIFOHEAD(fd,25 + sizeof(struct mmo_charstatus));
+ WFIFOW(fd,0) = 0x2afd;
+ WFIFOW(fd,2) = 25 + sizeof(struct mmo_charstatus);
+ WFIFOL(fd,4) = account_id;
+ WFIFOL(fd,8) = 0;
+ WFIFOL(fd,12) = 0;
+ WFIFOL(fd,16) = 0;
+ WFIFOL(fd,20) = 0;
+ WFIFOB(fd,24) = 0;
+ memcpy(WFIFOP(fd,25), cd, sizeof(struct mmo_charstatus));
+ WFIFOSET(fd, WFIFOW(fd,2));
+
+ set_char_online(id, char_id, account_id);
+ break;
+ }
+
if( runflag == CHARSERVER_ST_RUNNING &&
cd != NULL &&
node != NULL &&
@@ -3429,6 +3767,40 @@ int parse_frommap(int fd)
RFIFOFLUSH(fd);
}
break;
+
+ /* individual sc data insertion/update */
+ case 0x2740:
+ if( RFIFOREST(fd) < 28 )
+ return 0;
+ else {
+ int account_id = RFIFOL(fd, 2), char_id = RFIFOL(fd, 6),
+ val1 = RFIFOL(fd, 12), val2 = RFIFOL(fd, 16),
+ val3 = RFIFOL(fd, 20), val4 = RFIFOL(fd, 24);
+ short type = RFIFOW(fd, 10);
+
+ if( SQL_ERROR == SQL->Query(sql_handle, "REPLACE INTO `%s` (`account_id`,`char_id`,`type`,`tick`,`val1`,`val2`,`val3`,`val4`) VALUES ('%d','%d','%d',-1,'%d','%d','%d','%d')",
+ scdata_db, account_id, char_id, type, val1, val2, val3, val4) )
+ Sql_ShowDebug(sql_handle);
+
+ RFIFOSKIP(fd, 28);
+ }
+ break;
+
+ /* individual sc data delete */
+ case 0x2741:
+ if( RFIFOREST(fd) < 12 )
+ return 0;
+ else {
+ int account_id = RFIFOL(fd, 2), char_id = RFIFOL(fd, 6);
+ short type = RFIFOW(fd, 10);
+
+ if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '%d' AND `char_id` = '%d' AND `type` = '%d' LIMIT 1",
+ scdata_db, account_id, char_id, type) )
+ Sql_ShowDebug(sql_handle);
+
+ RFIFOSKIP(fd, 12);
+ }
+ break;
default:
@@ -3507,6 +3879,7 @@ int lan_subnetcheck(uint32 ip)
}
+/// Answers to deletion request (HC_DELETE_CHAR3_RESERVED)
/// @param result
/// 0 (0x718): An unknown error has occurred.
/// 1: none/success
@@ -3520,7 +3893,12 @@ void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date)
WFIFOW(fd,0) = 0x828;
WFIFOL(fd,2) = char_id;
WFIFOL(fd,6) = result;
- WFIFOL(fd,10) = TOL(delete_date);
+#if PACKETVER >= 20130000
+ WFIFOL(fd,10) = (int)(delete_date - time(NULL));
+#else
+ WFIFOL(fd,10) = (int)delete_date;
+
+#endif
WFIFOSET(fd,14);
}
@@ -3535,6 +3913,14 @@ void char_delete2_ack(int fd, int char_id, uint32 result, time_t delete_date)
/// Any (0x718): An unknown error has occurred.
void char_delete2_accept_ack(int fd, int char_id, uint32 result)
{// HC: <082a>.W <char id>.L <Msg:0-5>.L
+
+#if PACKETVER >= 20130000 /* not sure the exact date -- must refresh or client gets stuck */
+ if( result == 1 ) {
+ struct char_session_data* sd = (struct char_session_data*)session[fd]->session_data;
+ mmo_char_send099d(fd, sd);
+ }
+#endif
+
WFIFOHEAD(fd,10);
WFIFOW(fd,0) = 0x82a;
WFIFOL(fd,2) = char_id;
@@ -3559,7 +3945,7 @@ void char_delete2_cancel_ack(int fd, int char_id, uint32 result)
static void char_delete2_req(int fd, struct char_session_data* sd)
{// CH: <0827>.W <char id>.L
- int char_id, i;
+ int char_id, party_id, guild_id, i;
char* data;
time_t delete_date;
@@ -3586,22 +3972,34 @@ static void char_delete2_req(int fd, struct char_session_data* sd)
return;
}
-/*
- // Aegis imposes these checks probably to avoid dead member
- // entries in guilds/parties, otherwise they are not required.
- // TODO: Figure out how these are enforced during waiting.
- if( guild_id )
- {// character in guild
- char_delete2_ack(fd, char_id, 4, 0);
- return;
- }
+ // This check is imposed by Aegis to avoid dead entries in databases
+ // _it is not needed_ as we clear data properly
+ // see issue: 7338
+ if( char_aegis_delete )
+ {
+ if( SQL_SUCCESS != SQL->Query(sql_handle, "SELECT `party_id`, `guild_id` FROM `%s` WHERE `char_id`='%d'", char_db, char_id)
+ || SQL_SUCCESS != SQL->NextRow(sql_handle)
+ )
+ {
+ Sql_ShowDebug(sql_handle);
+ char_delete2_ack(fd, char_id, 3, 0);
+ return;
+ }
+ SQL->GetData(sql_handle, 0, &data, NULL); party_id = atoi(data);
+ SQL->GetData(sql_handle, 1, &data, NULL); guild_id = atoi(data);
- if( party_id )
- {// character in party
- char_delete2_ack(fd, char_id, 5, 0);
- return;
+ if( guild_id )
+ {
+ char_delete2_ack(fd, char_id, 4, 0);
+ return;
+ }
+
+ if( party_id )
+ {
+ char_delete2_ack(fd, char_id, 5, 0);
+ return;
+ }
}
-*/
// success
delete_date = time(NULL)+char_del_delay;
@@ -3620,7 +4018,7 @@ static void char_delete2_req(int fd, struct char_session_data* sd)
static void char_delete2_accept(int fd, struct char_session_data* sd)
{// CH: <0829>.W <char id>.L <birth date:YYMMDD>.6B
char birthdate[8+1];
- int char_id, i, k;
+ int char_id, i;
unsigned int base_level;
char* data;
time_t delete_date;
@@ -3683,11 +4081,8 @@ static void char_delete2_accept(int fd, struct char_session_data* sd)
}
// refresh character list cache
- for(k = i; k < MAX_CHARS-1; k++) {
- sd->found_char[k] = sd->found_char[k+1];
- }
- sd->found_char[MAX_CHARS-1] = -1;
-
+ sd->found_char[i] = -1;
+
char_delete2_accept_ack(fd, char_id, 1);
}
@@ -3721,7 +4116,6 @@ static void char_delete2_cancel(int fd, struct char_session_data* sd)
int parse_char(int fd)
{
- int i, ch;
char email[40];
unsigned short cmd;
int map_fd;
@@ -3750,8 +4144,14 @@ int parse_char(int fd)
while( RFIFOREST(fd) >= 2 ) {
//For use in packets that depend on an sd being present [Skotlex]
- #define FIFOSD_CHECK(rest) { if(RFIFOREST(fd) < rest) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,rest); return 0; } }
+ #define FIFOSD_CHECK(rest) do { if(RFIFOREST(fd) < (rest)) return 0; if (sd==NULL || !sd->auth) { RFIFOSKIP(fd,(rest)); return 0; } } while (0)
+ if( HPM->packetsc[hpParse_Char] ) {
+ int success = HPM->parse_packets(fd,hpParse_Char);
+ if( success == 1 ) continue;
+ else if( success == 2 ) return 0;
+ }
+
cmd = RFIFOW(fd,0);
switch( cmd ) {
@@ -3773,7 +4173,7 @@ int parse_char(int fd)
ShowInfo("request connect - account_id:%d/login_id1:%d/login_id2:%d\n", account_id, login_id1, login_id2);
if (sd) {
- //Received again auth packet for already authentified account?? Discard it.
+ //Received again auth packet for already authenticated account?? Discard it.
//TODO: Perhaps log this as a hack attempt?
//TODO: and perhaps send back a reply?
break;
@@ -3792,8 +4192,7 @@ int parse_char(int fd)
WFIFOL(fd,0) = account_id;
WFIFOSET(fd,4);
- if( runflag != CHARSERVER_ST_RUNNING )
- {
+ if( runflag != CHARSERVER_ST_RUNNING ) {
WFIFOHEAD(fd,3);
WFIFOW(fd,0) = 0x6c;
WFIFOB(fd,2) = 0;// rejected from server
@@ -3801,7 +4200,7 @@ int parse_char(int fd)
break;
}
- // search authentification
+ // search authentication
node = (struct auth_node*)idb_get(auth_db, account_id);
if( node != NULL &&
node->account_id == account_id &&
@@ -3809,6 +4208,22 @@ int parse_char(int fd)
node->login_id2 == login_id2 /*&&
node->ip == ipl*/ )
{// authentication found (coming from map server)
+ /* restrictions apply */
+ if( char_server_type == CST_MAINTENANCE && node->group_id < char_maintenance_min_group_id ) {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;// rejected from server
+ WFIFOSET(fd,3);
+ break;
+ }
+ /* the client will already deny this request, this check is to avoid someone bypassing. */
+ if( char_server_type == CST_PAYING && (time_t)node->expiration_time < time(NULL) ) {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0;// rejected from server
+ WFIFOSET(fd,3);
+ break;
+ }
idb_remove(auth_db, account_id);
char_auth_ok(fd, sd);
}
@@ -3816,7 +4231,7 @@ int parse_char(int fd)
{// authentication not found (coming from login server)
if (login_fd > 0) { // don't send request if no login-server
WFIFOHEAD(login_fd,23);
- WFIFOW(login_fd,0) = 0x2712; // ask login-server to authentify an account
+ WFIFOW(login_fd,0) = 0x2712; // ask login-server to authenticate an account
WFIFOL(login_fd,2) = sd->account_id;
WFIFOL(login_fd,6) = sd->login_id1;
WFIFOL(login_fd,10) = sd->login_id2;
@@ -3844,12 +4259,15 @@ int parse_char(int fd)
int char_id;
uint32 subnet_map_ip;
struct auth_node* node;
+ int server_id = 0;
+ int i;
int slot = RFIFOB(fd,2);
RFIFOSKIP(fd,3);
+
#if PACKETVER >= 20110309
if( *pincode->enabled ){ // hack check
- struct online_char_data* character;
+ struct online_char_data* character;
character = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
if( character && character->pincode_enable == -1){
WFIFOHEAD(fd,3);
@@ -3860,6 +4278,19 @@ int parse_char(int fd)
}
}
#endif
+
+ ARR_FIND( 0, ARRAYLENGTH(server), server_id, server[server_id].fd > 0 && server[server_id].map[0] );
+ /* not available, tell it to wait (client wont close; char select will respawn).
+ * magic response found by Ind thanks to Yommy <3 */
+ if( server_id == ARRAYLENGTH(server) ) {
+ WFIFOHEAD(fd, 24);
+ WFIFOW(fd, 0) = 0x840;
+ WFIFOW(fd, 2) = 24;
+ safestrncpy((char*)WFIFOP(fd,4), "0", 20);/* we can't send empty (otherwise the list will pop up) */
+ WFIFOSET(fd, 24);
+ break;
+ }
+
if ( SQL_SUCCESS != SQL->Query(sql_handle, "SELECT `char_id` FROM `%s` WHERE `account_id`='%d' AND `char_num`='%d'", char_db, sd->account_id, slot)
|| SQL_SUCCESS != SQL->NextRow(sql_handle)
|| SQL_SUCCESS != SQL->GetData(sql_handle, 0, &data, NULL) )
@@ -3876,7 +4307,16 @@ int parse_char(int fd)
char_id = atoi(data);
SQL->FreeResult(sql_handle);
- /* set char as online prior to loading its data so 3rd party applications will realise the sql data is not reliable */
+ /* client doesn't let it get to this point if you're banned, so its a forged packet */
+ if( sd->found_char[slot] == char_id && sd->unban_time[slot] > time(NULL) ) {
+ WFIFOHEAD(fd,3);
+ WFIFOW(fd,0) = 0x6c;
+ WFIFOB(fd,2) = 0; // rejected from server
+ WFIFOSET(fd,3);
+ break;
+ }
+
+ /* set char as online prior to loading its data so 3rd party applications will realize the sql data is not reliable */
set_char_online(-2,char_id,sd->account_id);
if( !mmo_char_fromsql(char_id, &char_dat, true) ) { /* failed? set it back offline */
set_char_offline(char_id, sd->account_id);
@@ -3894,10 +4334,11 @@ int parse_char(int fd)
if (log_char) {
char esc_name[NAME_LENGTH*2+1];
-
+ // FIXME: Why are we re-escaping the name if it was already escaped in rename/make_new_char? [Panikon]
SQL->EscapeStringLen(sql_handle, esc_name, char_dat.name, strnlen(char_dat.name, NAME_LENGTH));
- if( SQL_ERROR == SQL->Query(sql_handle, "INSERT INTO `%s`(`time`, `account_id`,`char_num`,`name`) VALUES (NOW(), '%d', '%d', '%s')",
- charlog_db, sd->account_id, slot, esc_name) )
+ if( SQL_ERROR == SQL->Query(sql_handle,
+ "INSERT INTO `%s`(`time`, `account_id`, `char_id`, `char_num`, `name`) VALUES (NOW(), '%d', '%d', '%d', '%s')",
+ charlog_db, sd->account_id, cd->char_id, slot, esc_name) )
Sql_ShowDebug(sql_handle);
}
ShowInfo("Selected char: (Account %d: %d - %s)\n", sd->account_id, slot, char_dat.name);
@@ -3918,22 +4359,22 @@ int parse_char(int fd)
WFIFOSET(fd,3);
break;
}
- if ((i = search_mapserver((j=mapindex_name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
+ if ((i = search_mapserver((j=mapindex->name2id(MAP_PRONTERA)),-1,-1)) >= 0) {
cd->last_point.x = 273;
cd->last_point.y = 354;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
+ } else if ((i = search_mapserver((j=mapindex->name2id(MAP_GEFFEN)),-1,-1)) >= 0) {
cd->last_point.x = 120;
cd->last_point.y = 100;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_MORROC)),-1,-1)) >= 0) {
+ } else if ((i = search_mapserver((j=mapindex->name2id(MAP_MORROC)),-1,-1)) >= 0) {
cd->last_point.x = 160;
cd->last_point.y = 94;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
+ } else if ((i = search_mapserver((j=mapindex->name2id(MAP_ALBERTA)),-1,-1)) >= 0) {
cd->last_point.x = 116;
cd->last_point.y = 57;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_PAYON)),-1,-1)) >= 0) {
+ } else if ((i = search_mapserver((j=mapindex->name2id(MAP_PAYON)),-1,-1)) >= 0) {
cd->last_point.x = 87;
cd->last_point.y = 117;
- } else if ((i = search_mapserver((j=mapindex_name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
+ } else if ((i = search_mapserver((j=mapindex->name2id(MAP_IZLUDE)),-1,-1)) >= 0) {
cd->last_point.x = 94;
cd->last_point.y = 103;
} else {
@@ -3967,7 +4408,7 @@ int parse_char(int fd)
WFIFOHEAD(fd,28);
WFIFOW(fd,0) = 0x71;
WFIFOL(fd,2) = cd->char_id;
- mapindex_getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
+ mapindex->getmapname_ext(mapindex_id2name(cd->last_point.map), (char*)WFIFOP(fd,6));
subnet_map_ip = lan_subnetcheck(ipl); // Advanced subnet check [LuzZza]
WFIFOL(fd,22) = htonl((subnet_map_ip) ? subnet_map_ip : server[i].ip);
WFIFOW(fd,26) = ntows(htons(server[i].port)); // [!] LE byte order here [!]
@@ -3992,41 +4433,51 @@ int parse_char(int fd)
#if PACKETVER >= 20120307
// S 0970 <name>.24B <slot>.B <hair color>.W <hair style>.W
case 0x970:
+ {
+ int result;
FIFOSD_CHECK(31);
#else
// S 0067 <name>.24B <str>.B <agi>.B <vit>.B <int>.B <dex>.B <luk>.B <slot>.B <hair color>.W <hair style>.W
case 0x67:
+ {
+ int result;
FIFOSD_CHECK(37);
#endif
if( !char_new ) //turn character creation on/off [Kevin]
- i = -2;
+ result = -2;
else
#if PACKETVER >= 20120307
- i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
+ result = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOW(fd,27),RFIFOW(fd,29));
#else
- i = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35));
+ result = make_new_char_sql(sd, (char*)RFIFOP(fd,2),RFIFOB(fd,26),RFIFOB(fd,27),RFIFOB(fd,28),RFIFOB(fd,29),RFIFOB(fd,30),RFIFOB(fd,31),RFIFOB(fd,32),RFIFOW(fd,33),RFIFOW(fd,35));
#endif
- //'Charname already exists' (-1), 'Char creation denied' (-2) and 'You are underaged' (-3)
- if (i < 0) {
+ if (result < 0) {
WFIFOHEAD(fd,3);
WFIFOW(fd,0) = 0x6e;
/* Others I found [Ind] */
/* 0x02 = Symbols in Character Names are forbidden */
- /* 0x03 = You are not elegible to open the Character Slot. */
- switch (i) {
- case -1: WFIFOB(fd,2) = 0x00; break;
- case -2: WFIFOB(fd,2) = 0xFF; break;
- case -3: WFIFOB(fd,2) = 0x01; break;
- case -4: WFIFOB(fd,2) = 0x03; break;
+ /* 0x03 = You are not eligible to open the Character Slot. */
+ /* 0x0B = This service is only available for premium users. */
+ switch (result) {
+ case -1: WFIFOB(fd,2) = 0x00; break; // 'Charname already exists'
+ case -2: WFIFOB(fd,2) = 0xFF; break; // 'Char creation denied'
+ case -3: WFIFOB(fd,2) = 0x01; break; // 'You are underaged'
+ case -4: WFIFOB(fd,2) = 0x03; break; // 'You are not eligible to open the Character Slot.'
+ case -5: WFIFOB(fd,2) = 0x02; break; // 'Symbols in Character Names are forbidden'
+
+ default:
+ ShowWarning("parse_char: Unknown result received from make_new_char_sql!\n");
+ WFIFOB(fd,2) = 0xFF;
+ break;
}
WFIFOSET(fd,3);
} else {
int len;
// retrieve data
struct mmo_charstatus char_dat;
- mmo_char_fromsql(i, &char_dat, false); //Only the short data is needed.
+ mmo_char_fromsql(result, &char_dat, false); //Only the short data is needed.
// send to player
WFIFOHEAD(fd,2+MAX_CHAR_BUF);
@@ -4035,15 +4486,14 @@ int parse_char(int fd)
WFIFOSET(fd,len);
// add new entry to the chars list
- ARR_FIND( 0, MAX_CHARS, ch, sd->found_char[ch] == -1 );
- if( ch < MAX_CHARS )
- sd->found_char[ch] = i; // the char_id of the new char
+ sd->found_char[char_dat.slot] = result; // the char_id of the new char
}
#if PACKETVER >= 20120307
RFIFOSKIP(fd,31);
#else
RFIFOSKIP(fd,37);
#endif
+ }
break;
// delete char
@@ -4054,9 +4504,10 @@ int parse_char(int fd)
if (cmd == 0x1fb) FIFOSD_CHECK(56);
{
int cid = RFIFOL(fd,2);
+ int i;
#if PACKETVER >= 20110309
if( *pincode->enabled ){ // hack check
- struct online_char_data* character;
+ struct online_char_data* character;
character = (struct online_char_data*)idb_get(online_char_db, sd->account_id);
if( character && character->pincode_enable == -1 ){
WFIFOHEAD(fd,3);
@@ -4096,9 +4547,7 @@ int parse_char(int fd)
}
// remove char from list and compact it
- for(ch = i; ch < MAX_CHARS-1; ch++)
- sd->found_char[ch] = sd->found_char[ch+1];
- sd->found_char[MAX_CHARS-1] = -1;
+ sd->found_char[i] = -1;
/* Delete character */
if(delete_char_sql(cid)<0){
@@ -4191,7 +4640,7 @@ int parse_char(int fd)
//Confirm change name.
// 0x28f <char_id>.L
case 0x28f:
- // 0: Sucessfull
+ // 0: Successful
// 1: This character's name has already been changed. You cannot change a character's name more than once.
// 2: User information is not correct.
// 3: You have failed to change this character's name.
@@ -4264,6 +4713,7 @@ int parse_char(int fd)
{
char* l_user = (char*)RFIFOP(fd,2);
char* l_pass = (char*)RFIFOP(fd,26);
+ int i;
l_user[23] = '\0';
l_pass[23] = '\0';
ARR_FIND( 0, ARRAYLENGTH(server), i, server[i].fd <= 0 );
@@ -4291,11 +4741,11 @@ int parse_char(int fd)
realloc_fifo(fd, FIFOSIZE_SERVERLINK, FIFOSIZE_SERVERLINK);
char_mapif_init(fd);
}
- socket_datasync(fd, true);
+ sockt->datasync(fd, true);
RFIFOSKIP(fd,60);
}
- return 0; // avoid processing of followup packets here
+ return 0; // avoid processing of follow-up packets here
// checks the entered pin
case 0x8b8:
@@ -4426,8 +4876,7 @@ int mapif_send(int fd, unsigned char *buf, unsigned int len)
return 0;
}
-int broadcast_user_count(int tid, unsigned int tick, int id, intptr_t data)
-{
+int broadcast_user_count(int tid, int64 tick, int id, intptr_t data) {
uint8 buf[6];
int users = count_users();
@@ -4472,8 +4921,7 @@ static int send_accounts_tologin_sub(DBKey key, DBData *data, va_list ap)
return 0;
}
-int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data)
-{
+int send_accounts_tologin(int tid, int64 tick, int id, intptr_t data) {
if (login_fd > 0 && session[login_fd])
{
// send account list to login server
@@ -4490,8 +4938,7 @@ int send_accounts_tologin(int tid, unsigned int tick, int id, intptr_t data)
return 0;
}
-int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data)
-{
+int check_connect_login_server(int tid, int64 tick, int id, intptr_t data) {
if (login_fd > 0 && session[login_fd] != NULL)
return 0;
@@ -4515,7 +4962,7 @@ int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data
WFIFOW(login_fd,58) = htons(char_port);
memcpy(WFIFOP(login_fd,60), server_name, 20);
WFIFOW(login_fd,80) = 0;
- WFIFOW(login_fd,82) = char_maintenance;
+ WFIFOW(login_fd,82) = char_server_type;
WFIFOW(login_fd,84) = char_new_display; //only display (New) if they want to [Kevin]
WFIFOSET(login_fd,86);
@@ -4526,8 +4973,7 @@ int check_connect_login_server(int tid, unsigned int tick, int id, intptr_t data
//Invoked 15 seconds after mapif_disconnectplayer in case the map server doesn't
//replies/disconnect the player we tried to kick. [Skotlex]
//------------------------------------------------
-static int chardb_waiting_disconnect(int tid, unsigned int tick, int id, intptr_t data)
-{
+static int chardb_waiting_disconnect(int tid, int64 tick, int id, intptr_t data) {
struct online_char_data* character;
if ((character = (struct online_char_data*)idb_get(online_char_db, id)) != NULL && character->waiting_disconnect == tid)
{ //Mark it offline due to timeout.
@@ -4553,15 +4999,14 @@ static int online_data_cleanup_sub(DBKey key, DBData *data, va_list ap)
return 0;
}
-static int online_data_cleanup(int tid, unsigned int tick, int id, intptr_t data)
-{
+static int online_data_cleanup(int tid, int64 tick, int id, intptr_t data) {
online_char_db->foreach(online_char_db, online_data_cleanup_sub);
return 0;
}
//----------------------------------
-// Reading Lan Support configuration
-// Rewrote: Anvanced subnet check [LuzZza]
+// Reading LAN Support configuration
+// Rewrote: Advanced subnet check [LuzZza]
//----------------------------------
int char_lan_config_read(const char *lancfgName)
{
@@ -4579,7 +5024,7 @@ int char_lan_config_read(const char *lancfgName)
if ((line[0] == '/' && line[1] == '/') || line[0] == '\n' || line[1] == '\n')
continue;
- if(sscanf(line,"%[^:]: %[^:]:%[^:]:%[^\r\n]", w1, w2, w3, w4) != 4) {
+ if (sscanf(line,"%63[^:]: %63[^:]:%63[^:]:%63[^\r\n]", w1, w2, w3, w4) != 4) {
ShowWarning("Error syntax of configuration file %s in line %d.\n", lancfgName, line_num);
continue;
@@ -4628,7 +5073,7 @@ void sql_config_read(const char* cfgName)
if(line[0] == '/' && line[1] == '/')
continue;
- if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
+ if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2)
continue;
if(!strcmpi(w1,"char_db"))
@@ -4643,8 +5088,6 @@ void sql_config_read(const char* cfgName)
safestrncpy(charlog_db, w2, sizeof(charlog_db));
else if(!strcmpi(w1,"storage_db"))
safestrncpy(storage_db, w2, sizeof(storage_db));
- else if(!strcmpi(w1,"reg_db"))
- safestrncpy(reg_db, w2, sizeof(reg_db));
else if(!strcmpi(w1,"skill_db"))
safestrncpy(skill_db, w2, sizeof(skill_db));
else if(!strcmpi(w1,"interlog_db"))
@@ -4691,8 +5134,21 @@ void sql_config_read(const char* cfgName)
safestrncpy(mercenary_owner_db,w2,sizeof(mercenary_owner_db));
else if(!strcmpi(w1,"ragsrvinfo_db"))
safestrncpy(ragsrvinfo_db,w2,sizeof(ragsrvinfo_db));
+ else if(!strcmpi(w1,"elemental_db"))
+ safestrncpy(elemental_db,w2,sizeof(elemental_db));
else if(!strcmpi(w1,"interreg_db"))
safestrncpy(interreg_db,w2,sizeof(interreg_db));
+ else if(!strcmpi(w1,"account_data_db"))
+ safestrncpy(account_data_db,w2,sizeof(account_data_db));
+ else if(!strcmpi(w1,"char_reg_num_db"))
+ safestrncpy(char_reg_num_db, w2, sizeof(char_reg_num_db));
+ else if(!strcmpi(w1,"char_reg_str_db"))
+ safestrncpy(char_reg_str_db, w2, sizeof(char_reg_str_db));
+ else if(!strcmpi(w1,"acc_reg_str_db"))
+ safestrncpy(acc_reg_str_db, w2, sizeof(acc_reg_str_db));
+ else if(!strcmpi(w1,"acc_reg_num_db"))
+ safestrncpy(acc_reg_num_db, w2, sizeof(acc_reg_num_db));
+
//support the import command, just like any other config
else if(!strcmpi(w1,"import"))
sql_config_read(w2);
@@ -4725,7 +5181,7 @@ int char_config_read(const char* cfgName)
if (line[0] == '/' && line[1] == '/')
continue;
- if (sscanf(line, "%[^:]: %[^\r\n]", w1, w2) != 2)
+ if (sscanf(line, "%1023[^:]: %1023[^\r\n]", w1, w2) != 2)
continue;
remove_control_chars(w1);
@@ -4773,8 +5229,8 @@ int char_config_read(const char* cfgName)
}
} else if (strcmpi(w1, "char_port") == 0) {
char_port = atoi(w2);
- } else if (strcmpi(w1, "char_maintenance") == 0) {
- char_maintenance = atoi(w2);
+ } else if (strcmpi(w1, "char_server_type") == 0) {
+ char_server_type = atoi(w2);
} else if (strcmpi(w1, "char_new") == 0) {
char_new = (bool)atoi(w2);
} else if (strcmpi(w1, "char_new_display") == 0) {
@@ -4796,7 +5252,7 @@ int char_config_read(const char* cfgName)
int x, y;
if (sscanf(w2, "%15[^,],%d,%d", map, &x, &y) < 3)
continue;
- start_point.map = mapindex_name2id(map);
+ start_point.map = mapindex->name2id(map);
if (!start_point.map)
ShowError("Specified start_point %s not found in map-index cache.\n", map);
start_point.x = x;
@@ -4807,18 +5263,25 @@ int char_config_read(const char* cfgName)
i = 0;
split = strtok(w2, ",");
- while (split != NULL && i < MAX_START_ITEMS*2) {
+ while (split != NULL && i < MAX_START_ITEMS*3) {
split2 = split;
split = strtok(NULL, ",");
start_items[i] = atoi(split2);
+
if (start_items[i] < 0)
start_items[i] = 0;
+
++i;
}
- if (i%2) { //we know it must be a even number
- ShowError("Specified 'start_items' is missing a parameter. Removing '%d'.\n", start_items[i - 1]);
- start_items[i - 1] = 0;
+ // Format is: id1,quantity1,stackable1,idN,quantityN,stackableN
+ if( i%3 )
+ {
+ ShowWarning("char_config_read: There are not enough parameters in start_items, ignoring last item...\n");
+ if( i%3 == 1 )
+ start_items[i-1] = 0;
+ else
+ start_items[i-2] = 0;
}
} else if (strcmpi(w1, "start_zeny") == 0) {
start_zeny = atoi(w2);
@@ -4839,6 +5302,8 @@ int char_config_read(const char* cfgName)
char_del_level = atoi(w2);
} else if (strcmpi(w1, "char_del_delay") == 0) {
char_del_delay = atoi(w2);
+ } else if (strcmpi(w1, "char_aegis_delete") == 0) {
+ char_aegis_delete = atoi(w2);
} else if(strcmpi(w1,"db_path")==0) {
safestrncpy(db_path, w2, sizeof(db_path));
} else if (strcmpi(w1, "fame_list_alchemist") == 0) {
@@ -4861,6 +5326,8 @@ int char_config_read(const char* cfgName)
}
} else if (strcmpi(w1, "guild_exp_rate") == 0) {
guild_exp_rate = atoi(w2);
+ } else if (strcmpi(w1, "char_maintenance_min_group_id") == 0) {
+ char_maintenance_min_group_id = atoi(w2);
} else if (strcmpi(w1, "import") == 0) {
char_config_read(w2);
} else
@@ -4872,10 +5339,13 @@ int char_config_read(const char* cfgName)
return 0;
}
-void do_final(void) {
+int do_final(void) {
int i;
+
ShowStatus("Terminating...\n");
+ HPM->event(HPET_FINAL);
+
set_all_offline(-1);
set_all_offline_sql();
@@ -4899,13 +5369,14 @@ void do_final(void) {
}
SQL->Free(sql_handle);
- mapindex_final();
+ mapindex->final();
for(i = 0; i < MAX_MAP_SERVERS; i++ )
if( server[i].map )
aFree(server[i].map);
ShowStatus("Finished.\n");
+ return EXIT_SUCCESS;
}
//------------------------------
@@ -4946,13 +5417,13 @@ int do_init(int argc, char **argv) {
for(i = 0; i < MAX_MAP_SERVERS; i++ )
server[i].map = NULL;
- //Read map indexes
- mapindex_init();
- start_point.map = mapindex_name2id("new_zone01");
-
-
+ mapindex_defaults();
pincode_defaults();
+ //Read map indexes
+ mapindex->init();
+ start_point.map = mapindex->name2id("new_zone01");
+
char_config_read((argc < 2) ? CHAR_CONF_NAME : argv[1]);
char_lan_config_read((argc > 3) ? argv[3] : LAN_CONF_NAME);
sql_config_read(SQL_CONF_NAME);
@@ -4967,14 +5438,19 @@ int do_init(int argc, char **argv) {
auth_db = idb_alloc(DB_OPT_RELEASE_DATA);
online_char_db = idb_alloc(DB_OPT_RELEASE_DATA);
+
+ HPM->share(sql_handle,"sql_handle");
+ HPM->config_read(NULL, 0);
+ HPM->event(HPET_INIT);
+
mmo_char_sql_init();
char_read_fame_list(); //Read fame lists.
- if ((naddr_ != 0) && (!login_ip || !char_ip)) {
+ if ((sockt->naddr_ != 0) && (!login_ip || !char_ip)) {
char ip_str[16];
- ip2str(addr_[0], ip_str);
+ ip2str(sockt->addr_[0], ip_str);
- if (naddr_ > 1)
+ if (sockt->naddr_ > 1)
ShowStatus("Multiple interfaces detected.. using %s as our IP address\n", ip_str);
else
ShowStatus("Defaulting to %s as our IP address\n", ip_str);
@@ -4992,17 +5468,17 @@ int do_init(int argc, char **argv) {
do_init_mapif();
// periodically update the overall user count on all mapservers + login server
- iTimer->add_timer_func_list(broadcast_user_count, "broadcast_user_count");
- iTimer->add_timer_interval(iTimer->gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000);
+ timer->add_func_list(broadcast_user_count, "broadcast_user_count");
+ timer->add_interval(timer->gettick() + 1000, broadcast_user_count, 0, 0, 5 * 1000);
// Timer to clear (online_char_db)
- iTimer->add_timer_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect");
+ timer->add_func_list(chardb_waiting_disconnect, "chardb_waiting_disconnect");
// Online Data timers (checking if char still connected)
- iTimer->add_timer_func_list(online_data_cleanup, "online_data_cleanup");
- iTimer->add_timer_interval(iTimer->gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000);
+ timer->add_func_list(online_data_cleanup, "online_data_cleanup");
+ timer->add_interval(timer->gettick() + 1000, online_data_cleanup, 0, 0, 600 * 1000);
- //Cleaning the tables for NULL entrys @ startup [Sirius]
+ //Cleaning the tables for NULL entries @ startup [Sirius]
//Chardb clean
if( SQL_ERROR == SQL->Query(sql_handle, "DELETE FROM `%s` WHERE `account_id` = '0'", char_db) )
Sql_ShowDebug(sql_handle);
@@ -5023,7 +5499,9 @@ int do_init(int argc, char **argv) {
}
Sql_HerculesUpdateCheck(sql_handle);
-
+#ifdef CONSOLE_INPUT
+ console->input->setSQL(sql_handle);
+#endif
ShowStatus("The char-server is "CL_GREEN"ready"CL_RESET" (Server is listening on the port %d).\n\n", char_port);
if( runflag != CORE_ST_STOP )
@@ -5032,5 +5510,7 @@ int do_init(int argc, char **argv) {
runflag = CHARSERVER_ST_RUNNING;
}
+ HPM->event(HPET_READY);
+
return 0;
}